aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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"