aboutsummaryrefslogtreecommitdiff
path: root/core/control_flow.nom
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2018-10-30 23:42:04 -0700
committerBruce Hill <bruce@bruce-hill.com>2018-10-30 23:42:36 -0700
commitea3197aaffba00318920ed5e1e33ca5f2a5e6c5c (patch)
tree2ec4aff13c7a54a3730994525b591ac60528b5ad /core/control_flow.nom
parente7e84c9eda38c930f5475301de4a449dcf59e8b6 (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.nom140
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