Upgraded core code to latest Nomsu verison.

This commit is contained in:
Bruce Hill 2018-07-17 23:08:13 -07:00
parent 854b2a652f
commit ba639f2bd0
16 changed files with 779 additions and 699 deletions

30
compatibility/2.nom Normal file
View File

@ -0,0 +1,30 @@
#!/usr/bin/env nomsu -V2
use "core"
use "compatibility/compatibility.nom"
upgrade %tree to "2" as:
unless (%tree is "Action" syntax tree): return
if (all[%tree.stub is "if % % else %", not (%tree.3 is "Var" syntax tree), not (%tree.5 is "Var" syntax tree)]):
%true_body <- (%tree.3 upgraded from "1.2")
unless (%true_body is "Block" syntax tree):
%true_body <- (=lua "Block(\%true_body.source, \%true_body)")
%false_body <- (%tree.5 upgraded from "1.2")
unless (%false_body is "Block" syntax tree):
%false_body <- (=lua "Block(\%false_body.source, \%false_body)")
return (..)
\(if %cond %true_body else %false_body)
..with vars {..}
cond:%tree.2 upgraded from "1.2", true_body:%true_body, false_body:%false_body
%need_blocks <- [..]
"if % %", "unless % %", "for % in % %", "for % = % in % %", "repeat while % %"
"repeat % times %", "repeat %", "repeat until % %", "for % in % to % by % %",
"for % in % to % via % %", "for % in % to % %", "for % % in % %", "do %"
"for % in recursive % %", "test %", "with % %", "result of %"
for %n in %need_blocks:
if ((%tree.stub is %n) and (not ((last in %tree) is "Var" syntax tree))):
%bits <- (((% upgraded from "1.2") if (% is syntax tree) else %) for % in %tree)
unless ((last in %bits) is "Block" syntax tree):
%body <- (last in %bits)
%bits.(length of %bits) <- (=lua "Block(\%body.source, \%body)")
return (=lua "Action(\%tree.source, unpack(\%bits))")

View File

@ -1,4 +1,4 @@
#!/usr/bin/env nomsu -V1
#!/usr/bin/env nomsu -V2.2.4.3
#
This file contains code that supports manipulating and using collections like lists
and dictionaries.
@ -8,173 +8,165 @@ use "core/control_flow.nom"
use "core/operators.nom"
# List/dict functions:
# Indexing
test: assume: (2nd to last in [1,2,3,4,5]) is 4
test: assume ((2 nd to last in [1, 2, 3, 4, 5]) is 4)
compile [..]
%index st to last in %list, %index nd to last in %list, %index rd to last in %list
%index th to last in %list
..to: Lua value "utils.nth_to_last(\(%list as lua expr), \(%index as lua expr))"
..to (Lua value "utils.nth_to_last(\(%list as lua expr), \(%index as lua expr))")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
parse [last in %list] as: 1st to last in %list
parse [first in %list] as: %list.1
parse [last in %list] as (1 st to last in %list)
parse [first in %list] as %list.1
# Membership testing
test: assume: 3 is in [1,2,3,4,5]
action [%item is in %list, %list contains %item, %list has %item]
for %key = %value in %list
if (%key is %item): return (yes)
test: assume (3 is in [1, 2, 3, 4, 5])
action [%item is in %list, %list contains %item, %list has %item]:
for %key = %value in %list: if (%key is %item): return (yes)
return (no)
test: assume: 99 isn't in [1,2,3]
test: assume (99 isn't in [1, 2, 3])
action [..]
%item isn't in %list, %item is not in %list
%list doesn't contain %item, %list does not contain %item
%list doesn't have %item, %list does not have %item
..
for %key = %value in %list
if (%key is %item): return (no)
%item isn't in %list, %item is not in %list, %list doesn't contain %item
%list does not contain %item, %list doesn't have %item, %list does not have %item
..:
for %key = %value in %list: if (%key is %item): return (no)
return (yes)
test: assume: {x:no} has key "x"
parse [%list has key %index, %list has index %index] as
%list.%index != (nil)
test: assume ({"x": no} has key "x")
parse [%list has key %index, %list has index %index] as (%list.%index != (nil))
test:
assume ({"x": no} doesn't have key "y")
assume (not ({"x": no} doesn't have key "x"))
test
assume: {x:no} doesn't have key "y"
assume: not: {x:no} doesn't have key "x"
parse [..]
%list doesn't have key %index, %list does not have key %index
%list doesn't have index %index, %list does not have index %index
..as
%list.%index = (nil)
..as (%list.%index = (nil))
compile [number of keys in %list] to
compile [number of keys in %list] to (..)
Lua value "utils.size(\(%list as lua expr))"
test
%list <- [1,2,3,4,5]
test:
%list <- [1, 2, 3, 4, 5]
append 6 to %list
assume: (last in %list) is 6
assume ((last in %list) is 6)
pop from %list
assume: (last in %list) is 5
assume ((last in %list) is 5)
remove index 1 from %list
assume: (first in %list) is 2
assume ((first in %list) is 2)
compile [append %item to %list, add %item to %list, to %list add %item, to %list append %item] to
Lua "table.insert(\(%list as lua expr), \(%item as lua expr))"
compile [..]
append %item to %list, add %item to %list, to %list add %item
to %list append %item
..to (Lua "table.insert(\(%list as lua expr), \(%item as lua expr))")
compile [pop from %list, remove last from %list] to
compile [pop from %list, remove last from %list] to (..)
Lua value "table.remove(\(%list as lua expr))"
compile [remove index %index from %list] to
compile [remove index %index from %list] to (..)
Lua value "table.remove(\(%list as lua expr), \(%index as lua expr))"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# List Comprehension
test: assume: ((% * %) for % in [1,2,3]) = [1,4,9]
parse [%expression for %item in %iterable] as
result of
test: assume (((% * %) for % in [1, 2, 3]) = [1, 4, 9])
parse [%expression for %item in %iterable] as (..)
result of:
%comprehension <- []
for %item in %iterable
add %expression to %comprehension
for %item in %iterable: add %expression to %comprehension
return %comprehension
parse [..]
%expression for %index in %start to %stop via %step
%expression for %index in %start to %stop by %step
..as
result of
..as (..)
result of:
%comprehension <- []
for %index in %start to %stop via %step
add %expression to %comprehension
for %index in %start to %stop via %step: add %expression to %comprehension
return %comprehension
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test: assume: ((% * %) for % in 1 to 3) = [1,4,9]
parse [%expression for %var in %start to %stop] as
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test: assume (((% * %) for % in 1 to 3) = [1, 4, 9])
parse [%expression for %var in %start to %stop] as (..)
%expression for %var in %start to %stop via 1
test: assume: ("\%k,\%v" for %k = %v in {x:1}) = ["x,1"]
test: assume (("\%k,\%v" for %k = %v in {"x": 1}) = ["x,1"])
parse [..]
%expression for %key = %value in %iterable
%expression for (%key,%value) in %iterable
..as
result of
%expression for %key %value in %iterable
..as (..)
result of:
%comprehension <- []
for %key = %value in %iterable
add %expression to %comprehension
for %key = %value in %iterable: add %expression to %comprehension
return %comprehension
# Dict comprehensions
test: assume: ((% * %) = % for % in [1,2,3]) = {1:1,4:2,9:3}
parse [..]
%key = %value for %item in %iterable
(%key,%value) for %item in %iterable
..as
result of
test: assume (((% * %) = % for % in [1, 2, 3]) = {1: 1, 4: 2, 9: 3})
parse [%key = %value for %item in %iterable, %key %value for %item in %iterable]
..as (..)
result of:
%comprehension <- {}
for %item in %iterable
%comprehension.%key <- %value
for %item in %iterable: %comprehension.%key <- %value
return %comprehension
test: assume: (%k = (%v * %v) for %k = %v in {x:1,y:2,z:3}) = {x:1,y:4,z:9}
test:
assume (..)
(%k = (%v * %v) for %k = %v in {"x": 1, "y": 2, "z": 3}) = {"x": 1, "y": 4, "z": 9}
parse [..]
%key = %value for %src_key = %src_value in %iterable
(%key,%value) for (%src_key,%src_value) in %iterable
..as
result of
%key %value for %src_key %src_value in %iterable
..as (..)
result of:
%comprehension <- {}
for %src_key = %src_value in %iterable
%comprehension.%key <- %value
for %src_key = %src_value in %iterable: %comprehension.%key <- %value
return %comprehension
parse [..]
%key = %value for %item in %start to %stop via %step
(%key,%value) for %item in %start to %stop via %step
..as
result of
%key %value for %item in %start to %stop via %step
..as (..)
result of:
%comprehension <- {}
for %item in %start to %stop via %step
%comprehension.%key <- %value
for %item in %start to %stop via %step: %comprehension.%key <- %value
return %comprehension
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test: assume: ((% * %) = % for % in 1 to 3) = {1:1,4:2,9:3}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test: assume (((% * %) = % for % in 1 to 3) = {1: 1, 4: 2, 9: 3})
parse [..]
%key = %value for %item in %start to %stop
(%key,%value) for %item in %start to %stop
..as: %key = %value for %item in %start to %stop via 1
%key %value for %item in %start to %stop
..as (%key = %value for %item in %start to %stop via 1)
test: assume: ([[1,2],[3,4]] flattened) = [1,2,3,4]
action [%lists flattened]
test: assume (([[1, 2], [3, 4]] flattened) = [1, 2, 3, 4])
action [%lists flattened]:
%flat <- []
for %list in %lists
for %item in %list
add %item to %flat
for %list in %lists: for %item in %list: add %item to %flat
return %flat
test: assume: (entries in {x:1}) = [{key:"x",value:1}]
parse [entries in %dict] as: {key:%k, value:%v} for %k = %v in %dict
test: assume: (keys in {x:1}) = ["x"]
parse [keys in %dict, keys of %dict] as: %k for %k = %v in %dict
test: assume: (values in {x:1}) = [1]
parse [values in %dict, values of %dict] as: %v for %k = %v in %dict
test: assume ((entries in {"x": 1}) = [{"key": "x", "value": 1}])
parse [entries in %dict] as ({"key": %k, "value": %v} for %k = %v in %dict)
test: assume ((keys in {"x": 1}) = ["x"])
parse [keys in %dict, keys of %dict] as (%k for %k = %v in %dict)
test: assume ((values in {"x": 1}) = [1])
parse [values in %dict, values of %dict] as (%v for %k = %v in %dict)
# Metatable stuff
test
test:
%t <- {}
set %t's metatable to {__tostring:[%]->"XXX"}
assume: "\%t" = "XXX"
compile [set %dict's metatable to %metatable] to
set %t 's metatable to {"__tostring": [%] -> "XXX"}
assume ("\%t" = "XXX")
compile [set %dict 's metatable to %metatable] to (..)
Lua "setmetatable(\(%dict as lua expr), \(%metatable as lua expr));"
test: assume: ({} with fallback % -> (% + 1)).10 = 11
compile [%dict with fallback %key -> %value] to
test: assume (({} with fallback % -> (% + 1)).10 = 11)
compile [%dict with fallback %key -> %value] to (..)
Lua value ".."
setmetatable(\(%dict as lua expr), {__index=function(self, \(%key as lua expr))
local value = \(%value as lua expr)
@ -182,48 +174,44 @@ compile [%dict with fallback %key -> %value] to
return value
end})
# Sorting
test
%x <- [3,1,2]
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}
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]
compile [sort %items] to: Lua "table.sort(\(%items as lua expr));"
parse [..]
sort %items by %item = %key_expr
sort %items by %item -> %key_expr
..as
do
assume (%x = [2, 3, 1])
compile [sort %items] to (Lua "table.sort(\(%items as lua expr));")
parse [sort %items by %item = %key_expr, sort %items by %item -> %key_expr] 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]
action [%items sorted, sorted %items]
test: assume ((sorted [3, 1, 2]) = [1, 2, 3])
action [%items sorted, sorted %items]:
%copy <- (% for % in %items)
sort %copy
return %copy
parse [..]
%items sorted by %item = %key
%items sorted by %item -> %key
..as
result of
parse [%items sorted by %item = %key, %items sorted by %item -> %key] as (..)
result of:
%copy <- (% for % in %items)
sort %copy by %item = %key
return %copy
test: assume: (unique [1,2,1,3,2,3]) = [1,2,3]
action [unique %items]
test: assume ((unique [1, 2, 1, 3, 2, 3]) = [1, 2, 3])
action [unique %items]:
%unique <- []
%seen <- {}
for % in %items
unless: %seen.%
for % in %items:
unless %seen.%:
add % to %unique
%seen.% <- (yes)
return %unique

View File

@ -1,4 +1,4 @@
#!/usr/bin/env nomsu -V1
#!/usr/bin/env nomsu -V2.2.4.3
#
This file contains compile-time actions that define basic control flow structures
like "if" statements and loops.
@ -10,19 +10,21 @@ use "core/errors.nom"
# No-Op
test: do nothing
compile [do nothing] to: Lua ""
compile [do nothing] to (Lua "")
# Conditionals
test: if (no): barf "conditional fail"
compile [if %condition %if_body] to
compile [if %condition %if_body] to (..)
Lua ".."
if \(%condition as lua expr) then
\(%if_body as lua statements)
end
test: unless (yes): barf "conditional fail"
parse [unless %condition %unless_body] as: if (not %condition) %unless_body
compile [if %condition %if_body else %else_body, unless %condition %else_body else %if_body] to
test: unless (yes): barf "conditional fail"
parse [unless %condition %unless_body] as (if (not %condition) %unless_body)
compile [..]
if %condition %if_body else %else_body, unless %condition %else_body else %if_body
..to (..)
Lua ".."
if \(%condition as lua expr) then
\(%if_body as lua statements)
@ -30,7 +32,7 @@ compile [if %condition %if_body else %else_body, unless %condition %else_body el
\(%else_body as lua statements)
end
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Conditional expression (ternary operator)
# Note: this uses a function instead of "(condition and if_expr or else_expr)"
@ -40,18 +42,20 @@ compile [..]
%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
..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)
return
if {"Text": yes, "List": yes, "Dict": yes, "Number": yes}.(%when_true_expr.type):
return (..)
Lua value ".."
(\(%condition as lua expr) and \(%when_true_expr as lua expr) or \(%when_false_expr as lua expr))
..else
..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
return (..)
Lua value ".."
((function()
if \(%condition as lua expr) then
@ -61,19 +65,21 @@ compile [..]
end
end)())
# GOTOs
compile [=== %label ===, --- %label ---, *** %label ***] to
compile [=== %label ===, --- %label ---, *** %label ***] to (..)
Lua "::label_\(%label as lua identifier)::"
compile [go to %label] to
compile [go to %label] to (..)
Lua "goto label_\(%label as lua identifier)"
# Basic loop control
compile [do next] to: Lua "continue"
compile [stop] to: Lua "break"
compile [do next] to (Lua "continue")
compile [stop] to (Lua "break")
# Helper function
#TODO: do "using % compile %" instead so it's actually a helper function
compile [%tree has subtree %subtree where %condition] to
compile [%tree has subtree %subtree where %condition] to (..)
Lua value ".."
(function()
for \(%subtree as lua expr) in coroutine.wrap(function() \(%tree as lua expr):map(coroutine.yield) end) do
@ -84,294 +90,271 @@ compile [%tree has subtree %subtree where %condition] to
return false
end)()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# While loops
compile [do next repeat] to: Lua "goto continue_repeat"
compile [stop repeating] to: Lua "goto stop_repeat"
compile [repeat while %condition %body] to
%lua <-
compile [do next repeat] to (Lua "goto continue_repeat")
compile [stop repeating] to (Lua "goto stop_repeat")
compile [repeat while %condition %body] to:
%lua <- (..)
Lua ".."
while \(%condition as lua expr) do
\(%body as lua statements)
if
%body has subtree % where: (%.type = "Action") and (%.stub is "do next repeat")
..:to %lua write "\n ::continue_repeat::"
to %lua write "\nend --while-loop"
if
%body has subtree % where: (%.type = "Action") and (%.stub is "stop repeating")
..
%lua <-
Lua ".."
do -- scope of "stop repeating" label
\%lua
::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
compile [..]
repeat %n times %body
..to
%lua <-
Lua ".."
for i=1,\(%n as lua expr) do
\(%body as lua statements)
if
%body has subtree % where: (%.type = "Action") and (%.stub is "do next repeat")
if (..)
%body has subtree % where ((%.type = "Action") and (%.stub is "do next repeat"))
..: to %lua write "\n ::continue_repeat::"
to %lua write "\nend --numeric for-loop"
if
%body has subtree % where: (%.type = "Action") and (%.stub is "stop repeating")
..
%lua <-
to %lua write "\nend --while-loop"
if (%body has subtree % where ((%.type = "Action") and (%.stub is "stop repeating"))):
%lua <- (..)
Lua ".."
do -- scope of "stop repeating" label
\%lua
::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)
compile [repeat %n times %body] to:
%lua <- (Lua "for i=1,\(%n as lua expr) do\n \(%body as lua statements)")
if (%body has subtree % where ((%.type = "Action") and (%.stub is "do next repeat"))):
to %lua write "\n ::continue_repeat::"
to %lua write "\nend --numeric for-loop"
if (%body has subtree % where ((%.type = "Action") and (%.stub is "stop repeating"))):
%lua <- (..)
Lua ".."
do -- scope of "stop repeating" label
\%lua
::stop_repeat::
end -- end of "stop repeating" label scope
return %lua
# For loop control flow
compile [stop %var] to
Lua "goto stop_\(%var as lua identifier)"
compile [do next %var] to
Lua "goto continue_\(%var as lua identifier)"
compile [=== stop %var ===, --- stop %var ---, *** stop %var ***] to
compile [stop %var] to (Lua "goto stop_\(%var as lua identifier)")
compile [do next %var] to (Lua "goto continue_\(%var as lua identifier)")
compile [===stop %var ===, ---stop %var ---, ***stop %var ***] to (..)
Lua "::stop_\(%var as lua identifier)::"
compile [=== next %var ===, --- next %var ---, *** next %var ***] to
compile [===next %var ===, ---next %var ---, ***next %var ***] to (..)
Lua "::continue_\(%var as lua identifier)::"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Numeric range for loops
compile [..]
for %var in %start to %stop by %step %body
for %var in %start to %stop via %step %body
..to
..to:
# This uses Lua's approach of only allowing loop-scoped variables in a loop
assume (%var.type is "Var") or barf "Loop expected variable, not: \%var"
%lua <-
%lua <- (..)
Lua ".."
for \(%var as lua expr)=\(%start as lua expr),\(%stop as lua expr),\(%step as lua expr) do
\(%body as lua statements)
if
%body has subtree % where
(%.type = "Action") and
(%.stub is "do next %") and
%.(3).1 = %var.1
..: to %lua write "\n \(compile as: === next %var ===)"
if (..)
%body has subtree % where (..)
(%.type = "Action") and ((%.stub is "do next %") and (%.(3).1 = %var.1))
..: to %lua write "\n \(compile as (===next %var ===))"
to %lua write "\nend --numeric for-loop"
if
%body has subtree % where
(%.type = "Action") and
(%.stub is "stop %") and
%.(2).1 = %var.1
..
%lua <-
if (..)
%body has subtree % where (..)
(%.type = "Action") and ((%.stub is "stop %") and (%.(2).1 = %var.1))
..:
%lua <- (..)
Lua ".."
do -- scope for stopping for-loop
\%lua
\(compile as: === stop %var ===)
\(compile as (===stop %var ===))
end -- end of scope for stopping for-loop
return %lua
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
parse [for %var in %start to %stop %body] as (..)
for %var in %start to %stop via 1 %body
parse [for %var in %start to %stop %body] as: for %var in %start to %stop via 1 %body
# For-each loop (lua's "ipairs()")
compile [for %var in %iterable %body] to
compile [for %var in %iterable %body] to:
# This uses Lua's approach of only allowing loop-scoped variables in a loop
assume (%var.type is "Var") or barf "Loop expected variable, not: \%var"
%lua <-
%lua <- (..)
Lua ".."
for i,\(%var as lua identifier) in ipairs(\(%iterable as lua expr)) do
\(%body as lua statements)
if
%body has subtree % where
(%.type = "Action") and
(%.stub is "do next %") and
%.3.(1) = %var.(1)
..: to %lua write (Lua "\n\(compile as: === next %var ===)")
if (..)
%body has subtree % where (..)
(%.type = "Action") and ((%.stub is "do next %") and (%.(3).1 = %var.1))
..: to %lua write (Lua "\n\(compile as (===next %var ===))")
to %lua write "\nend --foreach-loop"
if
%body has subtree % where
(%.type = "Action") and
(%.stub is "stop %") and
%.2.(1) = %var.(1)
..
%lua <-
if (..)
%body has subtree % where (..)
(%.type = "Action") and ((%.stub is "stop %") and (%.(2).1 = %var.1))
..:
%lua <- (..)
Lua ".."
do -- scope for stopping for-loop
\%lua
\(compile as: === stop %var ===)
\(compile as (===stop %var ===))
end -- end of scope for stopping for-loop
return %lua
# Dict iteration (lua's "pairs()")
compile [..]
for %key = %value in %iterable %body
for (%key,%value) in %iterable %body
..to
compile [for %key = %value in %iterable %body, for %key %value in %iterable %body] to:
# This uses Lua's approach of only allowing loop-scoped variables in a loop
assume (%key.type is "Var") or barf "Loop expected variable, not: \%key"
assume (%value.type is "Var") or barf "Loop expected variable, not: \%value"
%lua <-
%lua <- (..)
Lua ".."
for \(%key as lua identifier),\(%value as lua identifier) in pairs(\(%iterable as lua expr)) do
\(%body as lua statements)
if
%body has subtree % where
(%.type = "Action") and
(%.stub is "do next %") and
%.3.(1) = %key.(1)
..: to %lua write (Lua "\n\(compile as: === next %key ===)")
if
%body has subtree % where
(%.type = "Action") and
(%.stub is "do next %") and
%.3.(1) = %value.(1)
..: to %lua write (Lua "\n\(compile as: === next %value ===)")
to %lua write "\nend --foreach-loop"
if (..)
%body has subtree % where (..)
(%.type = "Action") and ((%.stub is "do next %") and (%.(3).1 = %key.1))
..: to %lua write (Lua "\n\(compile as (===next %key ===))")
if (..)
%body has subtree % where (..)
(%.type = "Action") and ((%.stub is "do next %") and (%.(3).1 = %value.1))
..: to %lua write (Lua "\n\(compile as (===next %value ===))")
to %lua write "\nend --foreach-loop"
%stop_labels <- (Lua "")
if
%body has subtree % where
(%.type = "Action") and
(%.stub is "stop %") and
%.2.(1) = %key.(1)
..: to %stop_labels write "\n\(compile as: === stop %key ===)"
if
%body has subtree % where
(%.type = "Action") and
(%.stub is "stop %") and
%.2.(1) = %value.(1)
..: to %stop_labels write "\n\(compile as: === stop %value ===)"
if: (length of "\%stop_labels") > 0
%lua <-
Lua ".."
do -- scope for stopping for % = % loop
\%lua\%stop_labels
end
if (..)
%body has subtree % where (..)
(%.type = "Action") and ((%.stub is "stop %") and (%.(2).1 = %key.1))
..: to %stop_labels write "\n\(compile as (===stop %key ===))"
if (..)
%body has subtree % where (..)
(%.type = "Action") and ((%.stub is "stop %") and (%.(2).1 = %value.1))
..: to %stop_labels write "\n\(compile as (===stop %value ===))"
if ((length of "\%stop_labels") > 0):
%lua <- (..)
Lua "do -- scope for stopping for % = % loop\n \%lua\%stop_labels\nend"
return %lua
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Switch statement/multi-branch if
compile [when %body] to
compile [when %body] to:
%code <- (Lua "")
%fallthroughs <- []
%is_first <- (yes)
%seen_else <- (no)
%branches <-
%body if (%body.type = "Block") else [%body]
for %func_call in %branches
assume (%func_call.type is "Action") or barf ".."
Invalid format for 'when' statement. Only '*' blocks are allowed.
with {..}
%star: %func_call.1
%condition: %func_call.2
%action: %func_call.3
..
assume (%star = "*") or barf ".."
Invalid format for 'when' statement. Lines must begin with '*'
%branches <- (%body if (%body.type = "Block") else [%body])
for %func_call in %branches:
assume (%func_call.type is "Action") or barf "Invalid format for 'when' statement. Only '*' blocks are allowed."
with {%star: %func_call.1, %condition: %func_call.2, %action: %func_call.3}:
assume (%star = "*") or barf "Invalid format for 'when' statement. Lines must begin with '*'"
assume %condition or barf ".."
Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else"
if: %action is (nil)
Invalid format for 'when' statement. Lines must begin with '*' and have a condition \
..or the word "else"
if (%action is (nil)):
lua> "table.insert(\%fallthroughs, \(%condition as lua expr))"
do next %func_call
if: %condition = "else"
if (%condition = "else"):
assume (not %is_first) or barf "'else' clause cannot be first in 'when % = ?' block"
to %code write "\nelse\n "
to %code write: %action as lua statements
to %code write (%action as lua statements)
%seen_else <- (yes)
..else
..else:
assume (not %seen_else) or barf "'else' clause needs to be last in 'when' block"
lua> "table.insert(\%fallthroughs, \(%condition as lua expr))"
to %code write "\("if" if %is_first else "\nelseif") "
for %i = %condition in %fallthroughs
for %i = %condition in %fallthroughs:
if (%i > 1): to %code write " or "
to %code write %condition
to %code write " then\n "
to %code write (%action as lua statements)
%fallthroughs <- []
%is_first <- (no)
assume (%fallthroughs = []) or barf "Unfinished fallthrough conditions in 'when' block"
assume ((length of "\%code") > 0) or barf "Empty body for 'when' block"
to %code write "\nend --when"
return %code
# Switch statement
compile [when %branch_value = ? %body, when %branch_value is ? %body] to
compile [when %branch_value = ? %body, when %branch_value is ? %body] to:
%code <- (Lua "")
%fallthroughs <- []
%is_first <- (yes)
%seen_else <- (no)
%branches <-
%body if (%body.type = "Block") else [%body]
for %func_call in %branches
assume (%func_call.type is "Action") or barf ".."
Invalid format for 'when' statement. Only '*' blocks are allowed.
with {%star:%func_call.1, %condition:%func_call.2, %action:%func_call.3}
assume (%star = "*") or barf ".."
Invalid format for 'when' statement. Lines must begin with '*'
%branches <- (%body if (%body.type = "Block") else [%body])
for %func_call in %branches:
assume (%func_call.type is "Action") or barf "Invalid format for 'when' statement. Only '*' blocks are allowed."
with {%star: %func_call.1, %condition: %func_call.2, %action: %func_call.3}:
assume (%star = "*") or barf "Invalid format for 'when' statement. Lines must begin with '*'"
assume %condition or barf ".."
Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else"
if: %action is (nil)
Invalid format for 'when' statement. Lines must begin with '*' and have a condition \
..or the word "else"
if (%action is (nil)):
lua> "table.insert(\%fallthroughs, \(%condition as lua expr))"
do next %func_call
if: %condition = "else"
if (%condition = "else"):
assume (not %is_first) or barf "'else' clause cannot be first in 'when % = ?' block"
to %code write "\nelse\n "
to %code write: %action as lua statements
..else
to %code write (%action as lua statements)
..else:
assume (not %seen_else) or barf "'else' clause needs to be last in 'when % = ?' block"
to %code write "\("if" if %is_first else "\nelseif") "
lua> "table.insert(\%fallthroughs, \(%condition as lua expr))"
for %i = % in %fallthroughs
if: %i > 1
to %code write " or "
if: (%.type is "Text") or (%.type is "Number")
for %i = % in %fallthroughs:
if (%i > 1): to %code write " or "
if ((%.type is "Text") or (%.type is "Number")):
to %code write "branch_value == \%"
..else
to %code write "utils.equivalent(branch_value, \%)"
..else: to %code write "utils.equivalent(branch_value, \%)"
to %code write "then\n "
to %code write (%action as lua statements)
%fallthroughs <- []
%is_first <- (no)
assume (%fallthroughs = []) or barf "Unfinished fallthrough conditions in 'when' block"
assume ((length of "\%code") > 0) or barf "No body for 'when % = ?' block!"
to %code write "\nend"
%code <-
%code <- (..)
Lua ".."
do --when % = ?
local branch_value = \(%branch_value as lua expr)
\%code
end --when % = ?
return %code
# Do/finally
compile [do %action] to
compile [do %action] to (..)
Lua ".."
do
\(%action as lua statements)
end --do
compile [do %action then always %final_action] to
compile [do %action then always %final_action] to (..)
Lua ".."
do
local fell_through = false
@ -384,23 +367,24 @@ compile [do %action then always %final_action] to
if not fell_through then return ret end
end
# Inline thunk:
compile [result of %body] to
Lua value "(\(compile as: [] -> %body))()"
compile [result of %body] to (Lua value "(\(compile as ([] -> %body)))()")
# Recurion control flow
compile [for %var in recursive %structure %body] to
with local compile actions
compile [recurse %v on %x] to
compile [for %var in recursive %structure %body] to (..)
with local compile actions:
compile [recurse %v on %x] to (..)
Lua "table.insert(stack\(%v as lua id), \(%x as lua expr))"
return
return (..)
Lua ".."
do
local stack\(%var as lua id) = list{\(%structure as lua expr)}
while #stack\(%var as lua id) > 0 do
\(%var as lua expr) = table.remove(stack\(%var as lua id), 1)
\(%body as lua statements)
\(compile as: === next %var ===)
\(compile as (===next %var ===))
end
\(compile as: === stop %var ===)
\(compile as (===stop %var ===))
end

View File

@ -1,18 +1,15 @@
#!/usr/bin/env nomsu -V1
#!/usr/bin/env nomsu -V2.2.4.3
#
This file defines the code that creates and manipulates coroutines
use "core/metaprogramming.nom"
compile [coroutine %body, generator %body] to (..)
Lua value "(function()\n \(%body as lua statements)\nend)"
compile [coroutine %body, generator %body] to
Lua value ".."
(function()
\(%body as lua statements)
end)
compile [->] to: Lua value "coroutine.yield(true)"
compile [-> %] to: Lua value "coroutine.yield(true, \(% as lua expr))"
compile [for % in coroutine %co %body] to
compile [->] to (Lua value "coroutine.yield(true)")
compile [-> %] to (Lua value "coroutine.yield(true, \(% as lua expr))")
compile [for % in coroutine %co %body] to (..)
Lua ".."
for junk,\(% as lua expr) in coroutine.wrap(\(%co as lua expr)) do
\(%body as lua statements)
end
end

View File

@ -1,32 +1,34 @@
#!/usr/bin/env nomsu -V1
#!/usr/bin/env nomsu -V2.2.4.3
#
This file contains basic error reporting code
use "core/metaprogramming.nom"
compile [traceback] to: Lua value "debug.traceback()"
compile [traceback %] to: Lua value "debug.traceback('', \(% as lua expr))"
compile [barf] to: Lua "error(nil, 0);"
compile [barf %msg] to: Lua "error(\(%msg as lua expr), 0);"
compile [assume %condition] to
lua> "local \%assumption = 'Assumption failed: '..tostring(nomsu:tree_to_nomsu(\%condition))"
return
compile [traceback] to (Lua value "debug.traceback()")
compile [traceback %] to (Lua value "debug.traceback('', \(% as lua expr))")
compile [barf] to (Lua "error(nil, 0);")
compile [barf %msg] to (Lua "error(\(%msg as lua expr), 0);")
compile [assume %condition] to:
lua> ".."
local \%assumption = 'Assumption failed: '..tostring(nomsu:tree_to_nomsu(\%condition))
return (..)
Lua ".."
if not \(%condition as lua expr) then
error(\(quote "\%assumption"), 0)
end
compile [assume %condition or barf %message] to
compile [assume %condition or barf %message] to (..)
Lua ".."
if not \(%condition as lua expr) then
error(\(%message as lua expr), 0)
end
# Try/except
compile [..]
try %action and if it succeeds %success or if it barfs %msg %fallback
try %action and if it barfs %msg %fallback or if it succeeds %success
..to
..to (..)
Lua ".."
do
local fell_through = false
@ -50,20 +52,23 @@ compile [..]
end
end
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
parse [..]
try %action and if it succeeds %success or if it barfs %fallback
try %action and if it barfs %fallback or if it succeeds %success
..as: try %action and if it succeeds %success or if it barfs (=lua "") %fallback
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
parse [try %action] as
try %action and if it succeeds: do nothing
..or if it barfs: do nothing
parse [try %action and if it barfs %fallback] as
try %action and if it succeeds: do nothing
..or if it barfs %fallback
parse [try %action and if it barfs %msg %fallback] as
try %action and if it succeeds: do nothing
..or if it barfs %msg %fallback
parse [try %action and if it succeeds %success] as
try %action and if it succeeds %success or if it barfs: do nothing
..as (try %action and if it succeeds %success or if it barfs (=lua "") %fallback)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
parse [try %action] as (..)
try %action and if it succeeds (do nothing) or if it barfs (do nothing)
parse [try %action and if it barfs %fallback] as (..)
try %action and if it succeeds (do nothing) or if it barfs %fallback
parse [try %action and if it barfs %msg %fallback] as (..)
try %action and if it succeeds (do nothing) or if it barfs %msg %fallback
parse [try %action and if it succeeds %success] as (..)
try %action and if it succeeds %success or if it barfs (do nothing)

View File

@ -1,10 +1,9 @@
#!/usr/bin/env nomsu -V1
#!/usr/bin/env nomsu -V2.2.4.3
#
This file contains basic input/output code
use "core/metaprogramming.nom"
compile [say %message] to
compile [say %message] to (..)
lua> ".."
if \%message.type == "Text" then
return LuaCode(tree.source, "print(", \(%message as lua expr), ");");
@ -12,10 +11,10 @@ compile [say %message] to
return LuaCode(tree.source, "print(tostring(", \(%message as lua expr), "));");
end
compile [ask %prompt] to
compile [ask %prompt] to (..)
lua> ".."
if \%prompt.type == "Text" then
return LuaCode.Value(tree.source, "(io.write(", \(%prompt as lua expr), ") and io.read())");
else
return LuaCode.Value(tree.source, "(io.write(tostring(", \(%prompt as lua expr), ")) and io.read())");
end
end

View File

@ -1,4 +1,4 @@
#!/usr/bin/env nomsu -V1
#!/usr/bin/env nomsu -V2.2.4.3
#
This file defines some common math literals and functions
@ -9,91 +9,119 @@ use "core/control_flow.nom"
use "core/collections.nom"
# Literals:
compile [infinity, inf] to: Lua value "math.huge"
compile [not a number, NaN, nan] to: Lua value "(0/0)"
compile [pi, Pi, PI] to: Lua value "math.pi"
compile [tau, Tau, TAU] to: Lua value "(2*math.pi)"
compile [golden ratio] to: Lua value "((1+math.sqrt(5))/2)"
compile [e] to: Lua value "math.exp(1)"
compile [infinity, inf] to (Lua value "math.huge")
compile [not a number, NaN, nan] to (Lua value "(0/0)")
compile [pi, Pi, PI] to (Lua value "math.pi")
compile [tau, Tau, TAU] to (Lua value "(2*math.pi)")
compile [golden ratio] to (Lua value "((1+math.sqrt(5))/2)")
compile [e] to (Lua value "math.exp(1)")
# Functions:
compile [% as a number, % as number] to: Lua value "tonumber(\(% as lua expr))"
compile [absolute value %, | % |, abs %] to: Lua value "math.abs(\(% as lua expr))"
compile [square root %, square root of %, √%, sqrt %] to: Lua value "math.sqrt(\(% as lua expr))"
compile [sine %, sin %] to: Lua value "math.sin(\(% as lua expr))"
compile [cosine %, cos %] to: Lua value "math.cos(\(% as lua expr))"
compile [tangent %, tan %] to: Lua value "math.tan(\(% as lua expr))"
compile [arc sine %, asin %] to: Lua value "math.asin(\(% as lua expr))"
compile [arc cosine %, acos %] to: Lua value "math.acos(\(% as lua expr))"
compile [arc tangent %, atan %] to: Lua value "math.atan(\(% as lua expr))"
compile [arc tangent %y / %x, atan2 %y %x] to: Lua value "math.atan2(\(%y as lua expr), \(%x as lua expr))"
compile [hyperbolic sine %, sinh %] to: Lua value "math.sinh(\(% as lua expr))"
compile [hyperbolic cosine %, cosh %] to: Lua value "math.cosh(\(% as lua expr))"
compile [hyperbolic tangent %, tanh %] to: Lua value "math.tanh(\(% as lua expr))"
compile [e^%, exp %] to: Lua value "math.exp(\(% as lua expr))"
compile [natural log %, ln %, log %] to: Lua value "math.log(\(% as lua expr))"
compile [log % base %base, log base %base of %] to: Lua value "math.log(\(% as lua expr), \(%base as lua expr))"
compile [floor %] to: Lua value "math.floor(\(% as lua expr))"
compile [ceiling %, ceil %] to: Lua value "math.ceil(\(% as lua expr))"
compile [round %, % rounded] to: Lua value "math.floor(\(% as lua expr) + .5)"
action [%n to the nearest %rounder]
compile [% as a number, % as number] to (Lua value "tonumber(\(% as lua expr))")
compile [absolute value %, | % |, abs %] to (..)
Lua value "math.abs(\(% as lua expr))"
compile [square root %, square root of %, √ %, sqrt %] to (..)
Lua value "math.sqrt(\(% as lua expr))"
compile [sine %, sin %] to (Lua value "math.sin(\(% as lua expr))")
compile [cosine %, cos %] to (Lua value "math.cos(\(% as lua expr))")
compile [tangent %, tan %] to (Lua value "math.tan(\(% as lua expr))")
compile [arc sine %, asin %] to (Lua value "math.asin(\(% as lua expr))")
compile [arc cosine %, acos %] to (Lua value "math.acos(\(% as lua expr))")
compile [arc tangent %, atan %] to (Lua value "math.atan(\(% as lua expr))")
compile [arc tangent %y / %x, atan2 %y %x] to (..)
Lua value "math.atan2(\(%y as lua expr), \(%x as lua expr))"
compile [hyperbolic sine %, sinh %] to (Lua value "math.sinh(\(% as lua expr))")
compile [hyperbolic cosine %, cosh %] to (..)
Lua value "math.cosh(\(% as lua expr))"
compile [hyperbolic tangent %, tanh %] to (..)
Lua value "math.tanh(\(% as lua expr))"
compile [e^ %, exp %] to (Lua value "math.exp(\(% as lua expr))")
compile [natural log %, ln %, log %] to (Lua value "math.log(\(% as lua expr))")
compile [log % base %base, log base %base of %] to (..)
Lua value "math.log(\(% as lua expr), \(%base as lua expr))"
compile [floor %] to (Lua value "math.floor(\(% as lua expr))")
compile [ceiling %, ceil %] to (Lua value "math.ceil(\(% as lua expr))")
compile [round %, % rounded] to (Lua value "math.floor(\(% as lua expr) + .5)")
action [%n to the nearest %rounder] (..)
=lua "(\%rounder)*math.floor((\%n / \%rounder) + .5)"
# Any/all/none
compile [all of %items, all %items] to
unless: %items.type is "List"
return: Lua value "utils.all(\(%items as lua expr))"
compile [all of %items, all %items] to:
unless (%items.type is "List"):
return (Lua value "utils.all(\(%items as lua expr))")
%clauses <- ((% as lua expr) for % in %items)
return: Lua value "(\(%clauses joined with " and "))"
parse [not all of %items, not all %items] as: not (all of %items)
compile [any of %items, any %items] to
unless: %items.type is "List"
return: Lua value "utils.any(\(%items as lua expr))"
return (Lua value "(\(%clauses joined with " and "))")
parse [not all of %items, not all %items] as (not (all of %items))
compile [any of %items, any %items] to:
unless (%items.type is "List"):
return (Lua value "utils.any(\(%items as lua expr))")
%clauses <- ((% as lua expr) for % in %items)
return: Lua value "(\(%clauses joined with " or "))"
parse [none of %items, none %items] as: not (any of %items)
compile [sum of %items, sum %items] to
unless: %items.type is "List"
return: Lua value "utils.sum(\(%items as lua expr))"
return (Lua value "(\(%clauses joined with " or "))")
parse [none of %items, none %items] as (not (any of %items))
compile [sum of %items, sum %items] to:
unless (%items.type is "List"):
return (Lua value "utils.sum(\(%items as lua expr))")
%clauses <- ((% as lua expr) for % in %items)
return: Lua value "(\(%clauses joined with " + "))"
compile [product of %items, product %items] to
unless: %items.type is "List"
return: Lua value "utils.product(\(%items as lua expr))"
return (Lua value "(\(%clauses joined with " + "))")
compile [product of %items, product %items] to:
unless (%items.type is "List"):
return (Lua value "utils.product(\(%items as lua expr))")
%clauses <- ((% as lua expr) for % in %items)
return: Lua value "(\(%clauses joined with " * "))"
action [avg of %items, average of %items]
=lua "(utils.sum(\%items)/#\%items)"
compile [min of %items, smallest of %items, lowest of %items] to
return (Lua value "(\(%clauses joined with " * "))")
action [avg of %items, average of %items] (=lua "(utils.sum(\%items)/#\%items)")
compile [min of %items, smallest of %items, lowest of %items] to (..)
Lua value "utils.min(\(%items as lua expr))"
compile [max of %items, biggest of %items, largest of %items, highest of %items] to
Lua value "utils.max(\(%items as lua expr))"
parse [min of %items by %item = %value_expr] as
result of
<- {%best:nil, %best_key:nil}
for %item in %items
compile [max of %items, biggest of %items, largest of %items, highest of %items]
..to (Lua value "utils.max(\(%items as lua expr))")
parse [min of %items by %item = %value_expr] 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
parse [max of %items by %item = %value_expr] 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}
if ((%best = (nil)) or (%key < %best_key)):
<- {%best: %item, %best_key: %key}
return %best
parse [max of %items by %item = %value_expr] 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
# Random functions
action [seed random with %]
lua> ".."
math.randomseed(\%);
for i=1,20 do math.random(); end
parse [seed random] as: seed random with (=lua "os.time()")
compile [random number, random, rand] to: Lua value "math.random()"
compile [random int %n, random integer %n, randint %n] to: Lua value "math.random(\(%n as lua expr))"
compile [random from %low to %high, random number from %low to %high, rand %low %high] to
Lua value "math.random(\(%low as lua expr), \(%high as lua expr))"
action [random choice from %elements, random choice %elements, random %elements]
action [seed random with %] (..)
lua> "math.randomseed(\%);\nfor i=1,20 do math.random(); end"
parse [seed random] as (seed random with (=lua "os.time()"))
compile [random number, random, rand] to (Lua value "math.random()")
compile [random int %n, random integer %n, randint %n] to (..)
Lua value "math.random(\(%n as lua expr))"
compile [random from %low to %high, random number from %low to %high, rand %low %high]
..to (Lua value "math.random(\(%low as lua expr), \(%high as lua expr))")
action [random choice from %elements, random choice %elements, random %elements] (..)
=lua "\%elements[math.random(#\%elements)]"

View File

@ -1,10 +1,9 @@
#!/usr/bin/env nomsu -V1
#!/usr/bin/env nomsu -V2.2.4.3
#
This File contains actions for making actions and compile-time actions and some helper
functions to make that easier.
lua> "NOMSU_CORE_VERSION = 2"
lua> ".."
nomsu.COMPILE_ACTIONS["% -> %"] = function(nomsu, tree, \%args, \%body)
local lua = LuaCode.Value(tree.source, "function(")
@ -29,73 +28,71 @@ lua> ".."
return lua
end
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
lua> ".."
nomsu.COMPILE_ACTIONS["compile % to %"] = function(nomsu, tree, \%actions, \%body)
local \%args = {"nomsu", "tree", unpack(table.map(\%actions[1]:get_args(), function(a) return tostring(nomsu:compile(a)) end))}
local lua = LuaCode(tree.source, "nomsu.COMPILE_ACTIONS[", repr(\%actions[1].stub),
"] = ", \(compile as: %args -> %body))
"] = ", \(compile as (%args -> %body)))
for i=2,#\%actions do
local alias = \%actions[i]
local \%alias_args = {"nomsu", "tree", unpack(table.map(alias:get_args(), function(a) return tostring(nomsu:compile(a)) end))}
lua:append("\nnomsu.COMPILE_ACTIONS[", repr(alias.stub), "] = ")
lua:append("\\nnomsu.COMPILE_ACTIONS[", repr(alias.stub), "] = ")
if utils.equivalent(\%args, \%alias_args) then
lua:append("nomsu.COMPILE_ACTIONS[", repr(\%actions[1].stub), "]")
else
lua:append("function(")
lua:concat_append(\%alias_args, ", ")
lua:append(")\n return nomsu.COMPILE_ACTIONS[", repr(\%actions[1].stub), "](")
lua:append(")\\n return nomsu.COMPILE_ACTIONS[", repr(\%actions[1].stub), "](")
lua:concat_append(\%args, ", ")
lua:append(")\nend")
lua:append(")\\nend")
end
end
return lua
end
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compile [call %fn with %args] to
compile [call %fn with %args] to (..)
lua> ".."
local lua = LuaCode.Value(tree.source, nomsu:compile(\%fn), "(")
lua:concat_append(table.map(\%args, function(a) return nomsu:compile(a) end), ", ")
lua:append(")")
return lua
compile [local action %actions %body] to
compile [local action %actions %body] to (..)
lua> ".."
local fn_name = "A"..string.as_lua_id(\%actions[1].stub)
local \%args = table.map(\%actions[1]:get_args(), function(a) return tostring(nomsu:compile(a)) end)
local lua = LuaCode(tree.source, fn_name, " = ", \(compile as: %args -> %body))
local lua = LuaCode(tree.source, fn_name, " = ", \(compile as (%args -> %body)))
lua:add_free_vars({fn_name})
for i=2,#\%actions do
local alias = \%actions[i]
local alias_name = "A"..string.as_lua_id(alias.stub)
lua:add_free_vars({alias_name})
local \%alias_args = table.map(alias:get_args(), function(a) return tostring(nomsu:compile(a)) end)
lua:append("\n", alias_name, " = ")
lua:append("\\n", alias_name, " = ")
if utils.equivalent(\%args, \%alias_args) then
lua:append(fn_name)
else
lua:append("function(")
lua:concat_append(\%alias_args, ", ")
lua:append(")\n return ", fn_name, "(")
lua:append(")\\n return ", fn_name, "(")
lua:concat_append(\%args, ", ")
lua:append(")\nend")
lua:append(")\\nend")
end
end
return lua
compile [action %actions %body] to
compile [action %actions %body] to (..)
lua> ".."
local lua = \(compile as: local action %actions %body)
local lua = \(compile as (local action %actions %body))
lua:remove_free_vars(table.map(\%actions, function(a) return "A"..string.as_lua_id(a.stub) end))
return lua
compile [action %action] to
Lua value "A\(%action.stub as lua id)"
compile [parse %actions as %body] to
compile [action %action] to (Lua value "A\(%action.stub as lua id)")
compile [parse %actions as %body] to (..)
lua> ".."
local replacements = {}
for i,arg in ipairs(\%actions[1]:get_args()) do
@ -115,56 +112,52 @@ compile [parse %actions as %body] to
end
local \%new_body = LuaCode(\%body.source,
"__MANGLE_INDEX = (__MANGLE_INDEX or 0) + 1",
"\nlocal tree = ", make_tree(\%body),
"\nlocal lua = nomsu:compile(tree); return lua")
local ret = \(compile as: compile %actions to %new_body)
"\\nlocal tree = ", make_tree(\%body),
"\\nlocal lua = nomsu:compile(tree); return lua")
local ret = \(compile as (compile %actions to %new_body))
return ret
compile [%tree as lua expr] to
compile [%tree as lua expr] to (..)
Lua value "nomsu:compile(\(=lua "nomsu:compile(\%tree):as_expr()")):as_expr()"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compile [%tree as lua] to
Lua value "nomsu:compile(\(%tree as lua expr))"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compile [%tree as lua statements] to
compile [%tree as lua] to (Lua value "nomsu:compile(\(%tree as lua expr))")
compile [%tree as lua statements] to (..)
Lua value "nomsu:compile(\(%tree as lua expr)):as_statements()"
compile [%tree as lua return] to
compile [%tree as lua return] to (..)
Lua value "nomsu:compile(\(%tree as lua expr)):as_statements('return ')"
compile [remove action %action] to
Lua ".."
A\(=lua "string.as_lua_id(\(%action.stub))") = nil
compile [remove action %action] to (..)
Lua "A\(=lua "string.as_lua_id(\(%action.stub))") = nil"
compile [%tree as nomsu] to
compile [%tree as nomsu] to (..)
Lua value "nomsu:tree_to_nomsu(\(%tree as lua expr))"
compile [%tree as inline nomsu] to
compile [%tree as inline nomsu] to (..)
Lua value "nomsu:tree_to_nomsu(\(%tree as lua expr), true)"
action [%var as lua identifier, %var as lua id]
action [%var as lua identifier, %var as lua id] (..)
lua> ".."
if type(\%var) == 'string' then return string.as_lua_id(\%var)
elseif \%var.type == 'Var' then return string.as_lua_id(\%var[1])
elseif \%var.type == 'Action' then return "A"..string.as_lua_id(\%var.stub)
end
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compile [% is syntax tree] to
Lua value "AST.is_syntax_tree(\(% as lua expr))"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compile [% is %kind syntax tree] to
compile [% is syntax tree] to (Lua value "AST.is_syntax_tree(\(% as lua expr))")
compile [% is %kind syntax tree] to (..)
Lua value "AST.is_syntax_tree(\(% as lua expr), \(%kind as lua expr))"
compile [%tree with %t -> %replacement] to
compile [%tree with %t -> %replacement] to (..)
Lua value ".."
\(%tree as lua expr):map(function(\(%t as lua expr))
\(%replacement as lua return)
end)
action [%tree with vars %replacements]
action [%tree with vars %replacements] (..)
=lua ".."
\%tree:map(function(\%t)
if \%t.type == "Var" then
@ -172,68 +165,69 @@ action [%tree with vars %replacements]
end
end)
compile [declare locals in %code] to
compile [declare locals in %code] to (..)
Lua value "\(%code as lua expr):declare_locals()"
compile [declare locals %locals in %code] to
compile [declare locals %locals in %code] to (..)
Lua value "\(%code as lua expr):declare_locals(\(%locals as lua expr))"
compile [add free vars %vars to %code] to
compile [add free vars %vars to %code] to (..)
Lua "\(%code as lua expr):add_free_vars(\(%vars as lua expr));"
compile [remove free vars %vars from %code] to
compile [remove free vars %vars from %code] to (..)
Lua "\(%code as lua expr):remove_free_vars(\(%vars as lua expr));"
compile [%lua <-write %code, to %lua write %code] to: Lua "\(%lua as lua expr):append(\(%code as lua expr));"
compile [%lua <-write %code, to %lua write %code] to (..)
Lua "\(%lua as lua expr):append(\(%code as lua expr));"
compile [to %lua write %code joined by %glue] to: Lua "\(%lua as lua expr):concat_append(\(%code as lua expr), \(%glue as lua expr));"
compile [to %lua write %code joined by %glue] to (..)
Lua "\(%lua as lua expr):concat_append(\(%code as lua expr), \(%glue as lua expr));"
compile [quote %s] to
Lua value ".."
repr(\(%s as lua expr))
compile [type of %obj] to: Lua value "type(\(%obj as lua expr))"
compile [quote %s] to (Lua value "repr(\(%s as lua expr))")
compile [type of %obj] to (Lua value "type(\(%obj as lua expr))")
compile [parse %text] to (..)
Lua value "nomsu:parse(NomsuCode(\"\(%text.source)\", \(%text as lua expr)))"
compile [parse %text] to
Lua value ".."
nomsu:parse(NomsuCode("\("\(%text.source)")", \(%text as lua expr)))
compile [parse %text from %filename] to
compile [parse %text from %filename] to (..)
Lua value ".."
nomsu:parse(NomsuCode(Source(\(%filename as lua expr), 1, #\(%text as lua expr)), \(%text as lua expr)))
compile [run %nomsu_code] to
Lua value "nomsu:run(\(%nomsu_code as lua expr), \(=lua "repr(tostring(\(%nomsu_code.source)))"))"
compile [run %nomsu_code] to (..)
Lua value ".."
nomsu:run(\(%nomsu_code as lua expr), \(=lua "repr(tostring(\(%nomsu_code.source)))"))
action [run tree %tree, %tree as value]
lua> ".."
return nomsu:run(\%tree)
compile [compile %block, compiled %block, %block compiled] to
action [run tree %tree, %tree as value] (lua> "return nomsu:run(\%tree)")
compile [compile %block, compiled %block, %block compiled] to (..)
Lua value "nomsu:compile(\(%block as lua))"
# 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.
compile [return] to: Lua "do return; end"
compile [return %return_value] to: Lua "do return \(%return_value as lua expr) end"
compile [return] to (Lua "do return; end")
compile [return %return_value] to (..)
Lua "do return \(%return_value as lua expr) end"
# Literals
compile [yes] to: Lua value "true"
compile [no] to: Lua value "false"
compile [nothing, nil, null] to: Lua value "nil"
compile [Nomsu syntax version] to: Lua value "NOMSU_SYNTAX_VERSION"
compile [Nomsu compiler version] to: Lua value "NOMSU_COMPILER_VERSION"
compile [core version] to: Lua value "NOMSU_CORE_VERSION"
compile [lib version] to: Lua value "NOMSU_LIB_VERSION"
compile [command line args] to: Lua value "arg"
compile [yes] to (Lua value "true")
compile [no] to (Lua value "false")
compile [nothing, nil, null] to (Lua value "nil")
compile [Nomsu syntax version] to (Lua value "NOMSU_SYNTAX_VERSION")
compile [Nomsu compiler version] to (Lua value "NOMSU_COMPILER_VERSION")
compile [core version] to (Lua value "NOMSU_CORE_VERSION")
compile [lib version] to (Lua value "NOMSU_LIB_VERSION")
compile [command line args] to (Lua value "arg")
~~~~
compile [with local compile actions %body] to
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compile [with local compile actions %body] to (..)
Lua ".."
do
local nomsu = table.fork(nomsu, {COMPILE_ACTIONS=table.fork(nomsu.COMPILE_ACTIONS)})
\(%body as lua statements)
end
action [Nomsu version]
action [Nomsu version]:
use "lib/version.nom"
return "\(Nomsu syntax version).\(core version).\(Nomsu compiler version).\(lib version)"
return ".."
\(Nomsu syntax version).\(core version).\(Nomsu compiler version).\(lib version)

View File

@ -1,4 +1,4 @@
#!/usr/bin/env nomsu -V1
#!/usr/bin/env nomsu -V2.2.4.3
#
This file contains definitions of operators like "+" and "and".
@ -6,14 +6,17 @@ use "core/metaprogramming.nom"
use "core/errors.nom"
# Comparison Operators
compile [%x < %y] to: Lua value "(\(%x as lua expr) < \(%y as lua expr))"
compile [%x > %y] to: Lua value "(\(%x as lua expr) > \(%y as lua expr))"
compile [%x <= %y] to: Lua value "(\(%x as lua expr) <= \(%y as lua expr))"
compile [%x >= %y] to: Lua value "(\(%x as lua expr) >= \(%y as lua expr))"
compile [%a is %b, %a = %b, %a == %b] to
compile [%x < %y] to (Lua value "(\(%x as lua expr) < \(%y as lua expr))")
compile [%x > %y] to (Lua value "(\(%x as lua expr) > \(%y as lua expr))")
compile [%x <= %y] to (Lua value "(\(%x as lua expr) <= \(%y as lua expr))")
compile [%x >= %y] to (Lua value "(\(%x as lua expr) >= \(%y as lua expr))")
compile [%a is %b, %a = %b, %a == %b] to (..)
Lua value "(\(%a as lua expr) == \(%b as lua expr))"
compile [%a isn't %b, %a is not %b, %a not= %b, %a != %b] to
compile [%a isn't %b, %a is not %b, %a not= %b, %a != %b] to (..)
Lua value "(\(%a as lua expr) ~= \(%b as lua expr))"
# For strict identity checking, use (%x's id) is (%y's id)
lua> ".."
do
@ -31,12 +34,13 @@ lua> ".."
end
})
end
compile [%'s id, id of %] to: Lua value "IDS[\(% as lua expr)]"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compile [% 's id, id of %] to (Lua value "IDS[\(% as lua expr)]")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Variable assignment operator
compile [%var <- %value] to
compile [%var <- %value] to:
lua> "local \%var_lua = \(%var as lua)"
assume %var_lua.is_value or barf "Invalid target for assignment: \%var"
lua> ".."
@ -46,7 +50,7 @@ compile [%var <- %value] to
end
end)
local \%value_lua = \(%value as lua)
assume %value_lua.is_value or barf "Invalid value for assignment: \%value"
lua> ".."
local lua = LuaCode(tree.source, \%var_lua, ' = ', \%value_lua, ';')
@ -55,10 +59,12 @@ compile [%var <- %value] to
end
return lua
# Simultaneous mutli-assignments like: x,y,z = 1,x,3;
compile [<- %assignments, assign %assignments] to
compile [<- %assignments, assign %assignments] to:
assume (%assignments.type is "Dict") or barf ".."
Expected a Dict for the assignments part of '<- %' statement, not \%assignments
lua> ".."
local lhs, rhs = LuaCode(tree.source), LuaCode(tree.source)
for i, item in ipairs(\%assignments) do
@ -84,21 +90,23 @@ compile [<- %assignments, assign %assignments] to
end
return LuaCode(tree.source, lhs, " = ", rhs, ";")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compile [external %var <- %value] to
compile [external %var <- %value] to:
%var_lua <- (%var as lua)
assume %var_lua.is_value or barf "Invalid target for assignment: \%var"
%value_lua <- (%value as lua)
assume %value_lua.is_value or barf "Invalid value for assignment: \%value"
return: Lua "\%var_lua = \%value_lua;"
return (Lua "\%var_lua = \%value_lua;")
compile [with external %externs %body] to
compile [with external %externs %body] to:
%body_lua <- (%body as lua statements)
lua> "\%body_lua:remove_free_vars(table.map(\%externs, function(v) return tostring(nomsu:compile(v)) end))"
lua> ".."
\%body_lua:remove_free_vars(table.map(\%externs, function(v) return tostring(nomsu:compile(v)) end))
return %body_lua
compile [with %assignments %body] to
compile [with %assignments %body] to:
%lua <- (%body as lua statements)
lua> ".."
local lhs, rhs = LuaCode(tree.source), LuaCode(tree.source)
@ -124,57 +132,79 @@ compile [with %assignments %body] to
end
end
\%lua:remove_free_vars(vars)
\%lua:prepend("local ", lhs, " = ", rhs, ";\n")
return
\%lua:prepend("local ", lhs, " = ", rhs, ";\\n")
return (..)
Lua ".."
do
\%lua
end -- 'with' block
# Math Operators
compile [%x wrapped around %y, %x mod %y] to: Lua value "(\(%x as lua expr) % \(%y as lua expr))"
compile [%x wrapped around %y, %x mod %y] to (..)
Lua value "(\(%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)
parse [%x < %y < %z] as: =lua "(function(x,y,z) return x < y and y < z; end)(\%x,\%y,\%z)"
parse [%x <= %y < %z] as: =lua "(function(x,y,z) return x <= y and y < z; end)(\%x,\%y,\%z)"
parse [%x < %y <= %z] as: =lua "(function(x,y,z) return x < y and y <= z; end)(\%x,\%y,\%z)"
parse [%x <= %y <= %z] as: =lua "(function(x,y,z) return x <= y and y <= z; end)(\%x,\%y,\%z)"
parse [%x > %y > %z] as: =lua "(function(x,y,z) return x > y and y > z; end)(\%x,\%y,\%z)"
parse [%x >= %y > %z] as: =lua "(function(x,y,z) return x >= y and y > z; end)(\%x,\%y,\%z)"
parse [%x > %y >= %z] as: =lua "(function(x,y,z) return x > y and y >= z; end)(\%x,\%y,\%z)"
parse [%x >= %y >= %z] as: =lua "(function(x,y,z) return x >= y and y >= z; end)(\%x,\%y,\%z)"
# TODO: optimize for common case where x,y,z are all either variables or number literals
parse [%x < %y < %z] as (..)
=lua "(function(x,y,z) return x < y and y < z; end)(\%x,\%y,\%z)"
parse [%x <= %y < %z] as (..)
=lua "(function(x,y,z) return x <= y and y < z; end)(\%x,\%y,\%z)"
parse [%x < %y <= %z] as (..)
=lua "(function(x,y,z) return x < y and y <= z; end)(\%x,\%y,\%z)"
parse [%x <= %y <= %z] as (..)
=lua "(function(x,y,z) return x <= y and y <= z; end)(\%x,\%y,\%z)"
parse [%x > %y > %z] as (..)
=lua "(function(x,y,z) return x > y and y > z; end)(\%x,\%y,\%z)"
parse [%x >= %y > %z] as (..)
=lua "(function(x,y,z) return x >= y and y > z; end)(\%x,\%y,\%z)"
parse [%x > %y >= %z] as (..)
=lua "(function(x,y,z) return x > y and y >= z; end)(\%x,\%y,\%z)"
parse [%x >= %y >= %z] as (..)
=lua "(function(x,y,z) return x >= y and y >= z; end)(\%x,\%y,\%z)"
# TODO: optimize for common case where x,y,z are all either variables or number literals
# Boolean Operators
compile [%x and %y] to: Lua value "(\(%x as lua expr) and \(%y as lua expr))"
compile [%x or %y] to: Lua value "(\(%x as lua expr) or \(%y as lua expr))"
compile [%x and %y] to (Lua value "(\(%x as lua expr) and \(%y as lua expr))")
compile [%x or %y] to (Lua value "(\(%x as lua expr) or \(%y as lua expr))")
# Bitwise Operators
# TODO: support bit.???() for luajit and bit32.??? for lua 5.2
compile [%a OR %b, %a | %b] to: Lua value "(\(%a as lua expr) | \(%b as lua expr))"
compile [%a XOR %b] to: Lua value "(\(%a as lua expr) ^ \(%b as lua expr))"
compile [%a AND %b, %a & %b] to: Lua value "(\(%a as lua expr) & \(%b as lua expr))"
compile [NOT %, ~ %] to: Lua value "~(\(% as lua expr))"
compile [%x LSHIFT %shift, %x << %shift] to: Lua value "(\(%x as lua expr) << \(%shift as lua expr))"
compile [%x RSHIFT %shift, %x >>> %shift] to: Lua value "(\(%x as lua expr) >>> \(%shift as lua expr))"
compile [%x ARSHIFT %shift, %x >> %shift] to: Lua value "(\(%x as lua expr) >> \(%shift as lua expr))"
compile [%a OR %b, %a | %b] to (..)
Lua value "(\(%a as lua expr) | \(%b as lua expr))"
compile [%a XOR %b] to (Lua value "(\(%a as lua expr) ^ \(%b as lua expr))")
compile [%a AND %b, %a & %b] to (..)
Lua value "(\(%a as lua expr) & \(%b as lua expr))"
compile [NOT %, ~ %] to (Lua value "~(\(% as lua expr))")
compile [%x LSHIFT %shift, %x << %shift] to (..)
Lua value "(\(%x as lua expr) << \(%shift as lua expr))"
compile [%x RSHIFT %shift, %x >>> %shift] to (..)
Lua value "(\(%x as lua expr) >>> \(%shift as lua expr))"
compile [%x ARSHIFT %shift, %x >> %shift] to (..)
Lua value "(\(%x as lua expr) >> \(%shift as lua expr))"
# TODO: implement OR, XOR, AND for multiple operands?
# Unary operators
compile [- %] to: Lua value "(- \(% as lua expr))"
compile [not %] to: Lua value "(not \(% as lua expr))"
test: assume: (length of [1,2,3]) = 3
compile [length of %list, || %list ||] to: Lua value "(#\(%list as lua expr))"
compile [- %] to (Lua value "(- \(% as lua expr))")
compile [not %] to (Lua value "(not \(% as lua expr))")
test: assume ((length of [1, 2, 3]) = 3)
compile [length of %list, || %list ||] to (Lua value "(#\(%list as lua expr))")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Update operators
parse [%var + <- %, %var +<- %] as: %var <- (%var + %)
parse [%var - <- %, %var -<- %] as: %var <- (%var - %)
parse [%var * <- %, %var *<- %] as: %var <- (%var * %)
parse [%var / <- %, %var /<- %] as: %var <- (%var / %)
parse [%var ^ <- %, %var ^<- %] as: %var <- (%var ^ %)
parse [%var and <- %] as: %var <- (%var and %)
parse [%var or <- %] as: %var <- (%var or %)
parse [wrap %var around %] as: %var <- (%var wrapped around %)
parse [%var + <- %, %var +<- %] as (%var <- (%var + %))
parse [%var - <- %, %var -<- %] as (%var <- (%var - %))
parse [%var * <- %, %var *<- %] as (%var <- (%var * %))
parse [%var / <- %, %var /<- %] as (%var <- (%var / %))
parse [%var ^ <- %, %var ^<- %] as (%var <- (%var ^ %))
parse [%var and<- %] as (%var <- (%var and %))
parse [%var or<- %] as (%var <- (%var or %))
parse [wrap %var around %] as (%var <- (%var wrapped around %))

View File

@ -1,4 +1,4 @@
#!/usr/bin/env nomsu -V1
#!/usr/bin/env nomsu -V2.2.4.3
#
This file contains definitions pertaining to variable scoping
@ -6,28 +6,21 @@ use "core/metaprogramming.nom"
use "core/operators.nom"
use "core/collections.nom"
use "core/control_flow.nom"
compile [with local %locals %body, with local %locals do %body] to
compile [with local %locals %body, with local %locals do %body] to:
%body_lua <- (%body as lua statements)
when %locals.type = ?
* "Dict"
%body_lua <-
Lua ".."
\(compile as: <- %locals)
\%body_lua
declare locals
"\(%.1 as lua)" for % in %locals
.. in %body_lua
* "List"
declare locals
"\(% as lua)" for % in %locals
.. in %body_lua
when %locals.type = ?:
* "Dict":
%body_lua <- (Lua "\(compile as (<- %locals))\n\%body_lua")
declare locals ("\(%.1 as lua)" for % in %locals) in %body_lua
* "List":
declare locals ("\(% as lua)" for % in %locals) in %body_lua
* "Var"
* "Action"
* "Action":
declare locals ["\(%locals as lua)"] in %body_lua
* else
barf "Unexpected local: \(%locals as nomsu)"
return
*else (barf "Unexpected local: \(%locals as nomsu)")
return (..)
Lua ".."
do
\%body_lua

View File

@ -1,4 +1,4 @@
#!/usr/bin/env nomsu -V1
#!/usr/bin/env nomsu -V2.2.4.3
#
This file contains some definitions of text escape sequences, including ANSI console
color codes.
@ -6,36 +6,39 @@
use "core/metaprogramming.nom"
# Text functions
action [%texts joined with %glue]
action [%texts joined with %glue] (..)
lua> ".."
local text_bits = {}
for i,bit in ipairs(\%texts) do text_bits[i] = stringify(bit) end
return table.concat(text_bits, \%glue)
parse [joined %texts, %texts joined] as: %texts joined with ""
compile [capitalized %text, %text capitalized] to
parse [joined %texts, %texts joined] as (%texts joined with "")
compile [capitalized %text, %text capitalized] to (..)
Lua value "((\(%text as lua expr)):gsub('%l', string.upper, 1))"
compile [%text with %sub instead of %patt, %text with %patt replaced by %sub, %text s/%patt / %sub] to
compile [..]
%text with %sub instead of %patt, %text with %patt replaced by %sub
%text s/ %patt / %sub
..to (..)
Lua value "((\(%text as lua expr)):gsub(\(%patt as lua expr), \(%sub as lua expr)))"
action [lines in %text, lines of %text]
action [lines in %text, lines of %text] (..)
lua> ".."
local result = list{}
for line in (\%text):gmatch('[^\n]+') do
for line in (\%text):gmatch('[^\\n]+') do
result[#result+1] = line
end
return result
compile [for %match where %text matches %patt %body] to
compile [for %match where %text matches %patt %body] to (..)
Lua ".."
for \(%match as lua expr) in \(%text as lua expr):gmatch(\(%patt as lua expr)) do
\(%body as lua statements)
\(compile as: === next %match ===)
\(compile as (===next %match ===))
end
\(compile as: === stop %match ===)
\(compile as (===stop %match ===))
compile [%expr for %match where %text matches %patt] to
compile [%expr for %match where %text matches %patt] to (..)
Lua value ".."
(function()
local ret = list{}
@ -45,19 +48,22 @@ compile [%expr for %match where %text matches %patt] to
return ret
end)()
compile [%text matches %pattern] to
compile [%text matches %pattern] to (..)
Lua value "(\(%text as lua expr):match(\(%pattern as lua expr)) and true or false)"
# Text literals
lua> ".."
do
local 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, e in pairs(escapes) do
local lua = "'"..e.."'"
nomsu.COMPILE_ACTIONS[name] = (function(nomsu, tree) return LuaCode.Value(tree.source, lua) end)
nomsu.COMPILE_ACTIONS[name] = function(nomsu, tree)
return LuaCode.Value(tree.source, lua)
end
end
end

View File

@ -1,13 +1,11 @@
#!/usr/bin/env nomsu -V1
#!/usr/bin/env nomsu -V2.2.4.3
# How do I...
# Write a comment? Put a # and go till the end of the line
# How do I write a multi-line comment?
After a comment line, any indented text
is considered part of the comment
(including any deeper-level indented text)
The comment ends when the indentation ends
# How do I import a file?
use "core/control_flow.nom"
@ -20,6 +18,7 @@ say "Hello world!"
# How do I set a variable?
%foobar <- 1
%text <- "Hello world"
# Expressions that are more than just literal values require parentheses:
%foobar <- (2 + 3)
%one-two <- 12
@ -27,6 +26,7 @@ say %one-two
# How do I modify a variable?
%foobar <- (%foobar + 1)
# Or, as a shorthand, you can do this to increment a variable:
%foobar +<- 1
@ -38,46 +38,50 @@ say %one-two
to the "..".
<- E.g. the 2 spaces here will be included as part of the text.
But this line will have no leading spaces.
The text will continue until the indentation ends, skipping trailing newlines.
# How do I put values inside text? (AKA string formatting, string interpolation)
say ".."
Text can contain a backslash followed by a variable, list, dict, or parenthesized
expression. This escaped value will be converted to readable text, like so:
The value of %foobar is \%foobar, isn't that nice?
These are some numbers: \[1+1, 2+1, 3+1]
These are some numbers: \[1 + 1, 2 + 1, 3 + 1]
The sum of 2 and 4 is \(2 + 4).
A backslash not followed by any of these, and not at the end of a line
like this: \ will just be treated as a backslash.
like this: \\ will just be treated as a backslash.
Or, two backlashes will be treated as a single backslash, no matter what follows,
like this: \\%foobar <- won't insert any values
If you need to split a long line without inserting a newline, you can \
..end a line with backslash and start the next line with two periods, like that.
Similarly, you can put a long interpolated indented value like: \
If you need to split a long line without inserting a newline, you can end a line \
..with backslash and start the next line with two periods, like that.
Similarly, you can put a long interpolated indented value like: \(..)
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9
.. between a backslash and two periods.
say "Single-line text can contain escape sequences like \", \\, \n, \065, and \x0A"
# How do I define a list?
%my-list <- [1,2,"hello"]
%my-list <- [1, 2, "hello"]
# Really long lists can use [..] followed by a bunch of indented values delimited
by commas and/or newlines
%my-really-long-list <- [..]
1,2,3,4
5,6
1, 2, 3, 4
5, 6
7
8,9,10
8, 9, 10
# How do I use a list?
%my-list <- ["first item", "second item", "third item"]
# Lists are 1-indexed because they're implemented as Lua tables, so this prints "first item"
say %my-list.1
# List entries can be modified like this:
%my-list.1 <- "ONE!!!"
say (length of %my-list)
@ -95,99 +99,105 @@ say %my-dict.x
%my-dict.x <- 9999
# How do I do conditional branching?
if: 1 < 10
if (1 < 10):
say "1 is indeed < 10"
if: 1 > 10
if (1 > 10):
say "this won't print"
..else
..else:
say "this will print"
# There's no "elseif", so for longer conditionals, a "when" branch is the best option
when
when:
* (3 > 6)
* (3 > 5)
* (3 > 4)
* (3 > 4):
say "this won't print"
* (3 > 3)
* (3 > 3):
say "this won't print"
* (3 > 2)
* (3 > 2):
say "this will print"
* else
*else:
say "this is the default case"
# How do I do a switch statement?
when 3 = ?
when 3 = ?:
* 0
* 1
* 2
* 2:
say "this won't print"
* 3
* 3:
say "this will print"
* else
*else:
say "this won't print"
# How do I loop over a list (a foreach loop)?
%list <- [1,2,3]
for %x in %list
%list <- [1, 2, 3]
for %x in %list:
say "For %x loop #\%x"
# How do I loop over a number range?
# This is inclusive, so it will loop over 1,2, and 3
for %i in 1 to 3
for %i in 1 to 3:
say "For %i in 1 to 3 loop #\%i"
# This will print 0,2, and 4
for %even in 0 to 5 by 2
for %even in 0 to 5 by 2:
say "Even #\%even"
for %backwards in 3 to 1 by -1
for %backwards in 3 to 1 by -1:
say "Backwards #\%backwards"
# How do I do a 'while' loop?
%x <- 1
repeat while: %x <= 3
repeat while (%x <= 3):
say "repeat while loop #\%x"
%x +<- 1
%x <- 1
repeat until: %x > 3
repeat until (%x > 3):
say "repeat until loop #\%x"
%x +<- 1
# How do I do an infinite loop?
%x <- 1
repeat
repeat:
say "repeat loop #\%x"
%x +<- 1
if: %x > 3
if (%x > 3):
stop repeating
# How do I do a 'goto'?
do
do:
%x <- 1
=== %again ===
say "GOTO loop #\%x"
%x +<- 1
if: %x <= 3
if (%x <= 3):
go to %again
say "finished going to"
# How do I define a function/method/procedure?
# In nomsu, they're called "action"s, and they can be declared like this:
action [say both %first and also %second]
action [say both %first and also %second]:
say %first
# Function arguments are accessed just like variables
say %second
# Actions can use "return" to return a value early
action [first fibonacci above %n]
action [first fibonacci above %n]:
%f1 <- 0
%f2 <- 1
repeat
repeat:
%tmp <- (%f1 + %f2)
%f1 <- %f2
%f2 <- %tmp
if: %f2 > %n
if (%f2 > %n):
return %f2
say (first fibonacci above 10)
@ -197,19 +207,18 @@ action [..]
I hate %worse-things more than %better-things
I think %worse-things are worse than %better-things
I like %better-things more than %worse-things
..
..:
say "\(%better-things capitalized) rule and \%worse-things drool!"
I like "dogs" more than "cats"
I think "chihuahuas" are worse than "corgis"
# Actions can have parts of the action's name spread throughout.
Everything that's not a literal value is treated as part of the action's name
say both "Hello" and also "again!"
# Actions can even start with a parameter
action [%what-she-said is what she said]
action [%what-she-said is what she said]:
say %what-she-said
say "-- she said"
@ -217,122 +226,123 @@ action [%what-she-said is what she said]
# The language only reserves []{}().,:;% as special characters, so actions
can have really funky names!
action [>> %foo-bar $$$^ --> % @& _~-^-~_~-^ %1 !]
action [>> %foo-bar $$$^ --> % @&_~-^-~_~-^ %1 !]:
say %foo-bar
say %
say %1
>> "wow" $$$^ --> "so flexible!" @& _~-^-~_~-^ "even numbers can be variables!" !
>> "wow" $$$^ --> "so flexible!" @&_~-^-~_~-^ "even numbers can be variables!" !
# There's also full unicode support
%こんにちは <- "こんにちは"
action [% と言う]
"\(%)世界"
action [% と言う] "\%世界"
say (%こんにちは と言う)
# Math and logic operations are just treated the same as actions in the syntax
say (2 + 3)
# So you can define your own operators, although they will need to be parenthesized to
play nicely with other operators
action [%a ++ %b]
2 * (%a + %b)
action [%a ++ %b] (2 * (%a + %b))
say (1 ++ (2 * 3))
# How do I do grouping?
# Expressions can be grouped by enclosing parentheses:
say (2 + 3)
# Or by an indented region
say
# Or by (..) followed by an indented region
say (..)
2 + 3
# Or by ":" until the end of the line
say: 2 + 3
# If you need to keep going after an indented region, you can start the next line with ".."
say both
"Very long first argument that needs its own line"
say both "Very long first argument that needs its own line"
..and also "short second arg"
action [my favorite number]: 21 + 2
action [my favorite number] (21 + 2)
# This can be nested:
say both
say both (..)
my favorite
..number
..and also "foo"
# Macros:
# The "lua> %" and "=lua %" macros can be used to write raw lua code:
action [say the time]
action [say the time] (..)
lua> ".."
io.write("The OS time is: "..os.time().."\n");
io.write("The OS time is: ", os.time(), "\\n");
say the time
say "Math expression result is: \(=lua "(1 + 2*3 + 3*4)^2")"
# Variables can be accessed via \%varname
action [square root of %n]
=lua "math.sqrt(\%n)"
action [square root of %n] (=lua "math.sqrt(\%n)")
say "The square root of 2 is \(square root of 2)"
# Macros can be defined to transform one bit of nomsu code into another using "parse % as %":
parse [if %condition is untrue %body] as
parse [if %condition is untrue %body] as (..)
if (not %condition) %body
# Or to transform nomsu code into custom lua code using "compile % to %"
compile [if %condition on opposite day %body] to
compile [if %condition on opposite day %body] to (..)
Lua ".."
if not \(%condition as lua expr) then
\(%body as lua statements)
end
# Constants can be defined as macros
parse [TWENTY] as: 20
parse [TWENTY] as 20
# When they're invoked, they'll need parentheses just like a function call
parse [TWENTY ONE] as: 21
parse [TWENTY ONE] as 21
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# If you need to use compile-time actions in the same file that they're defined in, you
can add a line of tildes (3 or more), and the file will be split into chunks, and each
chunk will run before the next one compiles. (note that each chunk has its own scope)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (1 > (TWENTY)) is untrue
if (1 > (TWENTY)) is untrue:
say "Nomsu parsing macros work!"
say "It looks like a keyword, but there's no magic here!"
if (1 > (TWENTY)) on opposite day
if (1 > (TWENTY)) on opposite day:
say "Lua compiling macros work!"
say "It looks like a keyword, but there's no magic here!"
# How do I use an action as a value?
# Well... it's always *possible* to fall back to Lua behavior for something like this:
action [best of %items according to %key-fn]
<- {%best:nil, %best-key:nil}
for %item in %items
action [best of %items according to %key-fn]:
<- {%best: nil, %best-key: nil}
for %item in %items:
%key <- (=lua "\%key-fn(\%item)")
if: (%best is (nil)) or (%key > %best-key)
<- {%best:%item, %best-key:%key}
if ((%best is (nil)) or (%key > %best-key)):
<- {%best: %item, %best-key: %key}
return %best
say: best of [2,-3,4,-8] according to ([%x] -> (%x * %x))
say (best of [2, -3, 4, -8] according to ([%x] -> (%x * %x)))
# But nomsu was mostly designed so that you don't *need* to. Instead of creating a
one-off function to pass to another function and get called a bunch of times, you
could use a macro to generate a single block of code that inlines the expression you
want to use:
parse [best of %items where %item-var has score %key-expr] as
result of
<- {%best:nil, %best-key:nil}
for %item-var in %items
parse [best of %items where %item-var has score %key-expr] as (..)
result of:
<- {%best: nil, %best-key: nil}
for %item-var in %items:
%key <- %key-expr
if: (%best is (nil)) or (%key > %best-key)
<- {%best:%item-var, %best-key:%key}
if ((%best is (nil)) or (%key > %best-key)):
<- {%best: %item-var, %best-key: %key}
return %best
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
say: best of [2,-3,4,-8] where %x has score (%x * %x)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
say (best of [2, -3, 4, -8] where %x has score (%x * %x))
# The first example generates code that looks like:
A_best_of_1_according_to_2 = function(items, key_fn)
local best, best_key = nil, nil
for _, item in ipairs(items) do
@ -346,9 +356,9 @@ say: best of [2,-3,4,-8] where %x has score (%x * %x)
print(A_best_of_1_according_to_2({2,-3,4,-8}, function(x)
return x * x
end))
But the second example produces something more like:
print((function()
local best, best_key = nil, nil
for _, x in ipairs({1,-2,3,-4}) do
@ -364,4 +374,3 @@ say: best of [2,-3,4,-8] where %x has score (%x * %x)
the code only has to do a multiplication, instead of calling a function that does the
multiplication. In addition to being more efficient, it's also more powerful and
flexible for the language to allow you to define syntax that manipulates expressions.

View File

@ -37,7 +37,7 @@ compile [%expr for file %f in %path] to
return ret
end)()
action [write to file %filename %text, to file %filename write %text]
action [write to file %filename %text, to file %filename write %text, write %text to file %filename]
lua> ".."
local file = io.open(\%filename, 'w')
file:write(\%text)

View File

@ -508,9 +508,14 @@ do
NomsuCompiler.compile = function(self, tree)
if tree.version then
do
local upgrade = self['A' .. string.as_lua_id("upgrade 1 from 2")]
if upgrade then
tree = upgrade(tree, tree.version)
local get_version = self['A' .. string.as_lua_id("Nomsu version")]
if get_version then
do
local upgrade = self['A' .. string.as_lua_id("1 upgraded from 2 to 3")]
if upgrade then
tree = upgrade(tree, tree.version, get_version())
end
end
end
end
end

View File

@ -328,8 +328,9 @@ with NomsuCompiler
.compile = (tree)=>
if tree.version
if upgrade = @['A'..string.as_lua_id("upgrade 1 from 2")]
tree = upgrade(tree, tree.version)
if get_version = @['A'..string.as_lua_id("Nomsu version")]
if upgrade = @['A'..string.as_lua_id("1 upgraded from 2 to 3")]
tree = upgrade(tree, tree.version, get_version!)
switch tree.type
when "Action"
stub = tree.stub

View File

@ -1,10 +1,21 @@
#!/usr/bin/env Nomsu -V 2.2.4.3
use "core"
use "compatibility"
use "lib/os.nom"
for %path in (=lua "arg"):
%args <- (command line args)
%inplace <- (no)
if (%args.1 is "-i"):
%inplace <- (yes)
remove index 1 from %args
for %path in %args:
if (%path is "-i"): %inplace <- (yes)
for file %filename in %path:
%tree <- (parse (read file %filename) from %filename)
%tree <- (%tree upgraded from %tree.version to (Nomsu version))
say "#!/usr/bin/env nomsu -V\(Nomsu version)\n\(%tree as nomsu)"
%text <- "#!/usr/bin/env nomsu -V\(Nomsu version)\n\(%tree as nomsu)"
if %inplace:
write %text to file %filename
..else:
say %text