aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/collections.nom143
-rw-r--r--core/control_flow.nom8
-rw-r--r--core/metaprogramming.nom3
-rw-r--r--core/operators.nom10
-rw-r--r--examples/how_do_i.nom119
-rw-r--r--nomsu.lua32
-rwxr-xr-xnomsu.moon13
-rw-r--r--nomsu.peg33
-rw-r--r--nomsu_tree.lua65
-rw-r--r--nomsu_tree.moon38
-rw-r--r--tests/control_flow.nom8
11 files changed, 242 insertions, 230 deletions
diff --git a/core/collections.nom b/core/collections.nom
index 97bc7ad..9086e23 100644
--- a/core/collections.nom
+++ b/core/collections.nom
@@ -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
-
- 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)()
-
-# 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
-
- 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)()
+ ..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
+
+ parse [%expression for %key = %value in %iterable] as
+ result of
+ %comprehension <- []
+ for %key = %value in %iterable
+ add %expression to %comprehension
+ return %comprehension
+
+ # 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]
diff --git a/core/control_flow.nom b/core/control_flow.nom
index eaf29f4..2816dfb 100644
--- a/core/control_flow.nom
+++ b/core/control_flow.nom
@@ -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)()
+
diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom
index fd70119..47faefe 100644
--- a/core/metaprogramming.nom
+++ b/core/metaprogramming.nom
@@ -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()"
diff --git a/core/operators.nom b/core/operators.nom
index 706909c..56e89cb 100644
--- a/core/operators.nom
+++ b/core/operators.nom
@@ -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
diff --git a/examples/how_do_i.nom b/examples/how_do_i.nom
index 18c0a89..f7b5c0b 100644
--- a/examples/how_do_i.nom
+++ b/examples/how_do_i.nom
@@ -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
diff --git a/nomsu.lua b/nomsu.lua
index 3a29261..43fafab 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -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
diff --git a/nomsu.moon b/nomsu.moon
index f76b530..e3e7217 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -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))
diff --git a/nomsu.peg b/nomsu.peg
index 82886d3..4deb4ef 100644
--- a/nomsu.peg
+++ b/nomsu.peg
@@ -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)+
diff --git a/nomsu_tree.lua b/nomsu_tree.lua
index 8740493..5b9d12b 100644
--- a/nomsu_tree.lua
+++ b/nomsu_tree.lua
@@ -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
diff --git a/nomsu_tree.moon b/nomsu_tree.moon
index de05795..6640030 100644
--- a/nomsu_tree.moon
+++ b/nomsu_tree.moon
@@ -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
diff --git a/tests/control_flow.nom b/tests/control_flow.nom
index 4ac3d8a..4fed7b4 100644
--- a/tests/control_flow.nom
+++ b/tests/control_flow.nom
@@ -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