All tests passing (except object)
This commit is contained in:
parent
dcb380f1f6
commit
da33269c30
@ -13,7 +13,7 @@ immediately:
|
||||
compile [..]
|
||||
%index st to last in %list, %index nd to last in %list, %index rd to last in %list
|
||||
%index th to last in %list
|
||||
..to {expr:"utils.nth_to_last(\(%list as lua expr), \(%index as lua expr))"}
|
||||
..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
|
||||
@ -37,35 +37,35 @@ immediately:
|
||||
|
||||
immediately:
|
||||
# Note: it's important to have the space after "[" to prevent confusion if %index is a string
|
||||
compile [%list has key %index, %list has index %index] to {..}
|
||||
expr: ".."
|
||||
compile [%list has key %index, %list has index %index] to
|
||||
Lua value ".."
|
||||
((\(%list as lua expr))[ \(%index as lua expr)] ~= nil)
|
||||
|
||||
# Note: it's important to have the space after "[" to prevent confusion if %index is a string
|
||||
compile [..]
|
||||
%list doesn't have key %index, %list does not have key %index
|
||||
%list doesn't have index %index, %list does not have index %index
|
||||
..to {expr:"((\(%list as lua expr))[ \(%index as lua expr)] == nil)"}
|
||||
..to: Lua value "((\(%list as lua expr))[ \(%index as lua expr)] == nil)"
|
||||
|
||||
compile [length of %list, size of %list, size %list, number of %list, len %list] to:
|
||||
{expr:"utils.size(\(%list as lua expr))"}
|
||||
compile [number of keys in %list] to:
|
||||
Lua value "utils.size(\(%list as lua expr))"
|
||||
|
||||
compile [append %item to %list, add %item to %list, to %list add %item, to %list append %item] to:
|
||||
{statements:"table.insert(\(%list as lua expr), \(%item as lua expr))"}
|
||||
Lua "table.insert(\(%list as lua expr), \(%item as lua expr))"
|
||||
|
||||
compile [pop from %list, remove last from %list] to:
|
||||
{statements:"table.remove(\(%list as lua expr))"}
|
||||
Lua "table.remove(\(%list as lua expr))"
|
||||
|
||||
compile [remove index %index from %list] to:
|
||||
{statements:"table.remove(\(%list as lua expr), \(%index as lua expr))"}
|
||||
Lua "table.remove(\(%list as lua expr), \(%index as lua expr))"
|
||||
|
||||
# List Comprehension
|
||||
immediately:
|
||||
compile [%expression for %item in %iterable] to:
|
||||
assume (%item.type is "Var") or barf ".."
|
||||
List comprehension has the wrong type for the loop variable. Expected Var, but got: \(%item.type)
|
||||
return {..}
|
||||
expr:".."
|
||||
return
|
||||
Lua value ".."
|
||||
(function()
|
||||
local comprehension = {};
|
||||
for i,\(%item as lua expr) in ipairs(\(%iterable as lua expr)) do
|
||||
@ -81,8 +81,8 @@ immediately:
|
||||
..to:
|
||||
assume (%index.type is "Var") or barf ".."
|
||||
List comprehension has the wrong type for the loop variable. Expected Var, but got: \(%index.type)
|
||||
return {..}
|
||||
expr:".."
|
||||
return
|
||||
Lua value ".."
|
||||
(function()
|
||||
local comprehension = {};
|
||||
for \(%index as lua expr)=\(%start as lua expr),\(%stop as lua expr),\(%step as lua expr) do
|
||||
@ -103,8 +103,8 @@ immediately:
|
||||
List comprehension has the wrong type for the key loop variable. Expected Var, but got: \(%key.type)
|
||||
assume (%value.type is "Var") or barf ".."
|
||||
List comprehension has the wrong type for the value loop variable. Expected Var, but got: \(%value.type)
|
||||
return {..}
|
||||
expr: ".."
|
||||
return
|
||||
Lua value ".."
|
||||
(function()
|
||||
local comprehension = {};
|
||||
for \(%key as lua expr), \(%value as lua expr) in pairs(\(%iterable as lua expr)) do
|
||||
@ -119,8 +119,8 @@ immediately:
|
||||
assume (%item.type is "Var") or barf ".."
|
||||
Dict comprehension has the wrong type for the loop variable. Expected Var, but got: \(%item.type)
|
||||
# Note: it's important to have the space after "[" to prevent confusion if %key is a string
|
||||
return {..}
|
||||
expr: ".."
|
||||
return
|
||||
Lua value ".."
|
||||
(function()
|
||||
local comprehension = {};
|
||||
for i,\(%item as lua expr) in ipairs(\(%iterable as lua expr)) do
|
||||
@ -136,8 +136,8 @@ immediately:
|
||||
assume (%src_value.type is "Var") or barf ".."
|
||||
Dict comprehension has the wrong type for the value loop variable. Expected Var, but got: \(%src_value.type)
|
||||
# Note: it's important to have the space after "[" to prevent confusion if %key is a string
|
||||
return {..}
|
||||
expr: ".."
|
||||
return
|
||||
Lua value ".."
|
||||
(function()
|
||||
local comprehension = {};
|
||||
for \(%src_key as lua expr), \(%src_value as lua expr) in pairs(\(%iterable as lua expr)) do
|
||||
@ -160,12 +160,12 @@ immediately:
|
||||
|
||||
# Sorting:
|
||||
immediately:
|
||||
compile [sort %items] to {statements:"table.sort(\(%items as lua expr))"}
|
||||
compile [sort %items by %key_expr] to {..}
|
||||
statements: ".."
|
||||
utils.sort(\(%items as lua expr), function(\(\% as lua expr))
|
||||
compile [sort %items] to: Lua "table.sort(\(%items as lua expr));"
|
||||
compile [sort %items by %key_expr] to
|
||||
Lua ".."
|
||||
utils.sort(\(%items as lua expr), function(_)
|
||||
return \(%key_expr as lua expr);
|
||||
end)
|
||||
end);
|
||||
|
||||
immediately:
|
||||
action [%items sorted, sorted %items]:
|
||||
@ -188,13 +188,13 @@ immediately:
|
||||
|
||||
immediately:
|
||||
# Metatable stuff
|
||||
compile [set %dict's metatable to %metatable] to {..}
|
||||
statements: "setmetatable(\(%dict as lua expr), \(%metatable as lua expr));"
|
||||
compile [set %dict's metatable to %metatable] to
|
||||
Lua "setmetatable(\(%dict as lua expr), \(%metatable as lua expr));"
|
||||
|
||||
compile [new counter] to {expr:"setmetatable({}, {__index=function() return 0; end})"}
|
||||
compile [new counter] to: Lua value "setmetatable({}, {__index=function() return 0; end})"
|
||||
|
||||
compile [new default dict] to {..}
|
||||
expr: ".."
|
||||
compile [new default dict] to
|
||||
Lua value ".."
|
||||
setmetatable({}, {__index=function(self, key)
|
||||
t = {};
|
||||
self[key] = t;
|
||||
|
@ -41,14 +41,14 @@ immediately
|
||||
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}
|
||||
return:
|
||||
Lua ".."
|
||||
Lua value ".."
|
||||
(\(%condition as lua expr) and \(%when_true_expr as lua expr) or \(%when_false_expr as lua expr))
|
||||
..else:
|
||||
#.. Otherwise, need to do an anonymous inline function (yuck, too bad lua
|
||||
doesn't have a proper ternary operator!)
|
||||
To see why this is necessary consider: (random()<.5 and false or 99)
|
||||
return:
|
||||
Lua ".."
|
||||
Lua value ".."
|
||||
(function()
|
||||
if \(%condition as lua expr) then
|
||||
return \(%when_true_expr as lua expr);
|
||||
@ -87,14 +87,15 @@ immediately:
|
||||
compile [do next repeat] to: Lua "goto continue_repeat;"
|
||||
compile [stop repeating] to: Lua "goto stop_repeat;"
|
||||
compile [repeat while %condition %body] to
|
||||
%lua <-: Lua "while \(%condition as lua expr) do"
|
||||
%lua <-
|
||||
Lua ".."
|
||||
while \(%condition as lua expr) do
|
||||
\(%body as lua statements)
|
||||
if %body has subtree % where:
|
||||
(%.type = "Action") and ((%'s stub) is "do next repeat")
|
||||
..:
|
||||
%lua <-write "\n::continue_repeat::;"
|
||||
%lua <-write "\n"
|
||||
%lua <-write (%body as lua statements)
|
||||
%lua <-write "\nend --while-loop"
|
||||
to %lua write "\n::continue_repeat::;"
|
||||
to %lua write "\nend --while-loop"
|
||||
if %body has subtree % where:
|
||||
(%.type = "Action") and ((%'s stub) is "stop repeating")
|
||||
..:
|
||||
@ -110,11 +111,14 @@ immediately:
|
||||
compile [..]
|
||||
repeat %n times %body
|
||||
..to:
|
||||
%lua <-: Lua "for i=1,\(%n as lua expr) do"
|
||||
%lua <-
|
||||
Lua ".."
|
||||
for i=1,\(%n as lua expr) do
|
||||
\(%body as lua statements)
|
||||
if %body has subtree % where
|
||||
(%.type = "Action") and ((%'s stub) is "do next repeat")
|
||||
..: %lua <-write "\n::continue_repeat::;"
|
||||
%lua <-write "\n\(%body as lua statements)\nend --numeric for-loop"
|
||||
..: to %lua write "\n::continue_repeat::;"
|
||||
to %lua write "\nend --numeric for-loop"
|
||||
if %body has subtree % where:
|
||||
(%.type = "Action") and ((%'s stub) is "stop repeating")
|
||||
..:
|
||||
@ -143,20 +147,21 @@ immediately:
|
||||
assume (%var.type is "Var") or barf "Loop expected variable, not: \(%var's source code)"
|
||||
%lua <-
|
||||
Lua ".."
|
||||
for \(%var as lua expr)=\(%start as lua expr),\(%n as lua expr) do
|
||||
for \(%var as lua expr)=\(%start as lua expr),\(%stop as lua expr),\(%step as lua expr) do
|
||||
\(%body as lua statements)
|
||||
if %body has subtree % where:
|
||||
(%.type = "Action") and
|
||||
((%'s stub) is "do next %") and
|
||||
%.value.3.value is %var.value
|
||||
..: %lua <-write "\n::continue_\(%var as lua identifier)::;"
|
||||
%lua <-write "\n\(%body as lua statements)\nend --numeric for-loop"
|
||||
..: to %lua write "\n::continue_\(%var as lua identifier)::;"
|
||||
to %lua write "\nend --numeric for-loop"
|
||||
|
||||
if %body has subtree % where:
|
||||
(%.type = "Action") and:
|
||||
((%'s stub) is "stop %") and:
|
||||
%.value.2.value is %var.value
|
||||
..:
|
||||
%lua <-write ".."
|
||||
to %lua write ".."
|
||||
do -- scope for stopping for-loop
|
||||
\%lua
|
||||
::stop_\(%var as lua identifier)::;
|
||||
@ -177,13 +182,16 @@ immediately:
|
||||
compile [for %var in %iterable %body] to:
|
||||
# This uses Lua's approach of only allowing loop-scoped variables in a loop
|
||||
assume (%var.type is "Var") or barf "Loop expected variable, not: \(%var's source code)"
|
||||
%lua <-: Lua "for i,\(%var as lua identifier) in ipairs(\(%iterable as lua expr)) do"
|
||||
%lua <-
|
||||
Lua ".."
|
||||
for i,\(%var as lua identifier) in ipairs(\(%iterable as lua expr)) do
|
||||
\(%body as lua statements)
|
||||
if %body has subtree % where:
|
||||
(%.type = "Action") and
|
||||
((%'s stub) is "do next %") and
|
||||
%.value.3.value is %var.value
|
||||
..: %lua <-write (Lua "\n::continue_\(%var as lua identifier)::;")
|
||||
%lua <-write (Lua "\n\(%body as lua statements)\nend --foreach-loop")
|
||||
..: to %lua write (Lua "\n::continue_\(%var as lua identifier)::;")
|
||||
to %lua write "\nend --foreach-loop"
|
||||
if %body has subtree % where:
|
||||
(%.type = "Action") and
|
||||
((%'s stub) is "stop %") and
|
||||
@ -205,34 +213,37 @@ immediately:
|
||||
# This uses Lua's approach of only allowing loop-scoped variables in a loop
|
||||
assume (%key.type is "Var") or barf "Loop expected variable, not: \(%key's source code)"
|
||||
assume (%value.type is "Var") or barf "Loop expected variable, not: \(%value's source code)"
|
||||
%lua <- (Lua "for \(%key as lua identifier),\(%value as lua identifier) in pairs(\(%iterable as lua expr)) do")
|
||||
%lua <-
|
||||
Lua ".."
|
||||
for \(%key as lua identifier),\(%value as lua identifier) in pairs(\(%iterable as lua expr)) do
|
||||
\(%body as lua statements)
|
||||
if %body has subtree % where:
|
||||
(%.type = "Action") and
|
||||
((%'s stub) is "do next %") and
|
||||
%.value.3.value is %key.value
|
||||
..: %lua <-write (Lua "\n::continue_\(%key as lua identifier)::;")
|
||||
..: to %lua write (Lua "\n::continue_\(%key as lua identifier)::;")
|
||||
|
||||
if %body has subtree % where:
|
||||
(%.type = "Action") and
|
||||
((%'s stub) is "do next %") and
|
||||
%.value.3.value is %value.value
|
||||
..: %lua <-write (Lua "\n::continue_\(%value as lua identifier)::;")
|
||||
%lua <-write (Lua "\n\(%body as lua statements)\nend --foreach-loop")
|
||||
..: to %lua write (Lua "\n::continue_\(%value as lua identifier)::;")
|
||||
to %lua write "\nend --foreach-loop"
|
||||
|
||||
%stop_labels <- ""
|
||||
%stop_labels <- (Lua "")
|
||||
if %body has subtree % where:
|
||||
(%.type = "Action") and
|
||||
((%'s stub) is "stop %") and
|
||||
%.value.2.value is %key.value
|
||||
..: %stop_labels <-write "\n::stop_\(%key as lua identifier)::;"
|
||||
..: to %stop_labels write "\n::stop_\(%key as lua identifier)::;"
|
||||
|
||||
if %body has subtree % where:
|
||||
(%.type = "Action") and
|
||||
((%'s stub) is "stop %") and
|
||||
%.value.2.value is %value.value
|
||||
..: %stop_labels <-write "\n::stop_\(%value as lua identifier)::;"
|
||||
..: to %stop_labels write "\n::stop_\(%value as lua identifier)::;"
|
||||
|
||||
if: %stop_labels is not ""
|
||||
if: (length of %stop_labels) > 0
|
||||
%lua <-
|
||||
Lua ".."
|
||||
do -- scope for stopping for % = % loop
|
||||
@ -243,63 +254,57 @@ immediately:
|
||||
# Switch statement/multi-branch if
|
||||
immediately:
|
||||
compile [when %body] to:
|
||||
%code <- ""
|
||||
%code <- (Lua "")
|
||||
%fallthroughs <- []
|
||||
%locals <- []
|
||||
%is_first <- (yes)
|
||||
%seen_else <- (no)
|
||||
for %func_call in %body.value:
|
||||
assume (%func_call.type is "Action") or barf ".."
|
||||
Invalid format for 'when' statement. Only '*' blocks are allowed.
|
||||
%tokens <- %func_call.value
|
||||
with {..}
|
||||
%tokens: %func_call.value
|
||||
%star: %tokens.1
|
||||
%condition: %tokens.2
|
||||
%action: %tokens.3
|
||||
..:
|
||||
assume (=lua "\%star and \%star.type == 'Word' and \%star.value == '*'") or barf ".."
|
||||
assume ((%star and (%star.type is "Word")) and (%star.value is "*")) or barf ".."
|
||||
Invalid format for 'when' statement. Lines must begin with '*'
|
||||
assume %condition or barf ".."
|
||||
Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else"
|
||||
if: %action is (nil)
|
||||
lua> "table.insert(\%fallthroughs, \(%condition as lua expr));"
|
||||
do next %func_call
|
||||
%action <- (%action as lua)
|
||||
%action_statements <- (%action.statements or "\(%action.expr);")
|
||||
for %local in (%action.locals or []):
|
||||
lua> "table.insert(\%locals, \%local);"
|
||||
|
||||
if: =lua "\%condition.type == 'Word' and \%condition.value == 'else'"
|
||||
if: (%condition.type is "Word") and (%condition.value is "else")
|
||||
assume (not %is_first) or barf "'else' clause cannot be first in 'when % = ?' block"
|
||||
%code <-write ".."
|
||||
to %code write ".."
|
||||
|
||||
else
|
||||
\%action_statements
|
||||
\(%action as lua statements)
|
||||
%seen_else <- (yes)
|
||||
..else:
|
||||
assume (not %seen_else) or barf "'else' clause needs to be last in 'when' block"
|
||||
lua> "table.insert(\%fallthroughs, \(%condition as lua expr));"
|
||||
%condition_code <- (%fallthroughs joined with " or ")
|
||||
%code <-write ".."
|
||||
|
||||
\("if" if %is_first else "elseif") \%condition_code then
|
||||
\%action_statements
|
||||
to %code write "\("if" if %is_first else "\nelseif") "
|
||||
for %i=%condition in %fallthroughs:
|
||||
if (%i > 1): to %code write " or "
|
||||
to %code write %condition
|
||||
to %code write " then\n"
|
||||
to %code write (%action as lua statements)
|
||||
|
||||
%fallthroughs <- []
|
||||
%is_first <- (no)
|
||||
|
||||
assume (%fallthroughs = []) or barf "Unfinished fallthrough conditions in 'when' block"
|
||||
if: %code is not ""
|
||||
%code <-write "\nend"
|
||||
lua> "utils.deduplicate(\%locals);"
|
||||
return {statements:%code, locals:%locals}
|
||||
assume ((length of %code) > 0) or barf "Empty body for 'when' block"
|
||||
to %code write "\nend"
|
||||
return %code
|
||||
|
||||
# Switch statement
|
||||
immediately:
|
||||
compile [when %branch_value = ? %body, when %branch_value is ? %body] to:
|
||||
%code <- ""
|
||||
%code <- (Lua "")
|
||||
%fallthroughs <- []
|
||||
%locals <- []
|
||||
%is_first <- (yes)
|
||||
%seen_else <- (no)
|
||||
for %func_call in %body.value:
|
||||
@ -307,7 +312,7 @@ immediately:
|
||||
Invalid format for 'when' statement. Only '*' blocks are allowed.
|
||||
%tokens <- %func_call.value
|
||||
with {%star:%tokens.1, %condition:%tokens.2, %action:%tokens.3}:
|
||||
assume (=lua "\%star and \%star.type == 'Word' and \%star.value == '*'") or barf ".."
|
||||
assume ((%star and (%star.type is "Word")) and (%star.value is "*")) or barf ".."
|
||||
Invalid format for 'when' statement. Lines must begin with '*'
|
||||
assume %condition or barf ".."
|
||||
Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else"
|
||||
@ -315,47 +320,39 @@ immediately:
|
||||
lua> "table.insert(\%fallthroughs, \(%condition as lua expr))"
|
||||
do next %func_call
|
||||
|
||||
%action <- (%action as lua)
|
||||
%action_statements <- (%action.statements or "\(%action.expr);")
|
||||
for %local in (%action.locals or []):
|
||||
lua> "table.insert(\%locals, \%local);"
|
||||
|
||||
if: =lua "\%condition.type == 'Word' and \%condition.value == 'else'"
|
||||
if: (%condition.type is "Word") and (%condition.value is "else")
|
||||
assume (not %is_first) or barf "'else' clause cannot be first in 'when % = ?' block"
|
||||
%code <-write ".."
|
||||
to %code write ".."
|
||||
|
||||
else
|
||||
\%action_statements
|
||||
end
|
||||
%seen_else <- (yes)
|
||||
\(%action as lua statements)
|
||||
..else:
|
||||
assume (not %seen_else) or barf "'else' clause needs to be last in 'when % = ?' block"
|
||||
to %code write "\("if" if %is_first else "\nelseif") "
|
||||
lua> "table.insert(\%fallthroughs, \(%condition as lua expr));"
|
||||
for %i = % in %fallthroughs
|
||||
if: %i > 1
|
||||
to %code write " or "
|
||||
if: (%.type is "Text") or (%.type is "Number")
|
||||
(%i'th in %fallthroughs) <- "branch_value == \%"
|
||||
..else
|
||||
(%i'th in %fallthroughs) <- "utils.equivalent(branch_value, \%)"
|
||||
%clause <- (%fallthroughs joined with " or ")
|
||||
%code <-write ".."
|
||||
|
||||
\("if" if %is_first else "elseif") \%clause then
|
||||
\%action_statements
|
||||
to %code write "branch_value == \%"
|
||||
..else:
|
||||
to %code write "utils.equivalent(branch_value, \%)"
|
||||
to %code write "then\n"
|
||||
to %code write (%action as lua statements)
|
||||
|
||||
%fallthroughs <- []
|
||||
%is_first <- (no)
|
||||
|
||||
assume (%fallthroughs = []) or barf "Unfinished fallthrough conditions in 'when' block"
|
||||
assume (%code is not "") or barf "No body for 'when % = ?' block!"
|
||||
unless %seen_else
|
||||
%code <-write "\nend"
|
||||
%code <- ".."
|
||||
do --when % = ?
|
||||
local branch_value = \(%branch_value as lua expr);\
|
||||
..\%code
|
||||
end --when % = ?
|
||||
lua> "utils.deduplicate(\%locals);"
|
||||
return {statements:%code, locals:%locals}
|
||||
assume ((length of %code) > 0) or barf "No body for 'when % = ?' block!"
|
||||
to %code write "\nend"
|
||||
%code <-
|
||||
Lua ".."
|
||||
do --when % = ?
|
||||
local branch_value = \(%branch_value as lua expr);
|
||||
\%code
|
||||
end --when % = ?
|
||||
return %code
|
||||
|
||||
# Try/except
|
||||
immediately:
|
||||
@ -363,33 +360,22 @@ immediately:
|
||||
try %action and if it succeeds %success or if it barfs %fallback
|
||||
try %action and if it barfs %fallback or if it succeeds %success
|
||||
..to:
|
||||
%locals <- []
|
||||
%action_lua <- (%action as lua)
|
||||
%success_lua <- (%success as lua)
|
||||
%fallback_lua <- (%fallback as lua)
|
||||
%fallback <- (%fallback as lua)
|
||||
for %block in [%action_lua, %success_lua, %fallback_lua]:
|
||||
for %local in (%block.locals or []):
|
||||
lua> "table.insert(\%locals, \%local);"
|
||||
lua> "utils.deduplicate(\%locals);"
|
||||
return {..}
|
||||
locals: %locals
|
||||
statements: ".."
|
||||
do
|
||||
local fell_through = false;
|
||||
local ok, ret = pcall(function()
|
||||
\(%action_lua.statements or "\(%action_lua.expr);")
|
||||
fell_through = true;
|
||||
end);
|
||||
if ok then
|
||||
\(%success_lua.statements or "\(%success_lua.expr);")
|
||||
end
|
||||
if not ok then
|
||||
\(%fallback_lua.statements or "\(%fallback_lua.expr);")
|
||||
elseif not fell_through then
|
||||
return ret;
|
||||
end
|
||||
Lua ".."
|
||||
do
|
||||
local fell_through = false;
|
||||
local ok, ret = pcall(function()
|
||||
\(%action as lua statements)
|
||||
fell_through = true;
|
||||
end);
|
||||
if ok then
|
||||
\(%success as lua statements)
|
||||
end
|
||||
if not ok then
|
||||
\(%fallback as lua statements)
|
||||
elseif not fell_through then
|
||||
return ret;
|
||||
end
|
||||
end
|
||||
parse [try %action] as:
|
||||
try %action and if it succeeds: do nothing
|
||||
..or if it barfs: do nothing
|
||||
@ -402,38 +388,26 @@ immediately:
|
||||
# Do/finally:
|
||||
immediately:
|
||||
compile [do %action] to:
|
||||
%action <- (%action as lua)
|
||||
return {..}
|
||||
locals: %action.locals
|
||||
statements: ".."
|
||||
do
|
||||
\(%action.statements or "\(%action.expr);")
|
||||
end
|
||||
Lua ".."
|
||||
do
|
||||
\(%action as lua statements)
|
||||
end
|
||||
|
||||
compile [do %action then always %final_action] to:
|
||||
%action <- (%action as lua)
|
||||
%final_action <- (%final_action as lua)
|
||||
%locals <- []
|
||||
for %sub_locals in [%action.locals, %final_action.locals]:
|
||||
for %local in %sub_locals:
|
||||
lua> "table.insert(\%locals, \%local);"
|
||||
lua> "utils.deduplicate(\%locals);"
|
||||
return {..}
|
||||
locals: %locals
|
||||
statements: ".."
|
||||
do
|
||||
local fell_through = false;
|
||||
local ok, ret1 = pcall(function()
|
||||
\(%action.statements or "\(%action.expr);")
|
||||
fell_through = true;
|
||||
end);
|
||||
local ok2, ret2 = pcall(function()
|
||||
\(%final_action.statements or "\(%final_action.expr);")
|
||||
end);
|
||||
if not ok then error(ret1); end
|
||||
if not ok2 then error(ret2); end
|
||||
if not fell_through then
|
||||
return ret1;
|
||||
end
|
||||
Lua ".."
|
||||
do
|
||||
local fell_through = false;
|
||||
local ok, ret1 = pcall(function()
|
||||
\(%action as lua statements)
|
||||
fell_through = true;
|
||||
end);
|
||||
local ok2, ret2 = pcall(function()
|
||||
\(%final_action as lua statements)
|
||||
end);
|
||||
if not ok then error(ret1); end
|
||||
if not ok2 then error(ret2); end
|
||||
if not fell_through then
|
||||
return ret1;
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -7,77 +7,77 @@ use "core/operators.nom"
|
||||
use "core/control_flow.nom"
|
||||
|
||||
# Literals:
|
||||
compile [infinity, inf] to {expr:"math.huge"}
|
||||
compile [not a number, NaN, nan] to {expr:"(0/0)"}
|
||||
compile [pi, Pi, PI] to {expr:"math.pi"}
|
||||
compile [tau, Tau, TAU] to {expr:"(2*math.pi)"}
|
||||
compile [golden ratio] to {expr:"((1+math.sqrt(5))/2)"}
|
||||
compile [e] to {expr:"math.exp(1)"}
|
||||
compile [infinity, inf] to: Lua value "math.huge"
|
||||
compile [not a number, NaN, nan] to: Lua value "(0/0)"
|
||||
compile [pi, Pi, PI] to: Lua value "math.pi"
|
||||
compile [tau, Tau, TAU] to: Lua value "(2*math.pi)"
|
||||
compile [golden ratio] to: Lua value "((1+math.sqrt(5))/2)"
|
||||
compile [e] to: Lua value "math.exp(1)"
|
||||
|
||||
# Functions:
|
||||
compile [% as a number] to {expr:"tonumber(\(% as lua expr))"}
|
||||
compile [absolute value %, | % |, abs %] to {expr:"math.abs(\(% as lua expr))"}
|
||||
compile [square root %, square root of %, √%, sqrt %] to {expr:"math.sqrt(\(% as lua expr))"}
|
||||
compile [sine %, sin %] to {expr:"math.sin(\(% as lua expr))"}
|
||||
compile [cosine %, cos %] to {expr:"math.cos(\(% as lua expr))"}
|
||||
compile [tangent %, tan %] to {expr:"math.tan(\(% as lua expr))"}
|
||||
compile [arc sine %, asin %] to {expr:"math.asin(\(% as lua expr))"}
|
||||
compile [arc cosine %, acos %] to {expr:"math.acos(\(% as lua expr))"}
|
||||
compile [arc tangent %, atan %] to {expr:"math.atan(\(% as lua expr))"}
|
||||
compile [arc tangent %y/%x, atan2 %y %x] to {expr:"math.atan2(\(%y as lua expr), \(%x as lua expr))"}
|
||||
compile [hyperbolic sine %, sinh %] to {expr:"math.sinh(\(% as lua expr))"}
|
||||
compile [hyperbolic cosine %, cosh %] to {expr:"math.cosh(\(% as lua expr))"}
|
||||
compile [hyperbolic tangent %, tanh %] to {expr:"math.tanh(\(% as lua expr))"}
|
||||
compile [e^%, exp %] to {expr:"math.exp(\(% as lua expr))"}
|
||||
compile [natural log %, ln %, log %] to {expr:"math.log(\(% as lua expr))"}
|
||||
compile [log % base %base, log_%base %, log base %base %] to {expr:"math.log(\(% as lua expr), \(%base as lua expr))"}
|
||||
compile [floor %] to {expr:"math.floor(\(% as lua expr))"}
|
||||
compile [ceiling %, ceil %] to {expr:"math.ceil(\(% as lua expr))"}
|
||||
compile [round %, % rounded] to {expr:"math.floor(\(% as lua expr) + .5)"}
|
||||
compile [% as a number] to: Lua value "tonumber(\(% as lua expr))"
|
||||
compile [absolute value %, | % |, abs %] to: Lua value "math.abs(\(% as lua expr))"
|
||||
compile [square root %, square root of %, √%, sqrt %] to: Lua value "math.sqrt(\(% as lua expr))"
|
||||
compile [sine %, sin %] to: Lua value "math.sin(\(% as lua expr))"
|
||||
compile [cosine %, cos %] to: Lua value "math.cos(\(% as lua expr))"
|
||||
compile [tangent %, tan %] to: Lua value "math.tan(\(% as lua expr))"
|
||||
compile [arc sine %, asin %] to: Lua value "math.asin(\(% as lua expr))"
|
||||
compile [arc cosine %, acos %] to: Lua value "math.acos(\(% as lua expr))"
|
||||
compile [arc tangent %, atan %] to: Lua value "math.atan(\(% as lua expr))"
|
||||
compile [arc tangent %y/%x, atan2 %y %x] to: Lua value "math.atan2(\(%y as lua expr), \(%x as lua expr))"
|
||||
compile [hyperbolic sine %, sinh %] to: Lua value "math.sinh(\(% as lua expr))"
|
||||
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 [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)"
|
||||
action [%n to the nearest %rounder]:
|
||||
=lua "(\%rounder)*math.floor((\%n / \%rounder) + .5)"
|
||||
|
||||
# Any/all/none
|
||||
compile [all of %items, all %items] to:
|
||||
unless: (%items' "type") is "List"
|
||||
return {expr:"utils.all(\(%items as lua expr))"}
|
||||
return: Lua value "utils.all(\(%items as lua expr))"
|
||||
%clauses <- []
|
||||
for all (%items' "value"): lua> "table.insert(\%clauses, \(% as lua expr));"
|
||||
return {expr:"(\(%clauses joined with " and "))"}
|
||||
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"
|
||||
return {expr:"utils.any(\(%items as lua expr))"}
|
||||
return: Lua value "utils.any(\(%items as lua expr))"
|
||||
%clauses <- []
|
||||
for all (%items' "value"): lua> "table.insert(\%clauses, \(% as lua expr));"
|
||||
return {expr:"(\(%clauses joined with " or "))"}
|
||||
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"
|
||||
return {expr:"utils.sum(\(%items as lua expr))"}
|
||||
return: Lua value "utils.sum(\(%items as lua expr))"
|
||||
%clauses <- []
|
||||
for all (%items' "value"): lua> "table.insert(\%clauses, \(% as lua expr));"
|
||||
return {expr:"(\(%clauses joined with " + "))"}
|
||||
return: Lua value "(\(%clauses joined with " + "))"
|
||||
compile [product of %items, product %items] to:
|
||||
unless: (%items' "type") is "List"
|
||||
return {expr:"utils.product(\(%items as lua expr))"}
|
||||
return: Lua value "utils.product(\(%items as lua expr))"
|
||||
%clauses <- []
|
||||
for all (%items' "value"): lua> "table.insert(\%clauses, \(% as lua expr));"
|
||||
return {expr:"(\(%clauses joined with " * "))"}
|
||||
return: Lua value "(\(%clauses joined with " * "))"
|
||||
action [avg of %items, average of %items]:
|
||||
=lua "(utils.sum(\%items)/#\%items)"
|
||||
compile [min of %items, smallest of %items, lowest of %items] to {..}
|
||||
expr:"utils.min(\(%items as lua expr))"
|
||||
compile [max of %items, biggest of %items, largest of %items, highest of %items] to {..}
|
||||
expr:"utils.max(\(%items as lua expr))"
|
||||
compile [min of %items by %value_expr] to {..}
|
||||
expr: ".."
|
||||
utils.min(\(%items as lua expr), function(\(\% as lua expr))
|
||||
compile [min of %items, smallest of %items, lowest of %items] to
|
||||
Lua value "utils.min(\(%items as lua expr))"
|
||||
compile [max of %items, biggest of %items, largest of %items, highest of %items] to
|
||||
Lua value "utils.max(\(%items as lua expr))"
|
||||
compile [min of %items by %value_expr] to
|
||||
Lua value ".."
|
||||
utils.min(\(%items as lua expr), function(_)
|
||||
return \(%value_expr as lua expr)
|
||||
end)
|
||||
compile [max of %items by %value_expr] to {..}
|
||||
expr: ".."
|
||||
utils.max(\(%items as lua expr), function(\(\% as lua expr))
|
||||
compile [max of %items by %value_expr] to
|
||||
Lua value ".."
|
||||
utils.max(\(%items as lua expr), function(_)
|
||||
return \(%value_expr as lua expr)
|
||||
end)
|
||||
|
||||
@ -87,8 +87,8 @@ action [seed random with %]:
|
||||
math.randomseed(\%);
|
||||
for i=1,20 do math.random(); end
|
||||
parse [seed random] as: seed random with (=lua "os.time()")
|
||||
compile [random number, random, rand] to {expr:"math.random()"}
|
||||
compile [random int %n, random integer %n, randint %n] to {expr:"math.random(\(%n as lua expr))"}
|
||||
compile [random number, random, rand] to: Lua value "math.random()"
|
||||
compile [random int %n, random integer %n, randint %n] to: Lua value "math.random(\(%n as lua expr))"
|
||||
compile [random from %low to %high, random number from %low to %high, rand %low %high] to
|
||||
"math.random(\(%low as lua expr), \(%high as lua expr))"
|
||||
action [random choice from %elements, random choice %elements, random %elements]:
|
||||
|
@ -25,7 +25,8 @@ immediately:
|
||||
end
|
||||
local body_lua = \%lua:as_lua(nomsu);
|
||||
body_lua:convert_to_statements("return ");
|
||||
body_lua:declare_locals(args);
|
||||
body_lua:remove_free_vars(args);
|
||||
body_lua:declare_locals();
|
||||
lua:append(")\\n ", body_lua, "\\nend);");
|
||||
return lua;
|
||||
end);
|
||||
@ -50,7 +51,8 @@ immediately:
|
||||
end
|
||||
local body_lua = \%body:as_lua(nomsu);
|
||||
body_lua:convert_to_statements("return ");
|
||||
body_lua:declare_locals(args);
|
||||
body_lua:remove_free_vars(args);
|
||||
body_lua:declare_locals();
|
||||
lua:append(")\\n ", body_lua, "\\nend);")
|
||||
return lua;
|
||||
|
||||
@ -72,14 +74,7 @@ immediately:
|
||||
lua:append(", ");
|
||||
lua:append(arg);
|
||||
end
|
||||
local template;
|
||||
if \%longhand.type == "Block" then
|
||||
local lines = {};
|
||||
for i, line in ipairs(\%longhand.value) do lines[i] = tostring(line.source:get_text()); end
|
||||
template = repr(table.concat(lines, "\\n"));
|
||||
else
|
||||
template = repr(tostring(\%longhand.source:get_text()));
|
||||
end
|
||||
local template = repr(tostring(\%longhand:as_nomsu()));
|
||||
local replacements = {};
|
||||
for i, a in ipairs(args) do replacements[i] = a.."="..a; end
|
||||
replacements = "{"..table.concat(replacements, ", ").."}";
|
||||
@ -117,22 +112,34 @@ immediately:
|
||||
lua> ".."
|
||||
local lua = \%tree:as_lua(nomsu);
|
||||
lua:convert_to_statements();
|
||||
--lua:declare_locals();
|
||||
return lua;
|
||||
|
||||
compile [declare locals in %tree] to
|
||||
Lua "\(%tree as lua expr):declare_locals();"
|
||||
|
||||
compile [declare locals %locals in %tree] to
|
||||
Lua "\(%tree as lua expr):declare_locals(\(%locals as lua expr));"
|
||||
|
||||
compile [remove free vars %vars from %tree] to:
|
||||
Lua "\(%tree as lua expr):remove_free_vars(unpack(\(%vars as lua expr)));"
|
||||
|
||||
action [%tree as value]:
|
||||
=lua "nomsu:tree_to_value(\%tree)"
|
||||
|
||||
|
||||
action [%tree's stub]:
|
||||
=lua "nomsu:tree_to_stub(\%tree)"
|
||||
|
||||
immediately:
|
||||
parse [%var <-write %code] as: lua> "\%var:append(\%code);"
|
||||
parse [to %var write %code] as: lua> "\%var:append(\%code);"
|
||||
|
||||
immediately:
|
||||
compile [%tree's source code, %tree' source code] to: Lua value "\(%tree as lua expr).source:get_text()"
|
||||
action [%tree's source code, %tree' source code]:
|
||||
=lua "\%tree.source:get_text()"
|
||||
|
||||
compile [repr %obj] to: Lua value "repr(\(%obj as lua expr))"
|
||||
compile [%obj as text] to: Lua value "tostring(\(%obj as lua expr))"
|
||||
compile [type of %obj] to: Lua value "type(\(%obj as lua expr))"
|
||||
|
||||
immediately:
|
||||
@ -190,10 +197,10 @@ immediately:
|
||||
|
||||
# Error functions
|
||||
immediately:
|
||||
compile [barf] to: Lua value "error(nil, 0);"
|
||||
compile [barf %msg] to: Lua value "error(\(%msg as lua expr), 0);"
|
||||
compile [barf] to: Lua "error(nil, 0);"
|
||||
compile [barf %msg] to: Lua "error(\(%msg as lua expr), 0);"
|
||||
compile [assume %condition] to:
|
||||
lua> "local \%assumption = 'Assumption failed: '..\%condition.source:get_text();"
|
||||
lua> "local \%assumption = 'Assumption failed: '..tostring(\%condition.source:get_text());"
|
||||
return:
|
||||
Lua ".."
|
||||
if not \(%condition as lua expr) then
|
||||
|
@ -54,7 +54,6 @@ immediately:
|
||||
lua> ".."
|
||||
local lua = Lua(tree.source, \%var_lua, ' = ', \%value_lua, ';');
|
||||
if \%var.type == 'Var' then
|
||||
print("Added var from assignment: "..tostring(\%var:as_lua(nomsu)));
|
||||
lua:add_free_vars(\%var);
|
||||
end
|
||||
return lua;
|
||||
@ -93,15 +92,43 @@ immediately:
|
||||
return: Lua "\(%var_lua) = \(%value_lua);"
|
||||
|
||||
compile [exporting %exported %body] to:
|
||||
%body_lua <- (%body as lua)
|
||||
lua> "\%body_lua:declare_locals(\%exported);"
|
||||
%body_lua <- (%body as lua statements)
|
||||
lua> "\%body_lua:remove_free_vars(unpack(\(%exported.value)));"
|
||||
return %body_lua
|
||||
|
||||
parse [with %assignments %body] as:
|
||||
# TODO: clean up and handle: with {%x:1}: %y <- 2
|
||||
lua> "do"
|
||||
<- %assignments
|
||||
lua> "end"
|
||||
compile [with %assignments %body] to:
|
||||
%lua <- (%body as lua statements)
|
||||
lua> ".."
|
||||
local lhs, rhs = Lua(tree.source), Lua(\%assignments.source);
|
||||
local vars = {};
|
||||
for i, item in ipairs(\%assignments.value) do
|
||||
local target, value = item.key, item.value;
|
||||
if not target.type == "Var" then
|
||||
error("Invalid target for 'with' assignment: "..tostring(target.source:get_text()));
|
||||
end
|
||||
local target_lua = nomsu:tree_to_lua(target);
|
||||
local value_lua = nomsu:tree_to_lua(value);
|
||||
if not value_lua.is_value then
|
||||
error("Invalid value for assignment: "..tostring(value.source:get_text()));
|
||||
end
|
||||
if target.type == "Var" then
|
||||
lhs:add_free_vars(target);
|
||||
end
|
||||
if i > 1 then
|
||||
lhs:append(", ");
|
||||
rhs:append(", ");
|
||||
end
|
||||
lhs:append(target_lua);
|
||||
rhs:append(value_lua);
|
||||
vars[i] = tostring(target_lua);
|
||||
end
|
||||
\%lua:remove_free_vars(vars);
|
||||
\%lua:prepend("local ", lhs, " = ", rhs, ";\\n");
|
||||
return
|
||||
Lua ".."
|
||||
do
|
||||
\%lua
|
||||
end -- 'with' block
|
||||
|
||||
immediately:
|
||||
# Math Operators
|
||||
@ -141,6 +168,7 @@ immediately:
|
||||
# Unary operators
|
||||
compile [- %] to: Lua value "(- \(% as lua expr))"
|
||||
compile [not %] to: Lua value "(not \(% as lua expr))"
|
||||
compile [length of %list] to: Lua value "(#\(%list as lua expr))"
|
||||
|
||||
# Update operators
|
||||
immediately:
|
||||
|
@ -12,16 +12,16 @@ action [%texts joined with %glue]:
|
||||
return table.concat(text_bits, \%glue)
|
||||
parse [joined %texts, %texts joined] as: %texts joined with ""
|
||||
|
||||
compile [capitalized %text, %text capitalized] to {..}
|
||||
expr:"((\(%text as lua expr)):gsub('%l', string.upper, 1))"
|
||||
compile [capitalized %text, %text capitalized] to
|
||||
Lua value "((\(%text as lua expr)):gsub('%l', string.upper, 1))"
|
||||
|
||||
compile [%text with %sub instead of %patt, %text s/%patt/%sub] to {..}
|
||||
expr:"((\(%text as lua expr)):gsub(\(%patt as lua expr), \(%sub as lua expr)))"
|
||||
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)))"
|
||||
|
||||
# TODO: figure out whether indent/dedent should affect first line
|
||||
compile [indented %text, %text indented] to {expr:"((\%text):gsub('\\n','\\n'..(' ')))"}
|
||||
compile [dedented %obj, %obj dedented] to {expr:"nomsu:dedent(\(%obj as lua expr))"}
|
||||
compile [%text indented %n times] to {expr:"((\%text):gsub('\\n','\\n'..(' '):rep(\%n)))"}
|
||||
compile [indented %text, %text indented] to: Lua value "((\%text):gsub('\\n','\\n'..(' ')))"
|
||||
compile [dedented %obj, %obj dedented] to: Lua value "nomsu:dedent(\(%obj as lua expr))"
|
||||
compile [%text indented %n times] to: Lua value "((\%text):gsub('\\n','\\n'..(' '):rep(\%n)))"
|
||||
|
||||
# Text literals
|
||||
lua> ".."
|
||||
@ -32,7 +32,7 @@ lua> ".."
|
||||
};
|
||||
for name, e in pairs(escapes) do
|
||||
local lua = "'"..e.."'";
|
||||
nomsu:define_compile_action(name, \(!! code location !!), function() return {expr=lua}; end);
|
||||
nomsu:define_compile_action(name, \(!! code location !!), 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",
|
||||
@ -47,9 +47,9 @@ lua> ".."
|
||||
for name, c in pairs(colors) do
|
||||
local color = "'"..c.."'";
|
||||
local reset = "'"..colors["reset color"].."'";
|
||||
nomsu:define_compile_action(name, \(!! code location !!), function() return {expr=color}; end);
|
||||
nomsu:define_compile_action(name, \(!! code location !!), function(tree) return Lua.Value(tree.source, color); end);
|
||||
nomsu:define_compile_action(name.." %", \(!! code location !!), function(\%)
|
||||
return {expr=color..".."..nomsu:tree_to_lua(\%).expr..".."..reset};
|
||||
return Lua.Value(tree.source, color, "..", nomsu:tree_to_lua(\%), "..", reset);
|
||||
end);
|
||||
end
|
||||
end
|
||||
|
@ -1,6 +1,6 @@
|
||||
use "core"
|
||||
|
||||
compile [@] to {expr:"self"}
|
||||
compile [@] to: Lua value "self"
|
||||
|
||||
compile [@%var] to:
|
||||
lua> ".."
|
||||
@ -8,11 +8,11 @@ compile [@%var] to:
|
||||
local key_attr = (key_lua:match("'([a-zA-Z][a-zA-Z0-9]*)'")
|
||||
or key_lua:match('"([a-zA-Z][a-zA-Z0-9]*)"'));
|
||||
if key_attr then
|
||||
return {expr="self."..key_attr};
|
||||
return Lua.value(tree.source, "self."..key_attr);
|
||||
elseif key_lua:sub(1,1) == "[" then
|
||||
key_lua = " "..key_lua.." ";
|
||||
key_lua = " "..key_lua;
|
||||
end
|
||||
return {expr="self["..key_lua.."]"};
|
||||
return Lua.Value(tree.source, "self["..key_lua.."]");
|
||||
|
||||
compile [@%var <- %val] to:
|
||||
lua> ".."
|
||||
@ -21,16 +21,17 @@ compile [@%var <- %val] to:
|
||||
local key_attr = (key_lua:match("'([a-zA-Z][a-zA-Z0-9]*)'")
|
||||
or key_lua:match('"([a-zA-Z][a-zA-Z0-9]*)"'));
|
||||
if key_attr then
|
||||
return {statements="self."..key_attr.." = "..val_lua..";"};
|
||||
return Lua(tree.source, "self.", key_attr, " = ", val_lua, ";");
|
||||
elseif key_lua:sub(1,1) == "[" then
|
||||
key_lua = " "..key_lua.." ";
|
||||
end
|
||||
return {statements="self["..key_lua.."] = "..val_lua..";"};
|
||||
return Lua(tree.source, "self[", key_lua, "] = ", val_lua, ";");
|
||||
|
||||
compile [as %instance %body] to:
|
||||
%body_lua <- (%body as lua)
|
||||
return {..}
|
||||
statements: ".."
|
||||
lua> "\%body_lua:convert_to_statements();"
|
||||
return
|
||||
Lua ".."
|
||||
do
|
||||
local self = \(%instance as lua expr);
|
||||
local global_actions = ACTIONS;
|
||||
@ -39,9 +40,8 @@ compile [as %instance %body] to:
|
||||
if method then return (function(...) return method(self, ...); end); end
|
||||
return global_actions[key];
|
||||
end});
|
||||
\((%body_lua's "statements") or "\(%body_lua's "expr");")
|
||||
\%body_lua
|
||||
end
|
||||
locals: %body_lua's "locals"
|
||||
|
||||
compile [define object %classname %class_body] to:
|
||||
%class_identifier <- (=lua "nomsu:var_to_lua_identifier(\(%classname as value)):sub(2,-1)")
|
||||
@ -56,7 +56,7 @@ compile [define object %classname %class_body] to:
|
||||
if: ((%line's "type") is "FunctionCall") and ((%line's stub) is "slots %")
|
||||
%slot_index_clauses <- []
|
||||
%slot_newindex_clauses <- []
|
||||
%slots <- ("value" in (2nd in (%line's "value")))
|
||||
%slots <- %line.value.2.value
|
||||
for %slot_index = %slot_var in %slots:
|
||||
to %slot_index_clauses add ".."
|
||||
if key == \(repr (%slot_var's "value")) or key == \(repr (%slot_var as lua expr)) then
|
||||
@ -78,10 +78,10 @@ compile [define object %classname %class_body] to:
|
||||
error("Attempt to store data in "..repr(key)..", which is not a valid slot on "..tostring(self.class));
|
||||
end
|
||||
do next %line
|
||||
assume (((%line's "type") is "FunctionCall") and ((%line's stub) is "action % %"))
|
||||
assume ((%line.type is "FunctionCall") and ((%line's stub) is "action % %"))
|
||||
..or barf "Only action definitions are supported inside 'define object % %', not \(%line's "src")"
|
||||
%actions <- (2nd in (%line's "value"))
|
||||
%body <- (3rd in (%line's "value"))
|
||||
%actions <- %line.value.2
|
||||
%body <- %line.value.3
|
||||
lua> ".."
|
||||
local stubs = {};
|
||||
for i, action in ipairs(\%actions.value) do
|
||||
@ -94,23 +94,14 @@ compile [define object %classname %class_body] to:
|
||||
local arg_set = {};
|
||||
for i, arg in ipairs(args) do arg_set[arg] = true; end
|
||||
local body_lua = nomsu:tree_to_lua(\%body);
|
||||
local body_code = body_lua.statements or ("return "..body_lua.expr..";");
|
||||
local undeclared_locals = {};
|
||||
for i, body_local in ipairs(body_lua.locals or {}) do
|
||||
if not arg_set[body_local] then
|
||||
table.insert(undeclared_locals, body_local);
|
||||
end
|
||||
end
|
||||
if #undeclared_locals > 0 then
|
||||
body_code = "local "..table.concat(undeclared_locals, ", ")..";\\n"..body_code;
|
||||
end
|
||||
body_lua:convert_to_statements();
|
||||
body_lua:declare_locals();
|
||||
local lua_fn_args = table.concat({"self", unpack(args)}, ", ");
|
||||
local def_tree = nomsu.compilestack[#nomsu.compilestack];
|
||||
local code_location = ("%s:%s,%s"):format(def_tree.filename, def_tree.start, def_tree.stop);
|
||||
|
||||
local compiled_args = {};
|
||||
for i, arg in ipairs(args) do
|
||||
compiled_args[i] = "nomsu:tree_to_lua("..arg..").expr";
|
||||
compiled_args[i] = "nomsu:tree_to_lua("..arg..")";
|
||||
end
|
||||
compiled_args = table.concat(compiled_args, "..', '..");
|
||||
table.insert(\%methods, ([==[
|
||||
@ -119,10 +110,10 @@ compile [define object %classname %class_body] to:
|
||||
end
|
||||
]==]):format(
|
||||
\%class_identifier, repr(stubs[1]), lua_fn_args,
|
||||
body_code));
|
||||
body_lua));
|
||||
|
||||
return {..}
|
||||
statements:".."
|
||||
return
|
||||
Lua ".."
|
||||
do -- \%class_identifier
|
||||
-- Create the class object:
|
||||
local \%class_identifier = setmetatable({
|
||||
|
112
lua_obj.lua
112
lua_obj.lua
@ -49,19 +49,13 @@ Source = immutable({
|
||||
return Source(self.filename, self.start + offset, self.stop)
|
||||
end,
|
||||
sub = function(self, start, stop)
|
||||
start = start or 1
|
||||
assert(start > 0 and (stop == nil or stop > 0), "Negative subscripts not supported")
|
||||
if not self.stop then
|
||||
assert(not stop, "cannot subscript non-range with range")
|
||||
assert(start > 0, "cannot subscript non-range with negative index")
|
||||
return Source(self.filename, self.start + (start or 0))
|
||||
return Source(self.filename, self.start + start - 1)
|
||||
else
|
||||
start = start or 1
|
||||
if start < 0 then
|
||||
start = self.stop + start + 1
|
||||
end
|
||||
stop = stop or -1
|
||||
if stop < 0 then
|
||||
stop = self.stop + stop + 1
|
||||
end
|
||||
stop = stop or self.stop
|
||||
return Source(self.filename, self.start + start - 1, self.start + stop - 1)
|
||||
end
|
||||
end,
|
||||
@ -126,7 +120,7 @@ do
|
||||
sub = function(self, start, stop)
|
||||
local str = tostring(self):sub(start, stop)
|
||||
local cls = self.__class
|
||||
return cls(self.source:sub(start - self.source.start + 1, stop - self.source.start + 1), str)
|
||||
return cls(self.source:sub(start, stop), str)
|
||||
end,
|
||||
append = function(self, ...)
|
||||
local n = select("#", ...)
|
||||
@ -206,6 +200,34 @@ do
|
||||
end
|
||||
end
|
||||
end,
|
||||
remove_free_vars = function(self, ...)
|
||||
local removals = { }
|
||||
for i = 1, select("#", ...) do
|
||||
local var = select(i, ...)
|
||||
if type(var) == 'userdata' and var.type == "Var" then
|
||||
var = tostring(var:as_lua())
|
||||
elseif type(var) ~= 'string' then
|
||||
var = tostring(var)
|
||||
end
|
||||
removals[var] = true
|
||||
end
|
||||
local remove_from
|
||||
remove_from = function(self)
|
||||
for i = #self.free_vars, 1, -1 do
|
||||
if removals[self.free_vars[i]] then
|
||||
remove(self.free_vars, i)
|
||||
end
|
||||
end
|
||||
local _list_0 = self.bits
|
||||
for _index_0 = 1, #_list_0 do
|
||||
local b = _list_0[_index_0]
|
||||
if type(b) ~= 'string' then
|
||||
remove_from(b)
|
||||
end
|
||||
end
|
||||
end
|
||||
return remove_from(self)
|
||||
end,
|
||||
convert_to_statements = function(self, prefix, suffix)
|
||||
if prefix == nil then
|
||||
prefix = ""
|
||||
@ -223,57 +245,37 @@ do
|
||||
return self:append(suffix)
|
||||
end
|
||||
end,
|
||||
declare_locals = function(self, skip)
|
||||
if skip == nil then
|
||||
skip = { }
|
||||
declare_locals = function(self, to_declare)
|
||||
if to_declare == nil then
|
||||
to_declare = nil
|
||||
end
|
||||
if next(skip) == 1 then
|
||||
do
|
||||
local _tbl_0 = { }
|
||||
for _index_0 = 1, #skip do
|
||||
local s = skip[_index_0]
|
||||
local _key_0, _val_0 = {
|
||||
[s] = true
|
||||
}
|
||||
_tbl_0[_key_0] = _val_0
|
||||
if to_declare == nil then
|
||||
local seen
|
||||
to_declare, seen = { }, { }
|
||||
local gather_from
|
||||
gather_from = function(self)
|
||||
local _list_0 = self.free_vars
|
||||
for _index_0 = 1, #_list_0 do
|
||||
local var = _list_0[_index_0]
|
||||
if not (seen[var]) then
|
||||
seen[var] = true
|
||||
to_declare[#to_declare + 1] = var
|
||||
end
|
||||
end
|
||||
skip = _tbl_0
|
||||
end
|
||||
end
|
||||
local to_declare = { }
|
||||
local walk
|
||||
walk = function(self)
|
||||
local _list_0 = self.free_vars
|
||||
for _index_0 = 1, #_list_0 do
|
||||
local var = _list_0[_index_0]
|
||||
if not (skip[var]) then
|
||||
skip[var] = true
|
||||
to_declare[#to_declare + 1] = var
|
||||
local _list_1 = self.bits
|
||||
for _index_0 = 1, #_list_1 do
|
||||
local bit = _list_1[_index_0]
|
||||
if bit.__class == Lua then
|
||||
gather_from(bit)
|
||||
end
|
||||
end
|
||||
end
|
||||
local _list_1 = self.bits
|
||||
for _index_0 = 1, #_list_1 do
|
||||
local bit = _list_1[_index_0]
|
||||
if bit.__class == Lua then
|
||||
walk(bit)
|
||||
end
|
||||
end
|
||||
if #self.free_vars > 0 then
|
||||
self.free_vars = { }
|
||||
end
|
||||
gather_from(self)
|
||||
end
|
||||
walk(self)
|
||||
self:remove_free_vars(to_declare)
|
||||
if #to_declare > 0 then
|
||||
self:prepend("local " .. tostring(concat(to_declare, ", ")) .. ";\n")
|
||||
return self:prepend("local " .. tostring(concat(to_declare, ", ")) .. ";\n")
|
||||
end
|
||||
return [[ if #@free_vars > 0
|
||||
@prepend "local #{concat @free_vars, ", "};\n"
|
||||
for var in *@free_vars do skip[var] = true
|
||||
@free_vars = {}
|
||||
for bit in *@bits
|
||||
if bit.__class == Lua
|
||||
bit\declare_locals(skip)
|
||||
]]
|
||||
end,
|
||||
__tostring = function(self)
|
||||
local buff = { }
|
||||
|
67
lua_obj.moon
67
lua_obj.moon
@ -29,15 +29,13 @@ Source = immutable {"filename","start","stop"}, {
|
||||
else assert(type(offset) == 'number', "Cannot add Source and #{type(offset)}")
|
||||
return Source(@filename, @start+offset, @stop)
|
||||
sub: (start, stop)=>
|
||||
start or= 1
|
||||
assert(start > 0 and (stop == nil or stop > 0), "Negative subscripts not supported")
|
||||
if not @stop
|
||||
assert(not stop, "cannot subscript non-range with range")
|
||||
assert(start > 0, "cannot subscript non-range with negative index")
|
||||
return Source(@filename, @start + (start or 0))
|
||||
return Source(@filename, @start + start - 1)
|
||||
else
|
||||
start or= 1
|
||||
if start < 0 then start = @stop + start + 1
|
||||
stop or= -1
|
||||
if stop < 0 then stop = @stop + stop + 1
|
||||
stop or= @stop
|
||||
return Source(@filename, @start + start - 1, @start + stop - 1)
|
||||
get_text: =>
|
||||
FILE_CACHE[@filename]\sub(@start,@stop)
|
||||
@ -94,7 +92,7 @@ class Code
|
||||
sub: (start,stop)=>
|
||||
str = tostring(self)\sub(start,stop)
|
||||
cls = @__class
|
||||
return cls(@source\sub(start-@source.start+1,stop-@source.start+1), str)
|
||||
return cls(@source\sub(start,stop), str)
|
||||
|
||||
append: (...)=>
|
||||
n = select("#",...)
|
||||
@ -133,6 +131,24 @@ class Lua extends Code
|
||||
@free_vars[#@free_vars+1] = var
|
||||
seen[var] = true
|
||||
|
||||
remove_free_vars: (...)=>
|
||||
removals = {}
|
||||
for i=1,select("#",...)
|
||||
var = select(i, ...)
|
||||
if type(var) == 'userdata' and var.type == "Var"
|
||||
var = tostring(var\as_lua!)
|
||||
elseif type(var) != 'string'
|
||||
var = tostring(var)
|
||||
removals[var] = true
|
||||
remove_from = =>
|
||||
for i=#@free_vars,1,-1
|
||||
if removals[@free_vars[i]]
|
||||
remove @free_vars, i
|
||||
for b in *@bits
|
||||
if type(b) != 'string'
|
||||
remove_from b
|
||||
remove_from self
|
||||
|
||||
convert_to_statements: (prefix="", suffix=";")=>
|
||||
unless @is_value
|
||||
return
|
||||
@ -141,32 +157,21 @@ class Lua extends Code
|
||||
if suffix != ""
|
||||
@append suffix
|
||||
|
||||
declare_locals: (skip={})=>
|
||||
if next(skip) == 1
|
||||
skip = {[s]:true for s in *skip}
|
||||
to_declare = {}
|
||||
walk = =>
|
||||
for var in *@free_vars
|
||||
unless skip[var]
|
||||
skip[var] = true
|
||||
to_declare[#to_declare+1] = var
|
||||
for bit in *@bits
|
||||
if bit.__class == Lua
|
||||
walk bit
|
||||
if #@free_vars > 0
|
||||
@free_vars = {}
|
||||
walk self
|
||||
declare_locals: (to_declare=nil)=>
|
||||
if to_declare == nil
|
||||
to_declare, seen = {}, {}
|
||||
gather_from = =>
|
||||
for var in *@free_vars
|
||||
unless seen[var]
|
||||
seen[var] = true
|
||||
to_declare[#to_declare+1] = var
|
||||
for bit in *@bits
|
||||
if bit.__class == Lua
|
||||
gather_from bit
|
||||
gather_from self
|
||||
@remove_free_vars to_declare
|
||||
if #to_declare > 0
|
||||
@prepend "local #{concat to_declare, ", "};\n"
|
||||
[[
|
||||
if #@free_vars > 0
|
||||
@prepend "local #{concat @free_vars, ", "};\n"
|
||||
for var in *@free_vars do skip[var] = true
|
||||
@free_vars = {}
|
||||
for bit in *@bits
|
||||
if bit.__class == Lua
|
||||
bit\declare_locals(skip)
|
||||
]]
|
||||
|
||||
__tostring: =>
|
||||
buff = {}
|
||||
|
@ -17,7 +17,7 @@ local colors = setmetatable({ }, {
|
||||
return ""
|
||||
end
|
||||
})
|
||||
local colored = setmetatable({ }, {
|
||||
colored = setmetatable({ }, {
|
||||
__index = function(_, color)
|
||||
return (function(msg)
|
||||
return colors[color] .. tostring(msg or '') .. colors.reset
|
||||
@ -170,6 +170,7 @@ do
|
||||
local line_no = 1
|
||||
local text_loc = lpeg.userdata.source_code.source:sub(pos, pos)
|
||||
line_no = text_loc:get_line_number()
|
||||
src = FILE_CACHE[text_loc.filename]
|
||||
local prev_line = src:sub(LINE_STARTS[src][line_no - 1] or 1, LINE_STARTS[src][line_no] - 1)
|
||||
local err_line = src:sub(LINE_STARTS[src][line_no], (LINE_STARTS[src][line_no + 1] or 0) - 1)
|
||||
local next_line = src:sub(LINE_STARTS[src][line_no + 1] or -1, (LINE_STARTS[src][line_no + 2] or 0) - 1)
|
||||
@ -187,7 +188,7 @@ setmetatable(NOMSU_DEFS, {
|
||||
if type(value) == 'table' then
|
||||
error("Not a tuple: " .. tostring(repr(value)))
|
||||
end
|
||||
local source = lpeg.userdata.source_code.source:sub(start, stop)
|
||||
local source = lpeg.userdata.source_code.source:sub(start, stop - 1)
|
||||
local node = Types[key](value, source)
|
||||
return node
|
||||
end
|
||||
|
@ -22,6 +22,7 @@ export Tuple
|
||||
Tuple = immutable(nil, {name:"Tuple"})
|
||||
{:repr, :stringify, :min, :max, :equivalent, :set, :is_list, :sum} = utils
|
||||
colors = setmetatable({}, {__index:->""})
|
||||
export colored
|
||||
colored = setmetatable({}, {__index:(_,color)-> ((msg)-> colors[color]..tostring(msg or '')..colors.reset)})
|
||||
{:insert, :remove, :concat} = table
|
||||
debug_getinfo = debug.getinfo
|
||||
@ -154,11 +155,13 @@ NOMSU_DEFS = with {}
|
||||
return start + #nodent
|
||||
|
||||
.error = (src,pos,err_msg)->
|
||||
--src = tostring(FILE_CACHE[lpeg.userdata.source_code.source.filename])
|
||||
if src\sub(pos,pos)\match("[\r\n]")
|
||||
pos += #src\match("[ \t\n\r]*", pos)
|
||||
line_no = 1
|
||||
text_loc = lpeg.userdata.source_code.source\sub(pos,pos)
|
||||
line_no = text_loc\get_line_number!
|
||||
src = FILE_CACHE[text_loc.filename]
|
||||
prev_line = src\sub(LINE_STARTS[src][line_no-1] or 1, LINE_STARTS[src][line_no]-1)
|
||||
err_line = src\sub(LINE_STARTS[src][line_no], (LINE_STARTS[src][line_no+1] or 0)-1)
|
||||
next_line = src\sub(LINE_STARTS[src][line_no+1] or -1, (LINE_STARTS[src][line_no+2] or 0)-1)
|
||||
@ -170,7 +173,7 @@ NOMSU_DEFS = with {}
|
||||
setmetatable(NOMSU_DEFS, {__index:(key)=>
|
||||
make_node = (start, value, stop)->
|
||||
if type(value) == 'table' then error("Not a tuple: #{repr value}")-- = Tuple(value)
|
||||
source = lpeg.userdata.source_code.source\sub(start,stop)
|
||||
source = lpeg.userdata.source_code.source\sub(start,stop-1)
|
||||
node = Types[key](value, source)
|
||||
return node
|
||||
self[key] = make_node
|
||||
|
@ -27,6 +27,15 @@ Tree = (name, methods)->
|
||||
.with_value = (value)=> getmetatable(self)(value, @source)
|
||||
.type = name
|
||||
.name = name
|
||||
.as_nomsu = =>
|
||||
leading_space = 0
|
||||
src_file = FILE_CACHE[@source.filename]
|
||||
while src_file\sub(@source.start-leading_space-1, @source.start-leading_space-1) == " "
|
||||
leading_space += 1
|
||||
if src_file\sub(@source.start-leading_space-1, @source.start-leading_space-1) != "\n"
|
||||
leading_space = 0
|
||||
ret = tostring(@source\get_text!)\gsub("\n"..((" ")\rep(leading_space)), "\n")
|
||||
return ret
|
||||
|
||||
Types[name] = immutable {"value","source"}, methods
|
||||
|
||||
@ -49,7 +58,7 @@ Tree "File",
|
||||
|
||||
Tree "Nomsu",
|
||||
as_lua: (nomsu)=>
|
||||
Lua.Value(@source, "nomsu:parse(Nomsu(",repr(@source),", ",repr(@source\get_text!),"))")
|
||||
Lua.Value(@source, "nomsu:parse(Nomsu(",repr(@value.source),", ",repr(tostring(@value.source\get_text!)),")).value[1]")
|
||||
|
||||
Tree "Block",
|
||||
as_lua: (nomsu)=>
|
||||
|
@ -11,7 +11,7 @@ assume (99 isn't in [1,2,3])
|
||||
assume ({x:no} has key "x")
|
||||
assume ({x:no} doesn't have key "y")
|
||||
assume (not ({x:no} doesn't have key "x"))
|
||||
assume ((size of [1,2,3]) = 3)
|
||||
assume ((length of [1,2,3]) = 3)
|
||||
%list <- [1,2,3,4,5]
|
||||
append 6 to %list
|
||||
assume ((last in %list) = 6)
|
||||
|
@ -4,11 +4,11 @@
|
||||
use "core"
|
||||
|
||||
immediately
|
||||
compile [five] to {expr:"5"}
|
||||
compile [five] to: Lua value "5"
|
||||
assume ((five) = 5) or barf "Compile to expression failed."
|
||||
|
||||
immediately
|
||||
compile [loc x] to {statements:"_x = 99", locals:["_x"]}
|
||||
compile [loc x] to: Lua "local _x = 99;"
|
||||
lua> "do"
|
||||
loc x
|
||||
assume (%x is 99) or barf "Compile to statements with locals failed."
|
||||
@ -18,7 +18,7 @@ assume (%x is (nil)) or barf "Failed to properly localize a variable."
|
||||
immediately
|
||||
compile [asdf] to
|
||||
%tmp <- ""
|
||||
return {statements:%tmp}
|
||||
return: Lua %tmp
|
||||
asdf
|
||||
assume (%tmp is (nil)) or barf "compile to is leaking variables"
|
||||
|
||||
@ -42,7 +42,7 @@ try: foo 99
|
||||
|
||||
assume ((\(5 + 5) as value) = 10) or barf "%tree as value failed."
|
||||
|
||||
assume ((\(foo %x)'s source code) = "foo %x") or barf "source code failed."
|
||||
assume (((\(foo %x)'s source code) as text) = "foo %x") or barf "source code failed."
|
||||
|
||||
assume ((repr [1,2]) = "{1, 2}") or barf "repr failed."
|
||||
|
||||
|
@ -1,23 +1,24 @@
|
||||
use "core"
|
||||
use "lib/object2.nom"
|
||||
|
||||
immediately:
|
||||
define object "Dog":
|
||||
action [bark]:
|
||||
%barks <- ("Bark!" for all 1 to (@%barks))
|
||||
return (%barks joined with " ")
|
||||
action [get pissed off]:
|
||||
(@%barks) +<- 1
|
||||
#..
|
||||
immediately:
|
||||
define object "Dog":
|
||||
action [bark]:
|
||||
%barks <- ("Bark!" for all 1 to (@%barks))
|
||||
return (%barks joined with " ")
|
||||
action [get pissed off]:
|
||||
(@%barks) +<- 1
|
||||
|
||||
%d <- (new Dog {barks:2})
|
||||
as %d:
|
||||
assume ((@) = %d)
|
||||
assume ((@%barks) = 2)
|
||||
assume ((bark) = "Bark! Bark!")
|
||||
get pissed off
|
||||
assume ((@%barks) = 3)
|
||||
assume ((bark) = "Bark! Bark! Bark!")
|
||||
assume ("\(%d's "class")" = "Dog")
|
||||
assume ((%d's "barks") = 3)
|
||||
%d <- (new Dog {barks:2})
|
||||
as %d:
|
||||
assume ((@) = %d)
|
||||
assume ((@%barks) = 2)
|
||||
assume ((bark) = "Bark! Bark!")
|
||||
get pissed off
|
||||
assume ((@%barks) = 3)
|
||||
assume ((bark) = "Bark! Bark! Bark!")
|
||||
assume ("\(%d's "class")" = "Dog")
|
||||
assume ((%d's "barks") = 3)
|
||||
|
||||
say "Object test passed."
|
||||
say "Object test passed."
|
||||
|
@ -17,23 +17,23 @@ assume ((%y = 10) and (%x = 20)) or barf "swapping vars failed."
|
||||
assume ({} is {}) or barf "Equality check failed."
|
||||
assume (({}'s id) is not ({}'s id)) or barf "Identity check failed."
|
||||
|
||||
<-{%x:"outer",%y:"outer"}
|
||||
<-{%foozle:"outer",%y:"outer"}
|
||||
action [set global x local y]
|
||||
export %x <- "inner"
|
||||
export %foozle <- "inner"
|
||||
%y <- "inner"
|
||||
set global x local y
|
||||
assume ((%x = "inner") and (%y = "outer")) or barf "export failed."
|
||||
assume ((%foozle = "inner") and (%y = "outer")) or barf "export failed."
|
||||
|
||||
<-{%x:"outer",%y:"outer"}
|
||||
<-{%foozle:"outer",%y:"outer"}
|
||||
action [set global x local y]
|
||||
exporting [%x]
|
||||
%x <- "inner"
|
||||
exporting [%foozle]
|
||||
%foozle <- "inner"
|
||||
%y <- "inner"
|
||||
set global x local y
|
||||
assume ((%x = "inner") and (%y = "outer")) or barf "export failed."
|
||||
assume ((%foozle = "inner") and (%y = "outer")) or barf "exporting failed."
|
||||
|
||||
<-{%x:1,%y:2}
|
||||
with [%z, %x<-999]
|
||||
with {%z:nil, %x:999}
|
||||
%z <- 999
|
||||
assume (%z = 999) or barf "'with' failed."
|
||||
assume (%x = 999) or barf "'with' assignment failed."
|
||||
|
Loading…
Reference in New Issue
Block a user