mirror of
https://github.com/Reuh/candran.git
synced 2025-10-27 09:59:29 +00:00
Candran 0.3.0
* Added @ self alias * Added short anonymous functions declaration * Made assignment operators works in every direction, except up, down, behind and below, because this would be hard to visualize. * Moved files around. * Error rewriting. * Discover the amazing can commandline tool, which includes a fantastic° REPL and program running abilities. * Added functions which plagiarize Lua. * Added 0.1.0 to the version number. * If you still love pineapple flavored bread, don't hesitate to show your feelings. Also, the tests are out of date. Sad. °: not really.
This commit is contained in:
parent
2a1e293aa5
commit
4af2b41a0d
17 changed files with 2413 additions and 1865 deletions
154
README.md
154
README.md
|
|
@ -4,11 +4,9 @@ Candran is a dialect of the [Lua 5.3](http://www.lua.org) programming language w
|
||||||
|
|
||||||
Unlike Moonscript, Candran tries to stay close to the Lua syntax.
|
Unlike Moonscript, Candran tries to stay close to the Lua syntax.
|
||||||
|
|
||||||
Candran code example :
|
|
||||||
|
|
||||||
````lua
|
````lua
|
||||||
#import("lib.thing")
|
#import("lib.thing")
|
||||||
#local debug = debug or false
|
#local debug or= false
|
||||||
|
|
||||||
local function calculate(toadd=25)
|
local function calculate(toadd=25)
|
||||||
local result = thing.do()
|
local result = thing.do()
|
||||||
|
|
@ -19,11 +17,22 @@ local function calculate(toadd=25)
|
||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
print(calculate())
|
local a = {
|
||||||
|
hey = true,
|
||||||
|
|
||||||
|
newHop = :(foo, thing)
|
||||||
|
@hey = thing(foo)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
a:newHop(42, (foo)
|
||||||
|
return "something " .. foo
|
||||||
|
end)
|
||||||
|
|
||||||
````
|
````
|
||||||
|
|
||||||
##### Quick setup
|
#### Quick setup
|
||||||
Install LPegLabel (```luarocks install LPegLabel```), download this repository and use Candran through ```canc.lua``` or ```candran.lua```.
|
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```.
|
||||||
|
|
||||||
The language
|
The language
|
||||||
------------
|
------------
|
||||||
|
|
@ -53,7 +62,8 @@ The preprocessor has access to the following variables :
|
||||||
|
|
||||||
### Syntax additions
|
### Syntax additions
|
||||||
After the preprocessor is run the Candran code is compiled to Lua. The Candran code adds the folowing syntax to Lua :
|
After the preprocessor is run the Candran code is compiled to Lua. The Candran code adds the folowing syntax to Lua :
|
||||||
##### New assignment operators
|
|
||||||
|
##### Assignment operators
|
||||||
* ````var += nb````
|
* ````var += nb````
|
||||||
* ````var -= nb````
|
* ````var -= nb````
|
||||||
* ````var *= nb````
|
* ````var *= nb````
|
||||||
|
|
@ -71,6 +81,10 @@ After the preprocessor is run the Candran code is compiled to Lua. The Candran c
|
||||||
|
|
||||||
For example, a ````var += nb```` assignment will be compiled into ````var = 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
|
##### Default function parameters
|
||||||
```lua
|
```lua
|
||||||
function foo(bar = "default", other = thing.do())
|
function foo(bar = "default", other = thing.do())
|
||||||
|
|
@ -83,43 +97,87 @@ It is equivalent to doing ```if arg == nil then arg = default end``` for each ar
|
||||||
|
|
||||||
The default values can be complete Lua expressions, and will be evaluated each time the function is run.
|
The default values can be complete Lua expressions, and will be evaluated each time the function is run.
|
||||||
|
|
||||||
|
##### @ self aliases
|
||||||
|
```lua
|
||||||
|
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
|
||||||
|
```lua
|
||||||
|
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.
|
||||||
|
|
||||||
Compile targets
|
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.
|
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, either explicitly give ```lua53``` or ```luajit``` as a second argument to ```candran.compile```, or set the ```target``` preprocessor argument when using ```candran.make``` or the command line tools.
|
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.
|
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
|
The library
|
||||||
-----------
|
-----------
|
||||||
### Command-line usage
|
### Command-line usage
|
||||||
The library can be used standalone through the ```canc``` utility:
|
The library can be used standalone through the ```canc``` and ```can``` utility:
|
||||||
|
|
||||||
* ````lua canc.lua````
|
* ````canc````
|
||||||
|
|
||||||
Display the information text (version and basic command-line usage).
|
Display the information text (version and basic command-line usage).
|
||||||
|
|
||||||
* ````lua canc.lua [arguments] filename...````
|
* ````canc [options] filename...````
|
||||||
|
|
||||||
Preprocess and compile each _filename_ Candran files, and creates the assiociated ```.lua``` files in the same directories.
|
Preprocess and compile each _filename_ Candran files, and creates the assiociated ```.lua``` files in the same directories.
|
||||||
|
|
||||||
_arguments_ is of type ````-somearg -anotherarg thing=somestring other=5 ...````, which will generate a Lua table ```{ somearg = true, anotherarg = true, thing = "somestring", other = 5 }```.
|
_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.
|
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.
|
```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.
|
||||||
|
|
||||||
* example uses :
|
* example uses :
|
||||||
|
|
||||||
````lua canc.lua foo.can````
|
````canc foo.can````
|
||||||
|
|
||||||
preprocess and compile _foo.can_ and write the result in _foo.lua_.
|
preprocess and compile _foo.can_ and write the result in _foo.lua_.
|
||||||
|
|
||||||
````lua canc.lua foo.can -verbose -print | lua````
|
````canc foo.can -verbose -print | lua````
|
||||||
|
|
||||||
preprocess _foo.can_ with _verbose_ set to _true_, compile it and execute it.
|
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
|
### Library usage
|
||||||
Candran can also be used as a Lua library. For example,
|
Candran can also be used as a Lua library. For example,
|
||||||
````lua
|
````lua
|
||||||
|
|
@ -132,14 +190,70 @@ f:close()
|
||||||
local compiled = candran.make(contents, { lang = "fr" })
|
local compiled = candran.make(contents, { lang = "fr" })
|
||||||
|
|
||||||
load(compiled)()
|
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.
|
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 :
|
The table returned by _require("candran")_ gives you access to :
|
||||||
|
|
||||||
|
##### Compiler & preprocessor API
|
||||||
* ````candran.VERSION```` : Candran's version string.
|
* ````candran.VERSION```` : Candran's version string.
|
||||||
* ````candran.preprocess(code[, args])```` : return the Candran code _code_, preprocessed with _args_ as argument table.
|
* ````candran.preprocess(code[, options])```` : return the Candran code _code_, preprocessed with _options_ as options table.
|
||||||
* ````candran.compile(code[, target])```` : return the Candran code compiled to Lua.
|
* ````candran.compile(code[, options])```` : return the Candran code compiled to Lua with _options_ as the option table.
|
||||||
* ````candran.make(code[, args])```` : return the Candran code, preprocessed with _args_ as argument table and compilled to Lua.
|
* ````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
|
||||||
|
|
||||||
|
```lua
|
||||||
|
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:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
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().
|
||||||
|
```
|
||||||
|
|
||||||
### Compiling the library
|
### Compiling the library
|
||||||
The Candran library itself is written is Candran, so you have to compile it with an already compiled Candran library.
|
The Candran library itself is written is Candran, so you have to compile it with an already compiled Candran library.
|
||||||
|
|
@ -149,9 +263,11 @@ The compiled _candran.lua_ should include every Lua library needed to run it. Yo
|
||||||
This command will use the precompilled version of this repository (candran.lua) to compile _candran.can_ and write the result in _candran.lua_ :
|
This command will use the precompilled version of this repository (candran.lua) to compile _candran.can_ and write the result in _candran.lua_ :
|
||||||
|
|
||||||
````
|
````
|
||||||
lua canc.lua candran.can
|
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 :
|
You can then run the tests on your build :
|
||||||
|
|
||||||
````
|
````
|
||||||
|
|
|
||||||
43
bin/can
Normal file
43
bin/can
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
#!/bin/lua
|
||||||
|
local candran = require("candran")
|
||||||
|
local cmdline = require("lib.cmdline")
|
||||||
|
|
||||||
|
local args = cmdline(arg)
|
||||||
|
|
||||||
|
if args.help or args.h then
|
||||||
|
print("Candran interpreter version "..candran.VERSION.." by Reuh")
|
||||||
|
print("Usage: "..arg[0].." [target=<target>] [options] filename")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if #args >= 1 then
|
||||||
|
candran.dofile(args[1], args)
|
||||||
|
else -- REPL
|
||||||
|
print("Candran " .. candran.VERSION)
|
||||||
|
candran.setup()
|
||||||
|
while true do
|
||||||
|
io.write("> ")
|
||||||
|
local line = io.read()
|
||||||
|
if line:match("^=") then
|
||||||
|
line = line:gsub("^=", "return tostring(") .. ")"
|
||||||
|
end
|
||||||
|
|
||||||
|
local p = dofile("lib/lua-parser/parser.lua")
|
||||||
|
local d = dofile("lib/lua-parser/pp.lua")
|
||||||
|
print(p.parse(line))
|
||||||
|
print(d.dump(p.parse(line)))
|
||||||
|
print(require"compiler.lua53"(p.parse(line)))
|
||||||
|
|
||||||
|
local t = { pcall(candran.load, line, "stdin") }
|
||||||
|
if t[1] == false then
|
||||||
|
print(t[2])
|
||||||
|
else
|
||||||
|
t = { pcall(t[2]) }
|
||||||
|
if t[1] == false then
|
||||||
|
print(t[2])
|
||||||
|
elseif #t > 1 then
|
||||||
|
print(unpack(t, 2))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
#!/bin/lua
|
#!/bin/lua
|
||||||
local candran = require("candran")
|
local candran = require("candran")
|
||||||
local cmdline = require("cmdline")
|
local cmdline = require("lib.cmdline")
|
||||||
|
|
||||||
if #arg < 1 then
|
if #arg < 1 then
|
||||||
print("Candran compiler version "..candran.VERSION.." by Reuh")
|
print("Candran compiler version "..candran.VERSION.." by Reuh")
|
||||||
print("Usage: "..arg[0].." [target=<target>] [dest=<destination directory>] [-print] [preprocessor arguments] filename...")
|
print("Usage: "..arg[0].." [target=<target>] [dest=<destination directory>] [-print] [-preprocess] [-compile] [options] filename...")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -25,7 +25,20 @@ for _, file in ipairs(args) do
|
||||||
local input = inputFile:read("*a")
|
local input = inputFile:read("*a")
|
||||||
inputFile:close()
|
inputFile:close()
|
||||||
|
|
||||||
local out = candran.make(input, args)
|
if args.chunkname == nil then
|
||||||
|
args.chunkname = file
|
||||||
|
end
|
||||||
|
|
||||||
|
local out = input
|
||||||
|
if args.preprocess then
|
||||||
|
out = candran.preprocess(out, args)
|
||||||
|
end
|
||||||
|
if args.compile then
|
||||||
|
out = candran.compile(out, args)
|
||||||
|
end
|
||||||
|
if args.compile == nil and args.preprocess == nil then
|
||||||
|
out = candran.make(input, args)
|
||||||
|
end
|
||||||
|
|
||||||
if args.print then
|
if args.print then
|
||||||
print(out)
|
print(out)
|
||||||
200
candran.can
200
candran.can
|
|
@ -1,28 +1,45 @@
|
||||||
#import("util")
|
#import("lib.util")
|
||||||
|
#import("lib.cmdline")
|
||||||
|
|
||||||
#import("compiler.lua53")
|
#import("compiler.lua53")
|
||||||
#import("compiler.luajit")
|
#import("compiler.luajit")
|
||||||
#import("lua-parser.scope")
|
|
||||||
#import("lua-parser.validator")
|
|
||||||
#import("lua-parser.pp")
|
|
||||||
#import("lua-parser.parser")
|
|
||||||
#import("cmdline")
|
|
||||||
|
|
||||||
local util = require("util")
|
#import("lib.lua-parser.scope")
|
||||||
|
#import("lib.lua-parser.validator")
|
||||||
|
#import("lib.lua-parser.pp")
|
||||||
|
#import("lib.lua-parser.parser")
|
||||||
|
|
||||||
local candran = {
|
local candran = {
|
||||||
VERSION = "0.2.0"
|
VERSION = "0.3.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
--- Default options.
|
||||||
|
local default = {
|
||||||
|
target = "lua53",
|
||||||
|
indentation = "",
|
||||||
|
newline = "\n",
|
||||||
|
requirePrefix = "CANDRAN_",
|
||||||
|
mapLines = true,
|
||||||
|
chunkname = "nil",
|
||||||
|
rewriteErrors = true
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Run the preprocessor
|
--- Run the preprocessor
|
||||||
-- @tparam input string input code
|
-- @tparam input string input code
|
||||||
-- @tparam args table arguments for the preprocessor. They will be inserted into the preprocessor environement.
|
-- @tparam options table arguments for the preprocessor. They will be inserted into the preprocessor environement.
|
||||||
-- @treturn output string output code
|
-- @treturn output string output code
|
||||||
function candran.preprocess(input, args={})
|
function candran.preprocess(input, options={})
|
||||||
|
options = util.merge(default, options)
|
||||||
|
|
||||||
-- generate preprocessor code
|
-- generate preprocessor code
|
||||||
local preprocessor = ""
|
local preprocessor = ""
|
||||||
|
local i = 0
|
||||||
for line in (input.."\n"):gmatch("(.-\n)") do
|
for line in (input.."\n"):gmatch("(.-\n)") do
|
||||||
|
i += 1
|
||||||
if line:match("^%s*#") and not line:match("^#!") then -- exclude shebang
|
if line:match("^%s*#") and not line:match("^#!") then -- exclude shebang
|
||||||
preprocessor ..= line:gsub("^%s*#", "")
|
preprocessor ..= line:gsub("^%s*#", "")
|
||||||
|
elseif options.mapLines then
|
||||||
|
preprocessor ..= ("write(%q)"):format(line:sub(1, -2) .. " -- "..options.chunkname..":" .. i) .. "\n"
|
||||||
else
|
else
|
||||||
preprocessor ..= ("write(%q)"):format(line:sub(1, -2)) .. "\n"
|
preprocessor ..= ("write(%q)"):format(line:sub(1, -2)) .. "\n"
|
||||||
end
|
end
|
||||||
|
|
@ -30,13 +47,7 @@ function candran.preprocess(input, args={})
|
||||||
preprocessor ..= "return output"
|
preprocessor ..= "return output"
|
||||||
|
|
||||||
-- make preprocessor environement
|
-- make preprocessor environement
|
||||||
local env = {}
|
local env = util.merge(_G, options)
|
||||||
for k,v in pairs(_G) do
|
|
||||||
env[k] = v
|
|
||||||
end
|
|
||||||
for k, v in pairs(args) do
|
|
||||||
env[k] = v
|
|
||||||
end
|
|
||||||
--- Candran library table
|
--- Candran library table
|
||||||
env.candran = candran
|
env.candran = candran
|
||||||
--- Current preprocessor output
|
--- Current preprocessor output
|
||||||
|
|
@ -45,15 +56,14 @@ function candran.preprocess(input, args={})
|
||||||
-- @tparam modpath string module path
|
-- @tparam modpath string module path
|
||||||
-- @tparam margs table preprocessor arguments to use when preprocessessing the module
|
-- @tparam margs table preprocessor arguments to use when preprocessessing the module
|
||||||
-- @tparam autoRequire[opt=true] boolean true to automatically load the module into a local variable
|
-- @tparam autoRequire[opt=true] boolean true to automatically load the module into a local variable
|
||||||
env.import = function(modpath, margs=args, autoRequire=true)
|
env.import = function(modpath, margs={}, autoRequire=true)
|
||||||
local filepath = assert(util.search(modpath), "No module named \""..modpath.."\"")
|
local filepath = assert(util.search(modpath), "No module named \""..modpath.."\"")
|
||||||
|
|
||||||
-- open module file
|
-- open module file
|
||||||
local f = io.open(filepath)
|
local f = io.open(filepath)
|
||||||
if not f then error("Can't open the module file to import") end
|
if not f then error("Can't open the module file to import") end
|
||||||
for k, v in pairs(args) do
|
|
||||||
if margs[k] == nil then margs[k] = v end
|
margs = util.merge(options, { chunkname = filepath }, margs)
|
||||||
end
|
|
||||||
local modcontent = candran.preprocess(f:read("*a"), margs)
|
local modcontent = candran.preprocess(f:read("*a"), margs)
|
||||||
f:close()
|
f:close()
|
||||||
|
|
||||||
|
|
@ -92,57 +102,143 @@ function candran.preprocess(input, args={})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- compile & load preprocessor
|
-- compile & load preprocessor
|
||||||
local preprocess, err = util.loadenv(candran.compile(preprocessor, args.target), "candran preprocessor", env)
|
local preprocess, err = util.load(candran.compile(preprocessor, args), "candran preprocessor", env)
|
||||||
if not preprocess then error("Error while creating Candran preprocessor: " .. err) end
|
if not preprocess then error("Error while creating Candran preprocessor: " .. err) end
|
||||||
|
|
||||||
-- execute preprocessor
|
-- execute preprocessor
|
||||||
local success, output = pcall(preprocess)
|
local success, output = pcall(preprocess)
|
||||||
if not success then error("Error while preprocessing file: " .. output .. "\nWith preprocessor : \n" .. preprocessor) end
|
if not success then error("Error while preprocessing file: " .. output) end
|
||||||
|
|
||||||
return output
|
return output
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Compiler
|
--- Run the compiler
|
||||||
function candran.compile(input, target="lua53")
|
-- @tparam input string input code
|
||||||
local parse = require("lua-parser.parser").parse
|
-- @tparam options table options for the compiler
|
||||||
|
-- @treturn output string output code
|
||||||
|
function candran.compile(input, options={})
|
||||||
|
options = util.merge(default, options)
|
||||||
|
|
||||||
local ast, errmsg = parse(input, "candran")
|
local ast, errmsg = parser.parse(input, "candran")
|
||||||
|
|
||||||
if not ast then
|
if not ast then
|
||||||
error("Compiler: error while parsing file: "..errmsg)
|
error("Compiler: error while parsing file: "..errmsg)
|
||||||
end
|
end
|
||||||
|
|
||||||
return require("compiler."..target)(ast)
|
return require("compiler."..options.target)(input, ast, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Preprocess & compile
|
--- Preprocess & compile code
|
||||||
function candran.make(code, args={})
|
-- @tparam code string input code
|
||||||
return candran.compile(candran.preprocess(code, args), args.target)
|
-- @tparam options table arguments for the preprocessor and compiler
|
||||||
|
-- @treturn output string output code
|
||||||
|
function candran.make(code, options)
|
||||||
|
return candran.compile(candran.preprocess(code, options), options)
|
||||||
end
|
end
|
||||||
|
|
||||||
function candran.searcher(modpath)
|
local errorRewritingActive = false
|
||||||
-- get module filepath
|
local codeCache = {}
|
||||||
local notfound = ""
|
--- Candran equivalent to the Lua 5.3's loadfile funtion.
|
||||||
local filepath
|
-- Will rewrite errors by default.
|
||||||
for path in package.path:gsub("%.lua", ".can"):gmatch("[^;]+") do
|
function candran.loadfile(filepath, env, options)
|
||||||
local path = path:gsub("%?", (modpath:gsub("%.", "/")))
|
local f, err = io.open(filepath)
|
||||||
local f = io.open(path)
|
if not f then error("can't open the file: "..err) end
|
||||||
if f then
|
local content = f:read("*a")
|
||||||
f:close()
|
|
||||||
filepath = path
|
|
||||||
else
|
|
||||||
notfound = notfound .. "\n\tno Candran file '"..path.."'"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if not filepath then return notfound end
|
|
||||||
|
|
||||||
-- open module file
|
|
||||||
local f = io.open(filepath)
|
|
||||||
if not f then error("Can't open the module file to import") end
|
|
||||||
local modcontent = f:read("*a")
|
|
||||||
f:close()
|
f:close()
|
||||||
|
|
||||||
return load(candran.make(modcontent))
|
return candran.load(content, filepath, env, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Candran equivalent to the Lua 5.3's load funtion.
|
||||||
|
-- Will rewrite errors by default.
|
||||||
|
function candran.load(chunk, chunkname, env, options={})
|
||||||
|
options = util.merge({ chunkname = tostring(chunkname or chunk) }, options)
|
||||||
|
|
||||||
|
codeCache[options.chunkname] = candran.make(chunk, options)
|
||||||
|
local f = util.load(codeCache[options.chunkname], options.chunkname, env)
|
||||||
|
|
||||||
|
if options.rewriteErrors == false then
|
||||||
|
return f
|
||||||
|
else
|
||||||
|
return function()
|
||||||
|
if not errorRewritingActive then
|
||||||
|
errorRewritingActive = true
|
||||||
|
local t = { xpcall(f, candran.messageHandler) }
|
||||||
|
errorRewritingActive = false
|
||||||
|
if t[1] == false then
|
||||||
|
error(t[2], 0)
|
||||||
|
end
|
||||||
|
return unpack(t, 2)
|
||||||
|
else
|
||||||
|
return f()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Candran equivalent to the Lua 5.3's dofile funtion.
|
||||||
|
-- Will rewrite errors by default.
|
||||||
|
function candran.dofile(filename, options)
|
||||||
|
return candran.loadfile(filename, nil, options)()
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Candran error message handler.
|
||||||
|
-- Use it in xpcall to rewrite stacktraces to display Candran source file lines instead of compiled Lua lines.
|
||||||
|
function candran.messageHandler(message)
|
||||||
|
return debug.traceback(message, 2):gsub("(\n?%s*)([^\n]-)%:(%d+)%:", function(indentation, source, line)
|
||||||
|
line = tonumber(line)
|
||||||
|
|
||||||
|
local originalFile
|
||||||
|
local strName = source:match("%[string \"(.-)\"%]")
|
||||||
|
if strName then
|
||||||
|
if codeCache[strName] then
|
||||||
|
originalFile = codeCache[strName]
|
||||||
|
source = strName
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local fi = io.open(source, "r")
|
||||||
|
if fi then
|
||||||
|
originalFile = fi:read("*a")
|
||||||
|
end
|
||||||
|
fi:close()
|
||||||
|
end
|
||||||
|
|
||||||
|
if originalFile then
|
||||||
|
local i = 0
|
||||||
|
for l in originalFile:gmatch("([^\n]*)") do
|
||||||
|
i = i +1
|
||||||
|
if i == line then
|
||||||
|
local extSource, lineMap = l:match("%-%- (.-)%:(%d+)$")
|
||||||
|
if lineMap then
|
||||||
|
if extSource ~= source then
|
||||||
|
return indentation .. extSource .. ":" .. lineMap .. "(" .. extSource .. ":" .. line .. "):"
|
||||||
|
else
|
||||||
|
return indentation .. extSource .. ":" .. lineMap .. "(" .. line .. "):"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Candran package searcher function. Use the existing package.path.
|
||||||
|
function candran.searcher(modpath)
|
||||||
|
local filepath = util.search(modpath)
|
||||||
|
if not filepath then
|
||||||
|
return "\n\tno candran file in package.path"
|
||||||
|
end
|
||||||
|
return candran.loadfile(filepath)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Register the Candran package searcher.
|
||||||
|
function candran.setup()
|
||||||
|
if _VERSION == "Lua 5.1" then
|
||||||
|
table.insert(package.loaders, 2, candran.searcher)
|
||||||
|
else
|
||||||
|
table.insert(package.searchers, 2, candran.searcher)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return candran
|
return candran
|
||||||
|
|
|
||||||
3694
candran.lua
3694
candran.lua
File diff suppressed because it is too large
Load diff
|
|
@ -1,13 +1,30 @@
|
||||||
return function(ast, opts)
|
return function(code, ast, options)
|
||||||
local options = {
|
local lastInputPos = 1
|
||||||
indentation = "\t",
|
local prevLinePos = 1
|
||||||
newline = "\n",
|
local lastSource = "nil"
|
||||||
requirePrefix = "CANDRAN_"
|
local lastLine = 1
|
||||||
}
|
|
||||||
|
|
||||||
local indentLevel = 0
|
local indentLevel = 0
|
||||||
local function newline()
|
local function newline()
|
||||||
return options.newline .. string.rep(options.indentation, indentLevel)
|
local r = options.newline .. string.rep(options.indentation, indentLevel)
|
||||||
|
if options.mapLines then
|
||||||
|
local sub = code:sub(lastInputPos)
|
||||||
|
local source, line = sub:sub(1, sub:find("\n")):match("%-%- (.-)%:(%d+)\n")
|
||||||
|
|
||||||
|
if source and line then
|
||||||
|
lastSource = source
|
||||||
|
lastLine = tonumber(line)
|
||||||
|
else
|
||||||
|
for _ in code:sub(prevLinePos, lastInputPos):gmatch("\n") do
|
||||||
|
lastLine += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
prevLinePos = lastInputPos
|
||||||
|
|
||||||
|
r = " -- " .. lastSource .. ":" .. lastLine .. r
|
||||||
|
end
|
||||||
|
return r
|
||||||
end
|
end
|
||||||
local function indent()
|
local function indent()
|
||||||
indentLevel += 1
|
indentLevel += 1
|
||||||
|
|
@ -32,6 +49,9 @@ return function(ast, opts)
|
||||||
|
|
||||||
local tags
|
local tags
|
||||||
local function lua(ast, forceTag, ...)
|
local function lua(ast, forceTag, ...)
|
||||||
|
if options.mapLines and ast.pos then
|
||||||
|
lastInputPos = ast.pos
|
||||||
|
end
|
||||||
return tags[forceTag or ast.tag](ast, ...)
|
return tags[forceTag or ast.tag](ast, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -54,14 +74,30 @@ return function(ast, opts)
|
||||||
Do = function(t)
|
Do = function(t)
|
||||||
return "do" .. indent() .. lua(t, "Block") .. unindent() .. "end"
|
return "do" .. indent() .. lua(t, "Block") .. unindent() .. "end"
|
||||||
end,
|
end,
|
||||||
-- Set{ {lhs+} opid? {expr+} }
|
-- Set{ {lhs+} (opid? = opid?)? {expr+} }
|
||||||
Set = function(t)
|
Set = function(t)
|
||||||
if #t == 2 then
|
if #t == 2 then
|
||||||
return lua(t[1], "_lhs") .. " = " .. lua(t[2], "_lhs")
|
return lua(t[1], "_lhs") .. " = " .. lua(t[2], "_lhs")
|
||||||
else
|
elseif #t == 3 then
|
||||||
local r = lua(t[1], "_lhs") .. " = " .. lua({ t[2], t[1][1], t[3][1] }, "Op")
|
return lua(t[1], "_lhs") .. " = " .. lua(t[3], "_lhs")
|
||||||
for i=2, math.min(#t[3], #t[1]), 1 do
|
elseif #t == 4 then
|
||||||
r = r .. ", " .. lua({ t[2], t[1][i], t[3][i] }, "Op")
|
if t[3] == "=" then
|
||||||
|
local r = lua(t[1], "_lhs") .. " = " .. lua({ t[2], t[1][1], t[4][1] }, "Op")
|
||||||
|
for i=2, math.min(#t[4], #t[1]), 1 do
|
||||||
|
r = r .. ", " .. lua({ t[2], t[1][i], t[4][i] }, "Op")
|
||||||
|
end
|
||||||
|
return r
|
||||||
|
else
|
||||||
|
local r = lua(t[1], "_lhs") .. " = " .. lua({ t[3], t[4][1], t[1][1] }, "Op")
|
||||||
|
for i=2, math.min(#t[4], #t[1]), 1 do
|
||||||
|
r = r .. ", " .. lua({ t[3], t[4][i], t[1][i] }, "Op")
|
||||||
|
end
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
else -- You are mad.
|
||||||
|
local r = lua(t[1], "_lhs") .. " = " .. lua({ t[2], t[1][1], { tag = "Op", t[4], t[5][1], t[1][1] } }, "Op")
|
||||||
|
for i=2, math.min(#t[5], #t[1]), 1 do
|
||||||
|
r = r .. ", " .. lua({ t[2], t[1][i], { tag = "Op", t[4], t[5][i], t[1][i] } }, "Op")
|
||||||
end
|
end
|
||||||
return r
|
return r
|
||||||
end
|
end
|
||||||
|
|
@ -274,12 +310,5 @@ return function(ast, opts)
|
||||||
|
|
||||||
#placeholder("patch")
|
#placeholder("patch")
|
||||||
|
|
||||||
if opts then
|
return requireStr .. lua(ast) .. newline()
|
||||||
for k, v in pairs(opts) do
|
|
||||||
options[k] = v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local r = lua(ast)
|
|
||||||
return requireStr .. r
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,8 @@ Parameters:
|
||||||
example: var1,var2=$$125 --> var1,var2 = "$125","$125"
|
example: var1,var2=$$125 --> var1,var2 = "$125","$125"
|
||||||
* if value is convertible to number, it is a number
|
* if value is convertible to number, it is a number
|
||||||
example: var1,var2=125 --> var1,var2 = 125,125
|
example: var1,var2=125 --> var1,var2 = 125,125
|
||||||
|
* if value is true of false, it is a boolean
|
||||||
|
example: var1=false --> var1 = false
|
||||||
* otherwise it is a string
|
* otherwise it is a string
|
||||||
example: name=John --> name = "John"
|
example: name=John --> name = "John"
|
||||||
|
|
||||||
|
|
@ -86,7 +88,13 @@ return function(t_in, options, params)
|
||||||
elseif v:find("=") then
|
elseif v:find("=") then
|
||||||
local ids, val = v:match("^([^=]+)%=(.*)") -- no space around =
|
local ids, val = v:match("^([^=]+)%=(.*)") -- no space around =
|
||||||
if not ids then return argerror("invalid assignment syntax", i) end
|
if not ids then return argerror("invalid assignment syntax", i) end
|
||||||
val = val:sub(1,1)=="$" and val:sub(2) or tonumber(val) or val
|
if val == "false" then
|
||||||
|
val = false
|
||||||
|
elseif val == "true" then
|
||||||
|
val = true
|
||||||
|
else
|
||||||
|
val = val:sub(1,1)=="$" and val:sub(2) or tonumber(val) or val
|
||||||
|
end
|
||||||
for id in ids:gmatch"[^,;]+" do
|
for id in ids:gmatch"[^,;]+" do
|
||||||
if not idcheck(id) then return iderror(i) end
|
if not idcheck(id) then return iderror(i) end
|
||||||
t_out[id] = val
|
t_out[id] = val
|
||||||
|
|
@ -8,7 +8,7 @@ block: { stat* }
|
||||||
|
|
||||||
stat:
|
stat:
|
||||||
`Do{ stat* }
|
`Do{ stat* }
|
||||||
| `Set{ {lhs+} {expr+} } -- lhs1, lhs2... = e1, e2...
|
| `Set{ {lhs+} (opid? = opid?)? {expr+} } -- lhs1, lhs2... op=op e1, e2...
|
||||||
| `While{ expr block } -- while e do b end
|
| `While{ expr block } -- while e do b end
|
||||||
| `Repeat{ block expr } -- repeat b until e
|
| `Repeat{ block expr } -- repeat b until e
|
||||||
| `If{ (expr block)+ block? } -- if e1 then b1 [elseif e2 then b2] ... [else bn] end
|
| `If{ (expr block)+ block? } -- if e1 then b1 [elseif e2 then b2] ... [else bn] end
|
||||||
|
|
@ -28,7 +28,7 @@ expr:
|
||||||
| `Boolean{ <boolean> }
|
| `Boolean{ <boolean> }
|
||||||
| `Number{ <number> }
|
| `Number{ <number> }
|
||||||
| `String{ <string> }
|
| `String{ <string> }
|
||||||
| `Function{ { `Id{ <string> }* `Dots? } block }
|
| `Function{ { ( `ParPair{ Id expr } | `Id{ <string> } )* `Dots? } block }
|
||||||
| `Table{ ( `Pair{ expr expr } | expr )* }
|
| `Table{ ( `Pair{ expr expr } | expr )* }
|
||||||
| `Op{ opid expr expr? }
|
| `Op{ opid expr expr? }
|
||||||
| `Paren{ expr } -- significant to cut multiple values returns
|
| `Paren{ expr } -- significant to cut multiple values returns
|
||||||
|
|
@ -257,6 +257,14 @@ local function makeIndexOrCall (t1, t2)
|
||||||
return { tag = "Index", pos = t1.pos, [1] = t1, [2] = t2[1] }
|
return { tag = "Index", pos = t1.pos, [1] = t1, [2] = t2[1] }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function fixAnonymousMethodParams(t1, t2)
|
||||||
|
if t1 == ":" then
|
||||||
|
t1 = t2
|
||||||
|
table.insert(t1, 1, { tag = "Id", "self" })
|
||||||
|
end
|
||||||
|
return t1
|
||||||
|
end
|
||||||
|
|
||||||
-- grammar
|
-- grammar
|
||||||
local G = { V"Lua",
|
local G = { V"Lua",
|
||||||
Lua = V"Shebang"^-1 * V"Skip" * V"Block" * expect(P(-1), "Extra");
|
Lua = V"Shebang"^-1 * V"Skip" * V"Block" * expect(P(-1), "Extra");
|
||||||
|
|
@ -288,7 +296,7 @@ local G = { V"Lua",
|
||||||
LocalStat = kw("local") * expect(V"LocalFunc" + V"LocalAssign", "DefLocal");
|
LocalStat = kw("local") * expect(V"LocalFunc" + V"LocalAssign", "DefLocal");
|
||||||
LocalFunc = tagC("Localrec", kw("function") * expect(V"Id", "NameLFunc") * V"FuncBody") / fixFuncStat;
|
LocalFunc = tagC("Localrec", kw("function") * expect(V"Id", "NameLFunc") * V"FuncBody") / fixFuncStat;
|
||||||
LocalAssign = tagC("Local", V"NameList" * (sym("=") * expect(V"ExprList", "EListLAssign") + Ct(Cc())));
|
LocalAssign = tagC("Local", V"NameList" * (sym("=") * expect(V"ExprList", "EListLAssign") + Ct(Cc())));
|
||||||
Assignment = tagC("Set", V"VarList" * V"AssignmentOp" * expect(V"ExprList", "EListAssign"));
|
Assignment = tagC("Set", V"VarList" * V"BinOp"^-1 * (sym("=") / "=") * V"BinOp"^-1 * expect(V"ExprList", "EListAssign"));
|
||||||
|
|
||||||
FuncStat = tagC("Set", kw("function") * expect(V"FuncName", "FuncName") * V"FuncBody") / fixFuncStat;
|
FuncStat = tagC("Set", kw("function") * expect(V"FuncName", "FuncName") * V"FuncBody") / fixFuncStat;
|
||||||
FuncName = Cf(V"Id" * (sym(".") * expect(V"StrId", "NameFunc1"))^0, insertIndex)
|
FuncName = Cf(V"Id" * (sym(".") * expect(V"StrId", "NameFunc1"))^0, insertIndex)
|
||||||
|
|
@ -342,13 +350,20 @@ local G = { V"Lua",
|
||||||
VarExpr = Cmt(V"SuffixedExpr", function(s, i, exp) return exp.tag == "Id" or exp.tag == "Index", exp end);
|
VarExpr = Cmt(V"SuffixedExpr", function(s, i, exp) return exp.tag == "Id" or exp.tag == "Index", exp end);
|
||||||
|
|
||||||
SuffixedExpr = Cf(V"PrimaryExpr" * (V"Index" + V"Call")^0, makeIndexOrCall);
|
SuffixedExpr = Cf(V"PrimaryExpr" * (V"Index" + V"Call")^0, makeIndexOrCall);
|
||||||
PrimaryExpr = V"Id" + tagC("Paren", sym("(") * expect(V"Expr", "ExprParen") * expect(sym(")"), "CParenExpr"));
|
PrimaryExpr = V"SelfId" * (V"SelfCall" + V"SelfIndex")
|
||||||
|
+ V"Id"
|
||||||
|
+ tagC("Paren", sym("(") * expect(V"Expr", "ExprParen") * expect(sym(")"), "CParenExpr"));
|
||||||
Index = tagC("DotIndex", sym("." * -P".") * expect(V"StrId", "NameIndex"))
|
Index = tagC("DotIndex", sym("." * -P".") * expect(V"StrId", "NameIndex"))
|
||||||
+ tagC("ArrayIndex", sym("[" * -P(S"=[")) * expect(V"Expr", "ExprIndex") * expect(sym("]"), "CBracketIndex"));
|
+ tagC("ArrayIndex", sym("[" * -P(S"=[")) * expect(V"Expr", "ExprIndex") * expect(sym("]"), "CBracketIndex"));
|
||||||
Call = tagC("Invoke", Cg(sym(":" * -P":") * expect(V"StrId", "NameMeth") * expect(V"FuncArgs", "MethArgs")))
|
Call = tagC("Invoke", Cg(sym(":" * -P":") * expect(V"StrId", "NameMeth") * expect(V"FuncArgs", "MethArgs")))
|
||||||
+ tagC("Call", V"FuncArgs");
|
+ tagC("Call", V"FuncArgs");
|
||||||
|
SelfIndex = tagC("DotIndex", V"StrId");
|
||||||
|
SelfCall = tagC("Invoke", Cg(V"StrId" * V"FuncArgs"));
|
||||||
|
|
||||||
FuncDef = kw("function") * V"FuncBody";
|
ShortFuncDef = tagC("Function", V"ShortFuncParams" * V"Block" * expect(kw("end"), "EndFunc"));
|
||||||
|
ShortFuncParams = (sym(":") / ":")^-1 * sym("(") * V"ParList" * sym(")") / fixAnonymousMethodParams;
|
||||||
|
|
||||||
|
FuncDef = (kw("function") * V"FuncBody") + V"ShortFuncDef";
|
||||||
FuncArgs = sym("(") * commaSep(V"Expr", "ArgList")^-1 * expect(sym(")"), "CParenArgs")
|
FuncArgs = sym("(") * commaSep(V"Expr", "ArgList")^-1 * expect(sym(")"), "CParenArgs")
|
||||||
+ V"Table"
|
+ V"Table"
|
||||||
+ tagC("String", V"String");
|
+ tagC("String", V"String");
|
||||||
|
|
@ -361,7 +376,8 @@ local G = { V"Lua",
|
||||||
+ V"StrId" * #("=" * -P"=");
|
+ V"StrId" * #("=" * -P"=");
|
||||||
FieldSep = sym(",") + sym(";");
|
FieldSep = sym(",") + sym(";");
|
||||||
|
|
||||||
Id = tagC("Id", V"Name");
|
SelfId = tagC("Id", sym"@" / "self");
|
||||||
|
Id = tagC("Id", V"Name") + V"SelfId";
|
||||||
StrId = tagC("String", V"Name");
|
StrId = tagC("String", V"Name");
|
||||||
|
|
||||||
-- lexer
|
-- lexer
|
||||||
|
|
@ -455,12 +471,12 @@ local G = { V"Lua",
|
||||||
+ sym("#") / "len"
|
+ sym("#") / "len"
|
||||||
+ sym("~") / "bnot";
|
+ sym("~") / "bnot";
|
||||||
PowOp = sym("^") / "pow";
|
PowOp = sym("^") / "pow";
|
||||||
AssignmentOp = (V"OrOp" + V"AndOp" + V"BOrOp" + V"BXorOp" + V"BAndOp" + V"ShiftOp" + V"ConcatOp" + V"AddOp" + V"MulOp" + V"PowOp")^-1 * sym("=")
|
BinOp = V"OrOp" + V"AndOp" + V"BOrOp" + V"BXorOp" + V"BAndOp" + V"ShiftOp" + V"ConcatOp" + V"AddOp" + V"MulOp" + V"PowOp";
|
||||||
}
|
}
|
||||||
|
|
||||||
local parser = {}
|
local parser = {}
|
||||||
|
|
||||||
local validator = require("lua-parser.validator")
|
local validator = require("lib.lua-parser.validator")
|
||||||
local validate = validator.validate
|
local validate = validator.validate
|
||||||
local syntaxerror = validator.syntaxerror
|
local syntaxerror = validator.syntaxerror
|
||||||
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
--[[
|
--[[
|
||||||
This module impements a validator for the AST
|
This module impements a validator for the AST
|
||||||
]]
|
]]
|
||||||
local scope = require "lua-parser.scope"
|
local scope = require "lib.lua-parser.scope"
|
||||||
|
|
||||||
local lineno = scope.lineno
|
local lineno = scope.lineno
|
||||||
local new_scope, end_scope = scope.new_scope, scope.end_scope
|
local new_scope, end_scope = scope.new_scope, scope.end_scope
|
||||||
|
|
@ -13,14 +13,28 @@ function util.search(modpath, exts={"can", "lua"})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function util.loadenv(str, name, env)
|
function util.load(str, name, env)
|
||||||
if _VERSION == "Lua 5.1" then
|
if _VERSION == "Lua 5.1" then
|
||||||
local fn, err = loadstring(str, name)
|
local fn, err = loadstring(str, name)
|
||||||
if not fn then return fn, err end
|
if not fn then return fn, err end
|
||||||
return env ~= nil and setfenv(fn, env) or fn
|
return env ~= nil and setfenv(fn, env) or fn
|
||||||
else
|
else
|
||||||
return load(str, name, nil, env)
|
if env then
|
||||||
|
return load(str, name, nil, env)
|
||||||
|
else
|
||||||
|
return load(str, name)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function util.merge(...)
|
||||||
|
local r = {}
|
||||||
|
for _, t in ipairs({...}) do
|
||||||
|
for k, v in pairs(t) do
|
||||||
|
r[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
|
||||||
return util
|
return util
|
||||||
37
rockspec/candran-0.3.0-1.rockspec
Normal file
37
rockspec/candran-0.3.0-1.rockspec
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
package = "Candran"
|
||||||
|
|
||||||
|
version = "0.3.0-1"
|
||||||
|
|
||||||
|
description = {
|
||||||
|
summary = "A simple Lua dialect and preprocessor.",
|
||||||
|
detailed = [[
|
||||||
|
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.
|
||||||
|
]],
|
||||||
|
license = "MIT",
|
||||||
|
homepage = "https://github.com/Reuh/Candran",
|
||||||
|
issues_url = "https://github.com/Reuh/Candran",
|
||||||
|
maintener = "Étienne 'Reuh' Fildadut <fildadut@reuh.eu>",
|
||||||
|
--labels = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
source = {
|
||||||
|
url = "git://github.com/Reuh/Candran",
|
||||||
|
tag = "v0.3.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies = {
|
||||||
|
"lua >= 5.1",
|
||||||
|
"lpeglabel >= 1.0.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
build = {
|
||||||
|
type = "builtin",
|
||||||
|
modules = {
|
||||||
|
candran = "candran.lua"
|
||||||
|
},
|
||||||
|
install = {
|
||||||
|
bin = { "bin/can", "bin/canc" }
|
||||||
|
}
|
||||||
|
--copy_directories = { "doc", "test" }
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue