aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/metaprogramming.nom19
-rw-r--r--nomsu.lua2
-rwxr-xr-xnomsu.moon2
-rw-r--r--nomsu_compiler.lua101
-rw-r--r--nomsu_compiler.moon80
-rw-r--r--syntax_tree.lua4
-rw-r--r--syntax_tree.moon4
-rwxr-xr-xtools/test.nom1
8 files changed, 117 insertions, 96 deletions
diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom
index f669493..93d5486 100644
--- a/core/metaprogramming.nom
+++ b/core/metaprogramming.nom
@@ -205,14 +205,8 @@ compile [parse %actions as %body] to (..)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-action [%tree as lua expr]:
- lua> "\
- ..\%tree_lua = nomsu:compile(\%tree)
- if not \%tree_lua.is_value then
- nomsu:compile_error(\%tree.source, "Could not convert %s to a Lua expression",
- nomsu:tree_to_nomsu(\%tree))
- end
- return \%tree_lua"
+# TODO: add check for .is_value
+compile [%tree as lua expr] to (Lua value "nomsu:compile(\(=lua "nomsu:compile(\%tree)"))")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -343,18 +337,17 @@ compile [parse %text from %filename] to (..)
test:
assume ((run "return (2 + 99)") == 101)
external %passed = (no)
- run \:
- \(external \%passed = \(yes))
+ run "external %passed = (yes)"
assume %passed
compile [run %nomsu_code] to (..)
Lua value "\
- ..nomsu:run(\(%nomsu_code as lua expr), \(..)
+ ..nomsu:run(NomsuCode(\(..)
=lua "repr(tostring(\(%nomsu_code.source)))"
- ..)"
+ .., \(%nomsu_code as lua expr)))"
test:
assume ((\(\(5) + \(5)) as value) == 10) or barf "%tree as value failed."
-action [run tree %tree, %tree as value] (lua> "return nomsu:run(\%tree)")
+compile [run tree %tree, %tree as value] to (Lua value "nomsu:run(\(%tree as lua expr))")
compile [compile %block, compiled %block, %block compiled] to (..)
Lua value "nomsu:compile(\(%block as lua))"
diff --git a/nomsu.lua b/nomsu.lua
index 328ef32..fda8dd4 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -187,7 +187,7 @@ run = function()
if not (args.no_core) then
for _, filename in Files.walk('core') do
if filename:match("%.nom$") then
- nomsu:run_file(filename)
+ nomsu:import(nomsu:run_file(filename))
end
end
end
diff --git a/nomsu.moon b/nomsu.moon
index fcae65d..04a9515 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -126,7 +126,7 @@ run = ->
unless args.no_core
for _,filename in Files.walk('core')
if filename\match "%.nom$"
- nomsu\run_file filename
+ nomsu\import(nomsu\run_file(filename))
get_file_and_source = (filename)->
local file, source
diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua
index bdacdfb..7d733e6 100644
--- a/nomsu_compiler.lua
+++ b/nomsu_compiler.lua
@@ -141,21 +141,9 @@ for version = 1, 999 do
end
end
local MAX_LINE = 80
-local NomsuCompiler = setmetatable({
- name = "Nomsu"
-}, {
- __index = function(self, k)
- do
- local _self = rawget(self, "self")
- if _self then
- return _self[k]
- else
- return nil
- end
- end
- end,
+local NomsuCompiler = setmetatable({ }, {
__tostring = function(self)
- return self.name
+ return "Nomsu"
end
})
local _anon_chunk = 0
@@ -163,6 +151,7 @@ do
NomsuCompiler.NOMSU_COMPILER_VERSION = 8
NomsuCompiler.NOMSU_SYNTAX_VERSION = max_parser_version
NomsuCompiler.nomsu = NomsuCompiler
+ NomsuCompiler.global = Dict({ })
NomsuCompiler.parse = function(self, nomsu_code, source, version)
if source == nil then
source = nil
@@ -316,6 +305,26 @@ do
NomsuCompiler.LOADED = { }
NomsuCompiler.TESTS = { }
NomsuCompiler.AST = AST
+ NomsuCompiler.fork = function(self)
+ local f = setmetatable({ }, {
+ __index = self
+ })
+ f.COMPILE_ACTIONS = setmetatable({ }, {
+ __index = self.COMPILE_ACTIONS
+ })
+ f.nomsu = f
+ return f
+ end
+ local math_expression = re.compile([[ ([+-] " ")* [0-9]+ (" " [*/^+-] (" " [+-])* " " [0-9]+)+ !. ]])
+ NomsuCompiler.get_compile_action = function(self, stub)
+ local ret = self.COMPILE_ACTIONS[stub]
+ if not (ret == nil) then
+ return ret
+ end
+ if math_expression:match(stub) then
+ return self.COMPILE_ACTIONS["# compile math expr #"]
+ end
+ end
NomsuCompiler.compile_error = function(self, source, err_format_string, ...)
err_format_string = err_format_string:gsub("%%[^s]", "%%%1")
local file = Files.read(source.filename)
@@ -330,7 +339,6 @@ do
local err_msg = err_format_string:format(src, ...)
return error(tostring(source.filename) .. ":" .. tostring(line_no) .. ": " .. err_msg, 0)
end
- local math_expression = re.compile([[ ([+-] " ")* [0-9]+ (" " [*/^+-] (" " [+-])* " " [0-9]+)+ !. ]])
local add_lua_bits
add_lua_bits = function(self, val_or_stmt, code)
local cls = val_or_stmt == "value" and LuaCode.Value or LuaCode
@@ -389,7 +397,7 @@ do
end
return operate_on_text(code)
end
- NomsuCompiler.COMPILE_ACTIONS = setmetatable({
+ NomsuCompiler.COMPILE_ACTIONS = {
["# compile math expr #"] = function(self, tree, ...)
local lua = LuaCode.Value(tree.source)
for i, tok in ipairs(tree) do
@@ -419,23 +427,23 @@ do
end,
["lua > 1"] = function(self, tree, code)
if code.type ~= "Text" then
- return LuaCode(tree.source, "nomsu:run_lua(", self:compile(code), ");")
+ return LuaCode(tree.source, "nomsu:run_lua(", self:compile(code), ", nomsu);")
end
return add_lua_bits(self, "statements", code)
end,
["= lua 1"] = function(self, tree, code)
if code.type ~= "Text" then
- return LuaCode.Value(tree.source, "nomsu:run_lua(", self:compile(code), ":as_statements('return '))")
+ return LuaCode.Value(tree.source, "nomsu:run_lua(", self:compile(code), ":as_statements('return '), nomsu)")
end
return add_lua_bits(self, "value", code)
end,
["use 1"] = function(self, tree, path)
if path.type == 'Text' and #path == 1 and type(path[1]) == 'string' then
for _, f in Files.walk(path[1]) do
- self:run_file(f)
+ self:import(self:run_file(f))
end
end
- return LuaCode(tree.source, "for i,f in Files.walk(", self:compile(path), ") do nomsu:run_file(f) end")
+ return LuaCode(tree.source, "for i,f in Files.walk(", self:compile(path), ") do nomsu:import(nomsu:run_file(f)) end")
end,
["tests"] = function(self, tree)
return LuaCode.Value(tree.source, "TESTS")
@@ -459,21 +467,19 @@ do
["Lua version"] = function(self, tree, code)
return LuaCode.Value(tree.source, repr(_VERSION))
end
- }, {
- __index = function(self, stub)
- if math_expression:match(stub) then
- return self["# compile math expr #"]
+ }
+ NomsuCompiler.import = function(self, mod)
+ for k, v in pairs(mod) do
+ if not (k == "COMPILE_ACTIONS" or k == "nomsu" or k == "_ENV") then
+ self[k] = v
end
end
- })
- NomsuCompiler.run = function(self, to_run, source, version)
- if source == nil then
- source = nil
- end
- if version == nil then
- version = nil
+ for k, v in pairs(mod.COMPILE_ACTIONS) do
+ self.COMPILE_ACTIONS[k] = v
end
- source = source or (to_run.source or Source(to_run, 1, #to_run))
+ end
+ NomsuCompiler.run = function(self, to_run)
+ local source = to_run.source or Source(to_run, 1, #to_run)
if type(source) == 'string' then
source = Source:from_string(source)
end
@@ -484,7 +490,7 @@ do
if AST.is_syntax_tree(to_run) then
tree = to_run
else
- tree = self:parse(to_run, source, version)
+ tree = self:parse(to_run, source)
end
if tree == nil then
return nil
@@ -528,10 +534,11 @@ do
end
end
insert(_running_files, filename)
- local ret = nil
+ local mod = self:fork()
+ mod.from_file = filename
if match(filename, "%.lua$") then
local file = assert(Files.read(filename), "Could not find file: " .. tostring(filename))
- ret = self:run_lua(file, Source(filename, 1, #file))
+ local ret = mod:run_lua(LuaCode(Source(filename, 1, #file), file))
elseif match(filename, "%.nom$") or match(filename, "^/dev/fd/[012]$") then
local ran_lua
if self.can_optimize(filename) then
@@ -539,7 +546,10 @@ do
do
local file = Files.read(lua_filename)
if file then
- ret = self:run_lua(file, Source(lua_filename, 1, #file))
+ local ret = mod:run_lua(LuaCode(Source(lua_filename, 1, #file), file))
+ if type(ret) == 'table' then
+ mod = ret
+ end
ran_lua = true
end
end
@@ -549,20 +559,19 @@ do
if not file then
error("Tried to run file that does not exist: " .. tostring(filename))
end
- ret = self:run(file, Source(filename, 1, #file))
+ local ret = mod:run(NomsuCode(Source(filename, 1, #file), file))
+ if type(ret) == 'table' then
+ mod = ret
+ end
end
else
error("Invalid filetype for " .. tostring(filename), 0)
end
- self.LOADED[filename] = ret or true
+ self.LOADED[filename] = mod
remove(_running_files)
- self.LOADED[filename] = ret or true
- return ret
+ return mod
end
- NomsuCompiler.run_lua = function(self, lua, source)
- if source == nil then
- source = nil
- end
+ NomsuCompiler.run_lua = function(self, lua)
local lua_string = tostring(lua)
local run_lua_fn, err = load(lua_string, nil and tostring(source or lua.source), "t", self)
if not run_lua_fn then
@@ -577,7 +586,7 @@ do
end)(), "\n")
error("Failed to compile generated code:\n" .. tostring(colored.bright(colored.blue(colored.onblack(line_numbered_lua)))) .. "\n\n" .. tostring(err), 0)
end
- source = source or lua.source
+ local source = lua.source or Source(lua_string, 1, #lua_string)
local source_key = tostring(source)
if not (SOURCE_MAP[source_key]) then
local map = { }
@@ -632,7 +641,7 @@ do
if "Action" == _exp_0 then
local stub = tree.stub
do
- local compile_action = self.COMPILE_ACTIONS[stub]
+ local compile_action = self:get_compile_action(stub)
if compile_action then
local args
do
diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon
index a86a9e7..944f7b8 100644
--- a/nomsu_compiler.moon
+++ b/nomsu_compiler.moon
@@ -84,14 +84,13 @@ for version=1,999
else break
MAX_LINE = 80 -- For beautification purposes, try not to make lines much longer than this value
-NomsuCompiler = setmetatable {name:"Nomsu"},
- __index: (k)=> if _self = rawget(@, "self") then _self[k] else nil
- __tostring: => @name
+NomsuCompiler = setmetatable {}, __tostring: => "Nomsu"
_anon_chunk = 0
with NomsuCompiler
.NOMSU_COMPILER_VERSION = 8
.NOMSU_SYNTAX_VERSION = max_parser_version
.nomsu = NomsuCompiler
+ .global = Dict{}
.parse = (nomsu_code, source=nil, version=nil)=>
source or= nomsu_code.source
nomsu_code = tostring(nomsu_code)
@@ -152,6 +151,24 @@ with NomsuCompiler
.TESTS = {}
.AST = AST
+ .fork = =>
+ f = setmetatable({}, {__index:@})
+ f.COMPILE_ACTIONS = setmetatable({}, {__index:@COMPILE_ACTIONS})
+ f.nomsu = f
+ return f
+
+ -- This is a bit of a hack, but this code handles arbitrarily complex
+ -- math expressions like 2*x + 3^2 without having to define a single
+ -- action for every possibility.
+ math_expression = re.compile [[ ([+-] " ")* [0-9]+ (" " [*/^+-] (" " [+-])* " " [0-9]+)+ !. ]]
+
+ .get_compile_action = (stub)=>
+ ret = @COMPILE_ACTIONS[stub]
+ return ret unless ret == nil
+ if math_expression\match(stub)
+ return @COMPILE_ACTIONS["# compile math expr #"]
+
+ -- TODO: use pretty_error instead of this
.compile_error = (source, err_format_string, ...)=>
err_format_string = err_format_string\gsub("%%[^s]", "%%%1")
file = Files.read(source.filename)
@@ -166,11 +183,6 @@ with NomsuCompiler
err_msg = err_format_string\format(src, ...)
error("#{source.filename}:#{line_no}: "..err_msg, 0)
- -- This is a bit of a hack, but this code handles arbitrarily complex
- -- math expressions like 2*x + 3^2 without having to define a single
- -- action for every possibility.
- math_expression = re.compile [[ ([+-] " ")* [0-9]+ (" " [*/^+-] (" " [+-])* " " [0-9]+)+ !. ]]
-
add_lua_bits = (val_or_stmt, code)=>
cls = val_or_stmt == "value" and LuaCode.Value or LuaCode
operate_on_text = (text)->
@@ -214,7 +226,7 @@ with NomsuCompiler
return lua
return operate_on_text code
- .COMPILE_ACTIONS = setmetatable {
+ .COMPILE_ACTIONS = {
["# compile math expr #"]: (tree, ...)=>
lua = LuaCode.Value(tree.source)
for i,tok in ipairs tree
@@ -239,19 +251,20 @@ with NomsuCompiler
["lua > 1"]: (tree, code)=>
if code.type != "Text"
- return LuaCode tree.source, "nomsu:run_lua(", @compile(code), ");"
+ return LuaCode tree.source, "nomsu:run_lua(", @compile(code), ", nomsu);"
return add_lua_bits(@, "statements", code)
["= lua 1"]: (tree, code)=>
if code.type != "Text"
- return LuaCode.Value tree.source, "nomsu:run_lua(", @compile(code), ":as_statements('return '))"
+ return LuaCode.Value tree.source, "nomsu:run_lua(", @compile(code), ":as_statements('return '), nomsu)"
return add_lua_bits(@, "value", code)
["use 1"]: (tree, path)=>
if path.type == 'Text' and #path == 1 and type(path[1]) == 'string'
for _,f in Files.walk(path[1])
- @run_file(f)
- return LuaCode(tree.source, "for i,f in Files.walk(", @compile(path), ") do nomsu:run_file(f) end")
+ @import(@run_file(f))
+
+ return LuaCode(tree.source, "for i,f in Files.walk(", @compile(path), ") do nomsu:import(nomsu:run_file(f)) end")
["tests"]: (tree)=> LuaCode.Value(tree.source, "TESTS")
["test 1"]: (tree, body)=>
@@ -263,17 +276,19 @@ with NomsuCompiler
["Lua version"]: (tree, code)=>
return LuaCode.Value(tree.source, repr(_VERSION))
- }, {
- __index: (stub)=>
- if math_expression\match(stub)
- return @["# compile math expr #"]
}
- .run = (to_run, source=nil, version=nil)=>
- source or= to_run.source or Source(to_run, 1, #to_run)
+ .import = (mod)=>
+ for k,v in pairs(mod)
+ @[k] = v unless k == "COMPILE_ACTIONS" or k == "nomsu" or k == "_ENV"
+ for k,v in pairs(mod.COMPILE_ACTIONS)
+ @COMPILE_ACTIONS[k] = v
+
+ .run = (to_run)=>
+ source = to_run.source or Source(to_run, 1, #to_run)
if type(source) == 'string' then source = Source\from_string(source)
if not Files.read(source.filename) then Files.spoof(source.filename, to_run)
- tree = if AST.is_syntax_tree(to_run) then to_run else @parse(to_run, source, version)
+ tree = if AST.is_syntax_tree(to_run) then to_run else @parse(to_run, source)
if tree == nil -- Happens if pattern matches, but there are no captures, e.g. an empty string
return nil
if tree.type != "FileChunks"
@@ -305,30 +320,33 @@ with NomsuCompiler
error("Circular import, this loops forever: #{concat loop, " -> "}...")
insert _running_files, filename
- ret = nil
+ mod = @fork!
+ mod.from_file = filename
if match(filename, "%.lua$")
file = assert(Files.read(filename), "Could not find file: #{filename}")
- ret = @run_lua file, Source(filename, 1, #file)
+ ret = mod\run_lua(LuaCode(Source(filename, 1, #file), file))
elseif match(filename, "%.nom$") or match(filename, "^/dev/fd/[012]$")
ran_lua = if @.can_optimize(filename) -- Look for precompiled version
lua_filename = gsub(filename, "%.nom$", ".lua")
if file = Files.read(lua_filename)
- ret = @run_lua file, Source(lua_filename, 1, #file)
+ ret = mod\run_lua(LuaCode(Source(lua_filename, 1, #file), file))
+ if type(ret) == 'table'
+ mod = ret
true
unless ran_lua
file = Files.read(filename)
if not file
error("Tried to run file that does not exist: #{filename}")
- ret = @run file, Source(filename,1,#file)
+ ret = mod\run(NomsuCode(Source(filename,1,#file), file))
+ if type(ret) == 'table'
+ mod = ret
else
error("Invalid filetype for #{filename}", 0)
- @LOADED[filename] = ret or true
+ @LOADED[filename] = mod
remove _running_files
+ return mod
- @LOADED[filename] = ret or true
- return ret
-
- .run_lua = (lua, source=nil)=>
+ .run_lua = (lua)=>
lua_string = tostring(lua)
run_lua_fn, err = load(lua_string, nil and tostring(source or lua.source), "t", self)
if not run_lua_fn
@@ -336,7 +354,7 @@ with NomsuCompiler
[format("%3d|%s",i,line) for i, line in ipairs Files.get_lines(lua_string)],
"\n")
error("Failed to compile generated code:\n#{colored.bright colored.blue colored.onblack line_numbered_lua}\n\n#{err}", 0)
- source or= lua.source
+ source = lua.source or Source(lua_string, 1, #lua_string)
source_key = tostring(source)
unless SOURCE_MAP[source_key]
map = {}
@@ -372,7 +390,7 @@ with NomsuCompiler
switch tree.type
when "Action"
stub = tree.stub
- if compile_action = @COMPILE_ACTIONS[stub]
+ if compile_action = @get_compile_action(stub)
args = [arg for arg in *tree when type(arg) != "string"]
-- Force Lua to avoid tail call optimization for debugging purposes
-- TODO: use tail call?
diff --git a/syntax_tree.lua b/syntax_tree.lua
index 38e71ef..72b510e 100644
--- a/syntax_tree.lua
+++ b/syntax_tree.lua
@@ -42,10 +42,10 @@ for _index_0 = 1, #types do
return getmetatable(x) == self
end
cls.__tostring = function(self)
- return tostring(self.type) .. tostring(repr(self))
+ return tostring(self.type) .. tostring(repr(self, (function() end)))
end
cls.__repr = function(self)
- return tostring(self.type) .. tostring(repr(self))
+ return tostring(self.type) .. tostring(repr(self, (function() end)))
end
cls.source_code_for_tree = setmetatable({ }, {
__index = function(self, t)
diff --git a/syntax_tree.moon b/syntax_tree.moon
index 633b5ca..305a1ee 100644
--- a/syntax_tree.moon
+++ b/syntax_tree.moon
@@ -19,8 +19,8 @@ for name in *types
.__name = name
.type = name
.is_instance = (x)=> getmetatable(x) == @
- .__tostring = => "#{@type}#{repr @}"
- .__repr = => "#{@type}#{repr @}"
+ .__tostring = => "#{@type}#{repr @, (->)}"
+ .__repr = => "#{@type}#{repr @, (->)}"
.source_code_for_tree = setmetatable({}, {__index:(t)=>
s = t.source
Files = require 'files'
diff --git a/tools/test.nom b/tools/test.nom
index 379f968..6d557ea 100755
--- a/tools/test.nom
+++ b/tools/test.nom
@@ -17,6 +17,7 @@ for %path in (command line args):
if (%filename::matches "%.nom$"): use %filename
for %path in (command line args): use %path
+
%tests = ((=lua "Source:from_string(\%s)") = %t for %s = %t in (tests))
for %path in (command line args):
for file %filename in %path: