aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--bootstrap.lua3
-rw-r--r--bootstrap.moon1
-rw-r--r--builtin_metatables.lua65
-rw-r--r--builtin_metatables.moon44
-rw-r--r--lib/core/metaprogramming.nom27
-rw-r--r--lib/core/operators.nom26
-rwxr-xr-xlib/tools/test.nom21
-rw-r--r--nomsu.lua1
-rwxr-xr-xnomsu.moon1
-rw-r--r--nomsu_compiler.lua26
-rw-r--r--nomsu_compiler.moon20
-rw-r--r--nomsu_environment.lua4
-rw-r--r--nomsu_environment.moon4
-rw-r--r--syntax_tree.lua24
-rw-r--r--syntax_tree.moon9
16 files changed, 234 insertions, 48 deletions
diff --git a/Makefile b/Makefile
index b95b926..fd0ad0b 100644
--- a/Makefile
+++ b/Makefile
@@ -13,10 +13,12 @@ UNINSTALL_VERSION=
MOON_FILES= code_obj.moon error_handling.moon files.moon nomsu.moon nomsu_compiler.moon \
syntax_tree.moon containers.moon bitops.moon parser.moon pretty_errors.moon \
- text.moon nomsu_decompiler.moon nomsu_environment.moon bootstrap.moon
+ text.moon nomsu_decompiler.moon nomsu_environment.moon bootstrap.moon \
+ builtin_metatables.moon
LUA_FILES= code_obj.lua error_handling.lua files.lua nomsu.lua nomsu_compiler.lua \
syntax_tree.lua containers.lua bitops.lua parser.lua pretty_errors.lua \
- text.lua nomsu_decompiler.lua nomsu_environment.lua bootstrap.lua
+ text.lua nomsu_decompiler.lua nomsu_environment.lua bootstrap.lua \
+ builtin_metatables.lua
CORE_NOM_FILES=$(shell cat lib/core/init.nom | sed -n 's;export "\(.*\)";lib/\1.nom;p') lib/core/init.nom
CORE_LUA_FILES= $(patsubst %.nom,%.lua, $(CORE_NOM_FILES))
COMPAT_NOM_FILES=$(wildcard lib/compatibility/*.nom)
diff --git a/bootstrap.lua b/bootstrap.lua
index 97a565d..31b03fc 100644
--- a/bootstrap.lua
+++ b/bootstrap.lua
@@ -124,9 +124,6 @@ local compile_actions = {
["is jit"] = function(self, _t, code)
return LuaCode("jit")
end,
- ["Lua version"] = function(self, _t, code)
- return LuaCode("_VERSION")
- end,
["nomsu environment"] = function(self, _t)
return LuaCode("_ENV")
end,
diff --git a/bootstrap.moon b/bootstrap.moon
index d30e56b..6413205 100644
--- a/bootstrap.moon
+++ b/bootstrap.moon
@@ -98,7 +98,6 @@ compile_actions = {
return LuaCode "TESTS[#{tostring(body.source)\as_lua!}] = ", test_text
["is jit"]: (_t, code)=> LuaCode("jit")
- ["Lua version"]: (_t, code)=> LuaCode("_VERSION")
["nomsu environment"]: (_t)=> LuaCode("_ENV")
["nomsu environment name"]: (_t)=> LuaCode('"_ENV"')
["this file was run directly"]: (_t)=> LuaCode('WAS_RUN_DIRECTLY')
diff --git a/builtin_metatables.lua b/builtin_metatables.lua
new file mode 100644
index 0000000..e579e6c
--- /dev/null
+++ b/builtin_metatables.lua
@@ -0,0 +1,65 @@
+require("text")
+local number_mt = {
+ __type = "a Number",
+ as_lua = tostring,
+ as_nomsu = tostring,
+ as_text = tostring,
+ as_a_number = function(self)
+ return self
+ end,
+ rounded = function(self)
+ return math.floor(self + .5)
+ end,
+ rounded_down = math.floor,
+ rounded_up = math.ceil,
+ to_the_nearest = function(self, rounder)
+ return rounder * math.floor(self / rounder + 0.5)
+ end,
+ base16 = function(self)
+ return ("%X"):format(self)
+ end
+}
+number_mt.__index = number_mt
+debug.setmetatable(0, number_mt)
+local bool_mt = {
+ __type = "a Boolean",
+ as_lua = tostring,
+ as_nomsu = function(self)
+ return self and "yes" or "no"
+ end,
+ as_text = function(self)
+ return self and "yes" or "no"
+ end
+}
+bool_mt.__index = bool_mt
+debug.setmetatable(true, bool_mt)
+local fn_mt = {
+ __type = "an Action",
+ as_text = function(self)
+ return (tostring(self):gsub("function", "Action"))
+ end
+}
+fn_mt.__index = fn_mt
+debug.setmetatable((function() end), fn_mt)
+local co_mt = {
+ __type = "a Coroutine",
+ as_text = function(self)
+ return (tostring(self):gsub("thread", "Coroutine"))
+ end
+}
+co_mt.__index = co_mt
+debug.setmetatable(coroutine.create(function() end), co_mt)
+local nil_mt = {
+ __type = "Nil",
+ as_lua = function(self)
+ return "nil"
+ end,
+ as_nomsu = function(self)
+ return "nil"
+ end,
+ as_text = function(self)
+ return "nil"
+ end
+}
+nil_mt.__index = nil_mt
+return debug.setmetatable(nil, nil_mt)
diff --git a/builtin_metatables.moon b/builtin_metatables.moon
new file mode 100644
index 0000000..bc3ec7c
--- /dev/null
+++ b/builtin_metatables.moon
@@ -0,0 +1,44 @@
+-- This file defines some methods on Lua numbers
+require "text"
+
+number_mt =
+ __type: "a Number"
+ as_lua: tostring
+ as_nomsu: tostring
+ as_text: tostring
+ as_a_number: => @
+ rounded: => math.floor(@ + .5)
+ rounded_down: math.floor
+ rounded_up: math.ceil
+ to_the_nearest: (rounder)=> rounder * math.floor(@/rounder + 0.5)
+ base16: => ("%X")\format(@)
+number_mt.__index = number_mt
+debug.setmetatable 0, number_mt
+
+bool_mt =
+ __type: "a Boolean"
+ as_lua: tostring
+ as_nomsu: => @ and "yes" or "no"
+ as_text: => @ and "yes" or "no"
+bool_mt.__index = bool_mt
+debug.setmetatable true, bool_mt
+
+fn_mt =
+ __type: "an Action"
+ as_text: => (tostring(@)\gsub("function", "Action"))
+fn_mt.__index = fn_mt
+debug.setmetatable (->), fn_mt
+
+co_mt =
+ __type: "a Coroutine"
+ as_text: => (tostring(@)\gsub("thread", "Coroutine"))
+co_mt.__index = co_mt
+debug.setmetatable(coroutine.create(->), co_mt)
+
+nil_mt =
+ __type: "Nil"
+ as_lua: => "nil"
+ as_nomsu: => "nil"
+ as_text: => "nil"
+nil_mt.__index = nil_mt
+debug.setmetatable nil, nil_mt
diff --git a/lib/core/metaprogramming.nom b/lib/core/metaprogramming.nom
index da89665..096c62c 100644
--- a/lib/core/metaprogramming.nom
+++ b/lib/core/metaprogramming.nom
@@ -4,7 +4,7 @@
functions to make that easier.
lua> "NOMSU_CORE_VERSION = 15"
-lua> "NOMSU_LIB_VERSION = 8"
+lua> "NOMSU_LIB_VERSION = 9"
lua> ("
do
local mangle_index = 0
@@ -93,8 +93,9 @@ lua> ("
if \$body.type == "Text" then
\$body = SyntaxTree{source=\$body.source, type="Action", "Lua", \$body}
end
- if not (\$action.type == "Action" or (\$action.type == "EscapedNomsu" and \$action[1]\
- ...type == "Action")) then
+ if not (\$action.type == "Action" or
+ (\$action.type == "EscapedNomsu" and \$action[1].type == "Action") or
+ \$action.type == "MethodCall") then
at_1_fail(\$action.source, "Compile error: "..
"This is neither an action nor an escaped action. "..
"Hint: This should probably be an action like:\\n"
@@ -182,7 +183,7 @@ test:
lua> ("
local lua = \(\($actions.1 means $body) as lua)
local first_def = (\$actions[1].type == "MethodCall"
- and LuaCode(\(nomsu environment):compile(\$actions[1][1]), ".", \$actions[1]:get_stub():as_lua_id())
+ and LuaCode(\(nomsu environment):compile(\$actions[1][1]), ".", \$actions[1][2]:get_stub():as_lua_id())
or LuaCode(\$actions[1]:get_stub():as_lua_id()))
local \$args = a_List(\$actions[1]:get_args())
for i=2,#\$actions do
@@ -190,7 +191,7 @@ test:
local \$alias_args = a_List(alias:get_args())
lua:add("\\n")
if alias.type == "MethodCall" then
- lua:add(\(nomsu environment):compile(alias[1]), ".", alias:get_stub():as_lua_id())
+ lua:add(\(nomsu environment):compile(alias[1]), ".", alias[2]:get_stub():as_lua_id())
else
lua:add(alias:get_stub():as_lua_id())
lua:add_free_vars({alias_name})
@@ -481,9 +482,9 @@ test:
")
# Literals
-(yes) compiles to "true"
-(no) compiles to "false"
-[nothing, nil, null] all compile to "nil"
+(yes) compiles to "(true)"
+(no) compiles to "(false)"
+[nothing, nil, null] all compile to "(nil)"
(Nomsu syntax version) compiles to "NOMSU_SYNTAX_VERSION"
(Nomsu compiler version) compiles to "NOMSU_COMPILER_VERSION"
(core version) compiles to "NOMSU_CORE_VERSION"
@@ -492,6 +493,16 @@ test:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+(at compilation $expr) compiles to:
+ lua> ("
+ local value = \(nomsu environment):run(\(\(return $expr)))
+ if lua_type_of(value) == 'table' or lua_type_of(value) == 'string' and value.as_lua then
+ return LuaCode(value:as_lua())
+ else
+ return LuaCode(tostring(value))
+ end
+ ")
+
test:
using compile rules:
(yes) compiles to "3"
diff --git a/lib/core/operators.nom b/lib/core/operators.nom
index c2e6b57..4bdb5bc 100644
--- a/lib/core/operators.nom
+++ b/lib/core/operators.nom
@@ -159,6 +159,18 @@ test:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Bitwise Operators
+# These can break if running the precompiled code from another Lua version:
+lua> ("
+ if \(at compilation $(LUA VERSION)) ~= \$(LUA VERSION) then
+ \(
+ fail ("
+ This code was precompiled with \(at compilation $(LUA VERSION)), but it is being run with \$(LUA VERSION)\
+ ... This will cause problems with bitwise operations.
+ ")
+ )
+ end
+")
+
# TODO: implement OR, XOR, AND for multiple operands?
test:
assume ((~ (~ 5)) == 5)
@@ -170,22 +182,22 @@ test:
# Lua 5.3 introduced bit operators like | and &. Use them when possible, otherwise
fall back to bit.bor(), bit.band(), etc.
-lua> "if \((is jit) or ((Lua version) == "Lua 5.2")) then"
-[NOT $, ~ $] all compile to "bit.bnot(\($ as lua expr))"
+lua> "if \((is jit) or ($(LUA API) == "Lua 5.2")) then"
+[NOT $, ~ $] all compile to "Bit.bnot(\($ as lua expr))"
[$x OR $y, $x | $y] all compile to
- "bit.bor(\($x as lua expr), \($y as lua expr))"
+ "Bit.bor(\($x as lua expr), \($y as lua expr))"
[$x XOR $y, $x ~ $y] all compile to
- "bit.bxor(\($x as lua expr), \($y as lua expr))"
+ "Bit.bxor(\($x as lua expr), \($y as lua expr))"
[$x AND $y, $x & $y] all compile to
- "bit.band(\($x as lua expr), \($y as lua expr))"
+ "Bit.band(\($x as lua expr), \($y as lua expr))"
[$x LSHIFT $shift, $x << $shift] all compile to
- "bit.lshift(\($x as lua expr), \($shift as lua expr))"
+ "Bit.lshift(\($x as lua expr), \($shift as lua expr))"
[$x RSHIFT $shift, $x >> $shift] all compile to
- "bit.rshift(\($x as lua expr), \($shift as lua expr))"
+ "Bit.rshift(\($x as lua expr), \($shift as lua expr))"
lua> "else"
[NOT $, ~ $] all compile to "~(\($ as lua expr))"
diff --git a/lib/tools/test.nom b/lib/tools/test.nom
index 761ec55..945ce8c 100755
--- a/lib/tools/test.nom
+++ b/lib/tools/test.nom
@@ -41,16 +41,19 @@ command line program with $args:
if $args.v:
say " \(yellow ($.test, with "\n" -> "\n "))"
- try:
+ if $args.e:
$(test environment), run $.test
- ..if it fails with $msg:
- $src = ($Source, from string $.source)
- $l1 = ($file, line number at $src.start)
- $l2 = ($file, line number at $src.stop)
- $failures, add ("
- \(yellow "\($src.filename):\($l1)-\$l2:")
- \(bright (red ($msg, indented)))
- ")
+ ..else:
+ try:
+ $(test environment), run $.test
+ ..if it fails with $msg:
+ $src = ($Source, from string $.source)
+ $l1 = ($file, line number at $src.start)
+ $l2 = ($file, line number at $src.stop)
+ $failures, add ("
+ \(yellow "\($src.filename):\($l1)-\$l2:")
+ \(bright (red ($msg, indented)))
+ ")
if ($failures is empty):
if $args.v:
diff --git a/nomsu.lua b/nomsu.lua
index 814065d..2b7f5a6 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -45,6 +45,7 @@ do
List, Dict = _obj_0.List, _obj_0.Dict
end
local Text = require('text')
+require('builtin_metatables')
local sep = "\3"
local parser = re.compile([[ args <- {| (flag %sep)*
{:files: {|
diff --git a/nomsu.moon b/nomsu.moon
index f71f5e0..972be7f 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -43,6 +43,7 @@ Files = require "files"
{:NomsuCode, :LuaCode, :Source} = require "code_obj"
{:List, :Dict} = require 'containers'
Text = require 'text'
+require 'builtin_metatables'
sep = "\3"
parser = re.compile([[
diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua
index 7e562ea..096cdd1 100644
--- a/nomsu_compiler.lua
+++ b/nomsu_compiler.lua
@@ -52,6 +52,14 @@ local math_expression = re.compile([[ (([*/^+-] / [0-9]+) " ")* [*/^+-] !. ]])
local MAX_LINE = 80
local compile
compile = function(self, tree)
+ if not (SyntaxTree:is_instance(tree)) then
+ do
+ local as_lua = tree.as_lua
+ if as_lua then
+ return as_lua(tree)
+ end
+ end
+ end
local _exp_0 = tree.type
if "Action" == _exp_0 then
local stub = tree.stub
@@ -119,6 +127,24 @@ compile = function(self, tree)
lua:add(")")
return lua
elseif "MethodCall" == _exp_0 then
+ local stub = tree:get_stub()
+ local compile_action = self.COMPILE_RULES[stub]
+ if compile_action then
+ local args = tree:get_args()
+ local ret = compile_action(self, tree, unpack(args))
+ if ret == nil then
+ local info = debug.getinfo(compile_action, "S")
+ local filename = Source:from_string(info.source).filename
+ fail_at(tree, ("Compile error: The compile-time method here (" .. tostring(stub) .. ") failed to return any value. " .. "Hint: Look at the implementation of (" .. tostring(stub) .. ") in " .. tostring(filename) .. ":" .. tostring(info.linedefined) .. " " .. "and make sure it's returning something."))
+ end
+ if not (SyntaxTree:is_instance(ret)) then
+ ret.source = ret.source or tree.source
+ return ret
+ end
+ if ret ~= tree then
+ return self:compile(ret)
+ end
+ end
local lua = LuaCode:from(tree.source)
local target_lua = self:compile(tree[1])
local target_text = target_lua:text()
diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon
index 1b3e952..068173e 100644
--- a/nomsu_compiler.moon
+++ b/nomsu_compiler.moon
@@ -62,8 +62,6 @@ compile = (tree)=>
if compile_action
args = [arg for arg in *tree when type(arg) != "string"]
- -- Force Lua to avoid tail call optimization for debugging purposes
- -- TODO: use tail call?
ret = compile_action(@, tree, unpack(args))
if ret == nil
info = debug.getinfo(compile_action, "S")
@@ -92,6 +90,24 @@ compile = (tree)=>
return lua
when "MethodCall"
+ stub = tree\get_stub!
+ compile_action = @COMPILE_RULES[stub]
+ if compile_action
+ args = tree\get_args!
+ ret = compile_action(@, tree, unpack(args))
+ if ret == nil
+ info = debug.getinfo(compile_action, "S")
+ filename = Source\from_string(info.source).filename
+ fail_at tree,
+ ("Compile error: The compile-time method here (#{stub}) failed to return any value. "..
+ "Hint: Look at the implementation of (#{stub}) in #{filename}:#{info.linedefined} "..
+ "and make sure it's returning something.")
+ unless SyntaxTree\is_instance(ret)
+ ret.source or= tree.source
+ return ret
+ if ret != tree
+ return @compile(ret)
+
lua = LuaCode\from tree.source
target_lua = @compile tree[1]
target_text = target_lua\text!
diff --git a/nomsu_environment.lua b/nomsu_environment.lua
index 0fdf1cf..e359257 100644
--- a/nomsu_environment.lua
+++ b/nomsu_environment.lua
@@ -131,7 +131,9 @@ nomsu_environment = Importer({
ipairs = ipairs,
jit = jit,
_VERSION = _VERSION,
- bit = (jit or _VERSION == "Lua 5.2") and require('bitops') or nil,
+ LUA_VERSION = (jit and jit.version or _VERSION),
+ LUA_API = _VERSION,
+ Bit = (jit or _VERSION == "Lua 5.2") and require('bitops') or nil,
a_List = List,
a_Dict = Dict,
Text = Text,
diff --git a/nomsu_environment.moon b/nomsu_environment.moon
index 8cd3228..1deac6f 100644
--- a/nomsu_environment.moon
+++ b/nomsu_environment.moon
@@ -58,8 +58,8 @@ nomsu_environment = Importer{
:error, :package, :os, :require, :tonumber, :tostring, :string, :xpcall,
:print, :loadfile, :rawset, :_VERSION, :collectgarbage, :rawget, :rawlen,
:table, :assert, :dofile, :loadstring, lua_type_of:type, :select, :math, :io, :load,
- :pairs, :ipairs, :jit, :_VERSION
- bit: (jit or _VERSION == "Lua 5.2") and require('bitops') or nil
+ :pairs, :ipairs, :jit, :_VERSION, LUA_VERSION: (jit and jit.version or _VERSION),
+ LUA_API: _VERSION, Bit: (jit or _VERSION == "Lua 5.2") and require('bitops') or nil
-- Nomsu types:
a_List:List, a_Dict:Dict, Text:Text,
-- Utilities and misc.
diff --git a/syntax_tree.lua b/syntax_tree.lua
index b9668e7..b7b7f83 100644
--- a/syntax_tree.lua
+++ b/syntax_tree.lua
@@ -147,13 +147,14 @@ do
assert(self.type == "Action" or self.type == "MethodCall", "Only actions and method calls have arguments")
local args = { }
if self.type == "MethodCall" then
- assert(#self == 2, "Can't get arguments for multiple method calls at once.")
args[1] = self[1]
- local _list_0 = self[2]
- for _index_0 = 1, #_list_0 do
- local tok = _list_0[_index_0]
- if type(tok) ~= 'string' then
- args[#args + 1] = tok
+ for i = 2, #self do
+ local _list_0 = self[i]
+ for _index_0 = 1, #_list_0 do
+ local tok = _list_0[_index_0]
+ if type(tok) ~= 'string' then
+ args[#args + 1] = tok
+ end
end
end
else
@@ -168,8 +169,15 @@ do
end,
get_stub = function(self)
if self.type == "MethodCall" then
- assert(#self == 2, "Can't get the stubs of multiple method calls at once.")
- return self[2]:get_stub()
+ return "0, " .. table.concat((function()
+ local _accum_0 = { }
+ local _len_0 = 1
+ for i = 2, #self do
+ _accum_0[_len_0] = self[i]:get_stub()
+ _len_0 = _len_0 + 1
+ end
+ return _accum_0
+ end)(), "; ")
end
local stub_bits = { }
local arg_i = 1
diff --git a/syntax_tree.moon b/syntax_tree.moon
index eb9c87c..278e22b 100644
--- a/syntax_tree.moon
+++ b/syntax_tree.moon
@@ -72,10 +72,10 @@ class SyntaxTree
assert(@type == "Action" or @type == "MethodCall", "Only actions and method calls have arguments")
args = {}
if @type == "MethodCall"
- assert(#@ == 2, "Can't get arguments for multiple method calls at once.")
args[1] = @[1]
- for tok in *@[2]
- if type(tok) != 'string' then args[#args+1] = tok
+ for i=2,#@
+ for tok in *@[i]
+ if type(tok) != 'string' then args[#args+1] = tok
else
for tok in *@
if type(tok) != 'string' then args[#args+1] = tok
@@ -83,8 +83,7 @@ class SyntaxTree
get_stub: =>
if @type == "MethodCall"
- assert(#@ == 2, "Can't get the stubs of multiple method calls at once.")
- return @[2]\get_stub!
+ return "0, "..table.concat([@[i]\get_stub! for i=2,#@], "; ")
stub_bits = {}
arg_i = 1
for a in *@