301 lines
9.4 KiB
Lua
301 lines
9.4 KiB
Lua
NOMSU_VERSION = {
|
|
7,
|
|
0,
|
|
1
|
|
}
|
|
local clibtype = package.cpath:match("?%.(so)") or package.cpath:match("?%.(dll)")
|
|
if NOMSU_PREFIX then
|
|
package.path = tostring(NOMSU_PREFIX) .. "/share/nomsu/" .. tostring(table.concat(NOMSU_VERSION, ".")) .. "/?.lua;" .. package.path
|
|
package.cpath = tostring(NOMSU_PREFIX) .. "/lib/nomsu/" .. tostring(table.concat(NOMSU_VERSION, ".")) .. "/?." .. tostring(clibtype) .. ";" .. package.cpath
|
|
end
|
|
COLOR_ENABLED = true
|
|
if clibtype == "dll" then
|
|
local ok, enable_colors = pcall(require, 'wincolors')
|
|
COLOR_ENABLED = false
|
|
if ok then
|
|
local _
|
|
ok, _ = pcall(enable_colors)
|
|
if ok then
|
|
COLOR_ENABLED = false
|
|
end
|
|
end
|
|
pcall(os.execute, "chcp 65001>nul")
|
|
end
|
|
local List, Dict
|
|
do
|
|
local _obj_0 = require('containers')
|
|
List, Dict = _obj_0.List, _obj_0.Dict
|
|
end
|
|
NOMSU_VERSION = List(NOMSU_VERSION)
|
|
local Text = require('text')
|
|
require('builtin_metatables')
|
|
local EXIT_FAILURE = 1
|
|
local EXIT_SUCCESS = 0
|
|
local usage = [=[Nomsu Usage: nomsu [-V version] [--help | -h] [--version] [-O optimization level] [-v] [-c] [-s] [-d debugger] [--no-core] [(file | -t tool | -e "nomsu code..." | files... -- ) [nomsu args...]]
|
|
|
|
OPTIONS
|
|
-t <tool> Run a tool.
|
|
-e Execute the specified string.
|
|
-O <level> Run the compiler with the given optimization level (>0: use precompiled .lua versions of Nomsu files, when available).
|
|
-v Verbose: print compiled lua code.
|
|
-c Compile the input files into a .lua files.
|
|
-s Check the input files for syntax errors.
|
|
-d <debugger> Attempt to use the specified debugger to wrap the main body of execution.
|
|
-h/--help Print this message.
|
|
--version Print the version number and exit.
|
|
--no-core Skip loading the Nomsu core by default.
|
|
-V specify which Nomsu version is desired.
|
|
<file> The Nomsu file to run (can be "-" to use stdin).
|
|
]=]
|
|
local ok, _ = pcall(function()
|
|
lpeg = require('lpeg')
|
|
re = require('re')
|
|
end)
|
|
if not ok then
|
|
print("Error: unable to find the 'lpeg' Lua module. Please install LPEG either from http://www.inf.puc-rio.br/~roberto/lpeg/re.html or, if you use luarocks: `luarocks install lpeg`")
|
|
os.exit(EXIT_FAILURE)
|
|
end
|
|
local Files = require("files")
|
|
local NomsuCode, LuaCode, Source
|
|
do
|
|
local _obj_0 = require("code_obj")
|
|
NomsuCode, LuaCode, Source = _obj_0.NomsuCode, _obj_0.LuaCode, _obj_0.Source
|
|
end
|
|
local sep = "\3"
|
|
local parser = re.compile([[ args <- {| (flag %sep)*
|
|
{:files: {|
|
|
( ("-m" %sep)? (file %sep)+ "--" %sep
|
|
/ file %sep
|
|
/ {~ '' %sep? -> 'nomsu://tools/repl.nom' ~}) |} :}
|
|
{:nomsu_args: {| (nomsu_flag %sep)* {:extras: {| ({[^%sep]+} %sep)* |} :} |} :}
|
|
|} ({.+}?)
|
|
|
|
file <-
|
|
( "-e" %sep ({[^%sep]+} -> spoof)
|
|
/ "-t" %sep {~ {[^%sep]+} -> "nomsu://tools/%1.nom" ~}
|
|
/ !"--" {[^%sep]+})
|
|
|
|
flag <- longflag / shortflag / "-" shortboolflag+
|
|
longflag <-
|
|
{:help: "--help" %true :}
|
|
/ {:version: "--version" %true :}
|
|
/ {:no_core: "--no-core" %true :}
|
|
shortflag <-
|
|
{:optimization: "-O" %sep? %number :}
|
|
/ {:debugger: ("-d" %sep? {[^%sep]+}) :}
|
|
/ {:requested_version: "-V" %sep? {([0-9.])+} :}
|
|
shortboolflag <-
|
|
{:check_syntax: "s" %true:}
|
|
/ {:compile: "c" %true:}
|
|
/ {:verbose: "v" %true :}
|
|
/ {:help: "h" %true :}
|
|
|
|
nomsu_flag <- nomsu_longflag / "-" nomsu_shortboolflag+
|
|
nomsu_shortboolflag <- {| {:key: [a-zA-Z] :} {:value: %true :} |}
|
|
nomsu_longflag <- '--' {| {:key: [^%sep=]+ :} {:value: ('=' {[^%sep]+}) / %true :} |}
|
|
]], {
|
|
["true"] = lpeg.Cc(true),
|
|
number = lpeg.R("09") ^ 1 / tonumber,
|
|
sep = lpeg.P(sep),
|
|
spoof = Files.spoof
|
|
})
|
|
local arg_string = table.concat(arg, sep) .. sep
|
|
local args, err = parser:match(arg_string)
|
|
if not args or err then
|
|
if err then
|
|
print("Didn't understand: " .. tostring(err))
|
|
end
|
|
print(usage)
|
|
os.exit(EXIT_FAILURE)
|
|
end
|
|
if args.help then
|
|
print("Nomsu - A dynamically typed programming language with natural syntax and strong metaprogramming abilities.")
|
|
print("https://nomsu.org\n")
|
|
print(usage)
|
|
os.exit(EXIT_SUCCESS)
|
|
end
|
|
if args.version then
|
|
print(NOMSU_VERSION:joined_with("."))
|
|
os.exit(EXIT_SUCCESS)
|
|
end
|
|
local nomsu_args = Dict({ })
|
|
local _list_0 = args.nomsu_args
|
|
for _index_0 = 1, #_list_0 do
|
|
local argpair = _list_0[_index_0]
|
|
nomsu_args[argpair.key] = argpair.value
|
|
end
|
|
nomsu_args.extras = List(args.nomsu_args.extras or { })
|
|
local optimization = tonumber(args.optimization or 1)
|
|
local nomsupath = { }
|
|
local suffixes
|
|
if optimization > 0 then
|
|
suffixes = {
|
|
"?.lua",
|
|
"?/init.lua",
|
|
"?.nom",
|
|
"?/init.nom"
|
|
}
|
|
else
|
|
suffixes = {
|
|
"?.nom",
|
|
"?/init.nom"
|
|
}
|
|
end
|
|
local add_path
|
|
add_path = function(p)
|
|
for _index_0 = 1, #suffixes do
|
|
local s = suffixes[_index_0]
|
|
table.insert(nomsupath, p .. "/" .. s)
|
|
end
|
|
end
|
|
if NOMSU_PREFIX then
|
|
add_path(tostring(NOMSU_PREFIX) .. "/share/nomsu/" .. tostring(NOMSU_VERSION:joined_with(".")) .. "/lib")
|
|
else
|
|
add_path("./lib")
|
|
end
|
|
local NOMSU_PACKAGEPATH = NOMSU_PACKAGEPATH or "/opt/nomsu"
|
|
add_path(NOMSU_PACKAGEPATH)
|
|
add_path(".")
|
|
package.nomsupath = table.concat(nomsupath, ";")
|
|
package.nomsuloaded = Dict({ })
|
|
local nomsu_environment = require('nomsu_environment')
|
|
nomsu_environment.NOMSU_VERSION = NOMSU_VERSION
|
|
nomsu_environment.COMMAND_LINE_ARGS = nomsu_args
|
|
nomsu_environment.OPTIMIZATION = optimization
|
|
nomsu_environment.NOMSU_PACKAGEPATH = NOMSU_PACKAGEPATH
|
|
nomsu_environment.NOMSU_PREFIX = NOMSU_PREFIX
|
|
nomsu_environment.COLOR_ENABLED = COLOR_ENABLED
|
|
local run
|
|
run = function()
|
|
if not (args.no_core) then
|
|
nomsu_environment:export("core")
|
|
end
|
|
local input_files = { }
|
|
if args.files and #args.files > 0 then
|
|
local _list_1 = args.files
|
|
for _index_0 = 1, #_list_1 do
|
|
local f = _list_1[_index_0]
|
|
do
|
|
local nomsu_name = f:match("^nomsu://(.*)%.nom")
|
|
if nomsu_name then
|
|
local path
|
|
path, err = package.searchpath(nomsu_name, package.nomsupath, "/")
|
|
if not path then
|
|
error(err)
|
|
end
|
|
table.insert(input_files, path)
|
|
else
|
|
table.insert(input_files, f)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
for _index_0 = 1, #input_files do
|
|
local filename = input_files[_index_0]
|
|
if args.check_syntax then
|
|
local code = Files.read(filename)
|
|
local source = Source(filename, 1, #code)
|
|
nomsu_environment._1_parsed(NomsuCode:from(source, code))
|
|
print("Parse succeeded: " .. tostring(filename))
|
|
elseif args.compile then
|
|
local code = Files.read(filename)
|
|
if not code then
|
|
error("Could not find file '" .. tostring(filename) .. "'")
|
|
end
|
|
if filename:match("%.lua$") then
|
|
error("Cannot compile a lua file (expected a nomsu file as input)")
|
|
end
|
|
local output
|
|
if filename == 'stdin' then
|
|
output = io.output()
|
|
else
|
|
output = io.open(filename:gsub("%.nom$", ".lua"), "w")
|
|
end
|
|
local source = Source(filename, 1, #code)
|
|
code = NomsuCode:from(source, code)
|
|
local env = nomsu_environment.new_environment()
|
|
env.MODULE_NAME = filename
|
|
local tree = env._1_parsed(code)
|
|
if tree.shebang then
|
|
output:write(tree.shebang)
|
|
end
|
|
if not (tree.type == 'FileChunks') then
|
|
tree = {
|
|
tree
|
|
}
|
|
end
|
|
for chunk_no, chunk in ipairs(tree) do
|
|
local lua = env:compile(chunk)
|
|
lua:declare_locals()
|
|
lua:prepend((chunk_no > 1) and '\n' or '', "-- File " .. tostring(filename) .. " chunk #" .. tostring(chunk_no) .. "\n")
|
|
if args.verbose then
|
|
print(lua:text())
|
|
end
|
|
env:run(chunk)
|
|
output:write(lua:text(), "\n")
|
|
end
|
|
print(("Compiled %-25s -> %s"):format(filename, filename:gsub("%.nom$", ".lua")))
|
|
output:close()
|
|
elseif args.verbose then
|
|
local env = nomsu_environment.new_environment()
|
|
env.MODULE_NAME = filename
|
|
env.WAS_RUN_DIRECTLY = true
|
|
local code = Files.read(filename)
|
|
local source = Source(filename, 1, #code)
|
|
if filename:match("%.lua$") then
|
|
code = LuaCode:from(Source(filename, 1, #code), code)
|
|
print(code:text())
|
|
env:run(code)
|
|
else
|
|
code = NomsuCode:from(source, code)
|
|
local tree = env._1_parsed(code)
|
|
if not (tree.type == 'FileChunks') then
|
|
tree = {
|
|
tree
|
|
}
|
|
end
|
|
for chunk_no, chunk in ipairs(tree) do
|
|
local lua = env:compile(chunk)
|
|
lua:declare_locals()
|
|
lua:prepend((chunk_no > 1) and '\n' or '', "-- File " .. tostring(filename) .. " chunk #" .. tostring(chunk_no) .. "\n")
|
|
print(lua:text())
|
|
env:run(lua)
|
|
end
|
|
end
|
|
else
|
|
local f = Files.read(filename)
|
|
if not f then
|
|
if filename:match("^-") then
|
|
print("Not a valid flag: " .. filename .. "\n")
|
|
print(usage)
|
|
else
|
|
print("File not found: " .. filename)
|
|
end
|
|
os.exit(EXIT_FAILURE)
|
|
end
|
|
if filename:match("%.lua$") then
|
|
f = LuaCode:from(Source(filename, 1, #f), f)
|
|
end
|
|
local env = nomsu_environment.new_environment()
|
|
env.MODULE_NAME = filename
|
|
env.WAS_RUN_DIRECTLY = true
|
|
env:run(f)
|
|
end
|
|
end
|
|
end
|
|
local debugger
|
|
if args.debugger == "nil" then
|
|
debugger = { }
|
|
else
|
|
debugger = require(args.debugger or 'error_handling')
|
|
end
|
|
local guard
|
|
if type(debugger) == 'function' then
|
|
guard = debugger
|
|
else
|
|
guard = debugger.guard or debugger.call or debugger.wrap or debugger.run or (function(fn)
|
|
return fn()
|
|
end)
|
|
end
|
|
return guard(run)
|