aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2019-01-14 15:42:48 -0800
committerBruce Hill <bruce@bruce-hill.com>2019-01-14 15:43:24 -0800
commitc1c32688a4afc43f6addb99b8b5fa878944a70e3 (patch)
treec886f21b5b08a9053aa74fcba4b241dae5ede76d /core
parent2309b696fc34b24f05f6658b94f9105ca8ee76e4 (diff)
Overhaul in progress, mostly working. Moved all the nomsu packages into
lib/, including core/*. Changes to how nomsu environments and importing work.
Diffstat (limited to 'core')
-rw-r--r--core/collections.nom145
-rw-r--r--core/control_flow.nom489
-rw-r--r--core/coroutines.nom40
-rw-r--r--core/errors.nom130
-rw-r--r--core/id.nom66
-rw-r--r--core/init.nom11
-rw-r--r--core/io.nom29
-rw-r--r--core/math.nom212
-rw-r--r--core/metaprogramming.nom454
-rw-r--r--core/operators.nom263
-rw-r--r--core/text.nom78
11 files changed, 0 insertions, 1917 deletions
diff --git a/core/collections.nom b/core/collections.nom
deleted file mode 100644
index 4cf54cd..0000000
--- a/core/collections.nom
+++ /dev/null
@@ -1,145 +0,0 @@
-#!/usr/bin/env nomsu -V6.14
-#
- This file contains code that supports manipulating and using collections like lists
- and dictionaries.
-
-use "core/metaprogramming"
-use "core/control_flow"
-use "core/operators"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-# List functionality:
-test:
- $list = [1, 2, 3, 4, 5]
- $visited = {}
- for $i = $x in $list:
- $visited.$i = (yes)
- assume ($visited == {.1, .2, .3, .4, .5})
- $visited = {}
- for $x in $list:
- $visited.$x = (yes)
- assume ($visited == {.1, .2, .3, .4, .5})
- assume (($list, 2 nd to last) == 4)
- assume (($list, first) == 1)
- assume ($list, has 3)
- assume (($list, index of 3) == 3)
- assume ((size of $list) == 5)
- $list, add 6
- assume (($list, last) == 6)
- $list, pop
- assume (($list, last) == 5)
- $list, remove index 1
- assume (($list, first) == 2)
- assume (([1, 2] + [3, 4]) == [1, 2, 3, 4])
-
-# Dict functionality
-test:
- $dict = {.x = 1, .y = 2, .z = 3}
- assume (size of $dict) == 3
- assume [: for $k = $v in {.x = 1}: add {.key = $k, .value = $v}] ==
- [{.key = "x", .value = 1}]
- assume ({.x = 1, .y = 1} + {.y = 10, .z = 10}) == {.x = 1, .y = 11, .z = 10}
- assume ({.x = 1, .y = 1} | {.y = 10, .z = 10}) == {.x = 1, .y = 1, .z = 10}
- assume ({.x = 1, .y = 1} & {.y = 10, .z = 10}) == {.y = 1}
- assume ({.x = 1, .y = 1} ~ {.y = 10, .z = 10}) == {.x = 1, .z = 10}
-
-test:
- assume (([[1, 2], [3, 4]] flattened) == [1, 2, 3, 4])
-
-externally ($lists flattened) means:
- $flat = []
- for $item in recursive $lists:
- if ($item is a "List"):
- for $ in $item:
- recurse $item on $
- ..else:
- $flat, add $item
- return $flat
-
-test:
- assume ((entries in {.x = 1}) == [{.key = "x", .value = 1}])
-
-(entries in $dict) parses as [
- : for $k = $v in $dict:
- add {.key = $k, .value = $v}
-]
-
-test:
- assume ((keys in {.x = 1}) == ["x"])
-
-[keys in $dict, keys of $dict] all parse as [: for $k = $v in $dict: add $k]
-test:
- assume ((values in {.x = 1}) == [1])
-[values in $dict, values of $dict] all parse as [: for $k = $v in $dict: add $v]
-
-# Metatable stuff
-test:
- $t = {}
- set $t's metatable to {.__tostring = ($ -> "XXX")}
- assume ("\$t" == "XXX")
-
-(set $dict's metatable to $metatable) compiles to
- "setmetatable(\($dict as lua expr), \($metatable as lua expr));"
-
-[$'s metatable, $'metatable] all compile to "getmetatable(\($ as lua expr))"
-test:
- assume (({} with fallback $ -> ($ + 1)).10 == 11)
-
-($dict with fallback $key -> $value) compiles to ("
- (function(d)
- local mt = {}
- for k,v in pairs(getmetatable(d) or {}) do mt[k] = v end
- mt.__index = function(self, \($key as lua expr))
- local value = \($value as lua expr)
- self[\($key as lua expr)] = value
- return value
- end
- return setmetatable(d, mt)
- end)(\($dict as lua expr))
-")
-
-# Sorting
-test:
- $x = [3, 1, 2]
- sort $x
- assume ($x == [1, 2, 3])
- sort $x by $ = (- $)
- assume ($x == [3, 2, 1])
- $keys = {.1 = 999, .2 = 0, .3 = 50}
- sort $x by $ = $keys.$
- assume ($x == [2, 3, 1])
-(sort $items) compiles to "table.sort(\($items as lua expr));"
-[sort $items by $item = $key_expr, sort $items by $item -> $key_expr]
-..all parse as
- do:
- $keys = ({} with fallback $item -> $key_expr)
- lua> "table.sort(\$items, function(x,y) return \$keys[x] < \$keys[y] end)"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-test:
- assume ((sorted [3, 1, 2]) == [1, 2, 3])
-
-externally [$items sorted, sorted $items] all mean:
- $copy = [: for $ in $items: add $]
- sort $copy
- return $copy
-
-[$items sorted by $item = $key, $items sorted by $item -> $key] all parse as
- result of:
- $copy = [: for $ in $items: add $]
- sort $copy by $item = $key
- return $copy
-
-test:
- assume ((unique [1, 2, 1, 3, 2, 3]) == [1, 2, 3])
-
-externally (unique $items) means:
- $unique = []
- $seen = {}
- for $ in $items:
- unless $seen.$:
- $unique, add $
- $seen.$ = (yes)
- return $unique
diff --git a/core/control_flow.nom b/core/control_flow.nom
deleted file mode 100644
index b0c4f27..0000000
--- a/core/control_flow.nom
+++ /dev/null
@@ -1,489 +0,0 @@
-#!/usr/bin/env nomsu -V6.14
-#
- This file contains compile-time actions that define basic control flow structures
- like "if" statements and loops.
-
-use "core/metaprogramming"
-use "core/operators"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-# No-Op
-test:
- do nothing
-(do nothing) compiles to ""
-
-# Conditionals
-test:
- if (no):
- fail "conditional fail"
-
-(if $condition $if_body) compiles to ("
- if \($condition as lua expr) then
- \($if_body as lua)
- end
-")
-
-test:
- unless (yes):
- fail "conditional fail"
-
-(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
-] all compile to ("
- if \($condition as lua expr) then
- \($if_body as lua)
- else
- \($else_body as lua)
- end
-")
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-# Conditional expression (ternary operator)
-# Note: this uses a function instead of "(condition and if_expr or else_expr)"
- because that breaks if $if_expr is falsey, e.g. "x < 5 and false or 99"
-test:
- assume ((1 if (yes) else 2) == 1)
- assume ((1 if (no) else 2) == 2)
-
-[
- $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
-] 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, .List, .Dict, .Number}.($when_true_expr.type):
- return
- Lua ("
- (\($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 ("
- ((function()
- if \($condition as lua expr) then
- return \($when_true_expr as lua expr)
- else
- return \($when_false_expr as lua expr)
- end
- end)())
- ")
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-# GOTOs
-test:
- $i = 0
- --- $loop ---
- $i += 1
- unless ($i == 10):
- go to $loop
- assume ($i == 10)
- --- (Loop) ---
- $i -= 1
- unless ($i == 0):
- go to (Loop)
- assume ($i == 0)
-
-(--- $label ---) compiles to ("
- ::label_\(
- ($label.stub, as lua id) if ($label.type == "Action") else
- $label as lua identifier
- )::
-")
-
-(go to $label) compiles to ("
- goto label_\(
- ($label.stub, as lua id) if ($label.type == "Action") else
- $label as lua identifier
- )
-")
-
-# Basic loop control
-(stop $var) compiles to:
- if $var:
- return (Lua "goto stop_\($var as lua identifier)")
- ..else:
- return (Lua "break")
-
-(do next $var) compiles to:
- if $var:
- return (Lua "goto continue_\($var as lua identifier)")
- ..else:
- return (Lua "goto continue")
-
-(---stop $var ---) compiles to "::stop_\($var as lua identifier)::"
-(---next $var ---) compiles to "::continue_\($var as lua identifier)::"
-
-# While loops
-test:
- $x = 0
- repeat while ($x < 10): $x += 1
- assume ($x == 10)
- repeat while ($x < 20): stop
- assume ($x == 10)
- repeat while ($x < 20):
- $x += 1
- if (yes):
- do next
- fail "Failed to 'do next'"
- assume ($x == 20)
-
-(repeat while $condition $body) compiles to:
- $lua =
- Lua ("
- while \($condition as lua expr) do
- \($body as lua)
- ")
-
- if ($body has subtree \(do next)):
- $lua, add "\n ::continue::"
-
- $lua, add "\nend --while-loop"
- return $lua
-
-(repeat $body) parses as (repeat while (yes) $body)
-(repeat until $condition $body) parses as (repeat while (not $condition) $body)
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-test:
- $nums = []
- for $x in 1 to 5:
- $nums, add $x
- assume ($nums == [1, 2, 3, 4, 5])
- $nums = []
- for $x in 1 to 5 via 2:
- $nums, add $x
- assume ($nums == [1, 3, 5])
- $nums = []
- for $outer in 1 to 100:
- for $inner in $outer to ($outer + 2):
- if ($inner == 2):
- $nums, add -2
- do next $inner
- $nums, add $inner
- if ($inner == 5):
- stop $outer
- assume ($nums == [1, -2, 3, -2, 3, 4, 3, 4, 5])
-
-# Numeric range for loops
-[
- for $var in $start to $stop by $step $body
- for $var in $start to $stop via $step $body
-] all compile to:
- # This uses Lua's approach of only allowing loop-scoped variables in a loop
- $lua =
- Lua ("
- for \($var as lua identifier)=\($start as lua expr),\($stop as lua expr),\
- ..\($step as lua expr) do
- ")
- $lua, add "\n " ($body as lua)
- if ($body has subtree \(do next)):
- $lua, add "\n ::continue::"
-
- if ($body has subtree \(do next $var)):
- $lua, add "\n " (\(---next $var ---) as lua)
-
- $lua, add "\nend -- numeric for " ($var as lua identifier) " loop"
- if ($body has subtree \(stop $var)):
- $lua =
- Lua ("
- do -- scope for (stop \($var as lua identifier))
- \$lua
- \(\(---stop $var ---) as lua)
- end -- scope for (stop \($var as lua identifier))
- ")
- return $lua
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-(for $var in $start to $stop $body) parses as
- for $var in $start to $stop via 1 $body
-
-test:
- $x = 0
- repeat 5 times:
- $x += 1
- assume $x == 5
-
-(repeat $n times $body) parses as (for (=lua "_XXX_") in 1 to $n $body)
-test:
- $a = [10, 20, 30, 40, 50]
- $b = []
- for $x in $a:
- $b, add $x
- assume ($a == $b)
- $b = []
- for $x in $a:
- if ($x == 10):
- do next $x
-
- if ($x == 50):
- stop $x
-
- $b, add $x
- assume ($b == [20, 30, 40])
-
-# For-each loop (lua's "ipairs()")
-(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
- \;
- ")
- $lua, add ($body as lua)
- if ($body has subtree \(do next)):
- $lua, add "\n ::continue::"
-
- if ($body has subtree \(do next $var)):
- $lua, add "\n " (\(---next $var ---) as lua)
-
- $lua, add "\nend --for \($var as lua identifier) loop"
- if ($body has subtree \(stop $var)):
- $inner_lua = $lua
- $lua = (Lua "do -- scope for stopping for-loop\n ")
- $lua, add $inner_lua "\n "
- $lua, add (\(---stop $var ---) as lua)
- $lua, add "\nend -- end of scope for stopping for-loop"
- return $lua
-
-(for $var in $iterable $body) parses as
- for $var in $iterable at (=lua "__") $body
-
-test:
- $d = {.a = 10, .b = 20, .c = 30, .d = 40, .e = 50}
- $result = []
- for $k = $v in $d:
- if ($k == "a"):
- do next $k
-
- if ($v == 20):
- do next $v
-
- $result, add "\$k = \$v"
- assume (($result sorted) == ["c = 30", "d = 40", "e = 50"])
-
-# Dict iteration (lua's "pairs()")
-[for $key = $value in $iterable $body, for $key $value in $iterable $body]
-..all compile to:
- $lua =
- Lua ("
- for \($key as lua identifier),\($value as lua identifier) in pairs(\
- ..\($iterable as lua expr)) do
- ")
- $lua, add "\n " ($body as lua)
- if ($body has subtree \(do next)):
- $lua, add "\n ::continue::"
-
- if ($body has subtree \(do next $key)):
- $lua, add "\n " (\(---next $key ---) as lua)
-
- if ($body has subtree \(do next $value)):
- $lua, add "\n " (\(---next $value ---) as lua)
-
- $lua, add "\nend --foreach-loop"
- $stop_labels = (Lua "")
- if ($body has subtree \(stop $key)):
- $stop_labels, add "\n" (\(---stop $key ---) as lua)
-
- if ($body has subtree \(stop $value)):
- $stop_labels, add "\n" (\(---stop $value ---) as lua)
-
- if ((size of "\$stop_labels") > 0):
- $inner_lua = $lua
- $lua = (Lua "do -- scope for stopping for $ = $ loop\n ")
- $lua, add $inner_lua $stop_labels "\nend"
-
- return $lua
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-test:
- when:
- (1 == 2) (100 < 0):
- fail "bad conditional"
- (1 == 0) (1 == 1) $not_a_variable.x: do nothing
- (1 == 1):
- fail "bad conditional"
-
- (1 == 2):
- fail "bad conditional"
-
- else:
- fail "bad conditional"
-
-# Multi-branch conditional (if..elseif..else)
-(when $body) compiles 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)."
- "Perhaps you forgot to put a ':' after 'if'?"
-
- for $line in $body:
- unless
- (($line.type is "Action") and ((size of $line) >= 2)) and
- $line.(size of $line) is "Block" syntax tree
- ..:
- compile error at $line "Invalid line for the body of an 'if' block." ("
- Each line should contain one or more conditional expressions followed by a block, or "else"\
- .. followed by a block.
- ")
- $action = $line.(size of $line)
- if (($line.1 is "else") and ((size of $line) == 2)):
- unless $else_allowed:
- compile error at $line "You can't have two 'else' blocks."
- "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 preceding condition" ("
- 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, add "\nelse\n " ($action as lua)
- $else_allowed = (no)
- ..else:
- $code, add $clause " "
- for $i in 1 to ((size of $line) - 1):
- if ($i > 1):
- $code, add " or "
- $code, add ($line.$i as lua expr)
- $code, add " then\n " ($action as lua)
- $clause = "\nelseif"
-
- if ((size of "\$code") == 0):
- compile error at $body "'if' block has an empty body."
- "This means nothing would happen, so the 'if' block should be deleted."
-
- $code, add "\nend --when"
- return $code
-
-test:
- if 5 is:
- 1 2 3:
- fail "bad switch statement"
-
- 4 5:
- do nothing
-
- 5 6:
- fail "bad switch statement"
-
- else:
- fail "bad switch statement"
-
-# Switch statement
-[if $branch_value is $body, when $branch_value is $body] all compile to:
- $code = (Lua "")
- $clause = "if"
- $else_allowed = (yes)
- define mangler
- unless ($body.type is "Block"):
- compile error at $body "'if' expected a Block, but got a \($body.type)"
- "Perhaps you forgot to put a ':' after the 'is'?"
-
- for $line in $body:
- unless
- (($line.type is "Action") and ((size of $line) >= 2)) and
- $line.(size of $line) is "Block" syntax tree
- ..:
- compile error at $line "Invalid line for 'if' block." ("
- Each line should contain expressions followed by a block, or "else" followed by a block
- ")
- $action = $line.(size of $line)
- if (($line.1 is "else") and ((size of $line) == 2)):
- unless $else_allowed:
- compile error at $line "You can't have two 'else' blocks."
- "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 preceding condition" ("
- 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, add "\nelse\n " ($action as lua)
- $else_allowed = (no)
- ..else:
- $code, add $clause " "
- for $i in 1 to ((size of $line) - 1):
- if ($i > 1):
- $code, add " or "
- $code, add "\(mangle "branch value") == " ($line.$i as lua expr)
- $code, add " then\n " ($action as lua)
- $clause = "\nelseif"
-
- if ((size of "\$code") == 0):
- compile error at $body "'if' block has an empty body."
- "This means nothing would happen, so the 'if' block should be deleted."
-
- $code, add "\nend --when"
- return
- Lua ("
- do --if $ is...
- local \(mangle "branch value") = \($branch_value as lua expr)
- \$code
- end -- if $ is...
- ")
-
-# Do/finally
-(do $action) compiles to ("
- do
- \($action as lua)
- end -- do
-")
-
-test:
- assume ((result of: return 99) == 99)
-
-# Inline thunk:
-(result of $body) compiles to "\(\(-> $body) as lua)()"
-test:
- $t = [1, [2, [[3], 4], 5, [[[6]]]]]
- $flat = []
- for $ in recursive $t:
- if ((lua type of $) is "table"):
- for $2 in $:
- recurse $ on $2
- ..else:
- $flat, add $
- assume (sorted $flat) == [1, 2, 3, 4, 5, 6]
-
-# Recurion control flow
-(recurse $v on $x) compiles to
- Lua "table.insert(_stack_\($v as lua expr), \($x as lua expr))"
-(for $var in recursive $structure $body) compiles to:
- $lua =
- Lua ("
- do
- local _stack_\($var as lua expr) = List{\($structure as lua expr)}
- while #_stack_\($var as lua expr) > 0 do
- \($var as lua expr) = table.remove(_stack_\($var as lua expr), 1)
- \($body as lua)
- ")
-
- if ($body has subtree \(do next)):
- $lua, add "\n ::continue::"
-
- if ($body has subtree \(do next $var)):
- $lua, add "\n \(\(---next $var ---) as lua)"
-
- $lua, add "\n end -- Recursive loop"
- if ($body has subtree \(stop $var)):
- $lua, add "\n \(\(---stop $var ---) as lua)"
- $lua, add "\nend -- Recursive scope"
- return $lua
diff --git a/core/coroutines.nom b/core/coroutines.nom
deleted file mode 100644
index 6a99f7e..0000000
--- a/core/coroutines.nom
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/usr/bin/env nomsu -V6.14
-#
- This file defines the code that creates and manipulates coroutines
-
-use "core/metaprogramming"
-use "core/operators"
-use "core/control_flow"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-test:
- $co =
- ->:
- yield 4
- yield 5
- repeat 3 times:
- yield 6
- $nums = []
- for $ in coroutine $co:
- $nums, add $
-
- unless ($nums == [4, 5, 6, 6, 6]):
- fail "Coroutine iteration failed"
-
- $d = {.x = 0}
- $co2 =
- coroutine:
- $d.x += 1
- yield 1
- $d.x += 1
- yield
- $d.x += 1
- repeat while ((coroutine status of $co2) != "dead"): resume $co2
- assume $d.x == 3
-(coroutine $body) parses as (coroutine from (-> $body))
-(for $ in coroutine $co $body) compiles to ("
- for \($ as lua expr) in coroutine_wrap(\($co as lua expr)) do
- \($body as lua)
- end
-")
diff --git a/core/errors.nom b/core/errors.nom
deleted file mode 100644
index 45fc8c5..0000000
--- a/core/errors.nom
+++ /dev/null
@@ -1,130 +0,0 @@
-#!/usr/bin/env nomsu -V6.14
-#
- This file contains basic error reporting code
-
-use "core/metaprogramming"
-use "core/operators"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-(fail $msg) compiles to "error(\(($msg as lua expr) if $msg else "nil"), 0);"
-(assume $condition) compiles to:
- lua> ("
- local \$assumption = 'Assumption failed: '..tostring((\$condition):get_source_code())
- ")
-
- return
- Lua ("
- if not \($condition as lua expr) then
- error(\(quote "\$assumption"), 0)
- end
- ")
-
-(assume $a == $b) compiles to:
- lua> "local \$assumption = 'Assumption failed: '..tostring(\(\($a == $b) as nomsu))"
-
- define mangler
-
- return
- Lua ("
- do
- local \(mangle "a"), \(mangle "b") = \($a as lua expr), \($b as lua expr)
- if \(mangle "a") ~= \(mangle "b") then
- error(\(quote "\$assumption").."\\n"..tostring(\(mangle "a")).." != "..tostring(\
- ..\(mangle "b")), 0)
- end
- end
- ")
-
-test:
- try: fail
- $worked = (no)
- try:
- fail "xx"
- ..if it fails with $failure:
- $worked = (yes)
- ..if it succeeds:
- fail "'try' incorrectly ran success case."
- assume $failure == "xx"
- unless $worked:
- fail "'try' failed to recover from failure"
-
-# Try/except
-[
- try $action if it succeeds $success if it fails with $msg $fallback
- try $action if it fails with $msg $fallback if it succeeds $success
-] all compile to:
- $success_lua = ($success as lua)
- if ((#"\$success_lua") > 0):
- $success_lua, add "\n"
- $success_lua, prepend "-- Success:\n"
- $success_lua,
- add "if not _fell_through then return table.unpack(_result, 2) end"
- $fallback_lua = ($fallback as lua)
- if ((#"\$fallback_lua") > 0):
- $msg_lua = ($msg as lua expr)
- if ((#"\$msg_lua") > 0):
- $fallback_lua, prepend "\n\$msg_lua = _result[2]\n"
- if ($msg_lua, text, is lua id):
- $fallback_lua, add free vars [($msg_lua, text)]
- $fallback_lua, prepend "-- Failure:"
- return
- Lua ("
- do
- local _fell_through = false
- local _result = {pcall(function()
- \($action as lua)
- _fell_through = true
- end)}
- if _result[1] then
- \$success_lua
- else
- \$fallback_lua
- end
- end
- ")
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-(try $action) parses as
- try $action if it succeeds (do nothing) if it fails (do nothing)
-
-(try $action if it fails $fallback) parses as
- try $action if it succeeds (do nothing) if it fails $fallback
-
-(try $action if it fails with $msg $fallback) parses as
- try $action if it succeeds (do nothing) if it fails with $msg $fallback
-
-(try $action if it succeeds $success) parses as
- try $action if it succeeds $success if it fails (do nothing)
-
-(try $action if it fails $fallback if it succeeds $success) parses as
- try $action if it fails with (=lua "") $fallback if it succeeds $success
-
-(try $action if it succeeds $success if it fails $fallback) parses as
- try $action if it succeeds $success if it fails with (=lua "") $fallback
-
-test:
- $success = (no)
- try:
- do: fail
- ..then always:
- $success = (yes)
- ..if it succeeds:
- fail "'try ... then always ...' didn't propagate failure"
-
- unless $success:
- fail "'try ... then always ...' didn't execute the 'always' code"
-
-(do $action then always $final_action) compiles to ("
- do -- do/then always
- local _fell_through = false
- local _results = {pcall(function()
- \($action as lua)
- _fell_through = true
- end)}
- \($final_action as lua)
- if not _results[1] then error(_results[2], 0) end
- if not _fell_through then return table.unpack(_results, 2) end
- end
-")
diff --git a/core/id.nom b/core/id.nom
deleted file mode 100644
index d2427b5..0000000
--- a/core/id.nom
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/usr/bin/env nomsu -V6.14
-#
- A simple UUID function based on RFC 4122: http://www.ietf.org/rfc/rfc4122.txt
-
-use "core/metaprogramming"
-use "core/operators"
-use "core/math"
-use "core/collections"
-use "core/control_flow"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-$NaN_surrogate = {}
-$nil_surrogate = {}
-$obj_by_id = {}
-set $obj_by_id's metatable to {.__mode = "v"}
-$id_by_obj = {}
-set $id_by_obj's metatable to {
- .__mode = "k"
- .__index =
- for ($self $key):
- if ($key == (nil)):
- return $self.$nil_surrogate
-
- if ($key != $key):
- return $self.$NaN_surrogate
-
- --- (retry) ---
- $id = (uuid)
- if ($obj_by_id.$id != (nil)): go to (retry)
- $self.$key = $id
- $obj_by_id.$id = $key
- return $id
-}
-
-externally (uuid) means:
- # Set all the other bits to randomly (or pseudo-randomly) chosen values.
- $bytes = [
- # time-low, time-mid, time-high-and-version
- randint (2 ^ (4 * 8)), randint (2 ^ (2 * 8)), randint (2 ^ (2 * 8 - 4))
- # clock-seq-and-reserved, clock-seq-low
- randint (2 ^ (1 * 8 - 2)), randint (2 ^ (1 * 8)), randint (2 ^ (3 * 8))
- # node
- randint (2 ^ (3 * 8))
- ]
-
- # Set the four most significant bits (bits 12 through 15) of the
- # time_hi_and_version field to the 4-bit version number from
- # Section 4.1.3.
- $bytes.3 += 0x4000
-
- # Set the two most significant bits (bits 6 and 7) of the
- # clock_seq_hi_and_reserved to zero and one, respectively.
- $bytes.4 += 0xC0
- return (=lua "('%08x-%04x-%04x-%02x%02x-%6x%6x'):format(unpack(\$bytes))")
-
-# For strict identity checking, use ($x's id) == ($y's id)
-test:
- assume (([] == []) and ((id of []) != (id of [])))
- seed random with 0
- $x = []
- assume ((id of $x) == (id of $x))
- seed random with 0
- assume ((id of $x) != (id of []))
- seed random
-externally [id of $, $'s id, $'id] all mean $id_by_obj.$
diff --git a/core/init.nom b/core/init.nom
deleted file mode 100644
index 0c8051d..0000000
--- a/core/init.nom
+++ /dev/null
@@ -1,11 +0,0 @@
-# Export everything
-export "core/metaprogramming"
-export "core/operators"
-export "core/control_flow"
-export "core/errors"
-export "core/collections"
-export "core/coroutines"
-export "core/math"
-export "core/id"
-export "core/io"
-export "core/text"
diff --git a/core/io.nom b/core/io.nom
deleted file mode 100644
index 7afe889..0000000
--- a/core/io.nom
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/usr/bin/env nomsu -V6.14
-#
- This file contains basic input/output code
-
-use "core/metaprogramming"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-(say $message) compiles to:
- lua> ("
- if \$message.type == "Text" then
- return LuaCode("say(", \($message as lua expr), ");");
- else
- return LuaCode("say(tostring(", \($message as lua expr), "));");
- end
- ")
-
-(say $message inline) compiles to:
- lua> ("
- if \$message.type == "Text" then
- return LuaCode("io.write(", \($message as lua expr), ")");
- else
- return LuaCode("io.write(tostring(", \($message as lua expr), "))");
- end
- ")
-
-externally (ask $prompt) means:
- $io.write $prompt
- return ($io.read())
diff --git a/core/math.nom b/core/math.nom
deleted file mode 100644
index 685ab1e..0000000
--- a/core/math.nom
+++ /dev/null
@@ -1,212 +0,0 @@
-#!/usr/bin/env nomsu -V6.14
-#
- This file defines some common math literals and functions
-
-use "core/metaprogramming"
-use "core/text"
-use "core/operators"
-use "core/control_flow"
-use "core/collections"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-# Literals:
-test:
- unless (all of [inf, NaN, pi, tau, golden ratio, e]):
- fail "math constants failed"
- $nan = (NaN)
- unless ($nan != $nan):
- fail "NaN failed"
-[infinity, inf] all compile to "math.huge"
-[not a number, NaN, nan] all compile to "(0/0)"
-[pi, Pi, PI] all compile to "math.pi"
-[tau, Tau, TAU] all compile to "(2*math.pi)"
-(golden ratio) compiles to "((1+math.sqrt(5))/2)"
-(e) compiles to "math.exp(1)"
-
-# Functions:
-test:
- assume (("5" as a number) == 5)
-external $($ as a number) = $(tonumber $)
-external $($ as number) = $(tonumber $)
-test:
- unless
- all of [
- abs 5, | 5 |, sqrt 5, √ 5, sine 5, cosine 5, tangent 5, arc sine 5, arc cosine 5
- arc tangent 5, arc tangent 5 / 10, hyperbolic sine 5, hyperbolic cosine 5
- hyperbolic tangent 5, e^ 5, ln 5, log 5 base 2, floor 5, ceiling 5, round 5
- ]
- ..:
- fail "math functions failed"
-external [$(absolute value $), $(absolute value of $), $(| $ |), $(abs $)] =
- [$math.abs, $math.abs, $math.abs, $math.abs]
-external [$(square root $), $(square root of $), $(√ $), $(sqrt $)] =
- [$math.sqrt, $math.sqrt, $math.sqrt, $math.sqrt]
-external [$(sine $), $(sin $)] = [$math.sin, $math.sin]
-external [$(cosine $), $(cos $)] = [$math.cos, $math.cos]
-external [$(tangent $), $(tan $)] = [$math.tan, $math.tan]
-external [$(arc sine $), $(asin $)] = [$math.asin, $math.asin]
-external [$(arc cosine $), $(acos $)] = [$math.acos, $math.acos]
-external [$(arc tangent $), $(atan $)] = [$math.atan, $math.atan]
-external [$(arc tangent $y / $x), $(atan2 $y $x)] = [$math.atan2, $math.atan2]
-external [$(hyperbolic sine $), $(sinh $)] = [$math.sinh, $math.sinh]
-external [$(hyperbolic cosine $), $(cosh $)] = [$math.cosh, $math.cosh]
-external [$(hyperbolic tangent $), $(tanh $)] = [$math.tanh, $math.tanh]
-external [$(e^ $), $(exp $)] = [$math.exp, $math.exp]
-external [$(natural log $), $(ln $), $(log $), $(log $ base $)] = [$math.log, $math.log, $math.log, $math.log]
-external $(floor $) = $math.floor
-external [$(ceiling $), $(ceil $)] = [$math.ceil, $math.ceil]
-externally [round $, $ rounded] all mean
- floor ($ + 0.5)
-test:
- unless ((463 to the nearest 100) == 500): fail "rounding failed"
- unless ((2.6 to the nearest 0.25) == 2.5): fail "rounding failed"
-
-externally ($n to the nearest $rounder) means
- $rounder * (floor ($n / $rounder + 0.5))
-
-# Any/all
-externally [all of $items, all $items] all mean:
- for $ in $items:
- unless $:
- return (no)
- return (yes)
-[not all of $items, not all $items] all parse as (not (all of $items))
-externally [any of $items, any $items] all mean:
- for $ in $items:
- if $:
- return (yes)
- return (no)
-[none of $items, none $items] all parse as (not (any of $items))
-
-# Sum/product
-externally [sum of $items, sum $items] all mean:
- $total = 0
- for $ in $items:
- $total += $
- return $total
-
-externally [product of $items, product $items] all mean:
- $prod = 1
- for $ in $items:
- $prod *= $
- return $prod
-
-externally [avg of $items, average of $items] all mean
- (sum of $items) / (size of $items)
-
-# Min/max
-externally [min of $items, smallest of $items, lowest of $items] all mean:
- $best = (nil)
- for $ in $items:
- if (($best == (nil)) or ($ < $best)): $best = $
- return $best
-
-externally [
- max of $items, biggest of $items, largest of $items, highest of $items
-] all mean:
- $best = (nil)
- for $ in $items:
- if (($best == (nil)) or ($ > $best)): $best = $
- return $best
-
-test:
- assume ((min of [3, -4, 1, 2] by $ = ($ * $)) == 1)
- assume ((max of [3, -4, 1, 2] by $ = ($ * $)) == -4)
-
-(min of $items by $item = $value_expr) parses as
- result of:
- $best = (nil)
- $best_key = (nil)
- for $item in $items:
- $key = $value_expr
- if (($best == (nil)) or ($key < $best_key)):
- $best = $item
- $best_key = $key
- return $best
-
-(max of $items by $item = $value_expr) parses as
- result of:
- $best = (nil)
- $best_key = (nil)
- for $item in $items:
- $key = $value_expr
- if (($best == (nil)) or ($key > $best_key)):
- $best = $item
- $best_key = $key
- return $best
-
-test:
- assume (100 clamped between 0 and 10) == 10
-
-externally ($ clamped between $min and $max) means:
- when:
- ($ < $min):
- return $min
-
- ($ > $max):
- return $max
-
- else:
- return $
-
-test:
- assume (-0.1 smoothed by 2.7) == 0
- assume (0 smoothed by 2.7) == 0
- assume (0.5 smoothed by 2.7) == 0.5
- assume (1 smoothed by 2.7) == 1
- assume (1.1 smoothed by 2.7) == 1
-
-externally ($ smoothed by $smoothness) means:
- $ = ($ clamped between 0 and 1)
- if ($smoothness == 0): return $
- $k = (2 ^ $smoothness)
- if ($ < 0.5):
- return (0.5 * (2 * $) ^ $k)
- ..else:
- return (1 - 0.5 * (2 - 2 * $) ^ $k)
-
-test:
- assume (5 to 7 mixed by -1.0) == 5
- assume (5 to 7 mixed by 0.0) == 5
- assume (5 to 7 mixed by 0.5) == 6
- assume (5 to 7 mixed by 1.0) == 7
- assume (5 to 7 mixed by 2.0) == 7
-
-externally ($lo to $hi mixed by $amount) means:
- $ = ($amount clamped between 0 and 1)
- return ((1 - $) * $lo + $ * $hi)
-
-test:
- assume ([0, 1, 11] mixed by 0.0) == 0
- assume ([0, 1, 11] mixed by 0.25) == 0.5
- assume ([0, 1, 11] mixed by 0.5) == 1
- assume ([0, 1, 11] mixed by 0.75) == 6
- assume ([0, 1, 11] mixed by 1.0) == 11
- assume ([99] mixed by 0.5) == 99
-
-externally ($nums mixed by $amount) means:
- $ = ($amount clamped between 0 and 1)
- $i = (1 + ($ * ((#$nums) - 1)))
- if ((floor $i) == (#$nums)):
- return $nums.(floor $i)
- [$lo, $hi] = [$nums.(floor $i), $nums.(floor ($i + 1))]
- return ($lo to $hi mixed by ($i mod 1))
-
-# Random functions
-externally (seed random with $) means:
- lua> ("
- math.randomseed(\$);
- for i=1,20 do math.random(); end
- ")
-(seed random) parses as (seed random with (=lua "os.time()"))
-[random number, random, rand] all compile to "math.random()"
-[random int $n, random integer $n, randint $n] all compile to
- "math.random(\($n as lua expr))"
-
-[random from $low to $high, random number from $low to $high, rand $low $high]
-..all compile to "math.random(\($low as lua expr), \($high as lua expr))"
-
-externally [
- random choice from $elements, random choice $elements, random $elements
-] all mean (=lua "\$elements[math.random(#\$elements)]")
diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom
deleted file mode 100644
index fa29a8a..0000000
--- a/core/metaprogramming.nom
+++ /dev/null
@@ -1,454 +0,0 @@
-#!/usr/bin/env nomsu -V6.14
-#
- This File contains actions for making actions and compile-time actions and some helper
- functions to make that easier.
-
-lua> "NOMSU_CORE_VERSION = 14"
-lua> "NOMSU_LIB_VERSION = 8"
-lua> ("
- do
- local mangle_index = 0
- function mangler()
- local my_mangle_index = mangle_index
- mangle_index = mangle_index + 1
- return function(varname)
- return (varname..(("\\3%X"):format(my_mangle_index))):as_lua_id()
- end
- end
- end
- COMPILE_RULES["define mangler"] = function(\(nomsu environment))
- return LuaCode("local mangle = mangler()")
- end
-")
-
-lua> ("
- COMPILE_RULES["1 ->"] = function(\(nomsu environment), \$args, \$body)
- if \$args and not \$body then \$args, \$body = {}, \$args end
- local body_lua = SyntaxTree:is_instance(\$body) and \(nomsu environment):compile(\$body) or \$body
- if SyntaxTree:is_instance(\$body) and \$body.type ~= "Block" then body_lua:prepend("\
- ..return ") end
- local lua = LuaCode("(function(")
- if SyntaxTree:is_instance(\$args) and (\$args.type == "Action" or \$args.type == "MethodCall") then
- \$args = \$args:get_args()
- elseif SyntaxTree:is_instance(\$args) and \$args.type == "Var" then \$args = {\$args} end
- for i, arg in ipairs(\$args) do
- local arg_lua = SyntaxTree:is_instance(arg) and \(nomsu environment):compile(arg):text() or arg
- if arg_lua == "..." then
- if i < #\$args then
- compile_error_at(SyntaxTree:is_instance(arg) and arg or nil,
- "Extra arguments must come last.", "Try removing any arguments after \
- ..(*extra arguments*)")
- end
- elseif not arg_lua:is_lua_id() then
- compile_error_at(SyntaxTree:is_instance(arg) and arg or nil,
- "This does not compile to a Lua identifier, so it can't be used as a function \
- ..argument.",
- "This should probably be a Nomsu variable instead (like $x).")
- end
- lua:add(i > 1 and ", " or "", arg_lua)
- body_lua:remove_free_vars({arg_lua})
- end
- body_lua:declare_locals()
- lua:add(")\\n ", body_lua, "\\nend)")
- return lua
- end
- COMPILE_RULES["->"] = COMPILE_RULES["1 ->"]
- COMPILE_RULES["for"] = COMPILE_RULES["1 ->"]
-")
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-test:
- (five) compiles to "5"
-
-test:
- unless ((five) == 5):
- fail "Compile to expression failed."
- (loc x) compiles to "local x = 99;"
-
-test:
- lua> "do"
- loc x
- unless ($x is 99):
- fail "Compile to statements with locals failed."
- lua> "end"
- unless ($x is (nil)):
- fail "Failed to properly localize a variable."
-
- (asdf) compiles to:
- $tmp = ""
- return (Lua $tmp)
-
-test:
- asdf
- unless ($tmp is (nil)):
- fail "compile to is leaking variables"
-
-lua> ("
- COMPILE_RULES["1 compiles to"] = function(env, \$action, \$body)
- local \$args = List{"\(nomsu environment)", unpack(\$action:get_args())}
- if \$body.type == "Text" then
- \$body = SyntaxTree{source=\$body.source, type="Action", "Lua", \$body}
- end
- return LuaCode("COMPILE_RULES[", \$action:get_stub():as_lua(),
- "] = ", \(\($args -> $body) as lua))
- end
-")
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-($actions all compile to $body) compiles to:
- lua> ("
- if \$actions.type ~= "List" then
- compile_error(\$actions, "This should be a list of actions.")
- end
- local lua = \(\($actions.1 compiles to $body) as lua)
- local \$args = List{"\(nomsu environment)", unpack(\$actions[1]:get_args())}
- local \$compiled_args = List{"\(nomsu environment)"};
- for i=2,#\$args do \$compiled_args[i] = \(nomsu environment):compile(\$args[i]) end
- for i=2,#\$actions do
- local alias = \$actions[i]
- local \$alias_args = List{"\(nomsu environment)", unpack(alias:get_args())}
- lua:add("\\nCOMPILE_RULES[", alias:get_stub():as_lua(), "] = ")
- if \$alias_args == \$args then
- lua:add("COMPILE_RULES[", \$actions[1]:get_stub():as_lua(), "]")
- else
- lua:add("function(")
- local \$compiled_alias_args = List{"\(nomsu environment)"};
- for i=2,#\$alias_args do \$compiled_alias_args[i] = \(nomsu environment):compile(\$alias_args[i]) end
- lua:concat_add(\$compiled_alias_args, ", ")
- lua:add(") return COMPILE_RULES[", \$actions[1]:get_stub():as_lua(), "](")
- lua:concat_add(\$compiled_args, ", ")
- lua:add(") end")
- end
- end
- return lua
- ")
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-test:
- (foo $x) means "outer"
- with [$(foo $)]:
- (foo $x) means:
- $y = ($x + 1)
- return $y
-
- unless ((foo 10) == 11):
- fail "Action didn't work."
-
- unless ($y is (nil)):
- fail "Action leaked a local into globals."
-
- (baz $) parses as (foo $)
- assume ((foo 1) == "outer")
-
-($action means $body) compiles to:
- lua> ("
-
- local lua = LuaCode()
- if \$action.type == "MethodCall" then
- lua:add(\(nomsu environment):compile(\$action[1]), ".", \$action[2]:get_stub():as_lua_id())
- elseif \$action.type == "Action" then
- lua:add(\$action:get_stub():as_lua_id())
- lua:add_free_vars({\$action:get_stub():as_lua_id()})
- else
- compile_error_at(\$action, "Expected an action or method call here")
- end
- lua:add(" = ", \(\($action -> $body) as lua), ";")
- return lua
- ")
-
-($actions all mean $body) compiles to:
- lua> ("
- local lua = \(\($actions.1 means $body) as lua)
- local first_def = (\$actions[1].type == "MethodCall"
- and LuaCode(\(nomsu environment):compile(\$actions[1][1]), ".", \$actions[1]:get_stub():as_lua_id())
- or LuaCode(\$actions[1]:get_stub():as_lua_id()))
- local \$args = List(\$actions[1]:get_args())
- for i=2,#\$actions do
- local alias = \$actions[i]
- local \$alias_args = List(alias:get_args())
- lua:add("\\n")
- if alias.type == "MethodCall" then
- lua:add(\(nomsu environment):compile(alias[1]), ".", alias:get_stub():as_lua_id())
- else
- lua:add(alias:get_stub():as_lua_id())
- lua:add_free_vars({alias_name})
- end
- if \$args == \$alias_args then
- lua:add(" = ", first_def, ";")
- else
- lua:add(" = ", \(\($alias_args -> $actions.1) as lua), ";")
- end
- end
- return lua
- ")
-
-test:
- externally (baz1) means:
- return "baz1"
- externally (baz2) means "baz2"
-
-test:
- assume ((baz1) == "baz1")
- assume ((baz2) == "baz2")
-
-(externally $action means $body) compiles to:
- lua> ("
- local lua = \(\($action means $body) as lua)
- lua:remove_free_vars({\$action:get_stub():as_lua_id()})
- return lua
- ")
-
-(externally $actions all mean $body) compiles to:
- lua> ("
- local lua = \(\($actions all mean $body) as lua)
- lua:remove_free_vars(table.map(\$actions, function(a) return a:get_stub():as_lua_id() end))
- return lua
- ")
-
-test:
- (swap $x and $y) parses as
- do:
- $tmp = $x
- $x = $y
- $y = $tmp
-
-test:
- [$1, $2] = [1, 2]
- swap $1 and $2
- unless (($1 == 2) and ($2 == 1)):
- fail "'parse $ as $' failed on 'swap $ and $'"
- [$tmp, $tmp2] = [1, 2]
- swap $tmp and $tmp2
- unless (($tmp == 2) and ($tmp2 == 1)):
- fail "'parse $ as $' variable mangling failed."
-
-($actions all parse as $body) compiles to:
- lua> ("
- local replacements = {}
- if \$actions.type ~= "List" then
- compile_error(\$actions, "This should be a list.")
- end
- for i,arg in ipairs(\$actions[1]:get_args()) do
- replacements[arg[1]] = \(nomsu environment):compile(arg):text()
- end
- local function make_tree(t)
- if SyntaxTree:is_instance(t) and t.type == "Var" then
- if replacements[t:as_var()] then
- return replacements[t:as_var()]
- else
- return "SyntaxTree{mangle("..t:as_var():as_lua().."), type="..t.type:as_lua()..", \
- ..source="..tostring(t.source):as_lua().."}"
- end
- elseif SyntaxTree:is_instance(t) then
- local ret = {}
- local i = 1
- for k, v in pairs(t) do
- if k == i then
- ret[#ret+1] = make_tree(t[i])
- i = i + 1
- elseif k == "source" then
- ret[#ret+1] = k.."= "..tostring(v):as_lua()
- elseif lua_type_of(k) == 'string' and k:is_a_lua_id() then
- ret[#ret+1] = k.."= "..make_tree(v)
- else
- ret[#ret+1] = "["..make_tree(k).."]= "..make_tree(v)
- end
- end
- return "SyntaxTree{"..table.concat(ret, ", ").."}"
- elseif lua_type_of(t) == 'number' then
- return tostring(t)
- else
- return t:as_lua()
- end
- end
- local \$new_body = LuaCode:from(\$body.source,
- "local mangle = mangler()",
- "\\nreturn ", make_tree(\$body))
- local ret = \(\($actions all compile to $new_body) as lua)
- return ret
- ")
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-[$action parses as $body] all parse as ([$action] all parse as $body)
-externally ($tree as lua expr) means:
- lua> ("
- local tree_lua = \(nomsu environment):compile(\$tree)
- if \$tree.type == 'Block' then
- tree_lua = LuaCode:from(\$tree.source, '(function()\\n ', tree_lua, '\\nend)()')
- elseif \$tree.type == 'MethodCall' and #\$tree > 2 then
- compile_error_at(\$tree, "This must be a single value instead of "..(#\$tree - 1).."\
- .. method calls.",
- "Replace this with a single method call.")
- end
- return tree_lua
- ")
-
-externally [$var as lua identifier, $var as lua id] all mean:
- lua> ("
- local lua = \($var as lua)
- if not lua:text():is_a_lua_id() then
- compile_error(\$var,
- "This is supposed to be something that compiles to a valid Lua identifier.",
- "This should probably be a variable.")
- end
- return lua
- ")
-
-test:
- (num args (*extra arguments*)) means (select "#" (*extra arguments*))
- assume (num args 1 2 3) == 3
- (extra args (*extra arguments*)) means [*extra arguments*]
- assume (extra args 1 2 3) == [1, 2, 3]
- (third arg (*extra arguments*)) means (select 3 (*extra arguments*))
- assume (third arg 5 6 7 8) == 7
-
-(*extra arguments*) compiles to "..."
-
-($ is syntax tree) compiles to "SyntaxTree:is_instance(\($ as lua expr))"
-
-externally ($ is $kind syntax tree) means
- =lua "SyntaxTree:is_instance(\$) and \$.type == \$kind"
-
-($tree with $t -> $replacement) compiles to ("
- \($tree as lua expr):map(function(\($t as lua expr))
- \(
- =lua ("
- \$replacement.type == 'Block' and \($replacement as lua) or 'return '..\
- ..\($replacement as lua expr):text()
- ")
- )
- end)
-")
-
-externally ($tree with vars $replacements) means
- =lua ("
- \$tree:map(function(\$t)
- if \$t.type == "Var" then
- return \$replacements[\$t:as_var()]
- end
- end)
- ")
-
-(tree $tree with vars $replacements) compiles to ("
- \(=lua "(\$tree):as_lua()"):map(function(t)
- if t.type == "Var" then
- return \($replacements as lua expr)[t:as_var()]
- end
- end)
-")
-
-($tree has subtree $match_tree) compiles to ("
- (function()
- local match_tree = \($match_tree as lua expr)
- for subtree in coroutine_wrap(function() \($tree as lua expr):map(yield) end) do
- if subtree == match_tree then return true end
- end
- end)()
-")
-
-externally (match $tree with $patt) means:
- lua> ("
- if \$patt.type == "Var" then return Dict{[\$patt:as_var()]=\$tree} end
- if \$patt.type == "Action" and \$patt:get_stub() ~= \$tree:get_stub() then return nil end
- if #\$patt ~= #\$tree then return nil end
- local matches = Dict{}
- for \($i)=1,#\$patt do
- if SyntaxTree:is_instance(\$tree[\$i]) then
- local submatch = \(match $tree.$i with $patt.$i)
- if not submatch then return nil end
- for k,v in pairs(submatch) do
- if matches[k] and matches[k] ~= v then return nil end
- matches[k] = v
- end
- end
- end
- return matches
- ")
-
-test:
- assume
- (
- quote ("
- one
- "two"
- ")
- ) == "\"one\\n\\\"two\\\"\""
-
-(quote $s) compiles to "tostring(\($s as lua expr)):as_lua()"
-test:
- assume (lua type of {}) == "table"
- assume (type of {}) == "Dict"
- assume ({} is a "Dict")
- assume ("" is text)
- assume ("" isn't a "Dict")
-externally ($ is text) means (=lua "\(lua type of $) == 'string'")
-externally [$ is not text, $ isn't text] all mean
- =lua "\(lua type of $) ~= 'string'"
-
-externally (type of $) means:
- lua> ("
- local lua_type = \(lua type of $)
- if lua_type == 'string' then return 'Text'
- elseif lua_type == 'table' or lua_type == 'userdata' then
- local mt = getmetatable(\$)
- if mt and mt.__type then return mt.__type end
- end
- return lua_type
- ")
-
-[$ is a $type, $ is an $type] all parse as ((type of $) == $type)
-[$ isn't a $type, $ isn't an $type, $ is not a $type, $ is not an $type]
-..all parse as ((type of $) != $type)
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-test:
- (foo) means:
- return 100 200 300
- assume (select 2 (foo)) == 200
-
-# Return statement is wrapped in a do..end block because Lua is unhappy if you
- put code after a return statement, unless you wrap it in a block.
-(return (*extra arguments*)) compiles to:
- lua> ("
- local lua = \(Lua "do return ")
- for i=1,select('#',...) do
- if i > 1 then lua:add(", ") end
- lua:add(\(nomsu environment):compile((select(i, ...))))
- end
- lua:add(" end")
- return lua
- ")
-
-# Literals
-(yes) compiles to "true"
-(no) compiles to "false"
-[nothing, nil, null] all compile to "nil"
-(Nomsu syntax version) compiles to "NOMSU_SYNTAX_VERSION"
-(Nomsu compiler version) compiles to "NOMSU_COMPILER_VERSION"
-(core version) compiles to "NOMSU_CORE_VERSION"
-(lib version) compiles to "NOMSU_LIB_VERSION"
-(command line args) compiles to "COMMAND_LINE_ARGS"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-#
- (with local compile actions $body) compiles to ("
- do
- local OLD_RULES = COMPILE_RULES
- local OLD_ENV = \(nomsu environment)
- local \(nomsu environment) = setmetatable({
- COMPILE_RULES=setmetatable({}, {__index=OLD_RULES})
- }, {__index=OLD_ENV})
- \($body as lua)
- end
- ")
-
-externally (Nomsu version) means:
- return ("
- \(Nomsu syntax version).\(core version).\(Nomsu compiler version).\(lib version)
- ")
diff --git a/core/operators.nom b/core/operators.nom
deleted file mode 100644
index dee76b6..0000000
--- a/core/operators.nom
+++ /dev/null
@@ -1,263 +0,0 @@
-#!/usr/bin/env nomsu -V6.14
-#
- This file contains definitions of operators like "+" and "and".
-
-use "core/metaprogramming"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-test:
- assume (all [1 < 2, 2 > 1, 1 <= 2, 2 >= 1, 1 == 1, 1 != 2])
-
-# Comparison Operators
-($x < $y) compiles to "(\($x as lua expr) < \($y as lua expr))"
-($x > $y) compiles to "(\($x as lua expr) > \($y as lua expr))"
-($x <= $y) compiles to "(\($x as lua expr) <= \($y as lua expr))"
-($x >= $y) compiles to "(\($x as lua expr) >= \($y as lua expr))"
-[$a is $b, $a == $b] all compile to "(\($a as lua expr) == \($b as lua expr))"
-[$a isn't $b, $a is not $b, $a not= $b, $a != $b] all compile to
- "(\($a as lua expr) ~= \($b as lua expr))"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-test:
- $x = 10
- assume ($x == 10)
- [$x, $y] = [10, 20]
- unless (($x == 10) and ($y == 20)):
- fail "mutli-assignment failed."
- [$x, $y] = [$y, $x]
- unless (($y == 10) and ($x == 20)):
- fail "swapping vars failed."
- $vals = [4, 5]
- [$x, $y] = (unpack $vals)
- unless (($x == 4) and ($y == 5)):
- fail "unpacking failed"
-
-# Variable assignment operator
-($var = $value) compiles to:
- lua> ("
- local lua = LuaCode()
- if \$var.type == "List" then
- for i, \$assignment in ipairs(\$var) do
- if i > 1 then lua:add(", ") end
- local assignment_lua = \($assignment as lua expr)
- lua:add(assignment_lua)
- if \$assignment.type == 'Var' then
- lua:add_free_vars({assignment_lua:text()})
- end
- end
- lua:add(' = ')
- if \$value.type == "List" then
- if #\$value ~= #\$var then
- compile_error_at(\$value,
- "This assignment has too "..(#\$value > #\$var and "many" or "few").." values.",
- "Make sure it has the same number of values on the left and right hand side \
- ..of the '=' operator.")
- end
- for i, \$val in ipairs(\$value) do
- if i > 1 then lua:add(", ") end
- local val_lua = \($val as lua expr)
- lua:add(val_lua)
- end
- lua:add(";")
- else
- lua:add(\($value as lua expr), ';')
- end
- else
- local var_lua = \($var as lua expr)
- lua:add(var_lua)
- if \$var.type == 'Var' then
- lua:add_free_vars({var_lua:text()})
- end
- lua:add(' = ', \($value as lua expr))
- end
- return lua
- ")
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-test:
- [$foozle, $y] = ["outer", "outer"]
- externally (set global x local y) means:
- external $foozle = "inner"
- $y = "inner"
- set global x local y
- unless (($foozle == "inner") and ($y == "outer")): fail "external failed."
-(external $var = $value) compiles to:
- $lua = ((SyntaxTree {.type = "Action", .source = $var.source, .1 = $var, .2 = "=", .3 = $value}) as lua)
- $lua, remove free vars
- return $lua
-test:
- [$foozle, $y] = ["outer", "outer"]
- externally (set global x local y) means:
- with external [$foozle]:
- $foozle = "inner"
- $y = "inner"
- set global x local y
- unless (($foozle == "inner") and ($y == "outer")):
- fail "'with external' failed."
-
-(with external $externs $body) compiles to:
- $body_lua = ($body as lua)
- lua> ("
- \$body_lua:remove_free_vars(table.map(\$externs, function(v) return \(nomsu environment):compile(v):text() end))
- ")
- return $body_lua
-
-test:
- [$x, $y] = [1, 2]
- with [$z, $x = 999]:
- assume $z == (nil)
- $z = 999
- unless ($z == 999):
- fail "'with' failed."
-
- unless ($x == 999):
- fail "'with' assignment failed."
-
- unless ($x == 1):
- fail "'with' scoping failed"
-
- unless ($z == (nil)):
- fail "'with' scoping failed"
-
-(with $assignments $body) compiles to:
- lua> ("
- local \$defs = LuaCode()
- for i, \$item in ipairs(\$assignments) do
- if i > 1 then \$defs:add("\\n") end
- local item_lua = \($item as lua)
- if \$item.type == 'Action' and \$item.stub == '1 =' then
- item_lua:remove_free_vars(item_lua.free_vars)
- end
- \$defs:add("local ", item_lua, ";")
- end
- ")
-
- return
- Lua ("
- do
- \$defs
- \($body as lua)
- end -- 'with' block
- ")
-
-# Math Operators
-test:
- unless ((5 wrapped around 2) == 1):
- fail "mod not working"
-
-[$x wrapped around $y, $x mod $y] all compile to
- "((\($x as lua expr)) % (\($y as lua expr)))"
-
-# 3-part chained comparisons
-# (uses a lambda to avoid re-evaluating middle value, while still being an expression)
-test:
- $calls = 0
- (one) means:
- external $calls = ($calls + 1)
- return 1
-
- unless (0 <= (one) <= 2):
- fail "Three-way chained comparison failed."
-
- unless ($calls == 1):
- fail "Three-way comparison evaluated middle value multiple times"
-($x < $y < $z) parses as ((($a $b $c) -> (($a < $b) and ($b < $c))) $x $y $z)
-($x <= $y < $z) parses as ((($a $b $c) -> (($a <= $b) and ($b < $c))) $x $y $z)
-($x < $y <= $z) parses as ((($a $b $c) -> (($a < $b) and ($b <= $c))) $x $y $z)
-($x <= $y <= $z) parses as ((($a $b $c) -> (($a <= $b) and ($b <= $c))) $x $y $z)
-($x > $y > $z) parses as ((($a $b $c) -> (($a > $b) and ($b > $c))) $x $y $z)
-($x >= $y > $z) parses as ((($a $b $c) -> (($a >= $b) and ($b > $c))) $x $y $z)
-($x > $y >= $z) parses as ((($a $b $c) -> (($a > $b) and ($b >= $c))) $x $y $z)
-($x >= $y >= $z) parses as ((($a $b $c) -> (($a >= $b) and ($b >= $c))) $x $y $z)
-
-# TODO: optimize for common case where x,y,z are all either variables or number literals
-# Boolean Operators
-test:
- (barfer) means (fail "short circuiting failed")
- assume (((no) and (barfer)) == (no))
- assume ((no) or (yes))
- assume ((yes) or (barfer))
-($x and $y) compiles to "(\($x as lua expr) and \($y as lua expr))"
-($x or $y) compiles to "(\($x as lua expr) or \($y as lua expr))"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-# Bitwise Operators
-# TODO: implement OR, XOR, AND for multiple operands?
-test:
- assume ((~ (~ 5)) == 5)
- assume ((1 | 4) == 5)
- assume ((1 ~ 3) == 2)
- assume ((1 & 3) == 1)
- assume ((1 << 2) == 4)
- assume ((4 >> 2) == 1)
-
-# Lua 5.3 introduced bit operators like | and &. Use them when possible, otherwise
- fall back to bit.bor(), bit.band(), etc.
-lua> "if \((is jit) or ((Lua version) == "Lua 5.2")) then"
-[NOT $, ~ $] all compile to "bit.bnot(\($ as lua expr))"
-[$x OR $y, $x | $y] all compile to
- "bit.bor(\($x as lua expr), \($y as lua expr))"
-
-[$x XOR $y, $x ~ $y] all compile to
- "bit.bxor(\($x as lua expr), \($y as lua expr))"
-
-[$x AND $y, $x & $y] all compile to
- "bit.band(\($x as lua expr), \($y as lua expr))"
-
-[$x LSHIFT $shift, $x << $shift] all compile to
- "bit.lshift(\($x as lua expr), \($shift as lua expr))"
-
-[$x RSHIFT $shift, $x >> $shift] all compile to
- "bit.rshift(\($x as lua expr), \($shift as lua expr))"
-
-lua> "else"
-[NOT $, ~ $] all compile to "~(\($ as lua expr))"
-[$x OR $y, $x | $y] all compile to "(\($x as lua expr) | \($y as lua expr))"
-[$x XOR $y, $x ~ $y] all compile to "(\($x as lua expr) ~ \($y as lua expr))"
-[$x AND $y, $x & $y] all compile to "(\($x as lua expr) & \($y as lua expr))"
-[$x LSHIFT $shift, $x << $shift] all compile to
- "(\($x as lua expr) << \($shift as lua expr))"
-
-[$x RSHIFT $shift, $x >> $shift] all compile to
- "(\($x as lua expr) >> \($shift as lua expr))"
-
-lua> "end"
-
-# Unary operators
-test:
- assume ((- 5) == -5)
- assume ((not (yes)) == (no))
-(- $) compiles to "(- \($ as lua expr))"
-(not $) compiles to "(not \($ as lua expr))"
-test:
- assume ((size of [1, 2, 3]) == 3)
- assume ((#[1, 2, 3]) == 3)
-[#$list, size of $list] all compile to "(#\($list as lua expr))"
-($list is empty) compiles to "(#\($list as lua expr) == 0)"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-# Update operators
-test:
- $x = 1
- $x += 1
- unless ($x == 2):
- fail "+= failed"
- $x *= 2
- unless ($x == 4):
- fail "*= failed"
- wrap $x around 3
- unless ($x == 1):
- fail "wrap around failed"
-($var += $) parses as ($var = (($var or 0) + $))
-($var -= $) parses as ($var = (($var or 0) - $))
-($var *= $) parses as ($var = (($var or 1) * $))
-($var /= $) parses as ($var = ($var / $))
-($var ^= $) parses as ($var = ($var ^ $))
-($var and= $) parses as ($var = ($var and $))
-($var or= $) parses as ($var = ($var or $))
-(wrap $var around $) parses as ($var = ($var wrapped around $))
diff --git a/core/text.nom b/core/text.nom
deleted file mode 100644
index 1351af6..0000000
--- a/core/text.nom
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/usr/bin/env nomsu -V6.14
-#
- This file contains some definitions of text escape sequences, including ANSI console
- color codes.
-
-use "core/metaprogramming"
-use "core/operators"
-use "core/control_flow"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-test:
- assume "\[1, 2, 3]" == "[1, 2, 3]"
- assume "foo = \(1 + 2)!" == "foo = 3!"
- assume ("
- one
- two
- ") == ("
- one
- two
- ")
- assume "nogap" == "nogap"
- assume (["x", "y"], joined with ",") == "x,y"
- assume (["x", "y"], joined) == "xy"
- assume ("BAR", byte 2) == 65
- assume ("BAR", bytes 1 to 2) == [66, 65]
- assume ("asdf", capitalized) == "Asdf"
- assume ("asdf", uppercase) == "ASDF"
- assume ("asdf", with "s" -> "X") == "aXdf"
- assume
- ("
- one
- two
-
- "), lines
- ..== ["one", "two", ""]
-
- ($spec とは $body) parses as ($spec means $body)
-
-test:
- $こんにちは = "こんにちは"
- ($ と言う) とは "\($)世界"
- assume ($こんにちは と言う) == "こんにちは世界"
-
-($expr for $match in $text matching $patt) compiles to:
- define mangler
- return
- Lua ("
- (function()
- local \(mangle "comprehension") = List{}
- for \($match as lua expr) in (\($text as lua expr)):gmatch(\($patt as lua expr)) do
- \(mangle "comprehension")[#\(mangle "comprehension")+1] = \($expr as lua)
- end
- return \(mangle "comprehension")
- end)()
- ")
-
-test:
- assume "\n" == (newline)
-
-test:
- assume (0xDEADBEEF as hex) == "0xDEADBEEF"
-
-externally ($num as hex) means:
- if ($num < 0):
- return ("-0x%X", formatted with (- $num))
- ..else:
- return ("0x%X", formatted with $num)
-
-# Text literals
-$escapes = {
- .nl = "\n", .newline = "\n", .tab = "\t", .bell = "\a", .cr = "\r", ."carriage return" = "\r"
- .backspace = "\b", ."form feed" = "\f", .formfeed = "\f", ."vertical tab" = "\v"
-}
-
-for $name = $str in $escapes:
- with [$lua = (Lua (quote $str))]:
- $(COMPILE RULES).$name = (-> $lua)