From da33269c307c8a045e548cb1df2a3281a7a0f99e Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Thu, 19 Apr 2018 17:23:44 -0700 Subject: All tests passing (except object) --- core/collections.nom | 58 ++++++------ core/control_flow.nom | 240 +++++++++++++++++++++-------------------------- core/math.nom | 90 +++++++++--------- core/metaprogramming.nom | 37 +++++--- core/operators.nom | 44 +++++++-- core/text.nom | 20 ++-- 6 files changed, 249 insertions(+), 240 deletions(-) (limited to 'core') diff --git a/core/collections.nom b/core/collections.nom index 481d283..d4d4c5b 100644 --- a/core/collections.nom +++ b/core/collections.nom @@ -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; diff --git a/core/control_flow.nom b/core/control_flow.nom index 39d496d..0f081fc 100644 --- a/core/control_flow.nom +++ b/core/control_flow.nom @@ -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 diff --git a/core/math.nom b/core/math.nom index 31be658..0df8f16 100644 --- a/core/math.nom +++ b/core/math.nom @@ -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]: diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom index 7ea437e..a446f42 100644 --- a/core/metaprogramming.nom +++ b/core/metaprogramming.nom @@ -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 diff --git a/core/operators.nom b/core/operators.nom index 63819da..1ea1df2 100644 --- a/core/operators.nom +++ b/core/operators.nom @@ -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: diff --git a/core/text.nom b/core/text.nom index 8213988..d877de7 100644 --- a/core/text.nom +++ b/core/text.nom @@ -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 -- cgit v1.2.3