aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2019-01-01 15:05:58 -0800
committerBruce Hill <bruce@bruce-hill.com>2019-01-01 15:07:10 -0800
commitb6d3cbd61cd08e39d20a569b7c5ece6bb25897dd (patch)
treeccf3930b7a2834ffad1a10a9d91f0042542dec34
parent0760d4fb6495c4aa4f74038457acede5063f514a (diff)
Misc changes, including text indented interpolations are now indented
relative to the text, not the opening '("', code objects can now remove all free vars, the REPL uses global vars. Error API is changing a bit.
-rw-r--r--code_obj.lua51
-rw-r--r--code_obj.moon28
-rw-r--r--containers.lua63
-rw-r--r--containers.moon28
-rw-r--r--core/collections.nom1
-rw-r--r--core/control_flow.nom27
-rw-r--r--core/errors.nom123
-rw-r--r--core/metaprogramming.nom10
-rw-r--r--core/operators.nom1
-rw-r--r--nomsu.6.peg6
-rw-r--r--nomsu_compiler.lua4
-rw-r--r--nomsu_compiler.moon4
-rw-r--r--parser.lua7
-rw-r--r--parser.moon7
-rwxr-xr-xtools/repl.nom57
15 files changed, 213 insertions, 204 deletions
diff --git a/code_obj.lua b/code_obj.lua
index 5afca1d..a09608f 100644
--- a/code_obj.lua
+++ b/code_obj.lua
@@ -320,6 +320,10 @@ do
return self:dirty()
end,
remove_free_vars = function(self, vars)
+ if vars == nil then
+ vars = nil
+ end
+ vars = vars or self:get_free_vars()
if not (#vars > 0) then
return
end
@@ -351,33 +355,34 @@ do
end
return self:dirty()
end,
- declare_locals = function(self, to_declare)
- if to_declare == nil then
- to_declare = nil
- end
- if to_declare == nil then
- local seen
- to_declare, seen = { }, { }
- local gather_from
- gather_from = function(self)
- local _list_0 = self.free_vars
- for _index_0 = 1, #_list_0 do
- local var = _list_0[_index_0]
- if not (seen[var]) then
- seen[var] = true
- to_declare[#to_declare + 1] = var
- end
+ get_free_vars = function(self)
+ local vars, seen = { }, { }
+ local gather_from
+ gather_from = function(self)
+ local _list_0 = self.free_vars
+ for _index_0 = 1, #_list_0 do
+ local var = _list_0[_index_0]
+ if not (seen[var]) then
+ seen[var] = true
+ vars[#vars + 1] = var
end
- local _list_1 = self.bits
- for _index_0 = 1, #_list_1 do
- local bit = _list_1[_index_0]
- if not (type(bit) == 'string') then
- gather_from(bit)
- end
+ end
+ local _list_1 = self.bits
+ for _index_0 = 1, #_list_1 do
+ local bit = _list_1[_index_0]
+ if not (type(bit) == 'string') then
+ gather_from(bit)
end
end
- gather_from(self)
end
+ gather_from(self)
+ return vars
+ end,
+ declare_locals = function(self, to_declare)
+ if to_declare == nil then
+ to_declare = nil
+ end
+ to_declare = to_declare or self:get_free_vars()
if #to_declare > 0 then
self:remove_free_vars(to_declare)
self:prepend("local " .. tostring(concat(to_declare, ", ")) .. ";\n")
diff --git a/code_obj.moon b/code_obj.moon
index bdce010..9315264 100644
--- a/code_obj.moon
+++ b/code_obj.moon
@@ -179,7 +179,8 @@ class LuaCode extends Code
seen[var] = true
@dirty!
- remove_free_vars: (vars)=>
+ remove_free_vars: (vars=nil)=>
+ vars or= @get_free_vars!
return unless #vars > 0
removals = {}
for var in *vars
@@ -198,18 +199,21 @@ class LuaCode extends Code
stack[#stack+1] = b
@dirty!
+ get_free_vars: =>
+ vars, seen = {}, {}
+ gather_from = =>
+ for var in *@free_vars
+ unless seen[var]
+ seen[var] = true
+ vars[#vars+1] = var
+ for bit in *@bits
+ unless type(bit) == 'string'
+ gather_from bit
+ gather_from self
+ return vars
+
declare_locals: (to_declare=nil)=>
- if to_declare == nil
- to_declare, seen = {}, {}
- gather_from = =>
- for var in *@free_vars
- unless seen[var]
- seen[var] = true
- to_declare[#to_declare+1] = var
- for bit in *@bits
- unless type(bit) == 'string'
- gather_from bit
- gather_from self
+ to_declare or= @get_free_vars!
if #to_declare > 0
@remove_free_vars to_declare
@prepend "local #{concat to_declare, ", "};\n"
diff --git a/containers.lua b/containers.lua
index d4514af..418a819 100644
--- a/containers.lua
+++ b/containers.lua
@@ -251,18 +251,6 @@ List = function(t)
return error("Unsupported List type: " .. type(t))
end
end
-local walk_items
-walk_items = function(self, i)
- i = i + 1
- local k, v = next(self.table, self.key)
- if k ~= nil then
- self.key = k
- return i, Dict({
- key = k,
- value = v
- })
- end
-end
local _dict_mt = {
__type = "Dict",
__eq = function(self, other)
@@ -321,12 +309,6 @@ local _dict_mt = {
return _accum_0
end)(), ", ") .. "}"
end,
- __ipairs = function(self)
- return walk_items, {
- table = self,
- key = nil
- }, 0
- end,
__band = function(self, other)
return Dict((function()
local _tbl_0 = { }
@@ -339,30 +321,28 @@ local _dict_mt = {
end)())
end,
__bor = function(self, other)
- local ret
- do
+ local ret = Dict((function()
local _tbl_0 = { }
for k, v in pairs(self) do
_tbl_0[k] = v
end
- ret = _tbl_0
- end
+ return _tbl_0
+ end)())
for k, v in pairs(other) do
if ret[k] == nil then
ret[k] = v
end
end
- return Dict(ret)
+ return ret
end,
__bxor = function(self, other)
- local ret
- do
+ local ret = Dict((function()
local _tbl_0 = { }
for k, v in pairs(self) do
_tbl_0[k] = v
end
- ret = _tbl_0
- end
+ return _tbl_0
+ end)())
for k, v in pairs(other) do
if ret[k] == nil then
ret[k] = v
@@ -370,17 +350,16 @@ local _dict_mt = {
ret[k] = nil
end
end
- return Dict(ret)
+ return ret
end,
__add = function(self, other)
- local ret
- do
+ local ret = Dict((function()
local _tbl_0 = { }
for k, v in pairs(self) do
_tbl_0[k] = v
end
- ret = _tbl_0
- end
+ return _tbl_0
+ end)())
for k, v in pairs(other) do
if ret[k] == nil then
ret[k] = v
@@ -388,17 +367,16 @@ local _dict_mt = {
ret[k] = ret[k] + v
end
end
- return Dict(ret)
+ return ret
end,
__sub = function(self, other)
- local ret
- do
+ local ret = Dict((function()
local _tbl_0 = { }
for k, v in pairs(self) do
_tbl_0[k] = v
end
- ret = _tbl_0
- end
+ return _tbl_0
+ end)())
for k, v in pairs(other) do
if ret[k] == nil then
ret[k] = -v
@@ -406,7 +384,7 @@ local _dict_mt = {
ret[k] = ret[k] - v
end
end
- return Dict(ret)
+ return ret
end
}
Dict = function(t)
@@ -430,11 +408,6 @@ Dict = function(t)
return error("Unsupported Dict type: " .. type(t))
end
end
-for i, entry in ipairs(Dict({
- x = 99
-})) do
- assert(i == 1 and entry.key == "x" and entry.value == 99, "ipairs compatibility issue")
-end
do
local reverse, upper, lower, find, byte, match, gmatch, gsub, sub, format, rep
do
@@ -502,9 +475,9 @@ do
return (match(self, patt))
end,
matching_groups = function(self, patt)
- return {
+ return List({
match(self, patt)
- }
+ })
end,
[as_lua_id("* 1")] = function(self, n)
return rep(self, n)
diff --git a/containers.moon b/containers.moon
index 26c1032..be0925b 100644
--- a/containers.moon
+++ b/containers.moon
@@ -106,13 +106,6 @@ List = (t)->
return l
else error("Unsupported List type: "..type(t))
-walk_items = (i)=>
- i = i + 1
- k, v = next(@table, @key)
- if k != nil
- @key = k
- return i, Dict{key:k, value:v}
-
_dict_mt =
__type: "Dict"
__eq: (other)=>
@@ -133,32 +126,31 @@ _dict_mt =
"{"..concat(["#{as_nomsu(k)}: #{as_nomsu(v)}" for k,v in pairs @], ", ").."}"
as_lua: =>
"Dict{"..concat(["[ #{as_lua(k)}]= #{as_lua(v)}" for k,v in pairs @], ", ").."}"
- __ipairs: => walk_items, {table:@, key:nil}, 0
__band: (other)=>
Dict{k,v for k,v in pairs(@) when other[k] != nil}
__bor: (other)=>
- ret = {k,v for k,v in pairs(@)}
+ ret = Dict{k,v for k,v in pairs(@)}
for k,v in pairs(other)
if ret[k] == nil then ret[k] = v
- return Dict(ret)
+ return ret
__bxor: (other)=>
- ret = {k,v for k,v in pairs(@)}
+ ret = Dict{k,v for k,v in pairs(@)}
for k,v in pairs(other)
if ret[k] == nil then ret[k] = v
else ret[k] = nil
- return Dict(ret)
+ return ret
__add: (other)=>
- ret = {k,v for k,v in pairs(@)}
+ ret = Dict{k,v for k,v in pairs(@)}
for k,v in pairs(other)
if ret[k] == nil then ret[k] = v
else ret[k] += v
- return Dict(ret)
+ return ret
__sub: (other)=>
- ret = {k,v for k,v in pairs(@)}
+ ret = Dict{k,v for k,v in pairs(@)}
for k,v in pairs(other)
if ret[k] == nil then ret[k] = -v
else ret[k] -= v
- return Dict(ret)
+ return ret
Dict = (t)->
if type(t) == 'table'
return setmetatable(t, _dict_mt)
@@ -171,8 +163,6 @@ Dict = (t)->
return d
else error("Unsupported Dict type: "..type(t))
-for i,entry in ipairs(Dict({x:99}))
- assert(i == 1 and entry.key == "x" and entry.value == 99, "ipairs compatibility issue")
do
{:reverse, :upper, :lower, :find, :byte, :match, :gmatch, :gsub, :sub, :format, :rep} = string
@@ -204,7 +194,7 @@ do
line_position_at: (i)=> select(3, line_at(@, i))
matches: (patt)=> match(@, patt) and true or false
matching: (patt)=> (match(@, patt))
- matching_groups: (patt)=> {match(@, patt)}
+ matching_groups: (patt)=> List{match(@, patt)}
[as_lua_id "* 1"]: (n)=> rep(@, n)
all_matches_of: (patt)=>
result = {}
diff --git a/core/collections.nom b/core/collections.nom
index 69685b8..6aac861 100644
--- a/core/collections.nom
+++ b/core/collections.nom
@@ -37,7 +37,6 @@ test:
test:
$dict = {.x = 1, .y = 2, .z = 3}
assume (size of $dict) == 3
- assume [: for $ in {.x = 1}: add $] == [{.key = "x", .value = 1}]
assume [: for $k = $v in {.x = 1}: add {.key = $k, .value = $v}] ==
[{.key = "x", .value = 1}]
assume ({.x = 1, .y = 1} + {.y = 10, .z = 10}) == {.x = 1, .y = 11, .z = 10}
diff --git a/core/control_flow.nom b/core/control_flow.nom
index 16f8537..f066767 100644
--- a/core/control_flow.nom
+++ b/core/control_flow.nom
@@ -5,7 +5,6 @@
use "core/metaprogramming.nom"
use "core/operators.nom"
-use "core/errors.nom"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -449,32 +448,6 @@ test:
")
test:
- $d = {}
- try:
- do:
- $d.x = "bad"
- barf
- ..then always:
- $d.x = "good"
- assume ($d.x == "good")
-
-(do $action then always $final_action) compiles to:
- define mangler
- return
- Lua ("
- do
- local \(mangle "fell_through") = false
- local \(mangle "ok"), \(mangle "ret") = pcall(function()
- \($action as lua)
- \(mangle "fell_through") = true
- end)
- \($final_action as lua)
- if not \(mangle "ok") then error(ret, 0) end
- if not \(mangle "fell_through") then return ret end
- end
- ")
-
-test:
assume ((result of: return 99) == 99)
# Inline thunk:
diff --git a/core/errors.nom b/core/errors.nom
index 6779922..0b63b5b 100644
--- a/core/errors.nom
+++ b/core/errors.nom
@@ -3,11 +3,12 @@
This file contains basic error reporting code
use "core/metaprogramming.nom"
+use "core/operators.nom"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-(barf $msg) compiles to
- "error(\(=lua "\$msg and \($msg as lua expr) or 'nil'"), 0);"
+(fail $msg) compiles to
+ "error(\(($msg as lua expr) if $msg else "nil"), 0);"
(assume $condition) compiles to:
lua> ("
@@ -37,62 +38,86 @@ use "core/metaprogramming.nom"
end
")
-(assume $condition or barf $message) compiles to ("
- if not \($condition as lua expr) then
- error(\($message as lua expr), 0)
- end
-")
-
test:
- try (barf) and if it succeeds:
- barf "try failed."
+ try: fail
$worked = (no)
- try (barf) and if it barfs:
+ try: fail
+ ..if it fails:
$worked = (yes)
- assume $worked or barf "try/catch failed"
- $x = 1
- try:
- $x = 2
- do (barf) then always: $x = 3
- ..and if it barfs:
- do nothing
- assume ($x == 3) or barf "do/then always failed"
-
+ ..if it succeeds:
+ fail "'try' incorrectly ran success case."
+
+ unless $worked:
+ fail "'try' failed to recover from failure"
# Try/except
[
- try $action and if it succeeds $success or if it barfs $msg $fallback
- try $action and if it barfs $msg $fallback or if it succeeds $success
-] all compile to ("
- do
- local fell_through = false
- local err, erred = nil, false
- local ok, ret = xpcall(function()
- \($action as lua)
- fell_through = true
- end, function(\(=lua "\$fallback and \($msg as lua expr) or ''"))
- local ok, ret = pcall(function()
- \((=lua "\$fallback or \$msg") as lua)
- end)
- if not ok then err, erred = ret, true end
- end)
- if ok then
- \($success as lua)
- if not fell_through then
- return ret
+ try $action if it succeeds $success if it fails $fallback
+ try $action if it fails $fallback if it succeeds $success
+] all compile to:
+ $success_lua = ($success as lua)
+ if ((#"\$success_lua") > 0): $success_lua, add "\n"
+ $success_lua, prepend "-- Success:\n"
+ $success_lua, add "if not _fell_through then return table.unpack(_result, 2) end"
+ $fallback_lua = ($fallback as lua)
+ if ((#"\$fallback_lua") > 0):
+ $fallback_lua, prepend "\nlocal function failure() return _result[2] end\n"
+ $fallback_lua, prepend "-- Failure:"
+ return
+ Lua ("
+ do
+ local _fell_through = false
+ local _result = {pcall(function()
+ \($action as lua)
+ _fell_through = true
+ end)}
+ if _result[1] then
+ \$success_lua
+ else
+ \$fallback_lua
+ end
end
- elseif erred then
- error(err, 0)
- end
- end
-")
+ ")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(try $action) parses as
- try $action and if it succeeds (do nothing) or if it barfs (do nothing)
+ try $action if it succeeds (do nothing) if it fails (do nothing)
+
+(try $action if it fails $msg $fallback) parses as
+ try $action if it succeeds (do nothing) if it fails $msg $fallback
+
+(try $action if it succeeds $success) parses as
+ try $action if it succeeds $success if it fails (do nothing)
+
+(try $action if it fails $fallback if it succeeds $success) parses as
+ try $action if it succeeds $success if it fails $fallback
+
+test:
+ $success = (no)
+ try:
+ do: fail
+ ..then always:
+ $success = (yes)
+ ..if it succeeds:
+ fail "'try ... then always ...' didn't propagate failure"
+
+ unless $success:
+ fail "'try ... then always ...' didn't execute the 'always' code"
+
+(do $action then always $final_action) compiles to ("
+ do -- do/then always
+ local _fell_through = false
+ local _results = {pcall(function()
+ \($action as lua)
+ _fell_through = true
+ end)}
+ \($final_action as lua)
+ if not _results[1] then error(_results[2], 0) end
+ if not _fell_through then return table.unpack(_results, 2) end
+ end
+")
-(try $action and if it barfs $msg $fallback) parses as
- try $action and if it succeeds (do nothing) or if it barfs $msg $fallback
+~~~
-(try $action and if it succeeds $success) parses as
- try $action and if it succeeds $success or if it barfs (do nothing)
+(barf $) parses as (fail $)
+(assume $1 or barf $2) parses as (unless $1: fail $2)
diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom
index 2e1bf6b..b4297dd 100644
--- a/core/metaprogramming.nom
+++ b/core/metaprogramming.nom
@@ -308,11 +308,11 @@ externally ($ is $kind syntax tree) means
($tree with $t -> $replacement) compiles to ("
\($tree as lua expr):map(function(\($t as lua expr))
\(
- =lua ("
- \$replacement.type == 'Block' and \($replacement as lua) or 'return '..\
- ..\($replacement as lua expr)
- ")
- )
+ =lua ("
+ \$replacement.type == 'Block' and \($replacement as lua) or 'return '..\
+ ..\($replacement as lua expr)
+ ")
+ )
end)
")
diff --git a/core/operators.nom b/core/operators.nom
index 8d646e9..6c089a6 100644
--- a/core/operators.nom
+++ b/core/operators.nom
@@ -3,7 +3,6 @@
This file contains definitions of operators like "+" and "and".
use "core/metaprogramming.nom"
-use "core/errors.nom"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/nomsu.6.peg b/nomsu.6.peg
index 6b4686d..6a1725a 100644
--- a/nomsu.6.peg
+++ b/nomsu.6.peg
@@ -168,7 +168,11 @@ blank_text_lines <-
{~ (%nl ((ws* -> '') (&%nl / !.) / (=curr_indent -> '') &[^%nl]))+ ~}
text_interpolation <-
- ("\" (indented_block (blank_lines =curr_indent "..")? / indented_expression))
+ ({|
+ -- %indentation will backtrack and match the actual indentation of the current line
+ "\" {:curr_indent: %indentation :}
+ (indented_block (blank_lines =curr_indent "..")? / indented_expression)
+ |} -> unpack)
/ inline_text_interpolation
diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua
index 9b8fc87..2b49112 100644
--- a/nomsu_compiler.lua
+++ b/nomsu_compiler.lua
@@ -304,7 +304,7 @@ local compile = setmetatable({
lua:add(",")
end
if lua:trailing_line_len() + #(entry_lua:text():match("^[\n]*")) > MAX_LINE then
- lua:add("\n")
+ lua:add("\n ")
elseif needs_comma then
lua:add(" ")
end
@@ -417,6 +417,8 @@ local compile = setmetatable({
if tree[i].type == "Comment" then
items_lua:add("\n")
sep = ''
+ elseif items_lua:trailing_line_len() > MAX_LINE then
+ sep = ',\n '
else
sep = ', '
end
diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon
index 12a7529..45e863d 100644
--- a/nomsu_compiler.moon
+++ b/nomsu_compiler.moon
@@ -234,7 +234,7 @@ compile = setmetatable({
entry_lua\add as_lua(v)
if needs_comma then lua\add ","
if lua\trailing_line_len! + #(entry_lua\text!\match("^[\n]*")) > MAX_LINE
- lua\add "\n"
+ lua\add "\n "
elseif needs_comma
lua\add " "
lua\add entry_lua
@@ -322,6 +322,8 @@ compile = setmetatable({
if tree[i].type == "Comment"
items_lua\add "\n"
sep = ''
+ elseif items_lua\trailing_line_len! > MAX_LINE
+ sep = ',\n '
else
sep = ', '
i += 1
diff --git a/parser.lua b/parser.lua
index 523e223..09386fa 100644
--- a/parser.lua
+++ b/parser.lua
@@ -26,6 +26,13 @@ do
_with_0.unpack = unpack or table.unpack
_with_0["nil"] = Cc(nil)
_with_0.userdata = Carg(1)
+ _with_0.indentation = lpeg.Cmt(P(0), function(s, i)
+ local sub = string.sub
+ while i > 1 and sub(s, i - 1, i - 1) ~= '\n' do
+ i = i - 1
+ end
+ return true, (s:match("^ *", i))
+ end)
_with_0.utf8_char = (R("\194\223") * R("\128\191") + R("\224\239") * R("\128\191") * R("\128\191") + R("\240\244") * R("\128\191") * R("\128\191") * R("\128\191"))
_with_0.Tree = function(t, userdata)
return userdata.make_tree(t, userdata)
diff --git a/parser.moon b/parser.moon
index 122b58c..3f36953 100644
--- a/parser.moon
+++ b/parser.moon
@@ -25,6 +25,13 @@ DEFS = with {}
.unpack = unpack or table.unpack
.nil = Cc(nil)
.userdata = Carg(1)
+ -- Always match and capture the indentation (spaces only) of the current line
+ -- i.e. the leading space of the chunk of non-newline characters leading up to s[i]
+ .indentation = lpeg.Cmt P(0),
+ (s, i)->
+ sub = string.sub
+ while i > 1 and sub(s,i-1,i-1) != '\n' do i -= 1
+ return true, (s\match("^ *", i))
.utf8_char = (
R("\194\223")*R("\128\191") +
R("\224\239")*R("\128\191")*R("\128\191") +
diff --git a/tools/repl.nom b/tools/repl.nom
index 983de5f..4240ddc 100755
--- a/tools/repl.nom
+++ b/tools/repl.nom
@@ -42,25 +42,44 @@ repeat:
if ((size of $buff) == 0): stop
$buff = ($buff, joined)
-
- # TODO: support local variables
spoof file $buff
try:
- $ret = (run $buff)
- ..and if it barfs $err: say $err
- ..or if it succeeds:
- if (type of $ret) is:
- "nil":
- do nothing
-
- "boolean":
- say "= \("yes" if $ret else "no")"
-
- "table":
- if $ret.as_nomsu:
- say "= \($ret, as nomsu)"
- ..else:
+ $tree = ($buff parsed)
+ ..and if it barfs $err:
+ say $err
+ do next
+
+ unless $tree:
+ do next
+
+ for $chunk in $tree:
+ try:
+ $lua = ($chunk as lua)
+ ..and if it barfs $err: say $err
+
+ unless $lua:
+ do next
+
+ # TODO: this is a bit hacky, it just defaults variables to global
+ so that stuff mostly works across multiple lines. It would be
+ nicer if local variables actually worked.
+ $lua, remove free vars
+ try:
+ $ret = (run $lua)
+ ..and if it barfs $err: say $err
+ ..or if it succeeds:
+ if (type of $ret) is:
+ "nil":
+ do nothing
+
+ "boolean":
+ say "= \("yes" if $ret else "no")"
+
+ "table":
+ if $ret.as_nomsu:
+ say "= \($ret, as nomsu)"
+ ..else:
+ say "= \$ret"
+
+ else:
say "= \$ret"
-
- else:
- say "= \$ret"