1
0
Fork 0
mirror of https://github.com/Reuh/candran.git synced 2025-10-27 09:59:29 +00:00

Use argparse to parse CLI args, separate preprocessor constants from options

This commit is contained in:
Étienne Fildadut 2021-06-17 19:45:53 +02:00
parent dd22f2de3d
commit e9ae8e21a3
8 changed files with 253 additions and 346 deletions

View file

@ -493,7 +493,7 @@ _assert(5 = 2, "failed") -- replaced with if 5 = 2 then error("failed") end
Candran provide some predefined macros by default: Candran provide some predefined macros by default:
* `__STR__(expr)`: returns a string litteral representing the expression (e.g., `__STR__(5 + 2)` expands to `"5 + 2"`) * `__STR__(expr)`: returns a string litteral representing the expression (e.g., `__STR__(5 + 2)` expands to `"5 + 2"`)
* `__CONSTEXPR__(expr)`: calculate the result of the expression in the preprocessor, and returns a representation of the returned value, i.e. precalculate an expression at compile time * `__CONSTEXPR__(expr)`: calculate the result of the expression in the preprocessor, and returns a representation of the returned value, i.e. precalculate an expression at compile time
You can disable these built-in macros using the `noBuiltInMacros` compiler option. You can disable these built-in macros using the `builtInMacros` compiler option.
Compile targets Compile targets
--------------- ---------------
@ -663,14 +663,15 @@ at the top of your main Lua file. If a Candran file is found when you call ```re
You can give arbitrary options to the compiler and preprocessor, but Candran already provide and uses these with their associated default values: You can give arbitrary options to the compiler and preprocessor, but Candran already provide and uses these with their associated default values:
```lua ```lua
target = "lua53" -- compiler target. "lua53", "lua52", "luajit" or "lua51" (default is automatically selected based on the Lua version used). target = "lua53" -- compiler target. "lua54", "lua53", "lua52", "luajit" or "lua51" (default is automatically selected based on the Lua version used).
indentation = "" -- character(s) used for indentation in the compiled file. indentation = "" -- character(s) used for indentation in the compiled file.
newline = "\n" -- character(s) used for newlines in the compiled file. newline = "\n" -- character(s) used for newlines in the compiled file.
variablePrefix = "__CAN_" -- Prefix used when Candran needs to set a local variable to provide some functionality (example: to load LuaJIT's bit lib when using bitwise operators). variablePrefix = "__CAN_" -- Prefix used when Candran needs to set a local variable to provide some functionality (example: to load 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. 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. 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(). rewriteErrors = true -- true to enable error rewriting when loading code using the helper functions. Will wrap the whole code in a xpcall().
noBuiltInMacros = false -- true to disable built-in macros __*__ builtInMacros = true -- false to disable built-in macros __*__
preprocessorEnv = {} -- environment to merge with the preprocessor environement
``` ```
You can change the defaults used for these variables in the table `candran.default`. You can change the defaults used for these variables in the table `candran.default`.

44
bin/can
View file

@ -1,28 +1,30 @@
#!/usr/bin/env lua #!/usr/bin/env lua
local candran = require("candran").setup() local candran = require("candran").setup()
local cmdline = require("candran.cmdline") local util = require("candran.util")
local argparse = require("argparse")
local args = cmdline(arg) -- Parse args --
if args.help or args.h then local parser = argparse()
print("Candran "..candran.VERSION.." interpreter by Reuh") :name "can"
print("Usage: "..arg[0].." [options] filename") :description("Candran "..candran.VERSION.." interpreter by Reuh.")
print("Specify no options to start the REPL.") :epilog "For more info, see https://github.com/Reuh/candran"
print("Use - instead of a filename to read from the standard input.")
print("Interpreter options:") parser:argument("filename", "Candran file to run. Use - to read from standard input. Start the REPL if no filename given.")
print(" -help or -h print this text") :args "?"
print("Default options:")
for opt, val in pairs(candran.default) do util.cli.addCandranOptions(parser)
if type(val) == "string" then val = val:gsub("\n", "\\n") end
print((" %s=%q"):format(opt, tostring(val))) local args = parser:parse()
end
return local options = util.cli.makeCandranOptions(args)
end
-- Run --
-- stdin -- stdin
if arg[#arg] == "-" then if args.filename == "-" then
local f, err = candran.load(io.read("*a"), "stdin", nil, args) local f, err = candran.load(io.read("*a"), "stdin", nil, options)
if not f then if not f then
io.stderr:write("can: "..err.."\n") io.stderr:write("can: "..err.."\n")
os.exit(1) os.exit(1)
@ -33,8 +35,8 @@ if arg[#arg] == "-" then
os.exit(1) os.exit(1)
end end
-- file -- file
elseif #args >= 1 then elseif args.filename then
local f, err = candran.loadfile(args[1], nil, args) local f, err = candran.loadfile(args.filename, nil, options)
if not f then if not f then
io.stderr:write("can: "..err.."\n") io.stderr:write("can: "..err.."\n")
os.exit(1) os.exit(1)
@ -47,6 +49,8 @@ elseif #args >= 1 then
end end
-- REPL -- REPL
else else
candran.default = util.merge(candran.default, options)
-- Setup linenoise -- Setup linenoise
local s, l = pcall(require, "linenoise") local s, l = pcall(require, "linenoise")
if not s then -- pure Lua compatibility thingy if not s then -- pure Lua compatibility thingy

View file

@ -1,48 +1,63 @@
#!/usr/bin/env lua #!/usr/bin/env lua
local candran = require("candran") local candran = require("candran")
local cmdline = require("candran.cmdline")
local parse = require("candran.can-parser.parser").parse local parse = require("candran.can-parser.parser").parse
local pp = require("candran.can-parser.pp") local pp = require("candran.can-parser.pp")
local util = require("candran.util")
local argparse = require("argparse")
local args = cmdline(arg) -- Parse args --
if #arg < 1 or args.help or args.h then local parser = argparse()
print("Candran "..candran.VERSION.." compiler by Reuh") :name "canc"
print("Usage: "..arg[0].." [options] filenames...") :description("Candran "..candran.VERSION.." compiler by Reuh.")
print("Use - instead of filenames to read from the standard input. The output file will be named stdin.lua by default.") :epilog "For more info, see https://github.com/Reuh/candran"
print("Compiler options:")
print(" dest=\"directory\" where compiled files should be written")
print(" out=\"name.lua\" output filename. By default, will use the same name as the input file with a .lua extension.")
print(" -print write to the standard output instead of creating files")
print(" -preprocess only run the preprocessor")
print(" -compile only run the compiler")
print(" -parse only parse the file and prints errors to stdout")
print(" -ast (for debugging purposes) only parse the files and dump the AST to stdout")
print(" -help or -h print this text")
print("Default options:")
for opt, val in pairs(candran.default) do
if type(val) == "string" then val = val:gsub("\n", "\\n") end
print((" %s=%q"):format(opt, tostring(val)))
end
return
end
if arg[#arg] == "-" then parser:argument("filename", "Candran files to compile. Use - to read from standard input; the output file will then be named stdin.lua by default.")
table.insert(args, io.stdin) :args "+"
end
for _, file in ipairs(args) do parser:group("Output options",
parser:option("-d --destination")
:description "Where compiled files should be written"
:argname "directory",
parser:option("-o --output")
:description "Output filename. (default: same name as the input file with a .lua extension)"
:argname "filename",
parser:flag("-p --print")
:description "Write to the standard output instead of creating files",
parser:flag("--preprocess")
:description "Only run the preprocessor",
parser:flag("--compile")
:description "Only run the compiler",
parser:flag("--parse")
:description "Only parse the file and prints syntax errors to stdout",
parser:flag("--ast")
:description"(for debugging purposes) Only parse the files and dump the AST to stdout"
)
util.cli.addCandranOptions(parser)
local args = parser:parse()
-- Compile --
for _, file in ipairs(args.filename) do
-- Read -- Read
local dest, input local dest, input
if file == io.stdin then if file == "-" then
dest = args.out or "stdin.lua" dest = args.output or "stdin.lua"
input = io.read("*a") input = io.read("*a")
args.chunkname = "stdin" args.chunkname = "stdin"
else else
dest = args.out or (file:gsub("%.can$", "")..".lua") dest = args.output or (file:gsub("%.can$", "")..".lua")
local inputFile, err = io.open(file, "r") local inputFile, err = io.open(file, "r")
if not inputFile then if not inputFile then
@ -69,8 +84,10 @@ for _, file in ipairs(args) do
end end
-- Compile and output -- Compile and output
if args.dest then local options = util.cli.makeCandranOptions(args)
dest = args.dest .. "/" .. dest
if args.destination then
dest = args.destination .. "/" .. dest
end end
if not args.print then if not args.print then
@ -79,7 +96,7 @@ for _, file in ipairs(args) do
local out = input local out = input
if args.preprocess then if args.preprocess then
local r, err = candran.preprocess(out, args) local r, err = candran.preprocess(out, options)
if not r then if not r then
io.stderr:write("canc: "..err.."\n") io.stderr:write("canc: "..err.."\n")
os.exit(1) os.exit(1)
@ -87,7 +104,7 @@ for _, file in ipairs(args) do
out = r out = r
end end
if args.compile then if args.compile then
local r, err = candran.compile(out, args) local r, err = candran.compile(out, options)
if not r then if not r then
io.stderr:write("canc: "..err.."\n") io.stderr:write("canc: "..err.."\n")
os.exit(1) os.exit(1)
@ -95,7 +112,7 @@ for _, file in ipairs(args) do
out = r out = r
end end
if args.compile == nil and args.preprocess == nil then if args.compile == nil and args.preprocess == nil then
local r, err = candran.make(input, args) local r, err = candran.make(input, options)
if not r then if not r then
io.stderr:write("canc: "..err.."\n") io.stderr:write("canc: "..err.."\n")
os.exit(1) os.exit(1)

View file

@ -1,5 +1,4 @@
#import("candran.util") #import("candran.util")
#import("candran.cmdline")
#import("candran.serpent") #import("candran.serpent")
#import("compiler.lua54") #import("compiler.lua54")
@ -29,7 +28,8 @@ candran.default = {
mapLines = true, mapLines = true,
chunkname = "nil", chunkname = "nil",
rewriteErrors = true, rewriteErrors = true,
noBuiltInMacros = false builtInMacros = true,
preprocessorEnv = {}
} }
-- Autodetect version -- Autodetect version
@ -92,7 +92,7 @@ function candran.preprocess(input, options={})
preprocessor ..= "return output" preprocessor ..= "return output"
-- make preprocessor environement -- make preprocessor environement
local env = util.merge(_G, options) local env = util.merge(_G, options.preprocessorEnv)
--- Candran library table --- Candran library table
env.candran = candran env.candran = candran
--- Current preprocessor output --- Current preprocessor output
@ -179,7 +179,7 @@ function candran.preprocess(input, options={})
end end
-- default macros -- default macros
if not options.noBuiltInMacros then if options.builtInMacros then
env.define("__STR__(x)", function(x) return ("%q"):format(x) end) env.define("__STR__(x)", function(x) return ("%q"):format(x) end)
local s = require("candran.serpent") local s = require("candran.serpent")
env.define("__CONSTEXPR__(expr)", function(expr) env.define("__CONSTEXPR__(expr)", function(expr)

View file

@ -1,147 +1,90 @@
local function _() -- candran.can:2 local function _() -- candran.can:2
local util = {} -- ./candran/util.can:1 local candran = require("candran") -- ./candran/util.can:1
util["search"] = function(modpath, exts) -- ./candran/util.can:3 local util = {} -- ./candran/util.can:2
if exts == nil then exts = {} end -- ./candran/util.can:3 util["search"] = function(modpath, exts) -- ./candran/util.can:4
for _, ext in ipairs(exts) do -- ./candran/util.can:4 if exts == nil then exts = {} end -- ./candran/util.can:4
for path in package["path"]:gmatch("[^;]+") do -- ./candran/util.can:5 for _, ext in ipairs(exts) do -- ./candran/util.can:5
local fpath = path:gsub("%.lua", "." .. ext):gsub("%?", (modpath:gsub("%.", "/"))) -- ./candran/util.can:6 for path in package["path"]:gmatch("[^;]+") do -- ./candran/util.can:6
local f = io["open"](fpath) -- ./candran/util.can:7 local fpath = path:gsub("%.lua", "." .. ext):gsub("%?", (modpath:gsub("%.", "/"))) -- ./candran/util.can:7
if f then -- ./candran/util.can:8 local f = io["open"](fpath) -- ./candran/util.can:8
f:close() -- ./candran/util.can:9 if f then -- ./candran/util.can:9
return fpath -- ./candran/util.can:10 f:close() -- ./candran/util.can:10
end -- ./candran/util.can:10 return fpath -- ./candran/util.can:11
end -- ./candran/util.can:10 end -- ./candran/util.can:11
end -- ./candran/util.can:10 end -- ./candran/util.can:11
end -- ./candran/util.can:10 end -- ./candran/util.can:11
util["load"] = function(str, name, env) -- ./candran/util.can:16 end -- ./candran/util.can:11
if _VERSION == "Lua 5.1" then -- ./candran/util.can:17 util["load"] = function(str, name, env) -- ./candran/util.can:17
local fn, err = loadstring(str, name) -- ./candran/util.can:18 if _VERSION == "Lua 5.1" then -- ./candran/util.can:18
if not fn then -- ./candran/util.can:19 local fn, err = loadstring(str, name) -- ./candran/util.can:19
return fn, err -- ./candran/util.can:19 if not fn then -- ./candran/util.can:20
end -- ./candran/util.can:19 return fn, err -- ./candran/util.can:20
return env ~= nil and setfenv(fn, env) or fn -- ./candran/util.can:20 end -- ./candran/util.can:20
else -- ./candran/util.can:20 return env ~= nil and setfenv(fn, env) or fn -- ./candran/util.can:21
if env then -- ./candran/util.can:22 else -- ./candran/util.can:21
return load(str, name, nil, env) -- ./candran/util.can:23 if env then -- ./candran/util.can:23
else -- ./candran/util.can:23 return load(str, name, nil, env) -- ./candran/util.can:24
return load(str, name) -- ./candran/util.can:25 else -- ./candran/util.can:24
end -- ./candran/util.can:25 return load(str, name) -- ./candran/util.can:26
end -- ./candran/util.can:25 end -- ./candran/util.can:26
end -- ./candran/util.can:25 end -- ./candran/util.can:26
util["recmerge"] = function(...) -- ./candran/util.can:30 end -- ./candran/util.can:26
local r = {} -- ./candran/util.can:31 util["recmerge"] = function(...) -- ./candran/util.can:31
for _, t in ipairs({ ... }) do -- ./candran/util.can:32 local r = {} -- ./candran/util.can:32
for k, v in pairs(t) do -- ./candran/util.can:33 for _, t in ipairs({ ... }) do -- ./candran/util.can:33
if type(v) == "table" then -- ./candran/util.can:34 for k, v in pairs(t) do -- ./candran/util.can:34
r[k] = util["merge"](v, r[k]) -- ./candran/util.can:35 if type(v) == "table" then -- ./candran/util.can:35
else -- ./candran/util.can:35 r[k] = util["merge"](v, r[k]) -- ./candran/util.can:36
r[k] = v -- ./candran/util.can:37 else -- ./candran/util.can:36
end -- ./candran/util.can:37 r[k] = v -- ./candran/util.can:38
end -- ./candran/util.can:37 end -- ./candran/util.can:38
end -- ./candran/util.can:37 end -- ./candran/util.can:38
return r -- ./candran/util.can:41 end -- ./candran/util.can:38
end -- ./candran/util.can:41 return r -- ./candran/util.can:42
util["merge"] = function(...) -- ./candran/util.can:44 end -- ./candran/util.can:42
local r = {} -- ./candran/util.can:45 util["merge"] = function(...) -- ./candran/util.can:45
for _, t in ipairs({ ... }) do -- ./candran/util.can:46 local r = {} -- ./candran/util.can:46
for k, v in pairs(t) do -- ./candran/util.can:47 for _, t in ipairs({ ... }) do -- ./candran/util.can:47
r[k] = v -- ./candran/util.can:48 for k, v in pairs(t) do -- ./candran/util.can:48
end -- ./candran/util.can:48 r[k] = v -- ./candran/util.can:49
end -- ./candran/util.can:48 end -- ./candran/util.can:49
return r -- ./candran/util.can:51 end -- ./candran/util.can:49
end -- ./candran/util.can:51 return r -- ./candran/util.can:52
return util -- ./candran/util.can:54 end -- ./candran/util.can:52
end -- ./candran/util.can:54 util["cli"] = { -- ./candran/util.can:55
local util = _() or util -- ./candran/util.can:58 ["addCandranOptions"] = function(parser) -- ./candran/util.can:57
package["loaded"]["candran.util"] = util or true -- ./candran/util.can:59 parser:group("Compiler options", parser:option("-t --target"):description("Target Lua version: lua54, lua53, lua52, luajit or lua51"):default(candran["default"]["target"]), parser:option("--indentation"):description("Character(s) used for indentation in the compiled file"):default(candran["default"]["indentation"]), parser:option("--newline"):description("Character(s) used for newlines in the compiled file"):default(candran["default"]["newline"]), parser:option("--variable-prefix"):description("Prefix used when Candran needs to set a local variable to provide some functionality"):default(candran["default"]["variablePrefix"]), parser:flag("--no-map-lines"):description("Do not add comments at the end of each line indicating the associated source line and file (error rewriting will not work)")) -- ./candran/util.can:76
local function _() -- ./candran/util.can:62 parser:group("Preprocessor options", parser:flag("--no-builtin-macros"):description("Disable built-in macros"), parser:option("-D --define"):description("Define a preprocessor constant"):args("1-2"):argname({ -- ./candran/util.can:86
local ipairs, pairs, setfenv, tonumber, loadstring, type = ipairs, pairs, setfenv, tonumber, loadstring, type -- ./candran/cmdline.lua:5 "name", -- ./candran/util.can:86
local tinsert, tconcat = table["insert"], table["concat"] -- ./candran/cmdline.lua:6 "value" -- ./candran/util.can:86
local function commonerror(msg) -- ./candran/cmdline.lua:8 }):count("*")) -- ./candran/util.can:87
return nil, ("[cmdline]: " .. msg) -- ./candran/cmdline.lua:9 parser:option("--chunkname"):description("Chunkname used when running the code") -- ./candran/util.can:91
end -- ./candran/cmdline.lua:9 parser:flag("--no-rewrite-errors"):description("Disable error rewriting when running the code") -- ./candran/util.can:94
local function argerror(msg, numarg) -- ./candran/cmdline.lua:12 end, -- ./candran/util.can:94
msg = msg and (": " .. msg) or "" -- ./candran/cmdline.lua:13 ["makeCandranOptions"] = function(args) -- ./candran/util.can:98
return nil, ("[cmdline]: bad argument #" .. numarg .. msg) -- ./candran/cmdline.lua:14 local preprocessorEnv = {} -- ./candran/util.can:99
end -- ./candran/cmdline.lua:14 for _, o in ipairs(args["define"]) do -- ./candran/util.can:100
local function iderror(numarg) -- ./candran/cmdline.lua:17 preprocessorEnv[o[1]] = tonumber(o[2]) or o[2] or true -- ./candran/util.can:101
return argerror("ID not valid", numarg) -- ./candran/cmdline.lua:18 end -- ./candran/util.can:101
end -- ./candran/cmdline.lua:18 local options = { -- ./candran/util.can:104
local function idcheck(id) -- ./candran/cmdline.lua:21 ["target"] = args["target"], -- ./candran/util.can:105
return id:match("^[%a_][%w_]*$") and true -- ./candran/cmdline.lua:22 ["indentation"] = args["indentation"], -- ./candran/util.can:106
end -- ./candran/cmdline.lua:22 ["newline"] = args["newline"], -- ./candran/util.can:107
return function(t_in, options, params) -- ./candran/cmdline.lua:73 ["variablePrefix"] = args["variable_prefix"], -- ./candran/util.can:108
local t_out = {} -- ./candran/cmdline.lua:74 ["mapLines"] = not args["no_map_lines"], -- ./candran/util.can:109
for i, v in ipairs(t_in) do -- ./candran/cmdline.lua:75 ["chunkname"] = args["chunkname"], -- ./candran/util.can:110
local prefix, command = v:sub(1, 1), v:sub(2) -- ./candran/cmdline.lua:76 ["rewriteErrors"] = not args["no_rewrite_errors"], -- ./candran/util.can:111
if prefix == "$" then -- ./candran/cmdline.lua:77 ["builtInMacros"] = not args["no_builtin_macros"], -- ./candran/util.can:112
tinsert(t_out, command) -- ./candran/cmdline.lua:78 ["preprocessorEnv"] = preprocessorEnv -- ./candran/util.can:113
elseif prefix == "-" then -- ./candran/cmdline.lua:79 } -- ./candran/util.can:113
for id in command:gmatch("[^,;]+") do -- ./candran/cmdline.lua:80 return options -- ./candran/util.can:115
if not idcheck(id) then -- ./candran/cmdline.lua:81 end -- ./candran/util.can:115
return iderror(i) -- ./candran/cmdline.lua:81 } -- ./candran/util.can:115
end -- ./candran/cmdline.lua:81 return util -- ./candran/util.can:119
t_out[id] = true -- ./candran/cmdline.lua:82 end -- ./candran/util.can:119
end -- ./candran/cmdline.lua:82 local util = _() or util -- ./candran/util.can:123
elseif prefix == "!" then -- ./candran/cmdline.lua:84 package["loaded"]["candran.util"] = util or true -- ./candran/util.can:124
local f, err = loadstring(command) -- ./candran/cmdline.lua:85 local function _() -- ./candran/util.can:127
if not f then -- ./candran/cmdline.lua:86
return argerror(err, i) -- ./candran/cmdline.lua:86
end -- ./candran/cmdline.lua:86
setfenv(f, t_out)() -- ./candran/cmdline.lua:87
elseif v:find("=") then -- ./candran/cmdline.lua:88
local ids, val = v:match("^([^=]+)%=(.*)") -- ./candran/cmdline.lua:89
if not ids then -- ./candran/cmdline.lua:90
return argerror("invalid assignment syntax", i) -- ./candran/cmdline.lua:90
end -- ./candran/cmdline.lua:90
if val == "false" then -- ./candran/cmdline.lua:91
val = false -- ./candran/cmdline.lua:92
elseif val == "true" then -- ./candran/cmdline.lua:93
val = true -- ./candran/cmdline.lua:94
else -- ./candran/cmdline.lua:94
val = val:sub(1, 1) == "$" and val:sub(2) or tonumber(val) or val -- ./candran/cmdline.lua:96
end -- ./candran/cmdline.lua:96
for id in ids:gmatch("[^,;]+") do -- ./candran/cmdline.lua:98
if not idcheck(id) then -- ./candran/cmdline.lua:99
return iderror(i) -- ./candran/cmdline.lua:99
end -- ./candran/cmdline.lua:99
t_out[id] = val -- ./candran/cmdline.lua:100
end -- ./candran/cmdline.lua:100
else -- ./candran/cmdline.lua:100
tinsert(t_out, v) -- ./candran/cmdline.lua:103
end -- ./candran/cmdline.lua:103
end -- ./candran/cmdline.lua:103
if options then -- ./candran/cmdline.lua:106
local lookup, unknown = {}, {} -- ./candran/cmdline.lua:107
for _, v in ipairs(options) do -- ./candran/cmdline.lua:108
lookup[v] = true -- ./candran/cmdline.lua:108
end -- ./candran/cmdline.lua:108
for k, _ in pairs(t_out) do -- ./candran/cmdline.lua:109
if lookup[k] == nil and type(k) == "string" then -- ./candran/cmdline.lua:110
tinsert(unknown, k) -- ./candran/cmdline.lua:110
end -- ./candran/cmdline.lua:110
end -- ./candran/cmdline.lua:110
if # unknown > 0 then -- ./candran/cmdline.lua:112
return commonerror("unknown options: " .. tconcat(unknown, ", ")) -- ./candran/cmdline.lua:113
end -- ./candran/cmdline.lua:113
end -- ./candran/cmdline.lua:113
if params then -- ./candran/cmdline.lua:116
local missing = {} -- ./candran/cmdline.lua:117
for _, v in ipairs(params) do -- ./candran/cmdline.lua:118
if t_out[v] == nil then -- ./candran/cmdline.lua:119
tinsert(missing, v) -- ./candran/cmdline.lua:119
end -- ./candran/cmdline.lua:119
end -- ./candran/cmdline.lua:119
if # missing > 0 then -- ./candran/cmdline.lua:121
return commonerror("missing parameters: " .. tconcat(missing, ", ")) -- ./candran/cmdline.lua:122
end -- ./candran/cmdline.lua:122
end -- ./candran/cmdline.lua:122
return t_out -- ./candran/cmdline.lua:125
end -- ./candran/cmdline.lua:125
end -- ./candran/cmdline.lua:125
local cmdline = _() or cmdline -- ./candran/cmdline.lua:130
package["loaded"]["candran.cmdline"] = cmdline or true -- ./candran/cmdline.lua:131
local function _() -- ./candran/cmdline.lua:134
local n, v = "serpent", "0.302" -- ./candran/serpent.lua:24 local n, v = "serpent", "0.302" -- ./candran/serpent.lua:24
local c, d = "Paul Kulchenko", "Lua serializer and pretty printer" -- ./candran/serpent.lua:25 local c, d = "Paul Kulchenko", "Lua serializer and pretty printer" -- ./candran/serpent.lua:25
local snum = { -- ./candran/serpent.lua:26 local snum = { -- ./candran/serpent.lua:26
@ -7067,19 +7010,20 @@ return parser -- ./candran/can-parser/parser.lua:807
end -- ./candran/can-parser/parser.lua:807 end -- ./candran/can-parser/parser.lua:807
local parser = _() or parser -- ./candran/can-parser/parser.lua:811 local parser = _() or parser -- ./candran/can-parser/parser.lua:811
package["loaded"]["candran.can-parser.parser"] = parser or true -- ./candran/can-parser/parser.lua:812 package["loaded"]["candran.can-parser.parser"] = parser or true -- ./candran/can-parser/parser.lua:812
local unpack = unpack or table["unpack"] -- candran.can:16 local unpack = unpack or table["unpack"] -- candran.can:15
local candran = { ["VERSION"] = "0.14.0" } -- candran.can:19 local candran = { ["VERSION"] = "0.14.0" } -- candran.can:18
package["loaded"]["candran"] = candran -- candran.can:21 package["loaded"]["candran"] = candran -- candran.can:20
candran["default"] = { -- candran.can:24 candran["default"] = { -- candran.can:23
["target"] = "lua54", -- candran.can:25 ["target"] = "lua54", -- candran.can:24
["indentation"] = "", -- candran.can:26 ["indentation"] = "", -- candran.can:25
["newline"] = "\ ["newline"] = "\
", -- candran.can:27 ", -- candran.can:26
["variablePrefix"] = "__CAN_", -- candran.can:28 ["variablePrefix"] = "__CAN_", -- candran.can:27
["mapLines"] = true, -- candran.can:29 ["mapLines"] = true, -- candran.can:28
["chunkname"] = "nil", -- candran.can:30 ["chunkname"] = "nil", -- candran.can:29
["rewriteErrors"] = true, -- candran.can:31 ["rewriteErrors"] = true, -- candran.can:30
["noBuiltInMacros"] = false -- candran.can:32 ["builtInMacros"] = true, -- candran.can:31
["preprocessorEnv"] = {} -- candran.can:32
} -- candran.can:32 } -- candran.can:32
if _VERSION == "Lua 5.1" then -- candran.can:36 if _VERSION == "Lua 5.1" then -- candran.can:36
if package["loaded"]["jit"] then -- candran.can:37 if package["loaded"]["jit"] then -- candran.can:37
@ -7132,7 +7076,7 @@ end -- candran.can:88
end -- candran.can:88 end -- candran.can:88
end -- candran.can:88 end -- candran.can:88
preprocessor = preprocessor .. ("return output") -- candran.can:92 preprocessor = preprocessor .. ("return output") -- candran.can:92
local env = util["merge"](_G, options) -- candran.can:95 local env = util["merge"](_G, options["preprocessorEnv"]) -- candran.can:95
env["candran"] = candran -- candran.can:97 env["candran"] = candran -- candran.can:97
env["output"] = "" -- candran.can:99 env["output"] = "" -- candran.can:99
env["import"] = function(modpath, margs) -- candran.can:106 env["import"] = function(modpath, margs) -- candran.can:106
@ -7207,7 +7151,7 @@ else -- candran.can:175
error(("invalid macro type %s"):format(tostring(iast["tag"]))) -- candran.can:177 error(("invalid macro type %s"):format(tostring(iast["tag"]))) -- candran.can:177
end -- candran.can:177 end -- candran.can:177
end -- candran.can:177 end -- candran.can:177
if not options["noBuiltInMacros"] then -- candran.can:182 if options["builtInMacros"] then -- candran.can:182
env["define"]("__STR__(x)", function(x) -- candran.can:183 env["define"]("__STR__(x)", function(x) -- candran.can:183
return ("%q"):format(x) -- candran.can:183 return ("%q"):format(x) -- candran.can:183
end) -- candran.can:183 end) -- candran.can:183

View file

@ -1,126 +0,0 @@
-- started: 2008-04-12 by Shmuel Zeigerman
-- license: public domain
local ipairs,pairs,setfenv,tonumber,loadstring,type =
ipairs,pairs,setfenv,tonumber,loadstring,type
local tinsert, tconcat = table.insert, table.concat
local function commonerror (msg)
return nil, ("[cmdline]: " .. msg)
end
local function argerror (msg, numarg)
msg = msg and (": " .. msg) or ""
return nil, ("[cmdline]: bad argument #" .. numarg .. msg)
end
local function iderror (numarg)
return argerror("ID not valid", numarg)
end
local function idcheck (id)
return id:match("^[%a_][%w_]*$") and true
end
--[[------------------------------------------------------------------------
Syntax:
t_out = getparam(t_in [,options] [,params])
Parameters:
t_in: table - list of string arguments to be processed in order
(usually it is the `arg' table created by the Lua interpreter).
* if an argument begins with $, the $ is skipped and the rest is inserted
into the array part of the output table.
* if an argument begins with -, the rest is a sequence of variables
(separated by commas or semicolons) that are all set to true;
example: -var1,var2 --> var1,var2 = true,true
* if an argument begins with !, the rest is a Lua chunk;
example: !a=(40+3)*5;b=20;name="John";window={w=600,h=480}
* if an argument contains =, then it is an assignment in the form
var1,...=value (no space is allowed around the =)
* if value begins with $, the $ is skipped, the rest is a string
example: var1,var2=$ --> var1,var2 = "",""
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
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
example: name=John --> name = "John"
* if an argument neither begins with one of the special characters (-,!,$),
nor contains =, it is inserted as is into the array part of the output
table.
options (optional): a list of names of all command-line options and parameters
permitted in the application; used to check that each found option
is valid; no checks are done if not supplied.
params (optional): a list of names of all command-line parameters required
by the application; used to check that each required parameter is present;
no checks are done if not supplied.
Returns:
On success: the output table, e.g. { [1]="./myfile.txt", name="John", age=40 }
On error: nil followed by error message string.
--]]------------------------------------------------------------------------
return function(t_in, options, params)
local t_out = {}
for i,v in ipairs(t_in) do
local prefix, command = v:sub(1,1), v:sub(2)
if prefix == "$" then
tinsert(t_out, command)
elseif prefix == "-" then
for id in command:gmatch"[^,;]+" do
if not idcheck(id) then return iderror(i) end
t_out[id] = true
end
elseif prefix == "!" then
local f, err = loadstring(command)
if not f then return argerror(err, i) end
setfenv(f, t_out)()
elseif v:find("=") then
local ids, val = v:match("^([^=]+)%=(.*)") -- no space around =
if not ids then return argerror("invalid assignment syntax", i) end
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
if not idcheck(id) then return iderror(i) end
t_out[id] = val
end
else
tinsert(t_out, v)
end
end
if options then
local lookup, unknown = {}, {}
for _,v in ipairs(options) do lookup[v] = true end
for k,_ in pairs(t_out) do
if lookup[k]==nil and type(k)=="string" then tinsert(unknown, k) end
end
if #unknown > 0 then
return commonerror("unknown options: " .. tconcat(unknown, ", "))
end
end
if params then
local missing = {}
for _,v in ipairs(params) do
if t_out[v]==nil then tinsert(missing, v) end
end
if #missing > 0 then
return commonerror("missing parameters: " .. tconcat(missing, ", "))
end
end
return t_out
end

View file

@ -1,3 +1,4 @@
local candran = require("candran")
local util = {} local util = {}
function util.search(modpath, exts={}) function util.search(modpath, exts={})
@ -51,4 +52,68 @@ function util.merge(...)
return r return r
end end
util.cli = {
-- add option to set Candran options to an argparse parser
addCandranOptions = function(parser)
parser:group("Compiler options",
parser:option("-t --target")
:description "Target Lua version: lua54, lua53, lua52, luajit or lua51"
:default(candran.default.target),
parser:option("--indentation")
:description "Character(s) used for indentation in the compiled file"
:default(candran.default.indentation),
parser:option("--newline")
:description "Character(s) used for newlines in the compiled file"
:default(candran.default.newline),
parser:option("--variable-prefix")
:description "Prefix used when Candran needs to set a local variable to provide some functionality"
:default(candran.default.variablePrefix),
parser:flag("--no-map-lines")
:description "Do not add comments at the end of each line indicating the associated source line and file (error rewriting will not work)"
)
parser:group("Preprocessor options",
parser:flag("--no-builtin-macros")
:description "Disable built-in macros",
parser:option("-D --define")
:description "Define a preprocessor constant"
:args("1-2")
:argname{"name", "value"}
:count("*")
)
parser:option("--chunkname")
:description "Chunkname used when running the code"
parser:flag("--no-rewrite-errors")
:description "Disable error rewriting when running the code"
end,
-- convert parsed arguments to a Candran options table
makeCandranOptions = function(args)
local preprocessorEnv = {}
for _, o in ipairs(args.define) do
preprocessorEnv[o[1]] = tonumber(o[2]) or o[2] or true
end
local options = {
target = args.target,
indentation = args.indentation,
newline = args.newline,
variablePrefix = args.variable_prefix,
mapLines = not args.no_map_lines,
chunkname = args.chunkname,
rewriteErrors = not args.no_rewrite_errors,
builtInMacros = not args.no_builtin_macros,
preprocessorEnv = preprocessorEnv
}
return options
end
}
return util return util

View file

@ -18,14 +18,16 @@ description = {
} }
source = { source = {
url = "git://github.com/Reuh/candran" url = "git://github.com/Reuh/candran",
branch = "argparse"
} }
dependencies = { dependencies = {
"lua >= 5.1", "lua >= 5.1",
"lpeglabel >= 1.5.0", "lpeglabel >= 1.5.0",
"linenoise >= 0.9", "linenoise >= 0.9",
"luacheck >= 0.23.0" "luacheck >= 0.23.0",
"argparse >= 0.7.0"
} }
build = { build = {