aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bitbucket@bruce-hill.com>2018-06-21 19:12:59 -0700
committerBruce Hill <bitbucket@bruce-hill.com>2018-06-21 19:13:47 -0700
commit86a3219e7fc3244331595819f742b365172f96ad (patch)
tree948a3f308bd9c45b85efa2e130af8432bb1a97e2
parent7761f715f7497e8b325a4f1134869f332848fd16 (diff)
Cleanup of some metaprogramming stuff, as well as adding support for
"package.nomsupath" to search for files in different locations, and prioritizing use of "luafilesystem" over system calls.
-rw-r--r--core/control_flow.nom15
-rw-r--r--core/metaprogramming.nom20
-rw-r--r--core/operators.nom10
-rw-r--r--core/scopes.nom8
-rw-r--r--error_handling.lua3
-rw-r--r--error_handling.moon3
-rw-r--r--lib/object.nom22
-rw-r--r--nomsu.lua114
-rwxr-xr-xnomsu.moon83
-rw-r--r--parser.lua5
-rw-r--r--parser.moon5
-rw-r--r--tests/scopes.nom2
12 files changed, 244 insertions, 46 deletions
diff --git a/core/control_flow.nom b/core/control_flow.nom
index 9aae937..0cc8f4e 100644
--- a/core/control_flow.nom
+++ b/core/control_flow.nom
@@ -383,3 +383,18 @@ compile [do %action then always %final_action] to
# Inline thunk:
compile [result of %body] to
Lua value "(\(compile as: [] -> %body))()"
+
+# Recurion control flow
+using
+ compile [%var's stack] to: Lua value "stack\(%var as lua id)"
+..compile
+ parse [for %var in recursive %structure %body] as
+ with local {(%var's stack): [%structure], action: recurse % on %}
+ action [recurse %v on %x]
+ add %x to (%v's stack)
+ repeat while: (length of (%var's stack)) > 0
+ %var <- (remove 1 from (%var's stack))
+ %body
+ === next %var ==
+ === stop %var ===
+
diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom
index 1e167d0..068513a 100644
--- a/core/metaprogramming.nom
+++ b/core/metaprogramming.nom
@@ -52,6 +52,20 @@ lua> ".."
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+compile [using %defs compile %body] to
+ lua> ".."
+ local lua = LuaCode(tree.source)
+ lua:append(
+ "local old_nomsu = nomsu\n",
+ "local nomsu = table.fork(old_nomsu, {COMPILE_ACTIONS=table.fork(old_nomsu.COMPILE_ACTIONS)})")
+ lua:append(nomsu:compile(\%defs))
+ lua:append("\n")
+ lua:append("local ret = nomsu:compile(tree)\n")
+ lua:append("return ret")
+ nomsu = table.fork(nomsu, {tree=\%body})
+ local output = nomsu:run_lua(lua)
+ return output
+
compile [local action %actions %body] to
lua> ".."
local fn_name = "A"..string.as_lua_id(\%actions[1].stub)
@@ -84,6 +98,9 @@ compile [action %actions %body] to
lua:remove_free_vars(table.map(\%actions, function(a) return "A"..string.as_lua_id(a.stub) end))
return lua
+compile [action %action] to
+ Lua value "A\(%action.stub as lua id)"
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compile [parse %actions as %body] to
@@ -160,6 +177,9 @@ compile [declare locals in %code] to
compile [declare locals %locals in %code] to
Lua value "\(%code as lua expr):declare_locals(\(%locals as lua expr))"
+compile [add free vars %vars to %code] to
+ Lua "\(%code as lua expr):add_free_vars(\(%vars as lua expr));"
+
compile [remove free vars %vars from %code] to
Lua "\(%code as lua expr):remove_free_vars(\(%vars as lua expr));"
diff --git a/core/operators.nom b/core/operators.nom
index c81760d..0756751 100644
--- a/core/operators.nom
+++ b/core/operators.nom
@@ -130,16 +130,6 @@ compile [with %assignments %body] to
\%lua
end -- 'with' block
-compile [local %var_or_vars] to
- %lua <- (Lua "")
- lua> ".."
- if \%var_or_vars.type == "List" then
- \%lua:add_free_vars(table.map(\%var_or_vars, function(v) return tostring(nomsu:compile(v)) end))
- else
- \%lua:add_free_vars({tostring(nomsu:compile(\%var_or_vars))})
- end
- return %lua
-
# Math Operators
compile [%x wrapped around %y, %x mod %y] to: Lua value "(\(%x as lua expr) % \(%y as lua expr))"
diff --git a/core/scopes.nom b/core/scopes.nom
index b5fdded..3af59c5 100644
--- a/core/scopes.nom
+++ b/core/scopes.nom
@@ -9,18 +9,18 @@ compile [with local %locals %body, with local %locals do %body] to
* "Dict"
%body_lua <-
Lua ".."
- \(=lua "A_assign_1(\%locals, \%locals)")
+ \(compile as: <- %locals)
\%body_lua
declare locals
- (%.1 as lua id) for % in %locals
+ "\(%.1 as lua)" for % in %locals
.. in %body_lua
* "List"
declare locals
- (% as lua id) for % in %locals
+ "\(% as lua)" for % in %locals
.. in %body_lua
* "Var"
* "Action"
- declare locals [%locals as lua id] in %body_lua
+ declare locals ["\(%locals as lua)"] in %body_lua
* else
barf "Unexpected local: \(%locals as nomsu)"
return
diff --git a/error_handling.lua b/error_handling.lua
index 5e7d715..90c5991 100644
--- a/error_handling.lua
+++ b/error_handling.lua
@@ -197,7 +197,8 @@ end
local error_handler
error_handler = function(error_message)
print_error(error_message)
- return os.exit(false, true)
+ local EXIT_FAILURE = 1
+ return os.exit(EXIT_FAILURE)
end
local run_safely
run_safely = function(fn)
diff --git a/error_handling.moon b/error_handling.moon
index 8aa0a82..c71e782 100644
--- a/error_handling.moon
+++ b/error_handling.moon
@@ -123,7 +123,8 @@ print_error = (error_message, stack_offset=3)->
error_handler = (error_message)->
print_error error_message
- os.exit(false, true)
+ EXIT_FAILURE = 1
+ os.exit(EXIT_FAILURE)
run_safely = (fn)->
xpcall(fn, error_handler)
diff --git a/lib/object.nom b/lib/object.nom
index c5c0091..5f12170 100644
--- a/lib/object.nom
+++ b/lib/object.nom
@@ -4,18 +4,18 @@
use "core"
compile [@, me] to: Lua value "self"
-compile [set methods %methods] to
- %lua <- (Lua "")
- for %m in %methods
- to %lua write "\nclass.\(%m as lua id) = \(%m as lua id)"
- return %lua
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-parse [method %actions %body] as
- with local %actions
- action %actions %body
- set methods %actions
+compile [method %actions %body] to
+ %lua <- (compile as: action %actions %body)
+ add free vars ((% as lua id) for % in %actions) to %lua
+ declare locals in %lua
+ for % in %actions
+ to %lua write "\nclass.\(% as lua id) = \(% as lua id)"
+ return
+ Lua ".."
+ do -- Method: \(%actions.1.stub)
+ \%lua
+ end
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
parse [as %instance %body] as
diff --git a/nomsu.lua b/nomsu.lua
index ca0f7ac..b561eb9 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -1,3 +1,4 @@
+local EXIT_SUCCESS, EXIT_FAILURE = 0, 1
local usage = [=[Nomsu Compiler
Usage: (lua nomsu.lua | moon nomsu.moon) [-i] [-O] [-v] [-c] [-f] [-s] [--help] [-p print_file] file1 file2... [-- nomsu args...]
@@ -13,8 +14,14 @@ OPTIONS
-p <file> Print to the specified file instead of stdout.
<input> Input file can be "-" to use stdin.
]=]
-local lpeg = require('lpeg')
-local re = require('re')
+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 Errhand = require("error_handling")
local NomsuCompiler = require("nomsu_compiler")
local NomsuCode, LuaCode, Source
@@ -46,10 +53,101 @@ local args = table.concat(arg, ";") .. ";"
args = parser:match(args)
if not args or args.help then
print(usage)
- os.exit()
+ os.exit(EXIT_FAILURE)
end
local nomsu = NomsuCompiler
nomsu.arg = args.nomsu_args
+FILE_CACHE = setmetatable({ }, {
+ __index = function(self, filename)
+ local file = io.open(filename)
+ if not (file) then
+ return nil
+ end
+ local contents = file:read("*a")
+ file:close()
+ self[filename] = contents
+ return contents
+ end
+})
+local match, sub, rep, gsub, format, byte, find
+do
+ local _obj_0 = string
+ match, sub, rep, gsub, format, byte, match, find = _obj_0.match, _obj_0.sub, _obj_0.rep, _obj_0.gsub, _obj_0.format, _obj_0.byte, _obj_0.match, _obj_0.find
+end
+local iterate_single
+iterate_single = function(item, prev)
+ if item == prev then
+ return nil
+ else
+ return item
+ end
+end
+local lfs
+ok, lfs = pcall(require, "lfs")
+if ok then
+ all_files = function(path)
+ local browse
+ browse = function(filename)
+ local file_type = lfs.attributes(filename, 'mode')
+ if file_type == 'file' then
+ if match(filename, "%.nom$") or match(filename, "%.lua$") then
+ coroutine.yield(filename)
+ return true
+ end
+ elseif file_type == 'directory' then
+ for subfile in lfs.dir(filename) do
+ if not (subfile == "." or subfile == "..") then
+ browse(filename .. "/" .. subfile)
+ end
+ end
+ return true
+ elseif file_type == 'char device' then
+ coroutine.yield(filename)
+ return true
+ end
+ return false
+ end
+ return coroutine.wrap(function()
+ if not browse(path) and package.nomsupath then
+ browse(package.nomsupath .. "/" .. path)
+ end
+ return nil
+ end)
+ end
+else
+ local ret = os.execute('find . -maxdepth 0')
+ if not (ret == true or ret == 0) then
+ error("Could not find 'luafilesystem' module and couldn't run system command `find` (this might happen on Windows). Please install `luafilesystem` (which can be found at: http://keplerproject.github.io/luafilesystem/ or `luarocks install luafilesystem`)", 0)
+ end
+ all_files = function(path)
+ if match(path, "%.nom$") or match(path, "%.lua$") or match(path, "^/dev/fd/[012]$") then
+ return iterate_single, path
+ end
+ path = gsub(path, "\\", "\\\\")
+ path = gsub(path, "`", "")
+ path = gsub(path, '"', '\\"')
+ path = gsub(path, "$", "")
+ return coroutine.wrap(function()
+ local f = io.popen('find -L "' .. path .. '" -not -path "*/\\.*" -type f -name "*.nom"')
+ local found = false
+ for line in f:lines() do
+ found = true
+ coroutine.yield(line)
+ end
+ if not found and package.nomsupath then
+ f:close()
+ f = io.popen('find -L "' .. package.nomsupath .. '/' .. path .. '" -not -path "*/\\.*" -type f -name "*.nom"')
+ for line in f:lines() do
+ coroutine.yield(line)
+ end
+ end
+ local success = f:close()
+ if not (success) then
+ return error("Invalid file path: " .. tostring(path))
+ end
+ end)
+ end
+end
local run
run = function()
for i, input in ipairs(args.inputs) do
@@ -120,7 +218,8 @@ run = function()
local filename = input_files[_index_0]
if args.syntax then
local file_contents = io.open(filename):read('*a')
- local ok, err = pcall(nomsu.parse, nomsu, file_contents, Source(filename, 1, #file_contents))
+ local err
+ ok, err = pcall(nomsu.parse, nomsu, file_contents, Source(filename, 1, #file_contents))
if not ok then
table.insert(parse_errs, err)
elseif print_file then
@@ -149,9 +248,9 @@ run = function()
if #parse_errs > 0 then
io.stderr:write(table.concat(parse_errs, "\n\n"))
io.stderr:flush()
- os.exit(false, true)
+ os.exit(EXIT_FAILURE)
elseif args.syntax then
- os.exit(true, true)
+ os.exit(EXIT_SUCCESS)
end
if args.interactive then
for repl_line = 1, math.huge do
@@ -179,7 +278,8 @@ run = function()
err_hand = function(error_message)
return Errhand.print_error(error_message)
end
- local ok, ret = xpcall(nomsu.run, err_hand, nomsu, buff, Source(pseudo_filename, 1, #buff))
+ local ret
+ ok, ret = xpcall(nomsu.run, err_hand, nomsu, buff, Source(pseudo_filename, 1, #buff))
if ok and ret ~= nil then
print("= " .. repr(ret))
elseif not ok then
diff --git a/nomsu.moon b/nomsu.moon
index cace55f..86097a7 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -1,5 +1,6 @@
#!/usr/bin/env moon
-- This file contains the command-line Nomsu runner.
+EXIT_SUCCESS, EXIT_FAILURE = 0, 1
usage = [=[
Nomsu Compiler
@@ -17,8 +18,13 @@ OPTIONS
<input> Input file can be "-" to use stdin.
]=]
-lpeg = require 'lpeg'
-re = require 're'
+ok, _ = pcall ->
+ export lpeg, re
+ lpeg = require 'lpeg'
+ re = require 're'
+if not ok
+ 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)
Errhand = require "error_handling"
NomsuCompiler = require "nomsu_compiler"
{:NomsuCode, :LuaCode, :Source} = require "code_obj"
@@ -45,11 +51,78 @@ args = table.concat(arg, ";")..";"
args = parser\match(args)
if not args or args.help
print usage
- os.exit!
+ os.exit(EXIT_FAILURE)
nomsu = NomsuCompiler
nomsu.arg = args.nomsu_args
+export FILE_CACHE
+-- FILE_CACHE is a map from filename (string) -> string of file contents
+FILE_CACHE = setmetatable {}, {
+ __index: (filename)=>
+ file = io.open(filename)
+ return nil unless file
+ contents = file\read("*a")
+ file\close!
+ self[filename] = contents
+ return contents
+}
+
+export all_files
+{:match, :sub, :rep, :gsub, :format, :byte, :match, :find} = string
+iterate_single = (item, prev) -> if item == prev then nil else item
+ok, lfs = pcall(require, "lfs")
+if ok
+ all_files = (path)->
+ browse = (filename)->
+ file_type = lfs.attributes(filename, 'mode')
+ if file_type == 'file'
+ if match(filename, "%.nom$") or match(filename, "%.lua$")
+ coroutine.yield filename
+ return true
+ elseif file_type == 'directory'
+ for subfile in lfs.dir(filename)
+ unless subfile == "." or subfile == ".."
+ browse(filename.."/"..subfile)
+ return true
+ elseif file_type == 'char device'
+ coroutine.yield(filename)
+ return true
+ return false
+ return coroutine.wrap ->
+ if not browse(path) and package.nomsupath
+ browse(package.nomsupath.."/"..path)
+ return nil
+else
+ ret = os.execute('find . -maxdepth 0')
+ unless ret == true or ret == 0
+ error "Could not find 'luafilesystem' module and couldn't run system command `find` (this might happen on Windows). Please install `luafilesystem` (which can be found at: http://keplerproject.github.io/luafilesystem/ or `luarocks install luafilesystem`)", 0
+
+ all_files = (path)->
+ -- Sanitize path
+ if match(path, "%.nom$") or match(path, "%.lua$") or match(path, "^/dev/fd/[012]$")
+ return iterate_single, path
+ -- TODO: improve sanitization
+ path = gsub(path,"\\","\\\\")
+ path = gsub(path,"`","")
+ path = gsub(path,'"','\\"')
+ path = gsub(path,"$","")
+ return coroutine.wrap ->
+ f = io.popen('find -L "'..path..'" -not -path "*/\\.*" -type f -name "*.nom"')
+ found = false
+ for line in f\lines!
+ found = true
+ coroutine.yield(line)
+ if not found and package.nomsupath
+ f\close!
+ f = io.popen('find -L "'..package.nomsupath..'/'..path..'" -not -path "*/\\.*" -type f -name "*.nom"')
+ for line in f\lines!
+ coroutine.yield(line)
+ success = f\close!
+ unless success
+ error("Invalid file path: "..tostring(path))
+
+
run = ->
for i,input in ipairs args.inputs
if input == "-" then args.inputs[i] = STDIN
@@ -126,9 +199,9 @@ run = ->
if #parse_errs > 0
io.stderr\write table.concat(parse_errs, "\n\n")
io.stderr\flush!
- os.exit(false, true)
+ os.exit(EXIT_FAILURE)
elseif args.syntax
- os.exit(true, true)
+ os.exit(EXIT_SUCCESS)
if args.interactive
-- REPL
diff --git a/parser.lua b/parser.lua
index a94418f..e685d56 100644
--- a/parser.lua
+++ b/parser.lua
@@ -127,7 +127,7 @@ do
ident <- [a-zA-Z_][a-zA-Z0-9_]*
comment <- "--" [^%nl]*
]])
- local nomsu_peg = peg_tidier:match(io.open("nomsu.peg"):read('*a'))
+ local nomsu_peg = peg_tidier:match(io.open((package.nomsupath or '.') .. "/nomsu.peg"):read('*a'))
NOMSU_PATTERN = re.compile(nomsu_peg, NOMSU_DEFS)
end
local parse
@@ -162,8 +162,7 @@ parse = function(nomsu_code, source)
end
errors = _accum_0
end
- io.stderr:write("Errors occurred while parsing:\n\n", table.concat(errors, "\n\n"), '\n')
- os.exit(1)
+ error("Errors occurred while parsing:\n\n" .. table.concat(errors, "\n\n"), 0)
end
return tree
end
diff --git a/parser.moon b/parser.moon
index a713e85..51538cc 100644
--- a/parser.moon
+++ b/parser.moon
@@ -98,7 +98,7 @@ NOMSU_PATTERN = do
ident <- [a-zA-Z_][a-zA-Z0-9_]*
comment <- "--" [^%nl]*
]]
- nomsu_peg = peg_tidier\match(io.open("nomsu.peg")\read('*a'))
+ nomsu_peg = peg_tidier\match(io.open((package.nomsupath or '.').."/nomsu.peg")\read('*a'))
re.compile(nomsu_peg, NOMSU_DEFS)
parse = (nomsu_code, source=nil)->
@@ -116,8 +116,7 @@ parse = (nomsu_code, source=nil)->
keys = utils.keys(userdata.errors)
table.sort(keys)
errors = [userdata.errors[k] for k in *keys]
- io.stderr\write("Errors occurred while parsing:\n\n", table.concat(errors, "\n\n"), '\n')
- os.exit(1)
+ error("Errors occurred while parsing:\n\n"..table.concat(errors, "\n\n"), 0)
return tree
diff --git a/tests/scopes.nom b/tests/scopes.nom
index b9d1f4f..67598be 100644
--- a/tests/scopes.nom
+++ b/tests/scopes.nom
@@ -7,7 +7,7 @@ with local %x
assume: %x = "outer"
action [foo] "outer foo"
-with local (foo)
+with local [action: foo]
action [foo] "inner foo"
assume: (foo) = "inner foo"
assume: (foo) = "outer foo"