diff options
Diffstat (limited to 'lib/core')
| -rw-r--r-- | lib/core/collections.nom | 62 | ||||
| -rw-r--r-- | lib/core/control_flow.nom | 3 | ||||
| -rw-r--r-- | lib/core/coroutines.nom | 2 | ||||
| -rw-r--r-- | lib/core/errors.nom | 4 | ||||
| -rw-r--r-- | lib/core/id.nom | 63 | ||||
| -rw-r--r-- | lib/core/init.nom | 2 | ||||
| -rw-r--r-- | lib/core/io.nom | 45 | ||||
| -rw-r--r-- | lib/core/math.nom | 392 | ||||
| -rw-r--r-- | lib/core/metaprogramming.nom | 217 | ||||
| -rw-r--r-- | lib/core/operators.nom | 33 | ||||
| -rw-r--r-- | lib/core/text.nom | 19 |
11 files changed, 412 insertions, 430 deletions
diff --git a/lib/core/collections.nom b/lib/core/collections.nom index 4cf54cd..dbe6900 100644 --- a/lib/core/collections.nom +++ b/lib/core/collections.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V6.14 +#!/usr/bin/env nomsu -V6.15.13.8 # This file contains code that supports manipulating and using collections like lists and dictionaries. @@ -45,19 +45,6 @@ test: 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 [ @@ -118,28 +105,29 @@ test: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -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: +external: + test: + assume ((sorted [3, 1, 2]) == [1, 2, 3]) + + [$items sorted, sorted $items] all mean: $copy = [: for $ in $items: add $] - sort $copy by $item = $key + sort $copy 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 + + [$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]) + + (unique $items) means: + $unique = [] + $seen = {} + for $ in $items: + unless $seen.$: + $unique, add $ + $seen.$ = (yes) + return $unique diff --git a/lib/core/control_flow.nom b/lib/core/control_flow.nom index b0c4f27..715630b 100644 --- a/lib/core/control_flow.nom +++ b/lib/core/control_flow.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V6.14 +#!/usr/bin/env nomsu -V6.15.13.8 # This file contains compile-time actions that define basic control flow structures like "if" statements and loops. @@ -466,6 +466,7 @@ test: # 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 (" diff --git a/lib/core/coroutines.nom b/lib/core/coroutines.nom index 6a99f7e..3bfb346 100644 --- a/lib/core/coroutines.nom +++ b/lib/core/coroutines.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V6.14 +#!/usr/bin/env nomsu -V6.15.13.8 # This file defines the code that creates and manipulates coroutines diff --git a/lib/core/errors.nom b/lib/core/errors.nom index 950de49..9a2cc9b 100644 --- a/lib/core/errors.nom +++ b/lib/core/errors.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V6.14 +#!/usr/bin/env nomsu -V6.15.13.8 # This file contains basic error reporting code @@ -23,9 +23,7 @@ use "core/control_flow" (assume $a == $b) compiles to: lua> "local \$assumption = 'Assumption failed: '..tostring(\(\($a == $b) as nomsu))" - define mangler - return Lua (" do diff --git a/lib/core/id.nom b/lib/core/id.nom index d2427b5..936fd40 100644 --- a/lib/core/id.nom +++ b/lib/core/id.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V6.14 +#!/usr/bin/env nomsu -V6.15.13.8 # A simple UUID function based on RFC 4122: http://www.ietf.org/rfc/rfc4122.txt @@ -33,34 +33,35 @@ set $id_by_obj's metatable to { 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)) - ] +external: + (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))") - # 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.$ + # 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 + [id of $, $'s id, $'id] all mean $id_by_obj.$ diff --git a/lib/core/init.nom b/lib/core/init.nom index 5b1074f..1319c5f 100644 --- a/lib/core/init.nom +++ b/lib/core/init.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V6.14.13.8 +#!/usr/bin/env nomsu -V6.15.13.8 # Export everything export "core/metaprogramming" export "core/operators" diff --git a/lib/core/io.nom b/lib/core/io.nom index 7afe889..90cfbd4 100644 --- a/lib/core/io.nom +++ b/lib/core/io.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V6.14 +#!/usr/bin/env nomsu -V6.15.13.8 # This file contains basic input/output code @@ -6,24 +6,25 @@ 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()) +external: + (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 + ") + + (ask $prompt) means: + $io.write $prompt + return ($io.read()) diff --git a/lib/core/math.nom b/lib/core/math.nom index 685ab1e..e2c759a 100644 --- a/lib/core/math.nom +++ b/lib/core/math.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V6.14 +#!/usr/bin/env nomsu -V6.15.13.8 # This file defines some common math literals and functions @@ -10,203 +10,201 @@ 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: +external: + # 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) + $($ as a number) = $(tonumber $) + $($ 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" + + [$(absolute value $), $(absolute value of $), $(| $ |), $(abs $)] = + [$math.abs, $math.abs, $math.abs, $math.abs] + + [$(square root $), $(square root of $), $(√ $), $(sqrt $)] = + [$math.sqrt, $math.sqrt, $math.sqrt, $math.sqrt] + + [$(sine $), $(sin $)] = [$math.sin, $math.sin] + [$(cosine $), $(cos $)] = [$math.cos, $math.cos] + [$(tangent $), $(tan $)] = [$math.tan, $math.tan] + [$(arc sine $), $(asin $)] = [$math.asin, $math.asin] + [$(arc cosine $), $(acos $)] = [$math.acos, $math.acos] + [$(arc tangent $), $(atan $)] = [$math.atan, $math.atan] + [$(arc tangent $y / $x), $(atan2 $y $x)] = [$math.atan2, $math.atan2] + [$(hyperbolic sine $), $(sinh $)] = [$math.sinh, $math.sinh] + [$(hyperbolic cosine $), $(cosh $)] = [$math.cosh, $math.cosh] + [$(hyperbolic tangent $), $(tanh $)] = [$math.tanh, $math.tanh] + [$(e^ $), $(exp $)] = [$math.exp, $math.exp] + [$(natural log $), $(ln $), $(log $), $(log $ base $)] = + [$math.log, $math.log, $math.log, $math.log] + $(floor $) = $math.floor + [$(ceiling $), $(ceil $)] = [$math.ceil, $math.ceil] + [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" + ($n to the nearest $rounder) means ($rounder * (floor ($n / $rounder + 0.5))) + + # Any/all + [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)) + [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 + [sum of $items, sum $items] all mean: + $total = 0 + for $ in $items: + $total += $ + return $total + + [product of $items, product $items] all mean: + $prod = 1 + for $ in $items: + $prod *= $ + return $prod + + [avg of $items, average of $items] all mean ((sum of $items) / (size of $items)) + + # Min/max + [min of $items, smallest of $items, lowest of $items] all mean: $best = (nil) - $best_key = (nil) - for $item in $items: - $key = $value_expr - if (($best == (nil)) or ($key < $best_key)): - $best = $item - $best_key = $key + for $ in $items: + if (($best == (nil)) or ($ < $best)): $best = $ return $best - -(max of $items by $item = $value_expr) parses as - result of: + + [max of $items, biggest of $items, largest of $items, highest of $items] all mean: $best = (nil) - $best_key = (nil) - for $item in $items: - $key = $value_expr - if (($best == (nil)) or ($key > $best_key)): - $best = $item - $best_key = $key + for $ in $items: + if (($best == (nil)) or ($ > $best)): $best = $ 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)]") + + 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 + + ($ 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 + + ($ 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) == 5 + assume (5 to 7 mixed by 0) == 5 + assume (5 to 7 mixed by 0.5) == 6 + assume (5 to 7 mixed by 1) == 7 + assume (5 to 7 mixed by 2) == 7 + + ($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 + 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) == 11 + assume ([99] mixed by 0.5) == 99 + + ($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 + (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))" + + [random choice from $elements, random choice $elements, random $elements] + ..all mean (=lua "\$elements[math.random(#\$elements)]") diff --git a/lib/core/metaprogramming.nom b/lib/core/metaprogramming.nom index 936f9bd..9b3d5c4 100644 --- a/lib/core/metaprogramming.nom +++ b/lib/core/metaprogramming.nom @@ -1,9 +1,9 @@ -#!/usr/bin/env nomsu -V6.14 +#!/usr/bin/env nomsu -V6.15.13.8 # 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_CORE_VERSION = 15" lua> "NOMSU_LIB_VERSION = 8" lua> (" do @@ -25,8 +25,7 @@ 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 + 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() @@ -41,8 +40,7 @@ lua> (" 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 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) @@ -186,26 +184,40 @@ test: ") test: - externally (baz1) means: - return "baz1" - externally (baz2) means "baz2" + $loc = 99 + external ($glob = 99) test: - assume ((baz1) == "baz1") - assume ((baz2) == "baz2") + assume $loc == (nil) + assume $glob == 99 -(externally $action means $body) compiles to: +(external $body) compiles to: lua> (" - local lua = \(\($action means $body) as lua) - lua:remove_free_vars({\$action:get_stub():as_lua_id()}) + local lua = \($body as lua) + lua:remove_free_vars() return lua ") -(externally $actions all mean $body) compiles to: +test: + [$x, $y] = ["outer", "outer"] + external: + (set external x local y) means: + with external [$x]: + $x = "inner" + $y = "inner" + set external x local y + unless (($x == "inner") and ($y == "outer")): + fail "'with external' failed." + +(with external $externals $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 + local body_lua = \($body as lua) + local varnames = {} + for i,\$v in ipairs(\$externals) do + varnames[i] = \($v as lua):text() + end + body_lua:remove_free_vars(varnames) + return body_lua ") test: @@ -239,8 +251,8 @@ test: 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().."}" + 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 = {} @@ -274,34 +286,37 @@ test: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [$action parses as $body] all parse as ([$action] all parse as $body) -externally (in (nomsu environment) $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 - ") +external: + (in (nomsu environment) $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 + ") # Need to make sure the proper environment is used for compilation (i.e. the caller's environment) -($tree as lua expr) compiles to (\(in \(nomsu environment) $tree as lua expr) as lua) +($tree as lua expr) compiles to + \(in \(nomsu environment) $tree as lua expr) as 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 - ") +external: + [$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*)) @@ -312,11 +327,10 @@ test: 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" +external: + ($ 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)) @@ -329,14 +343,15 @@ externally ($ is $kind syntax tree) means end) ") -externally ($tree with vars $replacements) means - =lua (" - \$tree:map(function(\$t) - if \$t.type == "Var" then - return \$replacements[\$t:as_var()] - end - end) - ") +external: + ($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) @@ -355,24 +370,25 @@ externally ($tree with vars $replacements) means 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 +external: + (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 - end - return matches - ") + return matches + ") test: assume @@ -390,20 +406,20 @@ test: 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 - ") +external: + ($ is text) means (=lua "\(lua type of $) == 'string'") + [$ is not text, $ isn't text] all mean (=lua "\(lua type of $) ~= 'string'") + (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] @@ -441,19 +457,24 @@ test: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# - (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 +test: + using compile rules: + (yes) compiles to "3" + assume $(COMPILE RULES).yes + ..do: + assume (yes) == 3 + assume (yes) == (=lua "true") + +(using compile rules $rules do $body) compiles to: + lua> (" + local env = \(new environment) + env:run(\$rules) + local lua = env:compile(\$body) + return lua ") -externally (Nomsu version) means: - return (" - \(Nomsu syntax version).\(core version).\(Nomsu compiler version).\(lib version) - ") +external: + (Nomsu version) means: + return (" + \(Nomsu syntax version).\(core version).\(Nomsu compiler version).\(lib version) + ") diff --git a/lib/core/operators.nom b/lib/core/operators.nom index 912b7c1..b0f37f0 100644 --- a/lib/core/operators.nom +++ b/lib/core/operators.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V6.14 +#!/usr/bin/env nomsu -V6.15.13.8 # This file contains definitions of operators like "+" and "and". @@ -78,34 +78,6 @@ test: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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} $var "=" $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) @@ -156,7 +128,8 @@ test: test: $calls = 0 (one) means: - external $calls = ($calls + 1) + external: + $calls = ($calls + 1) return 1 unless (0 <= (one) <= 2): diff --git a/lib/core/text.nom b/lib/core/text.nom index 1351af6..a1fcaae 100644 --- a/lib/core/text.nom +++ b/lib/core/text.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V6.14 +#!/usr/bin/env nomsu -V6.15.13.8 # This file contains some definitions of text escape sequences, including ANSI console color codes. @@ -34,7 +34,6 @@ test: "), lines ..== ["one", "two", ""] - ($spec とは $body) parses as ($spec means $body) test: @@ -61,16 +60,18 @@ test: 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) +external: + ($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" + .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: |
