aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bitbucket@bruce-hill.com>2018-06-14 21:59:25 -0700
committerBruce Hill <bitbucket@bruce-hill.com>2018-06-14 21:59:43 -0700
commit82cfd3e54b5910843c091a9fb6ef3ad6b64ba757 (patch)
treeaed04a3910646c82447b9b4b515169005b3010af
parent282565a309aef632502a64fef0a67b0b7efcfaaa (diff)
More streamlining and cleanup. Especially for core/metaprogramming.nom
-rw-r--r--code_obj.lua23
-rw-r--r--code_obj.moon16
-rw-r--r--core/collections.nom12
-rw-r--r--core/control_flow.nom2
-rw-r--r--core/math.nom27
-rw-r--r--core/metaprogramming.nom243
-rw-r--r--core/operators.nom15
-rw-r--r--core/text.nom20
-rw-r--r--nomsu.lua229
-rwxr-xr-xnomsu.moon180
-rw-r--r--nomsu_tree.lua12
-rw-r--r--nomsu_tree.moon3
-rw-r--r--tests/collections.nom4
-rw-r--r--tests/control_flow.nom2
-rw-r--r--tests/math.nom2
-rw-r--r--tests/object.nom2
-rw-r--r--tests/operators.nom4
17 files changed, 361 insertions, 435 deletions
diff --git a/code_obj.lua b/code_obj.lua
index 57abef9..426a973 100644
--- a/code_obj.lua
+++ b/code_obj.lua
@@ -98,6 +98,29 @@ do
end
self.__str = nil
end,
+ concat_append = function(self, values, joiner)
+ local bits, indents = self.bits, self.indents
+ local match = string.match
+ for i = 1, #values do
+ local b = values[i]
+ assert(b)
+ if i > 1 then
+ bits[#bits + 1] = joiner
+ end
+ bits[#bits + 1] = b
+ if type(b) == 'string' then
+ do
+ local spaces = match(b, "\n([ ]*)[^\n]*$")
+ if spaces then
+ self.current_indent = #spaces
+ end
+ end
+ elseif self.current_indent ~= 0 then
+ indents[#bits] = self.current_indent
+ end
+ end
+ self.__str = nil
+ end,
prepend = function(self, ...)
local n = select("#", ...)
local bits, indents = self.bits, self.indents
diff --git a/code_obj.moon b/code_obj.moon
index ec644a5..d3de65c 100644
--- a/code_obj.moon
+++ b/code_obj.moon
@@ -65,6 +65,22 @@ class Code
elseif @current_indent != 0
indents[#bits] = @current_indent
@__str = nil
+
+ concat_append: (values, joiner)=>
+ bits, indents = @bits, @indents
+ match = string.match
+ for i=1,#values
+ b = values[i]
+ assert(b)
+ if i > 1
+ bits[#bits+1] = joiner
+ bits[#bits+1] = b
+ if type(b) == 'string'
+ if spaces = match(b, "\n([ ]*)[^\n]*$")
+ @current_indent = #spaces
+ elseif @current_indent != 0
+ indents[#bits] = @current_indent
+ @__str = nil
prepend: (...)=>
n = select("#",...)
diff --git a/core/collections.nom b/core/collections.nom
index a8a28b2..8a59852 100644
--- a/core/collections.nom
+++ b/core/collections.nom
@@ -16,8 +16,8 @@ immediately
..to: Lua value "utils.nth_to_last(\(%list as lua expr), \(%index as lua expr))"
immediately
- parse [first in %list, first %list] as: 1 st in %list
- parse [last in %list, last %list] as: 1 st to last in %list
+ parse [last in %list] as: 1st to last in %list
+ parse [first in %list] as: %list.1
# Membership testing
immediately
@@ -62,8 +62,8 @@ immediately
parse [%expression for %item in %iterable] as
result of
%comprehension <- []
- for %i = %item in %iterable
- %comprehension.%i <- %expression
+ for %item in %iterable
+ add %expression to %comprehension
return %comprehension
parse [..]
@@ -163,8 +163,8 @@ immediately
%unique <- []
%seen <- {}
for % in %items
- unless: % in %seen
+ unless: %seen.%
add % to %unique
- (% in %seen) <- (yes)
+ %seen.% <- (yes)
return %unique
diff --git a/core/control_flow.nom b/core/control_flow.nom
index f0238a4..2c85221 100644
--- a/core/control_flow.nom
+++ b/core/control_flow.nom
@@ -39,7 +39,7 @@ immediately
..to
# If %when_true_expr is guaranteed to be truthy, we can use Lua's idiomatic
equivalent of a conditional expression: (cond and if_true or if_false)
- if: %when_true_expr.type in {Text:yes, List:yes, Dict:yes, Number:yes}
+ if: {Text:yes, List:yes, Dict:yes, Number:yes}.(%when_true_expr.type)
return
Lua value ".."
(\(%condition as lua expr) and \(%when_true_expr as lua expr) or \(%when_false_expr as lua expr))
diff --git a/core/math.nom b/core/math.nom
index 1e733e7..57088eb 100644
--- a/core/math.nom
+++ b/core/math.nom
@@ -5,6 +5,7 @@ use "core/metaprogramming.nom"
use "core/text.nom"
use "core/operators.nom"
use "core/control_flow.nom"
+use "core/collections.nom"
# Literals:
compile [infinity, inf] to: Lua value "math.huge"
@@ -30,7 +31,7 @@ compile [hyperbolic cosine %, cosh %] to: Lua value "math.cosh(\(% as lua expr))
compile [hyperbolic tangent %, tanh %] to: Lua value "math.tanh(\(% as lua expr))"
compile [e^%, exp %] to: Lua value "math.exp(\(% as lua expr))"
compile [natural log %, ln %, log %] to: Lua value "math.log(\(% as lua expr))"
-compile [log % base %base, log_%base %, log base %base %] to: Lua value "math.log(\(% as lua expr), \(%base as lua expr))"
+compile [log % base %base, log base %base of %] to: Lua value "math.log(\(% as lua expr), \(%base as lua expr))"
compile [floor %] to: Lua value "math.floor(\(% as lua expr))"
compile [ceiling %, ceil %] to: Lua value "math.ceil(\(% as lua expr))"
compile [round %, % rounded] to: Lua value "math.floor(\(% as lua expr) + .5)"
@@ -39,34 +40,26 @@ action [%n to the nearest %rounder]
# Any/all/none
compile [all of %items, all %items] to
- unless: (%items' "type") is "List"
+ unless: %items.type is "List"
return: Lua value "utils.all(\(%items as lua expr))"
- %clauses <- []
- for % in %items
- lua> "table.insert(\%clauses, \(% as lua expr));"
+ %clauses <- ((% as lua expr) for % in %items)
return: Lua value "(\(%clauses joined with " and "))"
parse [not all of %items, not all %items] as: not (all of %items)
compile [any of %items, any %items] to
- unless: (%items' "type") is "List"
+ unless: %items.type is "List"
return: Lua value "utils.any(\(%items as lua expr))"
- %clauses <- []
- for % in %items
- lua> "table.insert(\%clauses, \(% as lua expr));"
+ %clauses <- ((% as lua expr) for % in %items)
return: Lua value "(\(%clauses joined with " or "))"
parse [none of %items, none %items] as: not (any of %items)
compile [sum of %items, sum %items] to
- unless: (%items' "type") is "List"
+ unless: %items.type is "List"
return: Lua value "utils.sum(\(%items as lua expr))"
- %clauses <- []
- for % in %items
- lua> "table.insert(\%clauses, \(% as lua expr));"
+ %clauses <- ((% as lua expr) for % in %items)
return: Lua value "(\(%clauses joined with " + "))"
compile [product of %items, product %items] to
- unless: (%items' "type") is "List"
+ unless: %items.type is "List"
return: Lua value "utils.product(\(%items as lua expr))"
- %clauses <- []
- for % in %items
- lua> "table.insert(\%clauses, \(% as lua expr));"
+ %clauses <- ((% as lua expr) for % in %items)
return: Lua value "(\(%clauses joined with " * "))"
action [avg of %items, average of %items]
=lua "(utils.sum(\%items)/#\%items)"
diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom
index 83179f5..15c5817 100644
--- a/core/metaprogramming.nom
+++ b/core/metaprogramming.nom
@@ -5,161 +5,109 @@
# Compile-time action to make compile-time actions:
immediately
lua> ".."
- _ENV['ACTION'..string.as_lua_id("compile % to %")] = compile_time(function(tree, \%actions, \%lua)
- local lua = Lua(tree.source)
- local canonical = \%actions[1]
- lua:append("ACTION", string.as_lua_id(canonical.stub), ' = compile_time(function(tree')
- local args = {}
- for i,tok in ipairs(canonical) do
- if tok.type == "Var" then args[#args+1] = tok end
+ A_give_1_nickname_2 = compile_time(function(tree, \%action, \%nickname, is_compile_time)
+ local function arg_to_string(a) return tostring(nomsu:tree_to_lua(a)) end
+ local action_args = table.map(\%action:get_args(), arg_to_string)
+ local nickname_args = table.map(\%nickname:get_args(), arg_to_string)
+ if utils.equivalent(action_args, nickname_args) then
+ return Lua(tree.source, "A", string.as_lua_id(\%nickname.stub), " = A", string.as_lua_id(\%action.stub))
+ end
+ local lua = Lua(tree.source, "A", string.as_lua_id(\%nickname.stub), " = ")
+ if is_compile_time or COMPILE_TIME[_ENV["A"..string.as_lua_id(\%action.stub)]] then
+ lua:append("compile_time")
+ table.insert(action_args, 1, "tree")
+ table.insert(nickname_args, 1, "tree")
+ end
+ lua:append("(function(")
+ lua:concat_append(nickname_args, ", ")
+ lua:append(")\n return A", string.as_lua_id(\%action.stub), "(")
+ lua:concat_append(action_args, ", ")
+ lua:append(")\nend)")
+ return lua
+ end)
+
+ __MANGLE_INDEX = 0
+ A_parse_1_as_2 = compile_time(function(tree, \%actions, \%body)
+ local replacements = {}
+ for i,arg in ipairs(\%actions[1]:get_args()) do
+ replacements[arg[1]] = tostring(nomsu:tree_to_lua(arg))
+ end
+ local function make_tree(t)
+ if not AST.is_syntax_tree(t) then
+ return repr(t)
+ elseif t.type ~= 'Var' then
+ local args = table.map(t, make_tree)
+ table.insert(args, 1, repr(tostring(t.source)))
+ return t.type.."("..table.concat(args, ", ")..")"
+ elseif replacements[t[1]] then
+ return replacements[t[1]]
+ else
+ return t.type.."("..repr(tostring(t.source))..", "..repr(t[1].." \\0").."..('%X'):format(__MANGLE_INDEX))"
+ end
end
- local canonical_arg_positions = {}
- for i, arg in ipairs(args) do
- canonical_arg_positions[arg[1]] = i
+ local lua = Lua(tree.source, "A", string.as_lua_id(\%actions[1].stub), " = compile_time(function(tree")
+ for _,arg in ipairs(\%actions[1]:get_args()) do
lua:append(", ", nomsu:tree_to_lua(arg))
end
- local body_lua = nomsu:tree_to_lua(\%lua):as_statements("return ")
- body_lua:remove_free_vars(args)
- body_lua:declare_locals()
- lua:append(")\n ", body_lua, "\nend)")
+ lua:append(")\n __MANGLE_INDEX = __MANGLE_INDEX + 1",
+ "\n local tree = ", make_tree(\%body),
+ "\n local lua = nomsu:tree_to_lua(tree)",
+ "\n lua:remove_free_vars({")
+ local vars = table.map(\%actions[1]:get_args(), function(a)
+ return "Var("..repr(tostring(a.source))..", "..repr(a[1])..")"
+ end)
+ lua:concat_append(vars, ", ")
+ lua:append("})\n return lua\nend)")
for i=2,#\%actions do
- local action = \%actions[i]
- lua:append("\n", "ACTION", string.as_lua_id(action.stub), " = ACTION", string.as_lua_id(canonical.stub))
-
- local arg_positions = {}
- for _,tok in ipairs(action) do
- if tok.type == 'Var' then
- arg_positions[#arg_positions+1] = canonical_arg_positions[tok[1]]
- end
- end
- lua:append("\n", "ARG_ORDERS[", repr(action.stub), "] = ", repr(arg_positions))
+ lua:append("\n", A_give_1_nickname_2(\%actions[i], \%actions[1], \%actions[i], true))
end
- lua:append("\nALIASES[ACTION", string.as_lua_id(canonical.stub), "] = {")
- for i,action in ipairs(\%actions) do
- if i > 1 then lua:append(", ") end
- lua:append(repr(action.stub))
- end
- lua:append("}")
return lua
end)
-# Compile-time action to make actions
-immediately
- compile [action %actions %body] to
- lua> ".."
- local lua = Lua(tree.source)
- local canonical = \%actions[1]
- lua:append("ACTION", string.as_lua_id(canonical.stub), ' = function(')
- local args = {}
- for i,tok in ipairs(canonical) do
- if tok.type == "Var" then args[#args+1] = tok end
- end
- local canonical_arg_positions = {}
- for i, arg in ipairs(args) do
- canonical_arg_positions[arg[1]] = i
- lua:append(nomsu:tree_to_lua(arg))
- if i < #args then lua:append(", ") end
- end
+ A_action_1_2 = compile_time(function(tree, \%actions, \%body, is_compile_time)
+ local lua = Lua(tree.source, "A", string.as_lua_id(\%actions[1].stub), " = ")
+ if is_compile_time then lua:append("compile_time") end
+ lua:append("(function(")
+ local args = \%actions[1]:get_args()
+ local lua_args = table.map(args, function(a) return nomsu:tree_to_lua(a) end)
+ if is_compile_time then table.insert(lua_args, 1, "tree") end
+ lua:concat_append(lua_args, ", ")
local body_lua = nomsu:tree_to_lua(\%body):as_statements("return ")
body_lua:remove_free_vars(args)
body_lua:declare_locals()
- lua:append(")\n ", body_lua, "\nend")
-
+ lua:append(")\n ", body_lua, "\nend)")
for i=2,#\%actions do
- local action = \%actions[i]
- lua:append("\n", "ACTION", string.as_lua_id(action.stub), " = ACTION", string.as_lua_id(canonical.stub))
-
- local arg_positions = {}
- for _,tok in ipairs(action) do
- if tok.type == 'Var' then
- arg_positions[#arg_positions+1] = canonical_arg_positions[tok[1]]
- end
- end
- lua:append("\n", "ARG_ORDERS[", repr(action.stub), "] = ", repr(arg_positions))
- end
- lua:append("\nALIASES[ACTION", string.as_lua_id(canonical.stub), "] = {")
- for i,action in ipairs(\%actions) do
- if i > 1 then lua:append(", ") end
- lua:append(repr(action.stub))
+ lua:append("\n", A_give_1_nickname_2(\%actions[i], \%actions[1], \%actions[i], is_compile_time))
end
- lua:append("}")
return lua
+ end)
-# Macro to make nomsu macros
-immediately
- compile [parse %shorthand as %longhand] to
- lua> ".."
- local lua = Lua(tree.source)
- local canonical = \%shorthand[1]
- lua:append("ACTION", string.as_lua_id(canonical.stub), ' = compile_time(function(tree')
- local args = {}
- for i,tok in ipairs(canonical) do
- if tok.type == "Var" then args[#args+1] = tok end
- end
- local canonical_arg_positions = {}
- for i, arg in ipairs(args) do
- canonical_arg_positions[arg[1]] = i
- lua:append(", ", nomsu:tree_to_lua(arg))
- end
-
- local replacements = {}
- for i,tok in ipairs(canonical) do
- if tok.type == "Var" then
- local lua_var = tostring(nomsu:tree_to_lua(tok))
- replacements[tok[1]] = lua_var
- end
- end
- MANGLE_INDEX = (MANGLE_INDEX or 0) + 1
- local function make_tree(t)
- if type(t) ~= 'table' and type(t) ~= 'userdata' then
- return repr(t)
- elseif t.type == 'Var' and replacements[t[1]] then
- return replacements[t[1]]
- elseif t.type == 'Var' then
- return t.type.."("..repr(tostring(t.source))..", "..repr(t[1].."#"..tostring(MANGLE_INDEX))..")"
- else
- local bits = {repr(tostring(t.source))}
- for i, entry in ipairs(t) do
- bits[#bits+1] = make_tree(entry)
- end
- return t.type.."("..table.concat(bits, ", ")..")"
- end
- end
- lua:append(")\n local tree = ", make_tree(\%longhand), "\n return nomsu:tree_to_lua(tree)\nend)")
-
- for i=2,#\%shorthand do
- local action = \%shorthand[i]
- lua:append("\n", "ACTION", string.as_lua_id(action.stub), " = ACTION", string.as_lua_id(canonical.stub))
-
- local arg_positions = {}
- for _,tok in ipairs(action) do
- if tok.type == 'Var' then
- arg_positions[#arg_positions+1] = canonical_arg_positions[tok[1]]
- end
- end
- lua:append("\n", "ARG_ORDERS[", repr(action.stub), "] = ", repr(arg_positions))
- end
- lua:append("\nALIASES[ACTION", string.as_lua_id(canonical.stub), "] = {")
- for i,action in ipairs(\%shorthand) do
- if i > 1 then lua:append(", ") end
- lua:append(repr(action.stub))
- end
- lua:append("}")
- return lua
+ A_compile_1_to_2 = compile_time(function(tree, \%actions, \%body)
+ return A_action_1_2(tree, \%actions, \%body, true)
+ end)
compile [remove action %action] to
Lua ".."
- do
- local fn = ACTION\(=lua "string.as_lua_id(\(%action.stub))")
- for stub in pairs(ALIASES[fn]) do
- _ENV['ACTION'..string.as_lua_id(stub)] = nil
- end
- ARG_ORDERS[fn] = nil
- COMPILE_TIME[fn] = nil
- end
+ A\(=lua "string.as_lua_id(\(%action.stub))") = nil
+ ARG_ORDERS[fn] = nil
+ COMPILE_TIME[fn] = nil
immediately
+ action [read file %filename]
+ lua> ".."
+ local file = io.open(\%filename)
+ local contents = file:read("*a")
+ file:close()
+ return contents
+
+ action [sh> %cmd]
+ lua> ".."
+ local result = io.popen(\%cmd)
+ local contents = result:read("*a")
+ result:close()
+ return contents
+
action [%tree as nomsu]
=lua "nomsu:tree_to_nomsu(\%tree)"
@@ -182,11 +130,16 @@ immediately
action [%tree as lua return]
=lua "nomsu:tree_to_lua(\%tree):as_statements('return ')"
+
+ action [%var as lua identifier]
+ =lua "type(\%var) == 'string' and string.as_lua_id(\%var) or nomsu:tree_to_lua(\%var)"
+
+immediately
+ compile [parse %text] to
+ Lua value ".."
+ nomsu:parse(Nomsu("\("\(%text.source)")", \(%text as lua expr)))
immediately
- compile [%tree with vars %vars] to
- barf "Deprecated"
-
compile [%tree with %t -> %replacement] to
Lua value ".."
\(%tree as lua expr):map(function(\(%t as lua expr))
@@ -211,8 +164,7 @@ immediately
return nomsu:run_lua(lua)
immediately
- parse [%var <-write %code] as: lua> "\%var:append(\%code);"
- parse [to %var write %code] as: lua> "\%var:append(\%code);"
+ parse [%lua <-write %code, to %lua write %code] as: lua> "\%lua:append(\%code);"
immediately
compile [quote %s] to
@@ -222,7 +174,6 @@ immediately
immediately
compile [nomsu] to: Lua value "nomsu"
- compile [%var as lua identifier] to: Lua value "nomsu:tree_to_lua(\(%var as lua expr))"
# Compiler tools
immediately
@@ -239,9 +190,17 @@ immediately
compile [say %message] to
lua> ".."
if \%message.type == "Text" then
- return Lua(tree.source, "print(", \(%message as lua expr), ");");
+ return Lua(tree.source, "io.write(", \(%message as lua expr), ", '\\\\n');");
+ else
+ return Lua(tree.source, "io.write(tostring(", \(%message as lua expr), "), '\\\\n');");
+ end
+
+ compile [ask %prompt] to
+ lua> ".."
+ if \%prompt.type == "Text" then
+ return Lua.Value(tree.source, "(io.write(", \(%prompt as lua expr), ") and io.read())");
else
- return Lua(tree.source, "print(tostring(", \(%message as lua expr), "));");
+ return Lua.Value(tree.source, "(io.write(tostring(", \(%prompt as lua expr), ")) and io.read())");
end
# Return
diff --git a/core/operators.nom b/core/operators.nom
index 555a636..3ea0fe1 100644
--- a/core/operators.nom
+++ b/core/operators.nom
@@ -3,19 +3,6 @@
use "core/metaprogramming.nom"
-# Indexing
-immediately
- # NOTE!!! It's critical that there are spaces around %key if it's a string,
- otherwise, Lua will get confused and interpret %obj[[[foo]]] as %obj("[foo]")
- instead of %obj[ "foo" ].
- It's also critical to have parens around %obj, otherwise Lua is too dumb to
- realize that {x=1}["x"] is the same as ({x=1})["x"] or that
- {x=1}.x is the same as ({x=1}).x
- parse [..]
- %obj' %key, %obj's %key, %key in %obj, %key'th in %obj, %key of %obj,
- %key st in %obj, %key nd in %obj, %key rd in %obj, %key th in %obj,
- ..as: %obj.%key
-
# Comparison Operators
immediately
compile [%x < %y] to: Lua value "(\(%x as lua expr) < \(%y as lua expr))"
@@ -53,7 +40,7 @@ immediately
immediately
# Simultaneous mutli-assignments like: x,y,z = 1,x,3;
compile [<- %assignments] to
- assume ((%assignments' "type") is "Dict") or barf ".."
+ assume (%assignments.type is "Dict") or barf ".."
Expected a Dict for the assignments part of '<- %' statement, not \%assignments
lua> ".."
local lhs, rhs = Lua(tree.source), Lua(tree.source)
diff --git a/core/text.nom b/core/text.nom
index 8b75ca4..e6065c1 100644
--- a/core/text.nom
+++ b/core/text.nom
@@ -18,6 +18,14 @@ compile [capitalized %text, %text capitalized] to
compile [%text with %sub instead of %patt, %text s/%patt/%sub] to
Lua value "((\(%text as lua expr)):gsub(\(%patt as lua expr), \(%sub as lua expr)))"
+action [lines in %text, lines of %text]
+ lua> ".."
+ local result = {}
+ for line in (\%text):gmatch('[^\n]+') do
+ result[#result+1] = line
+ end
+ return result
+
# Text literals
lua> ".."
do
@@ -26,8 +34,8 @@ lua> ".."
backspace="\\\\b", ["form feed"]="\\\\f", formfeed="\\\\f", ["vertical tab"]="\\\\v",
};
for name, e in pairs(escapes) do
- local lua = "'"..e.."'";
- nomsu:define_compile_action(name, function(tree) return Lua.Value(tree.source, lua); end);
+ local lua = "'"..e.."'"
+ _ENV["A"..name:as_lua_id()] = compile_time(function(tree) return Lua.Value(tree.source, lua) end)
end
local colors = {
["reset color"]="\\\\27[0m", bright="\\\\27[1m", dim="\\\\27[2m", underscore="\\\\27[4m",
@@ -42,10 +50,10 @@ lua> ".."
for name, c in pairs(colors) do
local color = "'"..c.."'";
local reset = "'"..colors["reset color"].."'";
- nomsu:define_compile_action(name, function(tree) return Lua.Value(tree.source, color); end);
- nomsu:define_compile_action(name.." %", function(\%)
- return Lua.Value(tree.source, color, "..", \(% as lua), "..", reset);
- end);
+ _ENV["A"..name:as_lua_id()] = compile_time(function(tree) return Lua.Value(tree.source, color) end)
+ _ENV["A"..name:as_lua_id().."_1"] = compile_time(function(tree, text)
+ return Lua.Value(tree.source, color, "..", nomsu:tree_to_lua(text), "..", reset);
+ end)
end
end
diff --git a/nomsu.lua b/nomsu.lua
index 540fa8e..4d06969 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -44,6 +44,7 @@ end
local STDIN, STDOUT, STDERR = "/dev/fd/0", "/dev/fd/1", "/dev/fd/2"
string.as_lua_id = function(str)
local argnum = 0
+ str = gsub(str, "x([0-9A-F][0-9A-F])", "x\0%1")
str = gsub(str, "%W", function(c)
if c == ' ' then
return '_'
@@ -51,11 +52,20 @@ string.as_lua_id = function(str)
argnum = argnum + 1
return tostring(argnum)
else
- return format("x%X", byte(c))
+ return format("x%02X", byte(c))
end
end)
return '_' .. str
end
+table.map = function(self, fn)
+ local _accum_0 = { }
+ local _len_0 = 1
+ for _, v in ipairs(self) do
+ _accum_0[_len_0] = fn(v)
+ _len_0 = _len_0 + 1
+ end
+ return _accum_0
+end
FILE_CACHE = setmetatable({ }, {
__index = function(self, filename)
local file = io.open(filename)
@@ -273,52 +283,8 @@ end
local NomsuCompiler
do
local _class_0
- local compile_error, stub_pattern, var_pattern, _running_files, MAX_LINE, math_expression
+ local compile_error, _running_files, MAX_LINE, math_expression
local _base_0 = {
- define_action = function(self, signature, fn)
- if type(fn) ~= 'function' then
- error("Not a function: " .. tostring(repr(fn)))
- end
- if type(signature) == 'string' then
- signature = {
- signature
- }
- elseif type(signature) ~= 'table' then
- error("Invalid signature, expected list of strings, but got: " .. tostring(repr(signature)), 0)
- end
- local fn_info = debug_getinfo(fn, "u")
- assert(not fn_info.isvararg, "Vararg functions aren't supported. Sorry, use a list instead.")
- local fn_arg_positions
- do
- local _tbl_0 = { }
- for i = 1, fn_info.nparams do
- _tbl_0[debug.getlocal(fn, i)] = i
- end
- fn_arg_positions = _tbl_0
- end
- local arg_orders = { }
- for _index_0 = 1, #signature do
- local alias = signature[_index_0]
- local stub = concat(assert(stub_pattern:match(alias)), ' ')
- local stub_args = assert(var_pattern:match(alias))
- self.environment['ACTION' .. string.as_lua_id(stub)] = fn
- do
- local _accum_0 = { }
- local _len_0 = 1
- for _index_1 = 1, #stub_args do
- local a = stub_args[_index_1]
- _accum_0[_len_0] = fn_arg_positions[string.as_lua_id(a)]
- _len_0 = _len_0 + 1
- end
- arg_orders[stub] = _accum_0
- end
- end
- self.environment.ARG_ORDERS[fn] = arg_orders
- end,
- define_compile_action = function(self, signature, fn)
- self:define_action(signature, fn)
- self.environment.COMPILE_TIME[fn] = true
- end,
parse = function(self, nomsu_code)
assert(type(nomsu_code) ~= 'string')
local userdata = {
@@ -485,7 +451,7 @@ do
local _exp_0 = tree.type
if "Action" == _exp_0 then
local stub = tree.stub
- local action = self.environment['ACTION' .. string.as_lua_id(stub)]
+ local action = self.environment['A' .. string.as_lua_id(stub)]
if action and self.environment.COMPILE_TIME[action] then
local args
do
@@ -578,7 +544,7 @@ do
end
end
end
- lua:append("ACTION", string.as_lua_id(stub), "(")
+ lua:append("A", string.as_lua_id(stub), "(")
for i, arg in ipairs(args) do
lua:append(arg)
if i < #args then
@@ -1127,89 +1093,93 @@ do
end,
initialize_core = function(self)
local nomsu = self
- self:define_compile_action("immediately %block", function(self, _block)
- local lua = nomsu:tree_to_lua(_block):as_statements()
- lua:declare_locals()
- nomsu:run_lua(lua)
- return Lua(_block.source, "if IMMEDIATE then\n ", lua, "\nend")
- end)
- local add_lua_string_bits
- add_lua_string_bits = function(lua, code)
- local line_len = 0
- if code.type ~= "Text" then
- lua:append(", ", nomsu:tree_to_lua(code))
- return
- end
- for _index_0 = 1, #code do
- local bit = code[_index_0]
- local bit_lua
- if type(bit) == "string" then
- bit_lua = repr(bit)
- else
- bit_lua = nomsu:tree_to_lua(bit)
- if not (bit_lua.is_value) then
- compile_error(bit, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.")
- end
- bit_lua = bit_lua
+ do
+ local _with_0 = nomsu.environment
+ _with_0.A_immediately_1 = _with_0.compile_time(function(self, _block)
+ local lua = nomsu:tree_to_lua(_block):as_statements()
+ lua:declare_locals()
+ nomsu:run_lua(lua)
+ return Lua(_block.source, "if IMMEDIATE then\n ", lua, "\nend")
+ end)
+ local add_lua_string_bits
+ add_lua_string_bits = function(lua, code)
+ local line_len = 0
+ if code.type ~= "Text" then
+ lua:append(", ", nomsu:tree_to_lua(code))
+ return
end
- line_len = line_len + #tostring(bit_lua)
- if line_len > MAX_LINE then
- lua:append(",\n ")
- line_len = 4
- else
- lua:append(", ")
+ for _index_0 = 1, #code do
+ local bit = code[_index_0]
+ local bit_lua
+ if type(bit) == "string" then
+ bit_lua = repr(bit)
+ else
+ bit_lua = nomsu:tree_to_lua(bit)
+ if not (bit_lua.is_value) then
+ compile_error(bit, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.")
+ end
+ bit_lua = bit_lua
+ end
+ line_len = line_len + #tostring(bit_lua)
+ if line_len > MAX_LINE then
+ lua:append(",\n ")
+ line_len = 4
+ else
+ lua:append(", ")
+ end
+ lua:append(bit_lua)
end
- lua:append(bit_lua)
end
- end
- self:define_compile_action("Lua %code", function(self, _code)
- local lua = Lua.Value(_code.source, "Lua(", repr(tostring(_code.source)))
- add_lua_string_bits(lua, _code)
- lua:append(")")
- return lua
- end)
- self:define_compile_action("Lua value %code", function(self, _code)
- local lua = Lua.Value(_code.source, "Lua.Value(", repr(tostring(_code.source)))
- add_lua_string_bits(lua, _code)
- lua:append(")")
- return lua
- end)
- local add_lua_bits
- add_lua_bits = function(lua, code)
- for _index_0 = 1, #code do
- local bit = code[_index_0]
- if type(bit) == "string" then
- lua:append(bit)
- else
- local bit_lua = nomsu:tree_to_lua(bit)
- if not (bit_lua.is_value) then
- compile_error(bit, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.")
+ _with_0.A_Lua_1 = _with_0.compile_time(function(self, _code)
+ local lua = Lua.Value(_code.source, "Lua(", repr(tostring(_code.source)))
+ add_lua_string_bits(lua, _code)
+ lua:append(")")
+ return lua
+ end)
+ _with_0.A_Lua_value_1 = _with_0.compile_time(function(self, _code)
+ local lua = Lua.Value(_code.source, "Lua.Value(", repr(tostring(_code.source)))
+ add_lua_string_bits(lua, _code)
+ lua:append(")")
+ return lua
+ end)
+ local add_lua_bits
+ add_lua_bits = function(lua, code)
+ for _index_0 = 1, #code do
+ local bit = code[_index_0]
+ if type(bit) == "string" then
+ lua:append(bit)
+ else
+ local bit_lua = nomsu:tree_to_lua(bit)
+ if not (bit_lua.is_value) then
+ compile_error(bit, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.")
+ end
+ lua:append(bit_lua)
end
- lua:append(bit_lua)
end
+ return lua
end
- return lua
+ nomsu.environment["A" .. string.as_lua_id("lua > 1")] = _with_0.compile_time(function(self, _code)
+ if _code.type ~= "Text" then
+ return Lua(self.source, "nomsu:run_lua(", nomsu:tree_to_lua(_code), ");")
+ end
+ return add_lua_bits(Lua(self.source), _code)
+ end)
+ nomsu.environment["A" .. string.as_lua_id("= lua 1")] = _with_0.compile_time(function(self, _code)
+ if _code.type ~= "Text" then
+ return Lua.Value(self.source, "nomsu:run_lua(", nomsu:tree_to_lua(_code), ":as_statements('return '))")
+ end
+ return add_lua_bits(Lua.Value(self.source), _code)
+ end)
+ _with_0.A_use_1 = _with_0.compile_time(function(self, _path)
+ if not (_path.type == 'Text' and #_path == 1 and type(_path[1]) == 'string') then
+ return Lua(_path.source, "nomsu:run_file(" .. tostring(nomsu:tree_to_lua(_path)) .. ");")
+ end
+ local path = _path[1]
+ nomsu:run_file(path)
+ return Lua(_path.source, "nomsu:run_file(" .. tostring(repr(path)) .. ");")
+ end)
+ return _with_0
end
- self:define_compile_action("lua> %code", function(self, _code)
- if _code.type ~= "Text" then
- return Lua(self.source, "nomsu:run_lua(", nomsu:tree_to_lua(_code), ");")
- end
- return add_lua_bits(Lua(self.source), _code)
- end)
- self:define_compile_action("=lua %code", function(self, _code)
- if _code.type ~= "Text" then
- return Lua.Value(self.source, "nomsu:run_lua(", nomsu:tree_to_lua(_code), ":as_statements('return '))")
- end
- return add_lua_bits(Lua.Value(self.source), _code)
- end)
- return self:define_compile_action("use %path", function(self, _path)
- if not (_path.type == 'Text' and #_path == 1 and type(_path[1]) == 'string') then
- return Lua(_path.source, "nomsu:run_file(" .. tostring(nomsu:tree_to_lua(_path)) .. ");")
- end
- local path = _path[1]
- nomsu:run_file(path)
- return Lua(_path.source, "nomsu:run_file(" .. tostring(repr(path)) .. ");")
- end)
end
}
_base_0.__index = _base_0
@@ -1361,17 +1331,6 @@ do
local err_msg = err_format_string:format(src, ...)
return error(tostring(tok.source.filename) .. ":" .. tostring(line_no) .. ": " .. err_msg, 0)
end
- local stub_defs
- do
- stub_defs = {
- word = (-R("09") * NOMSU_DEFS.ident_char ^ 1) + NOMSU_DEFS.operator_char ^ 1,
- varname = (NOMSU_DEFS.ident_char ^ 1 * ((-P("'") * NOMSU_DEFS.operator_char ^ 1) + NOMSU_DEFS.ident_char ^ 1) ^ 0) ^ -1
- }
- end
- stub_pattern = re.compile([=[ stub <- {| tok (([ ])* tok)* |} !.
- tok <- ({'%'} %varname) / {%word}
- ]=], stub_defs)
- var_pattern = re.compile("{| ((('%' {%varname}) / %word) ([ ])*)+ !. |}", stub_defs)
_running_files = { }
MAX_LINE = 80
math_expression = re.compile([[ ([+-] " ")* "%" (" " [*/^+-] (" " [+-])* " %")+ !. ]])
diff --git a/nomsu.moon b/nomsu.moon
index 1181ae4..bf26844 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -37,14 +37,19 @@ STDIN, STDOUT, STDERR = "/dev/fd/0", "/dev/fd/1", "/dev/fd/2"
string.as_lua_id = (str)->
argnum = 0
+ -- Cut up escape-sequence-like chunks
+ str = gsub str, "x([0-9A-F][0-9A-F])", "x\0%1"
+ -- Alphanumeric unchanged, spaces to underscores, and everything else to hex escape sequences
str = gsub str, "%W", (c)->
if c == ' ' then '_'
elseif c == '%' then
argnum += 1
tostring(argnum)
- else format("x%X", byte(c))
+ else format("x%02X", byte(c))
return '_'..str
+table.map = (fn)=> [fn(v) for _,v in ipairs(@)]
+
-- TODO:
-- consider non-linear codegen, rather than doing thunks for things like comprehensions
-- type checking?
@@ -296,40 +301,6 @@ class NomsuCompiler
@environment._ENV = @environment
@initialize_core!
- local stub_defs
- with NOMSU_DEFS
- stub_defs = {
- word: (-R("09") * .ident_char^1) + .operator_char^1
- varname: (.ident_char^1 * ((-P("'") * .operator_char^1) + .ident_char^1)^0)^-1
- }
- stub_pattern = re.compile [=[
- stub <- {| tok (([ ])* tok)* |} !.
- tok <- ({'%'} %varname) / {%word}
- ]=], stub_defs
- var_pattern = re.compile "{| ((('%' {%varname}) / %word) ([ ])*)+ !. |}", stub_defs
- define_action: (signature, fn)=>
- if type(fn) != 'function'
- error("Not a function: #{repr fn}")
- if type(signature) == 'string'
- signature = {signature}
- elseif type(signature) != 'table'
- error("Invalid signature, expected list of strings, but got: #{repr signature}", 0)
-
- fn_info = debug_getinfo(fn, "u")
- assert(not fn_info.isvararg, "Vararg functions aren't supported. Sorry, use a list instead.")
- fn_arg_positions = {debug.getlocal(fn, i), i for i=1,fn_info.nparams}
- arg_orders = {}
- for alias in *signature
- stub = concat(assert(stub_pattern\match(alias)), ' ')
- stub_args = assert(var_pattern\match(alias))
- @environment['ACTION'..string.as_lua_id(stub)] = fn
- arg_orders[stub] = [fn_arg_positions[string.as_lua_id a] for a in *stub_args]
- @environment.ARG_ORDERS[fn] = arg_orders
-
- define_compile_action: (signature, fn)=>
- @define_action(signature, fn)
- @environment.COMPILE_TIME[fn] = true
-
parse: (nomsu_code)=>
assert(type(nomsu_code) != 'string')
userdata = {
@@ -444,7 +415,7 @@ class NomsuCompiler
switch tree.type
when "Action"
stub = tree.stub
- action = @environment['ACTION'..string.as_lua_id(stub)]
+ action = @environment['A'..string.as_lua_id(stub)]
if action and @environment.COMPILE_TIME[action]
args = [arg for arg in *tree when type(arg) != "string"]
-- Force all compile-time actions to take a tree location
@@ -491,7 +462,7 @@ class NomsuCompiler
if arg_orders = @environment.ARG_ORDERS[stub]
args = [args[p] for p in *arg_orders]
- lua\append "ACTION",string.as_lua_id(stub),"("
+ lua\append "A",string.as_lua_id(stub),"("
for i, arg in ipairs args
lua\append arg
if i < #args then lua\append ", "
@@ -909,74 +880,75 @@ class NomsuCompiler
initialize_core: =>
-- Sets up some core functionality
nomsu = self
- @define_compile_action "immediately %block", (_block)=>
- lua = nomsu\tree_to_lua(_block)\as_statements!
- lua\declare_locals!
- nomsu\run_lua(lua)
- return Lua(_block.source, "if IMMEDIATE then\n ", lua, "\nend")
-
- add_lua_string_bits = (lua, code)->
- line_len = 0
- if code.type != "Text"
- lua\append ", ", nomsu\tree_to_lua(code)
- return
- for bit in *code
- bit_lua = if type(bit) == "string"
- repr(bit)
- else
- bit_lua = nomsu\tree_to_lua(bit)
- unless bit_lua.is_value
- compile_error bit,
- "Cannot use:\n%s\nas a string interpolation value, since it's not an expression."
- bit_lua
- line_len += #tostring(bit_lua)
- if line_len > MAX_LINE
- lua\append ",\n "
- line_len = 4
- else
- lua\append ", "
- lua\append bit_lua
-
- @define_compile_action "Lua %code", (_code)=>
- lua = Lua.Value(_code.source, "Lua(", repr(tostring _code.source))
- add_lua_string_bits(lua, _code)
- lua\append ")"
- return lua
-
- @define_compile_action "Lua value %code", (_code)=>
- lua = Lua.Value(_code.source, "Lua.Value(", repr(tostring _code.source))
- add_lua_string_bits(lua, _code)
- lua\append ")"
- return lua
-
- add_lua_bits = (lua, code)->
- for bit in *code
- if type(bit) == "string"
- lua\append bit
- else
- bit_lua = nomsu\tree_to_lua(bit)
- unless bit_lua.is_value
- compile_error bit,
- "Cannot use:\n%s\nas a string interpolation value, since it's not an expression."
+ with nomsu.environment
+ .A_immediately_1 = .compile_time (_block)=>
+ lua = nomsu\tree_to_lua(_block)\as_statements!
+ lua\declare_locals!
+ nomsu\run_lua(lua)
+ return Lua(_block.source, "if IMMEDIATE then\n ", lua, "\nend")
+
+ add_lua_string_bits = (lua, code)->
+ line_len = 0
+ if code.type != "Text"
+ lua\append ", ", nomsu\tree_to_lua(code)
+ return
+ for bit in *code
+ bit_lua = if type(bit) == "string"
+ repr(bit)
+ else
+ bit_lua = nomsu\tree_to_lua(bit)
+ unless bit_lua.is_value
+ compile_error bit,
+ "Cannot use:\n%s\nas a string interpolation value, since it's not an expression."
+ bit_lua
+ line_len += #tostring(bit_lua)
+ if line_len > MAX_LINE
+ lua\append ",\n "
+ line_len = 4
+ else
+ lua\append ", "
lua\append bit_lua
- return lua
-
- @define_compile_action "lua> %code", (_code)=>
- if _code.type != "Text"
- return Lua @source, "nomsu:run_lua(", nomsu\tree_to_lua(_code), ");"
- return add_lua_bits(Lua(@source), _code)
-
- @define_compile_action "=lua %code", (_code)=>
- if _code.type != "Text"
- return Lua.Value @source, "nomsu:run_lua(", nomsu\tree_to_lua(_code), ":as_statements('return '))"
- return add_lua_bits(Lua.Value(@source), _code)
-
- @define_compile_action "use %path", (_path)=>
- unless _path.type == 'Text' and #_path == 1 and type(_path[1]) == 'string'
- return Lua(_path.source, "nomsu:run_file(#{nomsu\tree_to_lua(_path)});")
- path = _path[1]
- nomsu\run_file(path)
- return Lua(_path.source, "nomsu:run_file(#{repr path});")
+
+ .A_Lua_1 = .compile_time (_code)=>
+ lua = Lua.Value(_code.source, "Lua(", repr(tostring _code.source))
+ add_lua_string_bits(lua, _code)
+ lua\append ")"
+ return lua
+
+ .A_Lua_value_1 = .compile_time (_code)=>
+ lua = Lua.Value(_code.source, "Lua.Value(", repr(tostring _code.source))
+ add_lua_string_bits(lua, _code)
+ lua\append ")"
+ return lua
+
+ add_lua_bits = (lua, code)->
+ for bit in *code
+ if type(bit) == "string"
+ lua\append bit
+ else
+ bit_lua = nomsu\tree_to_lua(bit)
+ unless bit_lua.is_value
+ compile_error bit,
+ "Cannot use:\n%s\nas a string interpolation value, since it's not an expression."
+ lua\append bit_lua
+ return lua
+
+ nomsu.environment["A"..string.as_lua_id("lua > 1")] = .compile_time (_code)=>
+ if _code.type != "Text"
+ return Lua @source, "nomsu:run_lua(", nomsu\tree_to_lua(_code), ");"
+ return add_lua_bits(Lua(@source), _code)
+
+ nomsu.environment["A"..string.as_lua_id("= lua 1")] = .compile_time (_code)=>
+ if _code.type != "Text"
+ return Lua.Value @source, "nomsu:run_lua(", nomsu\tree_to_lua(_code), ":as_statements('return '))"
+ return add_lua_bits(Lua.Value(@source), _code)
+
+ .A_use_1 = .compile_time (_path)=>
+ unless _path.type == 'Text' and #_path == 1 and type(_path[1]) == 'string'
+ return Lua(_path.source, "nomsu:run_file(#{nomsu\tree_to_lua(_path)});")
+ path = _path[1]
+ nomsu\run_file(path)
+ return Lua(_path.source, "nomsu:run_file(#{repr path});")
-- Only run this code if this file was run directly with command line arguments, and not require()'d:
if arg and debug_getinfo(2).func != require
diff --git a/nomsu_tree.lua b/nomsu_tree.lua
index baec3ef..7288613 100644
--- a/nomsu_tree.lua
+++ b/nomsu_tree.lua
@@ -116,4 +116,16 @@ AST.Action.__init = function(self)
end
self.stub = concat(stub_bits, " ")
end
+AST.Action.get_args = function(self)
+ local _accum_0 = { }
+ local _len_0 = 1
+ for _index_0 = 1, #self do
+ local tok = self[_index_0]
+ if type(tok) ~= 'string' then
+ _accum_0[_len_0] = tok
+ _len_0 = _len_0 + 1
+ end
+ end
+ return _accum_0
+end
return AST
diff --git a/nomsu_tree.moon b/nomsu_tree.moon
index b9bcdbd..0c6e925 100644
--- a/nomsu_tree.moon
+++ b/nomsu_tree.moon
@@ -41,4 +41,7 @@ AST.Action.__init = =>
stub_bits = [type(a) == 'string' and a or '%' for a in *@]
@stub = concat stub_bits, " "
+AST.Action.get_args = =>
+ [tok for tok in *@ when type(tok) != 'string']
+
return AST
diff --git a/tests/collections.nom b/tests/collections.nom
index 2cc6adf..4170d17 100644
--- a/tests/collections.nom
+++ b/tests/collections.nom
@@ -4,8 +4,6 @@
use "core"
assume ((2nd to last in [1,2,3,4,5]) = 4)
-assume ((first in [1,2]) = 1)
-assume ((last in [1,2]) = 2)
assume (3 is in [1,2,3,4,5])
assume (99 isn't in [1,2,3])
assume ({x:no} has key "x")
@@ -27,7 +25,7 @@ assume (([[1,2],[3,4]] flattened) = [1,2,3,4])
assume ((entries in {x:1}) = [{key:"x",value:1}])
assume ((keys in {x:1}) = ["x"])
assume ((values in {x:1}) = [1])
-#assume ((sorted [3,1,2]) = [1,2,3])
+assume ((sorted [3,1,2]) = [1,2,3])
%x <- [3,1,2]
sort %x
assume (%x = [1,2,3])
diff --git a/tests/control_flow.nom b/tests/control_flow.nom
index 5553811..20ccabe 100644
--- a/tests/control_flow.nom
+++ b/tests/control_flow.nom
@@ -104,7 +104,7 @@ assume (%x = 6) or barf "backwards numeric for range failed"
%result <- {}
for %key = %value in {x:1,y:2}
- (%result's ("\%key\%key")) <- (%value * 11)
+ %result.("\%key\%key") <- (%value * 11)
assume (%result = {xx:11,yy:22}) or barf "key/value iteration failed"
for %key = %value in {x:1,y:2}
diff --git a/tests/math.nom b/tests/math.nom
index 8cfd0f4..115354c 100644
--- a/tests/math.nom
+++ b/tests/math.nom
@@ -11,7 +11,7 @@ assume
all of [..]
abs 5, |5|, sqrt 5, √(5), sine 5, cosine 5, tangent 5, arc sine 5, arc cosine 5,
arc tangent 5, arc tangent 5/10, hyperbolic sine 5, hyperbolic cosine 5,
- hyperbolic tangent 5, e^5, ln 5, log_(2) 5, floor 5, ceiling 5, round 5,
+ hyperbolic tangent 5, e^5, ln 5, log base 2 of 5, floor 5, ceiling 5, round 5,
..or barf "math functions failed"
assume ((463 to the nearest 100) = 500) or barf "rounding failed"
assume ((2.6 to the nearest 0.25) = 2.5) or barf "rounding failed"
diff --git a/tests/object.nom b/tests/object.nom
index 041b784..8ad5b82 100644
--- a/tests/object.nom
+++ b/tests/object.nom
@@ -18,7 +18,7 @@ as %d
assume: ((me).barks) = 3
assume: (bark) = "Bark! Bark! Bark!"
assume: "\(%d.class)" = "Dog"
-assume: (%d's "barks") = 3
+assume: %d.barks = 3
as: new "Dog" {barks:1}
assume: (bark) = "Bark!"
diff --git a/tests/operators.nom b/tests/operators.nom
index b3853e9..2452ba5 100644
--- a/tests/operators.nom
+++ b/tests/operators.nom
@@ -3,10 +3,6 @@
use "core"
-assume (({x:5}'s "x") = 5) or barf "indexing doesn't work."
-try: % <- ({}'s "[[[\n]]]")
-..and if it barfs: barf "failed to index a table literal with a string containing brackets n stuff"
-
<-{%x:10,%y:20}
assume ((%x = 10) and (%y = 20)) or barf "mutli-assignment failed."
<-{%x:%y, %y:%x}