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

View File

@ -423,3 +423,11 @@ immediately
end end
end --do-then-always 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(); lua:convert_to_statements();
return lua; return lua;
action [%tree with vars %vars]
=lua "nomsu:tree_with_replaced_vars(\%tree, \%vars)"
compile [declare locals in %code] to compile [declare locals in %code] to
Lua value "\(%code as lua expr):declare_locals()" Lua value "\(%code as lua expr):declare_locals()"

View File

@ -163,14 +163,8 @@ immediately
# Unary operators # Unary operators
compile [- %] to: Lua value "(- \(% as lua expr))" compile [- %] to: Lua value "(- \(% as lua expr))"
compile [not %] to: Lua value "(not \(% as lua expr))" compile [not %] to: Lua value "(not \(% as lua expr))"
compile [length of %list] to # Using custom "len()" instead of Lua's "#" operator for compatibility with luajit.
# A bit of a hack so that luajit works properly. compile [length of %list] to: Lua value "len(\(%list as lua expr))"
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))
# Update operators # Update operators
immediately immediately

View File

@ -13,29 +13,27 @@ use "core/control_flow.nom"
# How do I import all the files in a directory? # How do I import all the files in a directory?
use "core" use "core"
# Set a variable? # How do I print stuff?
say "Hello world!"
# How do I set a variable?
%x <- 1 %x <- 1
%str <- "Hello world" %str <- "Hello world"
# Expressions that are more than just literal values require parentheses: # Expressions that are more than just literal values require parentheses:
%x <- (2 + 3) %x <- (2 + 3)
# Modify a variable? # How do I modify a variable?
%foobar <- 100 %x <- (%x + 1)
# As a shorthand, you can type: # Or, as a shorthand, you can do this to increment a variable:
%foobar +<- 1 %x +<- 1
# which does the same thing as:
%foobar <- (%foobar + 1)
# Print stuff? # How do I define a mutli-line string?
say "Hello world!"
# Define a mutli-line string?
%mutli_str <- ".." %mutli_str <- ".."
Start with "..", then put lines below it Start with "..", then put lines below it
that are indented one level. that are indented one level.
The string will continue until the indentation ends. The string will continue until the indentation ends.
# Format a string? # How do I put values inside a string?
%format_str <- ".." %format_str <- ".."
Strings can contain a backslash followed by a variable, list, dict, or parenthesized 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: 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 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" %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"] %my_list <- [1,2,"hello"]
#.. Really long lists can use [..] followed by a bunch of indented values delimited #.. Really long lists can use [..] followed by a bunch of indented values delimited
by commas and/or newlines by commas and/or newlines
@ -54,7 +52,7 @@ say "Hello world!"
7 7
8,9,10 8,9,10
# Use a list? # How do I use a list?
%my_list <- ["first item", "second item", "third item"] %my_list <- ["first item", "second item", "third item"]
# Lists are 1-indexed because they're implemented as Lua tables, so this prints "first item" # Lists are 1-indexed because they're implemented as Lua tables, so this prints "first item"
say %my_list.1 say %my_list.1
@ -62,19 +60,19 @@ say %my_list.1
%my_list.1 <- "ONE!!!" %my_list.1 <- "ONE!!!"
say (length of %my_list) 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: 99, y: 101}
%my_dict <- {..} %my_dict <- {..}
x: 101, y: 2 x: 101, y: 2
"99 bottles": 99 "99 bottles": 99
653: 292 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 # Dicts are also implemented as Lua tables, so they're accessed and modified the same way as lists
say %my_dict.x say %my_dict.x
%my_dict.x <- 9999 %my_dict.x <- 9999
# Do conditional branching? # How do I do conditional branching?
if: 1 < 10 if: 1 < 10
say "1 is indeed < 10" say "1 is indeed < 10"
@ -96,7 +94,7 @@ when
* else * else
say "this is the default case" say "this is the default case"
# Do a switch statement? # How do I do a switch statement?
when 3 = ? when 3 = ?
* 0 * 0
* 1 * 1
@ -107,7 +105,7 @@ when 3 = ?
* else * else
say "this won't print" 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] %list <- [1,2,3]
for %x in %list for %x in %list
say "For %x loop #\%x" say "For %x loop #\%x"
@ -115,7 +113,7 @@ for %x in %list
for all %list for all %list
say "For all loop #\%" 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 # This is inclusive, so it will loop over 1,2, and 3
for %i from 1 to 3 for %i from 1 to 3
say "For %i from 1 to 3 loop #\%i" 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 for %backwards from 3 to 1 by -1
say "Backwards #\%backwards" say "Backwards #\%backwards"
# While loops: # How do I do a 'while' loop?
%x <- 1 %x <- 1
repeat while: %x <= 3 repeat while: %x <= 3
say "repeat while loop #\%x" say "repeat while loop #\%x"
@ -138,7 +136,7 @@ repeat until: %x > 3
say "repeat until loop #\%x" say "repeat until loop #\%x"
%x +<- 1 %x +<- 1
# Infinite loop: # How do I do an infinite loop?
%x <- 1 %x <- 1
repeat repeat
say "repeat loop #\%x" say "repeat loop #\%x"
@ -146,7 +144,7 @@ repeat
if: %x > 3 if: %x > 3
stop repeating stop repeating
# GOTOs: # How do I do a 'goto'?
do do
%x <- 1 %x <- 1
=== %again === === %again ===
@ -157,13 +155,14 @@ do
say "finished going to" 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] action [say both %first and also %second]
say %first say %first
# Function arguments are accessed just like variables # Function arguments are accessed just like variables
say %second 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] action [first fibonacci above %n]
%f1 <- 0 %f1 <- 0
%f2 <- 1 %f2 <- 1
@ -176,7 +175,7 @@ action [first fibonacci above %n]
say (first fibonacci above 10) 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 [..] action [..]
I hate %worse_things more than %better_things I hate %worse_things more than %better_things
I think %worse_things are worse 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" I think "chihuahuas" are worse than "corgis"
#.. Function calls can have parts of the function's name spread throughout. #.. Actions can have parts of the action's name spread throughout.
Everything that's not a literal value is treated as part of the function's name Everything that's not a literal value is treated as part of the action's name
say both "Hello" and also "again!" 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] action [%what_she_said is what she said]
say %what_she_said say %what_she_said
say "-- she said" say "-- she said"
"Howdy pardner" is what 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! can have really funky names!
action [>> %foo_bar $$$^ --> % @& _~-^-~_~-^ %1 !] action [>> %foo_bar $$$^ --> % @& _~-^-~_~-^ %1 !]
say %foo_bar say %foo_bar
@ -214,7 +213,7 @@ action [% と言う]
"\(%)世界" "\(%)世界"
say (%こんにちは と言う) 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) say (2 + 3)
#.. So you can define your own operators, although they will need to be parenthesized to #.. So you can define your own operators, although they will need to be parenthesized to
play nicely with other operators play nicely with other operators
@ -222,6 +221,7 @@ action [%a ++ %b]
2 * (%a + %b) 2 * (%a + %b)
say (1 ++ (2 * 3)) say (1 ++ (2 * 3))
# How do I do grouping? # How do I do grouping?
# Expressions can be grouped by enclosing parentheses: # Expressions can be grouped by enclosing parentheses:
say (2 + 3) say (2 + 3)
@ -282,3 +282,60 @@ if (1 > (TWENTY)) on opposite day
say "Lua compiling macros work!" say "Lua compiling macros work!"
say "It looks like a keyword, but there's no magic here!" 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 end
local tree = self:parse(nomsu_code) local tree = self:parse(nomsu_code)
assert(tree, "Failed to parse: " .. tostring(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) local lua = tree:as_lua(self)
lua:convert_to_statements() lua:convert_to_statements()
lua:declare_locals() lua:declare_locals()
@ -492,7 +491,7 @@ do
return return
end end
local _exp_0 = tree.type 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 local _list_0 = tree.value
for _index_0 = 1, #_list_0 do for _index_0 = 1, #_list_0 do
local v = _list_0[_index_0] local v = _list_0[_index_0]
@ -543,6 +542,18 @@ do
return tree:map(fn) return tree:map(fn)
end, end,
tree_with_replaced_vars = function(self, tree, replacements) 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) return tree:map(function(t)
if t.type == "Var" then if t.type == "Var" then
local id = tostring(t:as_lua(self)) local id = tostring(t:as_lua(self))
@ -737,6 +748,23 @@ do
load = load, load = load,
ipairs = ipairs 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 for k, v in pairs(Types) do
self.environment[k] = v self.environment[k] = v
end end

View File

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

View File

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

View File

@ -52,63 +52,9 @@ Tree = function(name, methods)
"source" "source"
}, methods) }, methods)
end 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", { Tree("Nomsu", {
as_lua = function(self, 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, end,
as_nomsu = function(self, inline) as_nomsu = function(self, inline)
if inline == nil then if inline == nil then
@ -162,6 +108,9 @@ Tree("Block", {
nomsu:append(line) nomsu:append(line)
if i < #self.value then if i < #self.value then
nomsu:append("\n") nomsu:append("\n")
if tostring(line):match("\n") then
nomsu:append("\n")
end
end end
end end
return nomsu return nomsu
@ -212,6 +161,9 @@ Tree("Action", {
args = _accum_0 args = _accum_0
end end
local ret = compile_action(self, unpack(args)) local ret = compile_action(self, unpack(args))
if not ret then
error("Failed to produce any Lua")
end
return ret return ret
end end
local action = rawget(nomsu.environment.ACTIONS, stub) local action = rawget(nomsu.environment.ACTIONS, stub)
@ -814,6 +766,9 @@ Tree("IndexChain", {
if not (bit_nomsu) then if not (bit_nomsu) then
return nil return nil
end end
if bit.type == "Action" or bit.type == "Block" then
bit_nomsu:parenthesize()
end
nomsu:append(bit_nomsu) nomsu:append(bit_nomsu)
end end
return nomsu return nomsu

View File

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

View File

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