Cleanup: removed "File" type trees (now just Block), overhauled

how_do_i.nom, added "result of %" macro, which allowed comprehensions to
be way more concisely defined. Moved len() operator into the nomsu
environment.
This commit is contained in:
Bruce Hill 2018-05-10 22:47:03 -07:00
parent 77c11a2443
commit 4126589afe
11 changed files with 239 additions and 227 deletions

View File

@ -36,16 +36,14 @@ immediately
return (yes)
immediately
# Note: it's important to have the space after "[" to prevent confusion if %index is a string
compile [%list has key %index, %list has index %index] to
Lua value ".."
((\(%list as lua expr))[ \(%index as lua expr)] ~= nil)
parse [%list has key %index, %list has index %index] as
%list.%index != (nil)
# Note: it's important to have the space after "[" to prevent confusion if %index is a string
compile [..]
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
..to: Lua value "((\(%list as lua expr))[ \(%index as lua expr)] == nil)"
..as
%list.%index = (nil)
compile [number of keys in %list] to
Lua value "utils.size(\(%list as lua expr))"
@ -61,90 +59,65 @@ immediately
# List Comprehension
immediately
compile [%expression for %item in %iterable] to
assume (%item.type is "Var") or barf ".."
List comprehension has the wrong type for the loop variable. Expected Var, but got: \(%item.type)
return
Lua value ".."
(function()
local comprehension = {};
for i,\(%item as lua expr) in ipairs(\(%iterable as lua expr)) do
comprehension[i] = \(%expression as lua expr);
end
return comprehension;
end)()
parse [%expression for all %iterable] as: %expression for % in %iterable
parse [%expression for %item in %iterable] as
result of
%comprehension <- []
for %i = %item in %iterable
%comprehension.%i <- %expression
return %comprehension
compile [..]
parse [%expression for all %iterable] as
%expression for % in %iterable
parse [..]
%expression for %index from %start to %stop via %step
%expression for %index from %start to %stop by %step
..to
assume (%index.type is "Var") or barf ".."
List comprehension has the wrong type for the loop variable. Expected Var, but got: \(%index.type)
return
Lua value ".."
(function()
local comprehension = {};
for \(%index as lua expr)=\(%start as lua expr),\(%stop as lua expr),\(%step as lua expr) do
comprehension[#comprehension+1] = \(%expression as lua expr);
end
return comprehension;
end)()
parse [%expression for all ] as: %expression for % in %iterable
parse [%expression for %var from %start to %stop] as: %expression for %var from %start to %stop via 1
..as
result of
%comprehension <- []
for %index from %start to %stop via %step
add %expression to %comprehension
return %comprehension
parse [%expression for all %iterable] as
%expression for % in %iterable
parse [%expression for %var from %start to %stop] as
%expression for %var from %start to %stop via 1
parse [..]
%expression for all %start to %stop by %step
%expression for all %start to %stop via %step
..as: %expression for % from %start to %stop via %step
parse [%expression for all %start to %stop] as: %expression for all %start to %stop via 1
..as
%expression for % from %start to %stop via %step
compile [%expression for %key = %value in %iterable] to
assume (%key.type is "Var") or barf ".."
List comprehension has the wrong type for the key loop variable. Expected Var, but got: \(%key.type)
assume (%value.type is "Var") or barf ".."
List comprehension has the wrong type for the value loop variable. Expected Var, but got: \(%value.type)
return
Lua value ".."
(function()
local comprehension = {};
for \(%key as lua expr), \(%value as lua expr) in pairs(\(%iterable as lua expr)) do
table.insert(comprehension, \(%expression as lua expr));
end
return comprehension;
end)()
parse [%expression for all %start to %stop] as
%expression for all %start to %stop via 1
# Dict comprehensions
immediately
compile [%key = %value for %item in %iterable] to
assume (%item.type is "Var") or barf ".."
Dict comprehension has the wrong type for the loop variable. Expected Var, but got: \(%item.type)
# Note: it's important to have the space after "[" to prevent confusion if %key is a string
return
Lua value ".."
(function()
local comprehension = {};
for i,\(%item as lua expr) in ipairs(\(%iterable as lua expr)) do
comprehension[ \(%key as lua expr)] = \(%value as lua expr)
end
return comprehension;
end)()
parse [%key = %value for all %iterable] as: %key = %value for % in %iterable
parse [%expression for %key = %value in %iterable] as
result of
%comprehension <- []
for %key = %value in %iterable
add %expression to %comprehension
return %comprehension
compile [%key = %value for %src_key = %src_value in %iterable] to
assume (%src_key.type is "Var") or barf ".."
Dict comprehension has the wrong type for the key loop variable. Expected Var, but got: \(%src_key.type)
assume (%src_value.type is "Var") or barf ".."
Dict comprehension has the wrong type for the value loop variable. Expected Var, but got: \(%src_value.type)
# Note: it's important to have the space after "[" to prevent confusion if %key is a string
return
Lua value ".."
(function()
local comprehension = {};
for \(%src_key as lua expr), \(%src_value as lua expr) in pairs(\(%iterable as lua expr)) do
comprehension[ \(%key as lua expr)] = \(%value as lua expr);
end
return comprehension;
end)()
# Dict comprehensions
parse [%key = %value for %item in %iterable] as
result of
%comprehension <- {}
for %item in %iterable
%comprehension.%key <- %value
return %comprehension
parse [%key = %value for all %iterable] as
%key = %value for % in %iterable
parse [%key = %value for %src_key = %src_value in %iterable] as
result of
%comprehension <- {}
for %src_key = %src_value in %iterable
%comprehension.%key <- %value
return %comprehension
immediately
action [%lists flattened]

View File

@ -423,3 +423,11 @@ immediately
end
end --do-then-always
# Inline thunk:
immediately
compile [result of %body] to
Lua value ".."
(function()
\(%body as lua statements)
end)()

View File

@ -127,6 +127,9 @@ immediately
lua:convert_to_statements();
return lua;
action [%tree with vars %vars]
=lua "nomsu:tree_with_replaced_vars(\%tree, \%vars)"
compile [declare locals in %code] to
Lua value "\(%code as lua expr):declare_locals()"

View File

@ -163,14 +163,8 @@ immediately
# Unary operators
compile [- %] to: Lua value "(- \(% as lua expr))"
compile [not %] to: Lua value "(not \(% as lua expr))"
compile [length of %list] to
# A bit of a hack so that luajit works properly.
Lua value ".."
(function(l)
local mt = getmetatable(l);
if mt and mt.__len then return mt.__len(l) end
return #l
end)(\(%list as lua expr))
# Using custom "len()" instead of Lua's "#" operator for compatibility with luajit.
compile [length of %list] to: Lua value "len(\(%list as lua expr))"
# Update operators
immediately

View File

@ -13,29 +13,27 @@ use "core/control_flow.nom"
# How do I import all the files in a directory?
use "core"
# Set a variable?
# How do I print stuff?
say "Hello world!"
# How do I set a variable?
%x <- 1
%str <- "Hello world"
# Expressions that are more than just literal values require parentheses:
%x <- (2 + 3)
# Modify a variable?
%foobar <- 100
# As a shorthand, you can type:
%foobar +<- 1
# which does the same thing as:
%foobar <- (%foobar + 1)
# How do I modify a variable?
%x <- (%x + 1)
# Or, as a shorthand, you can do this to increment a variable:
%x +<- 1
# Print stuff?
say "Hello world!"
# Define a mutli-line string?
# How do I define a mutli-line string?
%mutli_str <- ".."
Start with "..", then put lines below it
that are indented one level.
The string will continue until the indentation ends.
# Format a string?
# How do I put values inside a string?
%format_str <- ".."
Strings can contain a backslash followed by a variable, list, dict, or parenthesized
expression. This escaped value will be converted to a readable string, like so:
@ -44,7 +42,7 @@ say "Hello world!"
If you need to use a plain ol' backslash, you can do \\ <-- that
%format_str2 <- "Single-line strings can contain escape sequences like \", \\, \n, \065, and \x0A"
# Define a list?
# How do I define a list?
%my_list <- [1,2,"hello"]
#.. Really long lists can use [..] followed by a bunch of indented values delimited
by commas and/or newlines
@ -54,7 +52,7 @@ say "Hello world!"
7
8,9,10
# Use a list?
# 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
@ -62,19 +60,19 @@ say %my_list.1
%my_list.1 <- "ONE!!!"
say (length of %my_list)
# Define a dictionary/hash map?
# How do I define a dictionary/hash map?
%my_dict <- {x: 99, y: 101}
%my_dict <- {..}
x: 101, y: 2
"99 bottles": 99
653: 292
# Use a dict?
# How do I use a dict?
# Dicts are also implemented as Lua tables, so they're accessed and modified the same way as lists
say %my_dict.x
%my_dict.x <- 9999
# Do conditional branching?
# How do I do conditional branching?
if: 1 < 10
say "1 is indeed < 10"
@ -96,7 +94,7 @@ when
* else
say "this is the default case"
# Do a switch statement?
# How do I do a switch statement?
when 3 = ?
* 0
* 1
@ -107,7 +105,7 @@ when 3 = ?
* else
say "this won't print"
# Loop over a list (a foreach loop)?
# How do I loop over a list (a foreach loop)?
%list <- [1,2,3]
for %x in %list
say "For %x loop #\%x"
@ -115,7 +113,7 @@ for %x in %list
for all %list
say "For all loop #\%"
# Loop over a number range?
# How do I loop over a number range?
# This is inclusive, so it will loop over 1,2, and 3
for %i from 1 to 3
say "For %i from 1 to 3 loop #\%i"
@ -127,7 +125,7 @@ for %even from 0 to 5 by 2
for %backwards from 3 to 1 by -1
say "Backwards #\%backwards"
# While loops:
# How do I do a 'while' loop?
%x <- 1
repeat while: %x <= 3
say "repeat while loop #\%x"
@ -138,7 +136,7 @@ repeat until: %x > 3
say "repeat until loop #\%x"
%x +<- 1
# Infinite loop:
# How do I do an infinite loop?
%x <- 1
repeat
say "repeat loop #\%x"
@ -146,7 +144,7 @@ repeat
if: %x > 3
stop repeating
# GOTOs:
# How do I do a 'goto'?
do
%x <- 1
=== %again ===
@ -157,13 +155,14 @@ do
say "finished going to"
# Function definition:
# 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]
say %first
# Function arguments are accessed just like variables
say %second
# Functions can use "return" to return a value early
# Actions can use "return" to return a value early
action [first fibonacci above %n]
%f1 <- 0
%f2 <- 1
@ -176,7 +175,7 @@ action [first fibonacci above %n]
say (first fibonacci above 10)
# Functions can have aliases, which may or may not have the arguments in different order
# Actions can have aliases, which may or may not have the arguments in different order
action [..]
I hate %worse_things more than %better_things
I think %worse_things are worse than %better_things
@ -188,18 +187,18 @@ I like "dogs" more than "cats"
I think "chihuahuas" are worse than "corgis"
#.. Function calls can have parts of the function's name spread throughout.
Everything that's not a literal value is treated as part of the function's name
#.. 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!"
# Functions can even have their name at the end:
# Actions can even start with a parameter
action [%what_she_said is what she said]
say %what_she_said
say "-- she said"
"Howdy pardner" is what she said
#.. The language only reserves []{}().,:;% as special characters, so functions
#.. The language only reserves []{}().,:;% as special characters, so actions
can have really funky names!
action [>> %foo_bar $$$^ --> % @& _~-^-~_~-^ %1 !]
say %foo_bar
@ -214,7 +213,7 @@ action [% と言う]
"\(%)世界"
say (%こんにちは と言う)
# Math and logic operations are just treated the same as function calls in the syntax
# 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
@ -222,6 +221,7 @@ 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)
@ -282,3 +282,60 @@ 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 all %items
%key <- (=lua "\%key_fn(\%)")
if: (%best is (nil)) or (%key > %best_key)
<- {%best:%, %best_key:%key}
return %best
immediately
compile [function %var %body] to
Lua value ".."
(function(\(%var as lua expr))
return \(%body as lua expr)
end)
say: best of [2,-3,4,-8] according to (function %: % * %)
#.. 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:
immediately
parse [best of %items according to %key_expr] as
result of
<- {%best:nil, %best_key:nil}
for all %items
%key <- %key_expr
if: (%best is (nil)) or (%key > %best_key)
<- {%best:%, %best_key:%key}
return %best
#.. This results in generated code that is more efficient (no function calls in the
inner loop)
say: best of [2,-3,4,-8] according to (% * %)
#.. In a functional programming language, you might do something like:
doubled = map(list, function(x) return 2 * x end)
to get a new list with every entry multiplied by 2, but it's *much* more readable to
do something like:
%nums <- [1,2,3,4,5]
%double_nums <- ((2 * %num) for %num in %nums)
#.. Nomsu comes with built-in list comprehensions, but the flexible macro system makes it
incredibly easy to make similar constructs.
immediately
parse [%expr for %key in %list BACKWARDS!] as
result of
%result <- []
%N <- (length of %list)
for %i = %key in %list
%result.(%N - %i + 1) <- %expr
return %result
%double_nums <- ((2 * %num) for %num in %nums BACKWARDS!)
say %double_nums

View File

@ -375,7 +375,6 @@ do
end
local tree = self:parse(nomsu_code)
assert(tree, "Failed to parse: " .. tostring(nomsu_code))
assert(tree.type == "File", "Attempt to run non-file: " .. tostring(tree.type))
local lua = tree:as_lua(self)
lua:convert_to_statements()
lua:declare_locals()
@ -492,7 +491,7 @@ do
return
end
local _exp_0 = tree.type
if "List" == _exp_0 or "File" == _exp_0 or "Block" == _exp_0 or "Action" == _exp_0 or "Text" == _exp_0 or "IndexChain" == _exp_0 then
if "List" == _exp_0 or "Block" == _exp_0 or "Action" == _exp_0 or "Text" == _exp_0 or "IndexChain" == _exp_0 then
local _list_0 = tree.value
for _index_0 = 1, #_list_0 do
local v = _list_0[_index_0]
@ -543,6 +542,18 @@ do
return tree:map(fn)
end,
tree_with_replaced_vars = function(self, tree, replacements)
if not (next(replacements)) then
return tree
end
if next(replacements).type == "Var" then
do
local _tbl_0 = { }
for k, v in pairs(replacements) do
_tbl_0[self:var_to_lua_identifier(k)] = v
end
replacements = _tbl_0
end
end
return tree:map(function(t)
if t.type == "Var" then
local id = tostring(t:as_lua(self))
@ -737,6 +748,23 @@ do
load = load,
ipairs = ipairs
}
if jit then
self.environment.len = function(x)
do
local mt = getmetatable(x)
if mt then
if mt.__len then
return mt.__len(x)
end
end
end
return #x
end
else
self.environment.len = (function(x)
return #x
end)
end
for k, v in pairs(Types) do
self.environment[k] = v
end

View File

@ -254,6 +254,13 @@ class NomsuCompiler
:table, :assert, :dofile, :loadstring, :type, :select, :debug, :math, :io, :pairs,
:load, :ipairs,
}
@environment.len = if jit
(x)->
if mt = getmetatable(x)
if mt.__len
return mt.__len(x)
return #x
else ((x) -> #x)
for k,v in pairs(Types) do @environment[k] = v
@environment.Tuple = Tuple
@environment.Lua = Lua
@ -331,7 +338,6 @@ class NomsuCompiler
if #tostring(nomsu_code) == 0 then return nil
tree = @parse(nomsu_code)
assert tree, "Failed to parse: #{nomsu_code}"
assert tree.type == "File", "Attempt to run non-file: #{tree.type}"
lua = tree\as_lua(@)
lua\convert_to_statements!
lua\declare_locals!
@ -410,7 +416,7 @@ class NomsuCompiler
coroutine.yield(tree, depth)
return unless Types.is_node(tree)
switch tree.type
when "List", "File", "Block", "Action", "Text", "IndexChain"
when "List", "Block", "Action", "Text", "IndexChain"
for v in *tree.value
@walk_tree(v, depth+1)
when "Dict"
@ -445,6 +451,9 @@ class NomsuCompiler
return tree\map(fn)
tree_with_replaced_vars: (tree, replacements)=>
return tree unless next(replacements)
if next(replacements).type == "Var"
replacements = {@var_to_lua_identifier(k),v for k,v in pairs(replacements)}
tree\map (t)->
if t.type == "Var"
id = tostring(t\as_lua(self))

View File

@ -1,10 +1,8 @@
file (File):
{| shebang?
(ignored_line %nl)*
statement ((nodent (statement / (({} ([^%nl]* -> "Error while parsing line")) => error)))
/ (({} ((%nl %dedent) ->"Indentation error")) => error))*
(%nl ignored_line)*
|} -> Tuple
file:
shebang?
(ignored_line %nl)*
(block / action / expression)?
(%nl ignored_line)*
(!. / (({} (.* -> "Parse error")) => error))
shebang: "#!" [^%nl]* (!. / %nl)
@ -15,23 +13,26 @@ inline_statement: inline_action / inline_expression
inline_block (Block):
{| inline_statement (%ws* ";" %ws* inline_statement)+ |} -> Tuple
block (Block):
{| statement (nodent statement)+ |} -> Tuple
{| statement (nodent (statement / (({} ([^%nl]* -> "Error while parsing block line")) => error)))+ |} -> Tuple
inline_nomsu (Nomsu): "\" noindex_inline_expression
indented_nomsu (Nomsu):
"\" (noindex_inline_expression / (":" %ws* (inline_block / inline_action / inline_expression) eol) / indented_expression)
index_chain (IndexChain):
{| noindex_inline_expression ("." ((({} ({|{%operator / (!number plain_word)}|} -> Tuple) {}) -> Text) / noindex_inline_expression))+ |} -> Tuple
{|
noindex_inline_expression ("." (text_word / noindex_inline_expression))+
|} -> Tuple
noindex_inline_expression:
number / variable / inline_text / inline_list / inline_dict / inline_nomsu
/ (
"(" %ws* (inline_block / inline_action / inline_expression) %ws*
/ ( "("
%ws* (inline_block / inline_action / inline_expression) %ws*
(")"
/ (({} ((!. / &%nl) -> 'Expected to find a ) before the end of the line')) => error)
/ (({} ([^%nl]* -> 'Error while parsing subexpression')) => error))
/ (({} ([^%nl]* -> 'Error while parsing subexpression')) => error)
)
)
inline_expression:
index_chain / noindex_inline_expression
@ -49,10 +50,12 @@ inline_action (Action):
{| (inline_expression %ws*)* word (%ws* (inline_expression / word))*
(%ws* ":" %ws* (inline_block / inline_action / inline_expression))?|} -> Tuple
action (Action):
{| (expression (dotdot / %ws*))* word ((dotdot / %ws*) (expression / word))* |} -> Tuple
{| (expression (dotdot? %ws*))* word ((dotdot? %ws*) (expression / word))* |} -> Tuple
word (Word): { %operator / (!number plain_word) }
text_word (Text): {| {%operator / (!number plain_word)} |} -> Tuple
inline_text (Text):
!('".."' eol)
'"' ({|
@ -119,7 +122,7 @@ dict_line:
inline_dict_item:
((dict_key %ws* (":" %ws* (inline_block / inline_action / inline_expression)?)?)-> DictEntry)
dict_key:
(({} ({|{%operator / (!number plain_word)}|} -> Tuple) {}) -> Text) / inline_expression
text_word / inline_expression
block_comment: "#.." [^%nl]* (%nl+ %indent [^%nl]* (%nl+ %nodent [^%nl]*)* %dedent)?
line_comment: "#" [^%nl]*
@ -131,5 +134,5 @@ nodent: eol (%nl ignored_line)* %nl %nodent
dedent: eol (%nl ignored_line)* (((!.) &%dedent) / (&(%nl %dedent)))
non_dedent_error: (!dedent .)* eol (%nl ignored_line)* (!. / &%nl)
comma: %ws* "," %ws*
dotdot: nodent ".." %ws*
dotdot: nodent ".."
plain_word: ([a-zA-Z0-9_] / %utf8_char)+

View File

@ -52,63 +52,9 @@ Tree = function(name, methods)
"source"
}, methods)
end
Tree("File", {
as_lua = function(self, nomsu)
if #self.value == 1 then
return self.value[1]:as_lua(nomsu)
end
local lua = Lua(self.source)
for i, line in ipairs(self.value) do
local line_lua = line:as_lua(nomsu)
if not line_lua then
error("No lua produced by " .. tostring(repr(line)), 0)
end
if i > 1 then
lua:append("\n")
end
lua:convert_to_statements()
lua:append(line_lua)
end
lua:declare_locals()
return lua
end,
as_nomsu = function(self, inline)
if inline == nil then
inline = false
end
if inline then
return nil
end
local nomsu = Nomsu(self.source)
for i, line in ipairs(self.value) do
line = assert(line:as_nomsu(nil, true), "Could not convert line to nomsu")
nomsu:append(line)
if i < #self.value then
if tostring(line):match("\n") then
nomsu:append("\n")
end
nomsu:append("\n")
end
end
return nomsu
end,
map = function(self, fn)
return fn(self) or self:with_value(Tuple(unpack((function()
local _accum_0 = { }
local _len_0 = 1
local _list_0 = self.value
for _index_0 = 1, #_list_0 do
local v = _list_0[_index_0]
_accum_0[_len_0] = v:map(fn)
_len_0 = _len_0 + 1
end
return _accum_0
end)())))
end
})
Tree("Nomsu", {
as_lua = function(self, nomsu)
return Lua.Value(self.source, "nomsu:parse(Nomsu(", repr(self.value.source), ", ", repr(tostring(self.value.source:get_text())), ")).value[1]")
return Lua.Value(self.source, "nomsu:parse(Nomsu(", repr(self.value.source), ", ", repr(tostring(self.value:as_nomsu())), "))")
end,
as_nomsu = function(self, inline)
if inline == nil then
@ -162,6 +108,9 @@ Tree("Block", {
nomsu:append(line)
if i < #self.value then
nomsu:append("\n")
if tostring(line):match("\n") then
nomsu:append("\n")
end
end
end
return nomsu
@ -212,6 +161,9 @@ Tree("Action", {
args = _accum_0
end
local ret = compile_action(self, unpack(args))
if not ret then
error("Failed to produce any Lua")
end
return ret
end
local action = rawget(nomsu.environment.ACTIONS, stub)
@ -814,6 +766,9 @@ Tree("IndexChain", {
if not (bit_nomsu) then
return nil
end
if bit.type == "Action" or bit.type == "Block" then
bit_nomsu:parenthesize()
end
nomsu:append(bit_nomsu)
end
return nomsu

View File

@ -33,40 +33,9 @@ Tree = (name, methods)->
Types[name] = immutable {"value","source"}, methods
Tree "File",
as_lua: (nomsu)=>
if #@value == 1
return @value[1]\as_lua(nomsu)
lua = Lua(@source)
for i, line in ipairs @value
line_lua = line\as_lua(nomsu)
if not line_lua
error("No lua produced by #{repr line}", 0)
if i > 1
lua\append "\n"
lua\convert_to_statements!
lua\append line_lua
lua\declare_locals!
return lua
as_nomsu: (inline=false)=>
return nil if inline
nomsu = Nomsu(@source)
for i, line in ipairs @value
line = assert(line\as_nomsu(nil,true), "Could not convert line to nomsu")
nomsu\append line
if i < #@value
if tostring(line)\match("\n")
nomsu\append "\n"
nomsu\append "\n"
return nomsu
map: (fn)=>
fn(self) or @with_value(Tuple(unpack([v\map(fn) for v in *@value])))
Tree "Nomsu",
as_lua: (nomsu)=>
Lua.Value(@source, "nomsu:parse(Nomsu(",repr(@value.source),", ",repr(tostring(@value.source\get_text!)),")).value[1]")
Lua.Value(@source, "nomsu:parse(Nomsu(",repr(@value.source),", ",repr(tostring(@value\as_nomsu!)),"))")
as_nomsu: (inline=false)=>
nomsu = @value\as_nomsu(true)
@ -105,6 +74,8 @@ Tree "Block",
nomsu\append line
if i < #@value
nomsu\append "\n"
if tostring(line)\match("\n")
nomsu\append "\n"
return nomsu
map: (fn)=>
@ -121,6 +92,7 @@ Tree "Action",
args = [args[p-1] for p in *nomsu.environment.ARG_ORDERS[compile_action][stub]]
-- Force Lua to avoid tail call optimization for debugging purposes
ret = compile_action(self, unpack(args))
if not ret then error("Failed to produce any Lua")
return ret
action = rawget(nomsu.environment.ACTIONS, stub)
lua = Lua.Value(@source)
@ -492,6 +464,8 @@ Tree "IndexChain",
nomsu\append "."
bit_nomsu = bit\as_nomsu(true)
return nil unless bit_nomsu
if bit.type == "Action" or bit.type == "Block"
bit_nomsu\parenthesize!
nomsu\append bit_nomsu
return nomsu

View File

@ -192,3 +192,11 @@ try
assume (%x = 1) or barf "do/then always failed"
say "Control flow test passed."
assume
(..)
result of
%n <- 0
for all [1,2,3]: %n +<- %
return %n
..= 6