1
0
Fork 0
mirror of https://github.com/Reuh/candran.git synced 2025-10-27 09:59:29 +00:00
a simple Lua dialect
Find a file
Reuh 025a55f708 Fixed assignemnt operators priority bug
accidentaly added AST dumping to canc in the process
2017-08-24 17:32:20 +02:00
bin Fixed assignemnt operators priority bug 2017-08-24 17:32:20 +02:00
compiler Fixed assignemnt operators priority bug 2017-08-24 17:32:20 +02:00
lib Added let and continue 2017-08-23 14:06:34 +02:00
rockspec Added let and continue 2017-08-23 14:06:34 +02:00
test Fixed assignemnt operators priority bug 2017-08-24 17:32:20 +02:00
candran.can don't add line mappin comments ad infinitum 2017-08-23 19:22:18 +02:00
candran.lua Fixed assignemnt operators priority bug 2017-08-24 17:32:20 +02:00
ideas.txt Added let and continue 2017-08-23 14:06:34 +02:00
LICENSE Added let and continue 2017-08-23 14:06:34 +02:00
README.md Fixed assignemnt operators priority bug 2017-08-24 17:32:20 +02:00

Candran

Candran is a dialect of the Lua 5.3 programming language which compiles to Lua 5.3 and Lua 5.1/LuaJit. It adds a preprocessor and several useful syntax additions.

Unlike Moonscript, Candran tries to stay close to the Lua syntax.

#import("lib.thing")
#local debug or= false

local function calculate(toadd=25)
	local result = thing.do()
	result += toadd
    #if debug then
        print("Did something")
    #end
	return result
end

local a = {
	hey = true,

	newHop = :(foo, thing)
		@hey = thing(foo)
	end
}

a:newHop(42, (foo)
	return "something " .. foo
end)

Candran is released under the MIT License (see LICENSE for details).

Quick setup

Install Candran automatically using LuaRocks: sudo luarocks install rockspec/candran-0.4.0-1.rockspec.

Or manually install LPegLabel (luarocks install LPegLabel), download this repository and use Candran through the scripts in bin/ or use it as a library with the self-contained candran.lua.

Editor support

Most editors should be able to use their existing Lua support for Candran code. If you want full support for the additional syntax in your editor:

The language

Preprocessor

Before compiling, Candran's preprocessor is run. It execute every line starting with a # (ignoring whitespace) as Candran code. For example,

#if lang == "fr" then
	print("Bonjour")
#else
	print("Hello")
#end

Will output print("Bonjour") or print("Hello") depending of the "lang" argument passed to the preprocessor.

The preprocessor has access to the following variables :

  • candran : the Candran library table.
  • output : the current preprocessor output string.
  • import(module[, [options]) : a function which import a module. This should be equivalent to using require(module) in the Candran code, except the module will be embedded in the current file. options is an optional preprocessor arguments table for the imported module (current preprocessor arguments will be inherited). Options specific to this function: loadLocal (default true): true to automatically load the module into a local variable (i.e. local thing = require("module.thing")); loadPackage (default true): true to automatically load the module into the loaded packages table (so it will be available for following require("module") calls).
  • include(filename) : a function which copy the contents of the file filename to the output.
  • write(...) : write to the preprocessor output. For example, #print("hello()") will output hello() in the final file.
  • placeholder(name) : if the variable name is defined in the preprocessor environement, its content will be inserted here.
  • ... : each arguments passed to the preprocessor is directly available.
  • and every standard Lua library.

Syntax additions

After the preprocessor is run the Candran code is compiled to Lua. The Candran code adds the folowing syntax to Lua :

Assignment operators
  • var += nb
  • var -= nb
  • var *= nb
  • var /= nb
  • var //= nb
  • var ^= nb
  • var %= nb
  • var ..= str
  • var and= str
  • var or= str
  • var &= nb
  • var |= nb
  • var <<= nb
  • var >>= nb

For example, a var += nb assignment will be compiled into var = var + nb.

All theses operators can also be put right of the assigment operator, in which case var =+ nb will be compiled into var = nb + var.

If you feel like writing hard to understand code, right and left operator can be used at the same time.

Default function parameters
function foo(bar = "default", other = thing.do())
    -- stuff
end

If an argument isn't provided or nil when the function is called, it will be automatically set to a default value.

It is equivalent to doing if arg == nil then arg = default end for each argument at the start of the function.

The default values can be complete Lua expressions, and will be evaluated each time the function is run.

@ self aliases
a = {
	foo = "Hoi"
}

function a:hey()
	print(@foo) -- Hoi
	print(@["foo"]) -- also works
	print(@ == self) -- true
end

When a variable name is prefied with @, the name will be accessed in self.

When used by itself, @ is an alias for self.

Short anonymous function declaration
a = (arg1, arg2)
	print(arg1)
end

b = :(hop)
	print(self, hop)
end

Anonymous function (functions values) can be created in a more concise way by omitting the function keyword.

A : can prefix the parameters paranthesis to automatically add a self parameter.

let variable declaration
let a = {
	foo = function()
		print(type(a)) -- table
	end
}

Similar to local, but the variable will be declared before the assignemnt (i.e. it will compile into local a; a = value), so you can access it from functions defined in the value.

Can also be used as a shorter name for local.

continue keyword
for i=1, 10 do
	if i % 2 == 0 then
		continue
	end
	print(i) -- 1, 3, 5, 7, 9
end

Will skip the current loop iteration.

Compile targets

Candran is based on the Lua 5.3 syntax, but can be compiled to both Lua 5.3 and Lua 5.1/LuaJit.

To chose a compile target, set the target option to lua53 (default) or luajit in the option table when using the library or the command line tools.

Lua 5.3 specific syntax (bitwise operators, integer division) will automatically be translated in valid Lua 5.1 code, using LuaJIT's bit library if necessary.

The library

Command-line usage

The library can be used standalone through the canc and can utility:

  • canc

    Display the information text (version and basic command-line usage).

  • canc [options] filename...

    Preprocess and compile each filename Candran files, and creates the assiociated .lua files in the same directories.

    options is of type -somearg -anotherarg thing=somestring other=5 ..., which will generate a Lua table { somearg = true, anotherarg = true, thing = "somestring", other = 5 }.

    You can choose to use another directory where files should be written using the dest=destinationDirectory argument.

    canc can write to the standard output instead of creating files using the -print argument.

    You can choosed to run only the preprocessor or compile using the -preprocess and -compile flags.

    The -ast flag is also available for debugging, and will disable preprocessing, compiling and file writing, and instead directly dump the AST generated from the input file(s) to stdout.

    • example uses :

      canc foo.can

      preprocess and compile foo.can and write the result in foo.lua.

      canc foo.can -verbose -print | lua

      preprocess foo.can with verbose set to true, compile it and execute it.

  • can

    Start a simplisitic Candran REPL.

  • canc [options] filename

    Preprocess, compile and run filename using the options provided.

    This will automatically register the Candran package searcher so required file will be compiled as they are needed.

    This command will use error rewriting if enabled.

Library usage

Candran can also be used as a Lua library. For example,

local candran = require("candran")

local f = io.open("foo.can")
local contents = f:read("*a")
f:close()

local compiled = candran.make(contents, { lang = "fr" })

load(compiled)()

-- or simpler...
candran.dofile("foo.can")

Will load Candran, read the file foo.can, compile its contents with the argument lang set to "fr", and then execute the result.

The table returned by require("candran") gives you access to :

Compiler & preprocessor API
  • candran.VERSION : Candran's version string.
  • candran.preprocess(code[, options]) : return the Candran code code, preprocessed with options as options table.
  • candran.compile(code[, options]) : return the Candran code compiled to Lua with options as the option table.
  • candran.make(code[, options]) : return the Candran code, preprocessed and compiled with options as options table.
Code loading helpers
  • candran.loadfile(filepath, env, options) : Candran equivalent to the Lua 5.3's loadfile funtion. Will rewrite errors by default.
  • candran.load(chunk, chunkname, env, options) : Candran equivalent to the Lua 5.3's load funtion. Will rewrite errors by default.
  • candran.dofile(filepath, options) : Candran equivalent to the Lua 5.3's dofile funtion. Will rewrite errors by default.

Error rewriting

When using the command-line tools or the code loading helpers, Candran will automatically setup error rewriting: because the code is reformated when compiled and preprocessed, lines numbers given by Lua in case of error are hardly usable. To fix that, Candran map each line from the compiled file to the lines from the original file(s), inspired by MoonScript. Errors will be displayed as:

example.can:12(5): attempt to call a nil value (global 'iWantAnError')

12 is the line number in the original Candran file, and 5 is the line number in the compiled file.

If you are using the preprocessor import() function, the source Candran file and destination Lua file might not have the same name. In this case, the error will be:

example.can:12(final.lua:5): attempt to call a nil value (global 'iWantAnError')
  • candran.messageHandler(message) : The error message handler used by Candran. Use it in xpcall to rewrite stacktraces to display Candran source file lines instead of compiled Lua lines.
Package searching helpers

Candran comes with a custom package searcher which will automatically find, preprocesses and compile .can files. If you want to use Candran in your project without worrying about compiling the files, you can simply call

require("candran").setup()

at the top of your main Lua file. If a Candran is found when you call require(), it will be automatically compiled and loaded. If both a Lua and Candran file match a module name, the Candran file will be loaded.

  • candran.searcher(modpath) : Candran package searcher function. Use the existing package.path.
  • candran.setup() : Register the Candran package searcher.
Available compiler & preprocessor options

You can give arbitrary options which will be gived to the preprocessor, but Candran already provide and uses these with their associated default values:

target = "lua53" -- Compiler target. "lua53" or "luajit".
indentation = "" -- Character(s) used for indentation in the compiled file.
newline = "\n" -- Character(s) used for newlines in the compiled file.
requirePrefix = "CANDRAN_" -- Prefix used when Candran needs to require an external library to provide some functionality (example: LuaJIT's bit lib when using bitwise operators).
mapLines = true -- If true, compiled files will contain comments at the end of each line indicating the associated line and source file. Needed for error rewriting.
chunkname = "nil" -- The chunkname used when running code using the helper functions and writing the line origin comments. Candran will try to set it to the original filename if it knows it.
rewriteErrors = true -- True to enable error rewriting when loading code using the helper functions. Will wrap the whole code in a xpcall().

There are also a few function-specific options available, see the associated functions documentation for more information.

Compiling the library

The Candran library itself is written is Candran, so you have to compile it with an already compiled Candran library.

The compiled candran.lua should include every Lua library needed to run it. You will still need to install LPegLabel.

This command will use the precompilled version of this repository (candran.lua) to compile candran.can and write the result in candran.lua :

canc candran.can

The Candran build included in this repository were made using the mapLines=false options.

You can then run the tests on your build :

cd tests
lua test.lua ../candran.lua