aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/collections.nom2
-rw-r--r--core/control_flow.nom2
-rw-r--r--core/coroutines.nom33
-rw-r--r--core/id.nom2
-rw-r--r--core/math.nom8
-rw-r--r--core/metaprogramming.nom109
-rw-r--r--core/operators.nom120
-rw-r--r--core/text.nom2
8 files changed, 156 insertions, 122 deletions
diff --git a/core/collections.nom b/core/collections.nom
index 82b5dfb..a586882 100644
--- a/core/collections.nom
+++ b/core/collections.nom
@@ -72,7 +72,7 @@ test:
# Metatable stuff
test:
%t = {}
- set %t's metatable to {__tostring: [%] -> "XXX"}
+ set %t's metatable to {__tostring: % -> "XXX"}
assume ("\%t" == "XXX")
(set %dict's metatable to %metatable) compiles to "\
diff --git a/core/control_flow.nom b/core/control_flow.nom
index 964250e..9432a92 100644
--- a/core/control_flow.nom
+++ b/core/control_flow.nom
@@ -506,7 +506,7 @@ test:
assume ((result of: return 99) == 99)
# Inline thunk:
-(result of %body) compiles to "\(what ([] -> %body) compiles to)()"
+(result of %body) compiles to "\(what (-> %body) compiles to)()"
test:
%t = [1, [2, [[3], 4], 5, [[[6]]]]]
%flat = []
diff --git a/core/coroutines.nom b/core/coroutines.nom
index 7d17d63..0a625c2 100644
--- a/core/coroutines.nom
+++ b/core/coroutines.nom
@@ -3,29 +3,40 @@
This file defines the code that creates and manipulates coroutines
use "core/metaprogramming.nom"
+use "core/operators.nom"
+use "core/control_flow.nom"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test:
- %nums = []
%co = (..)
- coroutine:
- -> 4
- -> 5
- repeat 3 times: -> 6
+ ->:
+ yield 4
+ yield 5
+ repeat 3 times: yield 6
+ %nums = []
for % in coroutine %co:
%nums::add %
assume (%nums == [4, 5, 6, 6, 6]) or barf "Coroutine iteration failed"
-[coroutine %body, generator %body] all compile to "\
- ..(function()
- \(%body as lua)
- end)"
-(-> %) compiles to "coroutine.yield(true, \((% as lua expr) if % else "nil"))"
+ %d = {x:0}
+ %co2 = (..)
+ coroutine:
+ %d.x += 1
+ yield 1
+ %d.x += 1
+ yield
+ %d.x += 1
+ repeat while ((coroutine status of %co2) != "dead"):
+ resume %co2
+ assume %d.x == 3
+
+(coroutine %body) parses as (coroutine from (-> %body))
+
(for % in coroutine %co %body) compiles to "\
- ..for _junk,\(% as lua expr) in coroutine.wrap(\(%co as lua expr)) do
+ ..for \(% as lua expr) in coroutine_wrap(\(%co as lua expr)) do
\(%body as lua)
end"
diff --git a/core/id.nom b/core/id.nom
index 9cf5820..7de38f9 100644
--- a/core/id.nom
+++ b/core/id.nom
@@ -16,7 +16,7 @@ use "core/control_flow.nom"
set %obj_by_id's metatable to {__mode: "v"}
%id_by_obj = {}
set %id_by_obj's metatable to {..}
- __mode: "k", __index: [%self, %key] ->:
+ __mode: "k", __index: for (%self %key):
if (%key == (nil)):
return %self.%nil_surrogate
diff --git a/core/math.nom b/core/math.nom
index aa1d200..38fb984 100644
--- a/core/math.nom
+++ b/core/math.nom
@@ -70,7 +70,7 @@ externally [all of %items, all %items] all mean:
return (no)
return (yes)
-[all of %items, all %items] all compile to:
+#[all of %items, all %items] all compile to:
unless (%items.type is "List"):
return \(all of %items)
@@ -89,7 +89,7 @@ externally [any of %items, any %items] all mean:
return (yes)
return (no)
-[any of %items, any %items] all compile to:
+#[any of %items, any %items] all compile to:
unless (%items.type is "List"):
return \(any of %items)
@@ -110,7 +110,7 @@ externally [sum of %items, sum %items] all mean:
%total += %
return %total
-[sum of %items, sum %items] all compile to:
+#[sum of %items, sum %items] all compile to:
unless (%items.type is "List"):
return \(sum of %items)
@@ -128,7 +128,7 @@ externally [product of %items, product %items] all mean:
%prod *= %
return %prod
-[product of %items, product %items] all compile to:
+#[product of %items, product %items] all compile to:
unless (%items.type is "List"):
return \(product of %items)
diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom
index 944dc34..165a814 100644
--- a/core/metaprogramming.nom
+++ b/core/metaprogramming.nom
@@ -3,7 +3,8 @@
This File contains actions for making actions and compile-time actions and some helper
functions to make that easier.
-lua> "NOMSU_CORE_VERSION = 10\nNOMSU_LIB_VERSION = 7"
+lua> "NOMSU_CORE_VERSION = 11"
+lua> "NOMSU_LIB_VERSION = 8"
lua> "\
..do
local mangle_index = 0
@@ -21,23 +22,38 @@ lua> "\
lua> "\
..compile.action["1 ->"] = function(compile, \%args, \%body)
- local lua = LuaCode("(function(")
- if SyntaxTree:is_instance(\%args) and \%args.type == "Action" then \%args = \%args:get_args() end
- local lua_args = table.map(\%args, function(a) return SyntaxTree:is_instance(a) and compile(a):text(\
- ..) or a end)
- lua:concat_append(lua_args, ", ")
+ if \%args and not \%body then \%args, \%body = {}, \%args end
local body_lua = SyntaxTree:is_instance(\%body) and compile(\%body) or \%body
if SyntaxTree:is_instance(\%body) and \%body.type ~= "Block" then body_lua:prepend("return ") end
- body_lua:remove_free_vars(lua_args)
+ local lua = LuaCode("(function(")
+ if SyntaxTree:is_instance(\%args) and \%args.type == "Action" then \%args = \%args:get_args()
+ elseif SyntaxTree:is_instance(\%args) and \%args.type == "Var" then \%args = {\%args} end
+ for i, arg in ipairs(\%args) do
+ local arg_lua = SyntaxTree:is_instance(arg) and compile(arg):text() or arg
+ if arg_lua == "..." then
+ if i < #\%args then
+ compile_error_at(SyntaxTree:is_instance(arg) and arg or nil,
+ "Extra arguments must come last.", "Try removing any arguments after (*extra arguments*)")
+ end
+ elseif not arg_lua:is_lua_id() then
+ compile_error_at(SyntaxTree:is_instance(arg) and arg or nil,
+ "This does not compile to a Lua identifier, so it can't be used as a function argument.",
+ "This should probably be a Nomsu variable instead (like %x).")
+ end
+ lua:append(i > 1 and ", " or "", arg_lua)
+ body_lua:remove_free_vars({arg_lua})
+ end
body_lua:declare_locals()
lua:append(")\\n ", body_lua, "\\nend)")
return lua
- end"
+ end
+ compile.action["->"] = compile.action["1 ->"]
+ compile.action["for"] = compile.action["1 ->"]"
lua> "\
..compile.action["what 1 compiles to"] = function(compile, \%action)
local lua = LuaCode("compile.action[", \%action.stub:as_lua(), "](")
- local lua_args = table.map(\%action:get_args(), function(a) return compile(a) end)
+ local lua_args = table.map(\%action:get_args(), compile)
table.insert(lua_args, 1, "compile")
lua:concat_append(lua_args, ", ")
lua:append(")")
@@ -100,17 +116,6 @@ lua> "\
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-(call %fn with %args) compiles to:
- lua> "\
- ..local lua = LuaCode(compile(\%fn), "(")
- if \%args.type == 'List' then
- lua:concat_append(table.map(\%args, function(a) return compile(a) end), ", ")
- else
- lua:append('unpack(', compile(\%args), ')')
- end
- lua:append(")")
- return lua"
-
test:
(foo %x) means "outer"
with local [(foo %)'s meaning]:
@@ -124,27 +129,36 @@ test:
(%action means %body) compiles to:
lua> "\
- ..local fn_name = \%action.stub:as_lua_id()
- local \%args = \%action:get_args()
- local lua = LuaCode(fn_name, " = ", \(what (%args -> %body) compiles to))
- lua:add_free_vars({fn_name})
+ ..
+ local lua = LuaCode()
+ local fn_name = \%action.stub:as_lua_id()
+ if \%action.target then lua:append(compile(\%action.target), ".")
+ else lua:add_free_vars({fn_name}) end
+ lua:append(fn_name, " = ", \(what (%action -> %body) compiles to), ";")
return lua"
(%actions all mean %body) compiles to:
lua> "\
..local fn_name = \%actions[1].stub:as_lua_id()
+ local target = \%actions[1].target and compile(\%actions[1].target) or nil
local \%args = List(\%actions[1]:get_args())
local lua = \(what (%actions.1 means %body) compiles to)
for i=2,#\%actions do
local alias = \%actions[i]
local alias_name = alias.stub:as_lua_id()
- lua:add_free_vars({alias_name})
local \%alias_args = List(alias:get_args())
- lua:append("\\n", alias_name, " = ")
+ lua:append("\\n")
+ if alias.target then
+ lua:append(compile(alias.target), ".")
+ else
+ lua:add_free_vars({alias_name})
+ end
+ lua:append(alias_name, " = ")
if \%args == \%alias_args then
- lua:append(fn_name)
+ if target then lua:append(target, ".") end
+ lua:append(fn_name, ";")
else
- lua:append(\(what (%alias_args -> %actions.1) compiles to))
+ lua:append(\(what (%alias_args -> %actions.1) compiles to), ";")
end
end
return lua"
@@ -182,11 +196,11 @@ test:
%y = %tmp
test:
- set {%1: 1, %2: 2}
+ [%1, %2] = [1, 2]
swap %1 and %2
assume ((%1 == 2) and (%2 == 1)) or barf "\
..'parse % as %' failed on 'swap % and %'"
- set {%tmp: 1, %tmp2: 2}
+ [%tmp, %tmp2] = [1, 2]
swap %tmp and %tmp2
assume ((%tmp == 2) and (%tmp2 == 1)) or barf "\
..'parse % as %' variable mangling failed."
@@ -239,9 +253,15 @@ test:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[%action parses as %body] all parse as ([%action] all parse as %body)
-(%tree as lua expr) compiles to "compile(\(=lua "compile(\%tree, true)"), true)"
+#(%tree as lua expr) compiles to "compile(\(=lua "compile(\%tree, true)"), true)"
+externally (%tree as lua expr) means:
+ lua> "\
+ ..local tree_lua = compile(\%tree)
+ if \%tree.type == 'Block' then
+ tree_lua = LuaCode:from(\%tree.source, '(function()\n ', tree_lua, '\nend)()')
+ end
+ return tree_lua"
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
externally [%var as lua identifier, %var as lua id] all mean:
lua> "\
@@ -256,7 +276,14 @@ externally [%var as lua identifier, %var as lua id] all mean:
else error("Unknown type: "..tostring(\%var))
end"
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+test:
+ (num args (*extra arguments*)) means (select "#" (*extra arguments*))
+ assume (num args 1 2 3) == 3
+ (extra args (*extra arguments*)) means [*extra arguments*]
+ assume (extra args 1 2 3) == [1, 2, 3]
+ (third arg (*extra arguments*)) means (select 3 (*extra arguments*))
+ assume (third arg 5 6 7 8) == 7
+(*extra arguments*) compiles to "..."
(% is syntax tree) compiles to "SyntaxTree:is_instance(\(% as lua expr))"
externally (% is %kind syntax tree) means (..)
@@ -288,7 +315,7 @@ externally (%tree with vars %replacements) means (..)
(%tree has subtree %match_tree) compiles to "\
..(function()
local match_tree = \(%match_tree as lua expr)
- for subtree in coroutine.wrap(function() \(%tree as lua expr):map(coroutine.yield) end) do
+ for subtree in coroutine_wrap(function() \(%tree as lua expr):map(yield) end) do
if subtree == match_tree then return true end
end
end)()"
@@ -366,10 +393,20 @@ test:
[compile %block, compiled %block, %block compiled] all compile to "\
..compile(\(%block as lua))"
+test:
+ (foo) means: return 100 200 300
+ assume (select 2 (foo)) == 200
# Return statement is wrapped in a do..end block because Lua is unhappy if you
put code after a return statement, unless you wrap it in a block.
-(return %return_value) compiles to "\
- ..do return \(=lua "\%return_value and \(%return_value as lua expr) or ''") end"
+(return (*extra arguments*)) compiles to:
+ lua> "\
+ ..local lua = \(Lua "do return ")
+ for i=1,select('#',...) do
+ if i > 1 then lua:append(", ") end
+ lua:append(_1_as_lua((select(i, ...))))
+ end
+ lua:append(" end")
+ return lua"
# Literals
(yes) compiles to "true"
diff --git a/core/operators.nom b/core/operators.nom
index cc86398..a7cb116 100644
--- a/core/operators.nom
+++ b/core/operators.nom
@@ -24,57 +24,58 @@ test:
test:
%x = 10
assume (%x == 10)
-
-# Variable assignment operator
-(%var = %value) compiles to:
- lua> "\
- ..local \%var_lua = \(%var as lua expr)
- local \%value_lua = \(%value as lua expr)
- local lua = LuaCode(\%var_lua, ' = ', \%value_lua, ';')
- if \%var.type == 'Var' then
- lua:add_free_vars({compile(\%var):text()})
- end
- return lua"
-
-test:
- set {%x: 10, %y: 20}
+ [%x, %y] = [10, 20]
assume ((%x == 10) and (%y == 20)) or barf "mutli-assignment failed."
- set {%x: %y, %y: %x}
+ [%x, %y] = [%y, %x]
assume ((%y == 10) and (%x == 20)) or barf "swapping vars failed."
+ %vals = [4, 5]
+ [%x, %y] = (unpack %vals)
+ assume ((%x == 4) and (%y == 5)) or barf "unpacking failed"
-# Simultaneous mutli-assignments like: x,y,z = 1,x,3;
-# TODO: deprecate?
-(set %assignments) compiles to:
- assume (%assignments.type is "Dict") or barf "\
- ..Expected a Dict for the assignments part of '<- %' statement, not \%assignments"
-
+# Variable assignment operator
+(%var = %value) compiles to:
lua> "\
- ..local lhs, rhs = LuaCode(), LuaCode()
- for i, item in ipairs(\%assignments) do
- local \%target, \%value = item[1], item[2]
- \%value = \%value:map(function(t)
- if SyntaxTree:is_instance(t) and t.type == "Action" and t.stub == "?" then
- return \%target
+ ..
+ local lua = LuaCode()
+ if \%var.type == "List" then
+ for i, \%assignment in ipairs(\%var) do
+ if i > 1 then lua:append(", ") end
+ local assignment_lua = \(%assignment as lua expr)
+ lua:append(assignment_lua)
+ if \%assignment.type == 'Var' then
+ lua:add_free_vars({assignment_lua:text()})
end
- end)
- local target_lua = \(%target as lua)
- local value_lua = \(%value as lua)
- if \%target.type == "Var" then
- lhs:add_free_vars({target_lua:text()})
end
- if i > 1 then
- lhs:append(", ")
- rhs:append(", ")
+ lua:append(' = ')
+ if \%value.type == "List" then
+ if #\%value ~= #\%var then
+ compile_error_at(\%value,
+ "This assignment has too "..(#\%value > #\%var and "many" or "few").." values.",
+ "Make sure it has the same number of values on the left and right hand side of the '=' operator.")
+ end
+ for i, \%val in ipairs(\%value) do
+ if i > 1 then lua:append(", ") end
+ local val_lua = \(%val as lua expr)
+ lua:append(val_lua)
+ end
+ lua:append(";")
+ else
+ lua:append(\(%value as lua expr), ';')
end
- lhs:append(target_lua)
- rhs:append(value_lua)
+ else
+ local var_lua = \(%var as lua expr)
+ lua:append(var_lua)
+ if \%var.type == 'Var' then
+ lua:add_free_vars({var_lua:text()})
+ end
+ lua:append(' = ', \(%value as lua expr), ';')
end
- return LuaCode(lhs, " = ", rhs, ";")"
+ return lua"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test:
- set {%foozle: "outer", %y: "outer"}
+ [%foozle, %y] = ["outer", "outer"]
externally (set global x local y) means:
external %foozle = "inner"
%y = "inner"
@@ -82,7 +83,7 @@ test:
assume ((%foozle == "inner") and (%y == "outer")) or barf "external failed."
(external %var = %value) compiles to "\(%var as lua) = \(%value as lua)"
test:
- set {%foozle: "outer", %y: "outer"}
+ [%foozle, %y] = ["outer", "outer"]
externally (set global x local y) means:
with external [%foozle]:
%foozle = "inner"
@@ -97,7 +98,7 @@ test:
return %body_lua
test:
- set {%x: 1, %y: 2}
+ [%x, %y] = [1, 2]
with {%z: nil, %x: 999}:
%z = 999
assume (%z == 999) or barf "'with' failed."
@@ -149,29 +150,14 @@ test:
assume (%calls == 1) or barf "\
..Three-way comparison evaluated middle value multiple times"
-(%x < %y < %z) parses as (..)
- call ([%a, %b, %c] -> ((%a < %b) and (%b < %c))) with [%x, %y, %z]
-
-(%x <= %y < %z) parses as (..)
- call ([%a, %b, %c] -> ((%a <= %b) and (%b < %c))) with [%x, %y, %z]
-
-(%x < %y <= %z) parses as (..)
- call ([%a, %b, %c] -> ((%a < %b) and (%b <= %c))) with [%x, %y, %z]
-
-(%x <= %y <= %z) parses as (..)
- call ([%a, %b, %c] -> ((%a <= %b) and (%b <= %c))) with [%x, %y, %z]
-
-(%x > %y > %z) parses as (..)
- call ([%a, %b, %c] -> ((%a > %b) and (%b > %c))) with [%x, %y, %z]
-
-(%x >= %y > %z) parses as (..)
- call ([%a, %b, %c] -> ((%a >= %b) and (%b > %c))) with [%x, %y, %z]
-
-(%x > %y >= %z) parses as (..)
- call ([%a, %b, %c] -> ((%a > %b) and (%b >= %c))) with [%x, %y, %z]
-
-(%x >= %y >= %z) parses as (..)
- call ([%a, %b, %c] -> ((%a >= %b) and (%b >= %c))) with [%x, %y, %z]
+(%x < %y < %z) parses as (((%a %b %c) -> ((%a < %b) and (%b < %c))) %x %y %z)
+(%x <= %y < %z) parses as (((%a %b %c) -> ((%a <= %b) and (%b < %c))) %x %y %z)
+(%x < %y <= %z) parses as (((%a %b %c) -> ((%a < %b) and (%b <= %c))) %x %y %z)
+(%x <= %y <= %z) parses as (((%a %b %c) -> ((%a <= %b) and (%b <= %c))) %x %y %z)
+(%x > %y > %z) parses as (((%a %b %c) -> ((%a > %b) and (%b > %c))) %x %y %z)
+(%x >= %y > %z) parses as (((%a %b %c) -> ((%a >= %b) and (%b > %c))) %x %y %z)
+(%x > %y >= %z) parses as (((%a %b %c) -> ((%a > %b) and (%b >= %c))) %x %y %z)
+(%x >= %y >= %z) parses as (((%a %b %c) -> ((%a >= %b) and (%b >= %c))) %x %y %z)
# TODO: optimize for common case where x,y,z are all either variables or number literals
# Boolean Operators
@@ -249,9 +235,9 @@ test:
assume (%x == 4) or barf "*= failed"
wrap %x around 3
assume (%x == 1) or barf "wrap around failed"
-(%var += %) parses as (%var = (%var + %))
-(%var -= %) parses as (%var = (%var - %))
-(%var *= %) parses as (%var = (%var * %))
+(%var += %) parses as (%var = ((%var or 0) + %))
+(%var -= %) parses as (%var = ((%var or 0) - %))
+(%var *= %) parses as (%var = ((%var or 1) * %))
(%var /= %) parses as (%var = (%var / %))
(%var ^= %) parses as (%var = (%var ^ %))
(%var and= %) parses as (%var = (%var and %))
diff --git a/core/text.nom b/core/text.nom
index 50a0ab5..62b6656 100644
--- a/core/text.nom
+++ b/core/text.nom
@@ -63,4 +63,4 @@ externally (%num as hex) means:
for %name = %str in %escapes:
with {%lua: Lua (quote %str)}:
- %compile.action.%name = ([] -> %lua)
+ %compile.action.%name = (-> %lua)