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:
parent
77c11a2443
commit
4126589afe
@ -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]
|
||||
|
@ -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)()
|
||||
|
||||
|
@ -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()"
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
32
nomsu.lua
32
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
|
||||
|
13
nomsu.moon
13
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))
|
||||
|
33
nomsu.peg
33
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)+
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user