diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2018-10-30 23:42:04 -0700 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2018-10-30 23:42:36 -0700 |
| commit | ea3197aaffba00318920ed5e1e33ca5f2a5e6c5c (patch) | |
| tree | 2ec4aff13c7a54a3730994525b591ac60528b5ad /core/control_flow.nom | |
| parent | e7e84c9eda38c930f5475301de4a449dcf59e8b6 (diff) | |
Fully working version of (action [foo]: baz) -> ((foo) means: baz)
refactor and misc other changes.
Diffstat (limited to 'core/control_flow.nom')
| -rw-r--r-- | core/control_flow.nom | 140 |
1 files changed, 75 insertions, 65 deletions
diff --git a/core/control_flow.nom b/core/control_flow.nom index 37b2b9c..2b53ce7 100644 --- a/core/control_flow.nom +++ b/core/control_flow.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V4.8.8.6 +#!/usr/bin/env nomsu -V4.8.10 # This file contains compile-time actions that define basic control flow structures like "if" statements and loops. @@ -10,13 +10,13 @@ use "core/errors.nom" # No-Op test: do nothing -compile [do nothing] to (Lua "") +(do nothing) compiles to (Lua "") # Conditionals test: if (no): barf "conditional fail" -compile [if %condition %if_body] to: +(if %condition %if_body) compiles to: %lua = (Lua "if ") %lua::append (%condition as lua expr) %lua::append " then\n " @@ -27,10 +27,10 @@ compile [if %condition %if_body] to: test: unless (yes): barf "conditional fail" -parse [unless %condition %unless_body] as (if (not %condition) %unless_body) -compile [..] +(unless %condition %unless_body) parses as (if (not %condition) %unless_body) +[..] if %condition %if_body else %else_body, unless %condition %else_body else %if_body -..to: +..all compile to: %lua = (Lua "if ") %lua::append (%condition as lua expr) %lua::append " then\n " @@ -48,12 +48,12 @@ compile [..] test: assume ((1 if (yes) else 2) == 1) assume ((1 if (no) else 2) == 2) -compile [..] +[..] %when_true_expr if %condition else %when_false_expr %when_true_expr if %condition otherwise %when_false_expr %when_false_expr unless %condition else %when_true_expr %when_false_expr unless %condition then %when_true_expr -..to: +..all compile to: # If %when_true_expr is guaranteed to be truthy, we can use Lua's idiomatic equivalent of a conditional expression: (cond and if_true or if_false) if {Text:yes, List:yes, Dict:yes, Number:yes}.(%when_true_expr.type): @@ -89,15 +89,21 @@ test: %i -= 1 unless (%i == 0): go to (Loop) assume (%i == 0) -compile [=== %label ===, --- %label ---, *** %label ***] to (..) - Lua "::label_\((%label.stub if (%label.type == "Action") else %label) as lua identifier)::" - -compile [go to %label] to (..) - Lua "goto label_\((%label.stub if (%label.type == "Action") else %label) as lua identifier)" +[=== %label ===, --- %label ---, *** %label ***] all compile to (..) + Lua "\ + ..::label_\(..) + (%label.stub if (%label.type == "Action") else %label) as lua identifier + ..::" + +(go to %label) compiles to (..) + Lua "\ + ..goto label_\(..) + (%label.stub if (%label.type == "Action") else %label) as lua identifier + .." # Basic loop control -compile [do next] to (Lua "goto continue") -compile [stop] to (Lua "break") +(do next) compiles to (Lua "goto continue") +(stop) compiles to (Lua "break") # While loops test: @@ -119,9 +125,9 @@ test: barf "Failed to 'do next repeat'" assume (%x == 30) -compile [do next repeat] to (Lua "goto continue_repeat") -compile [stop repeating] to (Lua "goto stop_repeat") -compile [repeat while %condition %body] to: +(do next repeat) compiles to (Lua "goto continue_repeat") +(stop repeating) compiles to (Lua "goto stop_repeat") +(repeat while %condition %body) compiles to: %lua = (..) Lua "\ ..while \(%condition as lua expr) do @@ -137,25 +143,24 @@ compile [repeat while %condition %body] to: %lua = (Lua "do -- scope of 'stop repeating' label\n ") %lua::append %inner_lua %lua::append "\ - .. - ::stop_repeat:: - end -- end of 'stop repeating' label scope" + .. + ::stop_repeat:: + end -- end of 'stop repeating' label scope" return %lua -parse [repeat %body] as (repeat while (yes) %body) -parse [repeat until %condition %body] as (repeat while (not %condition) %body) +(repeat %body) parses as (repeat while (yes) %body) +(repeat until %condition %body) parses as (repeat while (not %condition) %body) test: %x = 0 repeat 10 times: %x += 1 assume (%x == 10) -compile [repeat %n times %body] to: +(repeat %n times %body) compiles to: define mangler %lua = (..) Lua "for \(mangle "i")=1,\(%n as lua expr) do\n " %lua::append (%body as lua statements) - if (%body has subtree \(do next)): %lua::append "\n ::continue::" if (%body has subtree \(do next repeat)): @@ -166,21 +171,20 @@ compile [repeat %n times %body] to: %lua = (Lua "do -- scope of 'stop repeating' label\n ") %lua::append %inner_lua %lua::append "\ - .. - ::stop_repeat:: - end -- end of 'stop repeating' label scope" + .. + ::stop_repeat:: + end -- end of 'stop repeating' label scope" return %lua # For loop control flow -compile [stop %var] to (..) +(stop %var) compiles to (..) Lua "goto stop_\((%var.stub if (%var.type == "Action") else %var) as lua identifier)" -compile [do next %var] to (..) +(do next %var) compiles to (..) Lua "goto continue_\((%var.stub if (%var.type == "Action") else %var) as lua identifier)" -compile [===stop %var ===, ---stop %var ---, ***stop %var ***] to (..) +[===stop %var ===, ---stop %var ---, ***stop %var ***] all compile to (..) Lua "::stop_\((%var.stub if (%var.type == "Action") else %var) as lua identifier)::" - -compile [===next %var ===, ---next %var ---, ***next %var ***] to (..) +[===next %var ===, ---next %var ---, ***next %var ***] all compile to (..) Lua "::continue_\((%var.stub if (%var.type == "Action") else %var) as lua identifier)::" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -205,10 +209,10 @@ test: assume (%nums == [1, -2, 3, -2, 3, 4, 3, 4, 5]) # Numeric range for loops -compile [..] +[..] for %var in %start to %stop by %step %body for %var in %start to %stop via %step %body -..to: +..all compile to: # This uses Lua's approach of only allowing loop-scoped variables in a loop unless (%var.type is "Var"): compile error at %var "Expected a variable here, not a \(%var.type)" @@ -217,28 +221,29 @@ compile [..] ..for \(%var as lua expr)=\(%start as lua expr),\(%stop as lua expr),\(..) %step as lua expr .. do" + %lua::append "\n " %lua::append (%body as lua statements) - if (%body has subtree \(do next)): %lua::append "\n ::continue::" if (%body has subtree \(do next %var)): %lua::append "\n " - %lua::append (compile as (===next %var ===)) + %lua::append (what (===next %var ===) compiles to) + %lua::append "\nend --numeric for-loop" if (%body has subtree \(stop %var)): %inner_lua = %lua %lua = (Lua "do -- scope for stopping for-loop\n ") %lua::append %inner_lua %lua::append "\n " - %lua::append (compile as (===stop %var ===)) + %lua::append (what (===stop %var ===) compiles to) %lua::append "\nend -- end of scope for stopping for-loop" return %lua ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -parse [for %var in %start to %stop %body] as (..) +(for %var in %start to %stop %body) parses as (..) for %var in %start to %stop via 1 %body test: @@ -255,48 +260,48 @@ test: assume (%b == [20, 30, 40]) # For-each loop (lua's "ipairs()") -compile [for %var in %iterable %body] to: +(for %var in %iterable %body) compiles to: define mangler # This uses Lua's approach of only allowing loop-scoped variables in a loop %lua = (..) Lua "for \(mangle "i"),\(%var as lua identifier) in ipairs(\(%iterable as lua expr)) do\n " %lua::append (%body as lua statements) - if (%body has subtree \(do next)): %lua::append "\n ::continue::" if (%body has subtree \(do next %var)): %lua::append "\n " - %lua::append (compile as (===next %var ===)) + %lua::append (what (===next %var ===) compiles to) + %lua::append "\nend --foreach-loop" if (%body has subtree \(stop %var)): %inner_lua = %lua %lua = (Lua "do -- scope for stopping for-loop\n ") %lua::append %inner_lua %lua::append "\n " - %lua::append (compile as (===stop %var ===)) + %lua::append (what (===stop %var ===) compiles to) %lua::append "\nend -- end of scope for stopping for-loop" return %lua # TODO: reduce code duplication -compile [for %var in %iterable at %i %body] to: +(for %var in %iterable at %i %body) compiles to: # This uses Lua's approach of only allowing loop-scoped variables in a loop %lua = (..) Lua "for \(%i as lua identifier),\(%var as lua identifier) in ipairs(\(%iterable as lua expr)) do\n " %lua::append (%body as lua statements) - if (%body has subtree \(do next)): %lua::append "\n ::continue::" if (%body has subtree \(do next %var)): %lua::append "\n " - %lua::append (compile as (===next %var ===)) + %lua::append (what (===next %var ===) compiles to) + %lua::append "\nend --foreach-loop" if (%body has subtree \(stop %var)): %inner_lua = %lua %lua = (Lua "do -- scope for stopping for-loop\n ") %lua::append %inner_lua %lua::append "\n " - %lua::append (compile as (===stop %var ===)) + %lua::append (what (===stop %var ===) compiles to) %lua::append "\nend -- end of scope for stopping for-loop" return %lua @@ -312,9 +317,9 @@ test: assume ((%result sorted) == ["c = 30", "d = 40", "e = 50"]) # Dict iteration (lua's "pairs()") -compile [..] +[..] for %key = %value in %iterable %body, for %key %value in %iterable %body -..to: +..all compile to: # This uses Lua's approach of only allowing loop-scoped variables in a loop unless (%key.type is "Var"): compile error at %key "Expected a variable here, not a \(%key.type)" @@ -325,25 +330,29 @@ compile [..] ..for \(%key as lua identifier),\(%value as lua identifier) in pairs(\(..) %iterable as lua expr ..) do" + %lua::append "\n " %lua::append (%body as lua statements) - if (%body has subtree \(do next)): %lua::append "\n ::continue::" if (%body has subtree \(do next %key)): %lua::append "\n " - %lua::append (compile as (===next %key ===)) + %lua::append (what (===next %key ===) compiles to) + if (%body has subtree \(do next %value)): %lua::append "\n " - %lua::append (compile as (===next %value ===)) + %lua::append (what (===next %value ===) compiles to) + %lua::append "\nend --foreach-loop" %stop_labels = (Lua "") if (%body has subtree \(stop %key)): %stop_labels::append "\n" - %stop_labels::append (compile as (===stop %key ===)) + %stop_labels::append (what (===stop %key ===) compiles to) + if (%body has subtree \(stop %value)): %stop_labels::append "\n" - %stop_labels::append (compile as (===stop %value ===)) + %stop_labels::append (what (===stop %value ===) compiles to) + if ((size of "\%stop_labels") > 0): %inner_lua = %lua %lua = (Lua "do -- scope for stopping for % = % loop\n ") @@ -368,13 +377,14 @@ test: barf "bad conditional" # Multi-branch conditional (if..elseif..else) -compile [if %body, when %body] to: +[if %body, when %body] all compile to: %code = (Lua "") %clause = "if" %else_allowed = (yes) unless (%body.type is "Block"): compile error at %body "'if' expected a Block, but got a \(%body.type)." ..hint "Perhaps you forgot to put a ':' after 'if'?" + for %line in %body: unless (..) ((%line.type is "Action") and ((size of %line) >= 2)) and (..) @@ -389,13 +399,14 @@ compile [if %body, when %body] to: unless %else_allowed: compile error at %line "You can't have two 'else' blocks." ..hint "Merge all of the 'else' blocks together." + unless ((size of "\%code") > 0): compile error at %line "\ ..You can't have an 'else' block without a preceeding condition" ..hint "If you want the code in this block to always execute, you don't \ ..need a conditional block around it. Otherwise, make sure the 'else' \ ..block comes last." - + %code::append "\nelse\n " %code::append (%action as lua statements) %else_allowed = (no) @@ -428,7 +439,7 @@ test: barf "bad switch statement" # Switch statement -compile [if %branch_value is %body, when %branch_value is %body] to: +[if %branch_value is %body, when %branch_value is %body] all compile to: %code = (Lua "") %clause = "if" %else_allowed = (yes) @@ -488,7 +499,7 @@ compile [if %branch_value is %body, when %branch_value is %body] to: return %lua # Do/finally -compile [do %action] to: +(do %action) compiles to: %lua = (Lua "do\n ") %lua::append (%action as lua statements) %lua::append "\nend -- do" @@ -504,7 +515,7 @@ test: ..and if it barfs: do nothing assume (%d.x == "good") -compile [do %action then always %final_action] to: +(do %action then always %final_action) compiles to: define mangler %lua = (..) Lua "\ @@ -528,7 +539,7 @@ test: assume ((result of (: return 99)) == 99) # Inline thunk: -compile [result of %body] to (Lua value "\(compile as ([] -> %body))()") +(result of %body) compiles to (Lua value "\(what ([] -> %body) compiles to)()") test: %t = [1, [2, [[3], 4], 5, [[[6]]]]] @@ -541,10 +552,10 @@ test: assume (sorted %flat) == [1, 2, 3, 4, 5, 6] # Recurion control flow -compile [for %var in recursive %structure %body] to: +(for %var in recursive %structure %body) compiles to: with local compile actions: define mangler - compile [recurse %v on %x] to (..) + (recurse %v on %x) compiles to (..) Lua "table.insert(\(mangle "stack \(%v.1)"), \(%x as lua expr))" %lua = (..) Lua "\ @@ -554,13 +565,12 @@ compile [for %var in recursive %structure %body] to: \(%var as lua expr) = table.remove(\(mangle "stack \(%var.1)"), 1)" %lua::append "\n " %lua::append (%body as lua statements) - if (%body has subtree \(do next)): %lua::append "\n ::continue::" if (%body has subtree \(do next %var)): - %lua::append "\n \(compile as (===next %var ===))" + %lua::append "\n \(what (===next %var ===) compiles to)" %lua::append "\n end -- Recursive loop" if (%body has subtree \(stop %var)): - %lua::append "\n \(compile as (===stop %var ===))" + %lua::append "\n \(what (===stop %var ===) compiles to)" %lua::append "\nend -- Recursive scope" return %lua |
