SkillAgentSearch skills...

Candran

a Lua dialect and simple preprocessor

Install / Use

/learn @Reuh/Candran
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Candran

Candran is a dialect of the Lua 5.5 programming language which compiles to Lua 5.5, Lua 5.4, Lua 5.3, Lua 5.2, LuaJIT and Lua 5.1 compatible code. It adds several useful syntax additions which aims to make Lua faster and easier to write, and a simple preprocessor.

Unlike Moonscript, Candran tries to stay close to the Lua syntax, and existing Lua code should be able to run on Candran unmodified.

#import("lib.thing") -- static import
#local DEBUG = false

#if DEBUG then
#	define("log(...)", "print(...)") -- macro: calls to log() will be replaced with print() in compiled code
#else
#	define("log(...)", "") -- remove calls to log from the compiled code when DEBUG is true
#end
log("example macro") -- preprocessor macros

local function calculate(toadd=25) -- default parameters
	local result = thing.do()
	result += toadd
	#if DEBUG then -- preprocessor conditionals
		print("Did something")
	#end
	return result
end

let a = {
	hey = 5 // 2, -- Lua 5.3+ syntax, that will be translated to work with the current Lua version

	child = nil,

	method = :(foo, thing) -- short function declaration, with self
		@hey = thing(foo) -- @ as an alias for self
	end,

	selfReference = () -- short function declaration, without self
		return a -- no need for a prior local declaration when using let
	end
}

const five = 5 -- shortcut for Lua 5.4 attributes 

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

local fn = a:method -- bundles an object and method in a function
fn(42, (foo)
	return "something" .. foo
end)

a.child?:method?() -- safe navigation operator

local {hey, method} = a -- destructuring assignment

local odd = [ -- table comprehension
	for i=1, 10 do
		if i%2 == 0 then
			continue -- continue keyword
		end
		i -- implicit push
	end
]

local count = [for i=1,10 i] -- single line statements

local a = if condition then "one" else "two" end -- statement as expressions

print("Hello %s":format("world")) -- methods calls on strings (and tables) literals without enclosing parentheses

if f, err = io.open("data") then -- if condition with assignments
	thing.process(f)
else
	error("can't open data: "..err)
end

Current status: Candran is stable ; I use it heavily used in several of my personal projects and maintain it. If there's no activity on the repo, it means there's no bug or new Lua version that requires an update.

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

Quick setup

Install Candran automatically using LuaRocks: sudo luarocks install candran.

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

You can optionally install lua-linenoise (luarocks install linenoise, version 0.9 or above) for an improved REPL, and luacheck (luarocks install luacheck, version 0.23.0 or above) to be able to use cancheck. Installing Candran using LuaRocks will install linenoise and luacheck by default.

You can register the Candran package searcher in your main Lua file (require("candran").setup()) and any subsequent require call in your project will automatically search for Candran modules.

If you use LÖVE, some integration with Candran is detailled here.

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:

For linting, if your editor support luacheck, you should be able to replace it with cancheck (in this repository bin/cancheck, or installed automatically if Candran was installed using LuaRocks), which is a wrapper around luacheck that monkey-patch it to support Candran.

The language

Syntax additions

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

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 assignment operator, in which case var =+ nb will be compiled into var = nb + var.

Right and left operator can be used at the same time.

Please note that the code a=-1 will be compiled into a = -1 and not a = a - 1, like in pure Lua. If you want the latter, spacing is required between the =- and the expression: a=- 1. Yes, this is also valid Lua code, but as far as I'm aware, nobody write code like this; people who really like spacing would write a= - 1 or a = - 1, and Candran will read both of those as it is expected in pure Lua. This is the only incompatibility between Candran and pure Lua.

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

If an argument isn't provided or set to nil when the function is called, it will automatically be set to its 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 any Lua expression, which will be evaluated in the function's scope each time the default value end up being used.

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 parenthesis to automatically add a self parameter.

@ 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.

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.

This does not support Lua 5.4 attributes.

Can also be used as a shorter name for local.

const and close variable declaration
const a = 5
close b = {}

const x, y, z = 1, 2, 3 -- every variable will be defined using <const>

Shortcut to Lua 5.4 variable attribute. Do not behave like let, as attributes require the variable to be constant and therefore can't be predeclared. Only compatibel with Lua 5.4 target.

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.

push keyword
function a()
	for i=1, 5 do
		push i, "next"
	end
	return "done"
end
print(a()) -- 1, next, 2, next, 3, next, 4, next, 5, next, done

push "hey" -- Does *not* work, because it is a valid Lua syntax for push("hey")

Add one or more value to the returned value list. If you use a return afterwards, the pushed values will be placed before the return values, otherwise the function will only return what was pushed.

In particular, this keyword is useful when used through implicit push with table comprehension and statement expressions.

Please note that, in order to stay compatible with vanilla Lua syntax, any push immediatly followed by a "string expression", {table expression} or (parenthesis) will be interpreted as a function call. It's recommended to use the implicit push when possible.

Implicit push
function a()
	for i=1, 5 do
		i, next
	end
	return "done"
end
print(a()) -- 1, next, 2, next, 3, next, 4, next, 5, next, done

-- or probably more useful...
local square = (x) x*x end -- function(x) return x*x end

Any list of expressions placed at the end of a block will be converted into a push automatically.

Please note that this doesn't work with v() function calls, because these are already valid statements. Use push v() in this case.

Table comprehension
a = [
	for i=1, 10 do
		i
	end
] -- { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }

a = [
	for i=1, 10 do
		if i%2 == 0 then
			@[i] = true
		end
	end
] -- { [2] = true, [4] = true, [6] = true, [8] = true, [10] = true }

a = [push unpack(t1); push unpack(t2)] -- concatenate t1 and t2

Comprehensions provide a shorter syntax for defining and initializing tables based on a block of code.

You can write any code you want between [ and ], this code will be run as if it was a separate function which is immediadtly run.

Values returned by the function will be inserted in the generated table in the order they were returned. This

Related Skills

View on GitHub
GitHub Stars31
CategoryDevelopment
Updated3mo ago
Forks2

Languages

Lua

Security Score

92/100

Audited on Dec 26, 2025

No findings