Simplifying the control flow API and deduplicating the code.

This commit is contained in:
Bruce Hill 2018-11-26 16:21:42 -08:00
parent cbbe6b1c14
commit 8e5f1b9e1e
6 changed files with 107 additions and 131 deletions

18
compatibility/4.12.nom Normal file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env nomsu -V4.12
#
This file defines upgrades from Nomsu <4.11 to Nomsu 4.11
(overhaul of function literals, deleting (if all of ...), etc. shorthand)
use "compatibility/compatibility.nom"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
upgrade action "do next repeat" to "4.12" via (..)
for %tree:
compile error at %tree "This method has been deprecated." "\
..Use either (do next) or (go to (label)) instead."
upgrade action "stop repeating" to "4.12" via (..)
for %tree:
compile error at %tree "This method has been deprecated." "\
..Use either (stop) or (go to (label)) instead."

View File

@ -87,29 +87,29 @@ test:
assume (%i == 0)
(--- %label ---) compiles to "\
..::label_\((%label.stub if (%label.type == "Action") else %label) as lua identifier)::"
..::label_\((%label.stub::as lua id) if (%label.type == "Action") else (%label as lua identifier))::"
(go to %label) compiles to "\
..goto label_\((%label.stub if (%label.type == "Action") else %label) as lua identifier)"
..goto label_\((%label.stub::as lua id) if (%label.type == "Action") else (%label as lua identifier))"
# Basic loop control
(stop %var) compiles to:
if %var:
return (Lua "goto stop_\((%var.stub if (%var.type == "action") else %var) as lua identifier)")
return (Lua "goto stop_\(%var as lua identifier)")
..else:
return (Lua "break")
(do next %var) compiles to:
if %var:
return (Lua "goto continue_\((%var.stub if (%var.type == "action") else %var) as lua identifier)")
return (Lua "goto continue_\(%var as lua identifier)")
..else:
return (Lua "goto continue")
(---stop %var ---) compiles to "\
..::stop_\((%var.stub if (%var.type == "action") else %var) as lua identifier)::"
..::stop_\(%var as lua identifier)::"
(---next %var ---) compiles to "\
..::continue_\((%var.stub if (%var.type == "action") else %var) as lua identifier)::"
..::continue_\(%var as lua identifier)::"
# While loops
test:
@ -117,8 +117,6 @@ test:
repeat while (%x < 10): %x += 1
assume (%x == 10)
repeat while (%x < 20): stop
repeat while (%x < 20):
stop repeating
assume (%x == 10)
repeat while (%x < 20):
%x += 1
@ -126,57 +124,14 @@ test:
do next
barf "Failed to 'do next'"
assume (%x == 20)
repeat while (%x < 30):
%x += 1
if (yes):
do next repeat
barf "Failed to 'do next repeat'"
assume (%x == 30)
(do next repeat) compiles to "goto continue_repeat"
(stop repeating) compiles to "goto stop_repeat"
(repeat while %condition %body) compiles to:
%lua = (Lua "while \(%condition as lua expr) do\n \(%body as lua)")
if (%body has subtree \(do next)):
%lua::append "\n ::continue::"
if (%body has subtree \(do next repeat)):
%lua::append "\n ::continue_repeat::"
%lua::append "\nend --while-loop"
if (%body has subtree \(stop repeating)):
%inner_lua = %lua
%lua = (Lua "do -- scope of 'stop repeating' label\n ")
%lua::append %inner_lua "\
..
::stop_repeat::
end -- end of 'stop repeating' label scope"
return %lua
(repeat %body) parses as (repeat while (yes) %body)
(repeat until %condition %body) parses as (repeat while (not %condition) %body)
test:
%x = 0
repeat 10 times: %x += 1
assume (%x == 10)
(repeat %n times %body) compiles to:
define mangler
%lua = (Lua "for \(mangle "i")=1,\(%n as lua expr) do\n ")
%lua::append (%body as lua)
if (%body has subtree \(do next)):
%lua::append "\n ::continue::"
if (%body has subtree \(do next repeat)):
%lua::append "\n ::continue_repeat::"
%lua::append "\nend --numeric for-loop"
if (%body has subtree \(stop repeating)):
%inner_lua = %lua
%lua = (Lua "do -- scope of 'stop repeating' label\n ")
%lua::append %inner_lua "\
..
::stop_repeat::
end -- end of 'stop repeating' label scope"
return %lua
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -206,22 +161,20 @@ test:
for %var in %start to %stop via %step %body
..all compile to:
# This uses Lua's approach of only allowing loop-scoped variables in a loop
unless (%var.type is "Var"):
compile error at %var "Expected a variable here, not a \(%var.type)"
%lua = (Lua "for \(%var as lua expr)=\(%start as lua expr),\(%stop as lua expr),\(%step as lua expr) do")
%lua = (Lua "for \(%var as lua identifier)=\(%start as lua expr),\(%stop as lua expr),\(%step as lua expr) do")
%lua::append "\n " (%body as lua)
if (%body has subtree \(do next)):
%lua::append "\n ::continue::"
if (%body has subtree \(do next %var)):
%lua::append "\n " (what (---next %var ---) compiles to)
%lua::append "\n " (\(---next %var ---) as lua)
%lua::append "\nend --numeric for-loop"
if (%body has subtree \(stop %var)):
%inner_lua = %lua
%lua = (Lua "do -- scope for stopping for-loop\n ")
%lua::append %inner_lua "\n "
%lua::append (what (---stop %var ---) compiles to)
%lua::append (\(---stop %var ---) as lua)
%lua::append "\nend -- end of scope for stopping for-loop"
return %lua
@ -230,6 +183,12 @@ test:
(for %var in %start to %stop %body) parses as (..)
for %var in %start to %stop via 1 %body
test:
%x = 0
repeat 5 times: %x += 1
assume %x == 5
(repeat %n times %body) parses as (for (=lua "_XXX_") in 1 to %n %body)
test:
%a = [10, 20, 30, 40, 50]
%b = []
@ -248,31 +207,6 @@ test:
assume (%b == [20, 30, 40])
# For-each loop (lua's "ipairs()")
(for %var in %iterable %body) compiles to:
define mangler
# This uses Lua's approach of only allowing loop-scoped variables in a loop
%lua = (..)
Lua "\
..for \(mangle "i"),\(%var as lua identifier) in ipairs(\(%iterable as lua expr)) do
"
%lua::append (%body as lua)
if (%body has subtree \(do next)):
%lua::append "\n ::continue::"
if (%body has subtree \(do next %var)):
%lua::append "\n " (what (---next %var ---) compiles to)
%lua::append "\nend --foreach-loop"
if (%body has subtree \(stop %var)):
%inner_lua = %lua
%lua = (Lua "do -- scope for stopping for-loop\n ")
%lua::append %inner_lua "\n "
%lua::append (what (---stop %var ---) compiles to)
%lua::append "\nend -- end of scope for stopping for-loop"
return %lua
# TODO: reduce code duplication
(for %var in %iterable at %i %body) compiles to:
# This uses Lua's approach of only allowing loop-scoped variables in a loop
%lua = (..)
@ -284,17 +218,19 @@ test:
%lua::append "\n ::continue::"
if (%body has subtree \(do next %var)):
%lua::append "\n " (what (---next %var ---) compiles to)
%lua::append "\n " (\(---next %var ---) as lua)
%lua::append "\nend --foreach-loop"
%lua::append "\nend --for \(%var as lua identifier) loop"
if (%body has subtree \(stop %var)):
%inner_lua = %lua
%lua = (Lua "do -- scope for stopping for-loop\n ")
%lua::append %inner_lua "\n "
%lua::append (what (---stop %var ---) compiles to)
%lua::append (\(---stop %var ---) as lua)
%lua::append "\nend -- end of scope for stopping for-loop"
return %lua
(for %var in %iterable %body) parses as (for %var in %iterable at (=lua "__") %body)
test:
%d = {a: 10, b: 20, c: 30, d: 40, e: 50}
%result = []
@ -311,31 +247,24 @@ test:
# Dict iteration (lua's "pairs()")
[for %key = %value in %iterable %body, for %key %value in %iterable %body] \
..all compile to:
# This uses Lua's approach of only allowing loop-scoped variables in a loop
unless (%key.type is "Var"):
compile error at %key "Expected a variable here, not a \(%key.type)"
unless (%value.type is "Var"):
compile error at %value "Expected a variable here, not a \(%value.type)"
%lua = (Lua "for \(%key as lua identifier),\(%value as lua identifier) in pairs(\(%iterable as lua expr)) do")
%lua::append "\n " (%body as lua)
if (%body has subtree \(do next)):
%lua::append "\n ::continue::"
if (%body has subtree \(do next %key)):
%lua::append "\n " (what (---next %key ---) compiles to)
%lua::append "\n " (\(---next %key ---) as lua)
if (%body has subtree \(do next %value)):
%lua::append "\n " (what (---next %value ---) compiles to)
%lua::append "\n " (\(---next %value ---) as lua)
%lua::append "\nend --foreach-loop"
%stop_labels = (Lua "")
if (%body has subtree \(stop %key)):
%stop_labels::append "\n" (what (---stop %key ---) compiles to)
%stop_labels::append "\n" (\(---stop %key ---) as lua)
if (%body has subtree \(stop %value)):
%stop_labels::append "\n" (what (---stop %value ---) compiles to)
%stop_labels::append "\n" (\(---stop %value ---) as lua)
if ((size of "\%stop_labels") > 0):
%inner_lua = %lua
@ -506,7 +435,7 @@ test:
assume ((result of: return 99) == 99)
# Inline thunk:
(result of %body) compiles to "\(what (-> %body) compiles to)()"
(result of %body) compiles to "\(\(-> %body) as lua)()"
test:
%t = [1, [2, [[3], 4], 5, [[[6]]]]]
%flat = []
@ -537,10 +466,10 @@ test:
%lua::append "\n ::continue::"
if (%body has subtree \(do next %var)):
%lua::append "\n \(what (---next %var ---) compiles to)"
%lua::append "\n \(\(---next %var ---) as lua)"
%lua::append "\n end -- Recursive loop"
if (%body has subtree \(stop %var)):
%lua::append "\n \(what (---stop %var ---) compiles to)"
%lua::append "\n \(\(---stop %var ---) as lua)"
%lua::append "\nend -- Recursive scope"
return %lua

View File

@ -3,7 +3,7 @@
This File contains actions for making actions and compile-time actions and some helper
functions to make that easier.
lua> "NOMSU_CORE_VERSION = 11"
lua> "NOMSU_CORE_VERSION = 12"
lua> "NOMSU_LIB_VERSION = 8"
lua> "\
..do
@ -90,7 +90,7 @@ lua> "\
\%body = SyntaxTree{source=\%body.source, type="Action", "Lua", \%body}
end
return LuaCode("compile.action[", \%action.stub:as_lua(),
"] = ", \(what (%args -> %body) compiles to))
"] = ", \(\(%args -> %body) as lua))
end"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -100,8 +100,9 @@ lua> "\
..if \%actions.type ~= "List" then
compile_error(\%actions, "This should be a list of actions.")
end
local lua = \(what (%actions.1 compiles to %body) compiles to)
local lua = \(\(%actions.1 compiles to %body) as lua)
local \%args = List{\(\%compile), unpack(\%actions[1]:get_args())}
local \%compiled_args = List(table.map(\%args, compile))
for i=2,#\%actions do
local alias = \%actions[i]
local \%alias_args = List{\(\%compile), unpack(alias:get_args())}
@ -109,7 +110,11 @@ lua> "\
if \%alias_args == \%args then
lua:append("compile.action[", \%actions[1].stub:as_lua(), "]")
else
lua:append(\(what (%alias_args -> \(what %actions.1 compiles to)) compiles to))
lua:append("function(")
lua:concat_append(table.map(\%alias_args, compile), ", ")
lua:append(") return compile.action[", \%actions[1].stub:as_lua(), "](")
lua:concat_append(\%compiled_args, ", ")
lua:append(") end")
end
end
return lua"
@ -134,7 +139,7 @@ test:
local fn_name = \%action.stub:as_lua_id()
if \%action.target then lua:append(compile(\%action.target), ".")
else lua:add_free_vars({fn_name}) end
lua:append(fn_name, " = ", \(what (%action -> %body) compiles to), ";")
lua:append(fn_name, " = ", \(\(%action -> %body) as lua), ";")
return lua"
(%actions all mean %body) compiles to:
@ -142,7 +147,7 @@ test:
..local fn_name = \%actions[1].stub:as_lua_id()
local target = \%actions[1].target and compile(\%actions[1].target) or nil
local \%args = List(\%actions[1]:get_args())
local lua = \(what (%actions.1 means %body) compiles to)
local lua = \(\(%actions.1 means %body) as lua)
for i=2,#\%actions do
local alias = \%actions[i]
local alias_name = alias.stub:as_lua_id()
@ -158,7 +163,7 @@ test:
if target then lua:append(target, ".") end
lua:append(fn_name, ";")
else
lua:append(\(what (%alias_args -> %actions.1) compiles to), ";")
lua:append(\(\(%alias_args -> %actions.1) as lua), ";")
end
end
return lua"
@ -174,20 +179,20 @@ test:
(externally %action means %body) compiles to:
lua> "\
..local lua = \(what (%action means %body) compiles to)
..local lua = \(\(%action means %body) as lua)
lua:remove_free_vars({\%action.stub:as_lua_id()})
return lua"
(externally %actions all mean %body) compiles to:
lua> "\
..local lua = \(what (%actions all mean %body) compiles to)
..local lua = \(\(%actions all mean %body) as lua)
lua:remove_free_vars(table.map(\%actions, function(a) return a.stub:as_lua_id() end))
return lua"
test:
assume (((say %)'s meaning) == (=lua "say"))
(%action's meaning) compiles to (Lua (%action.stub as lua id))
(%action's meaning) compiles to (Lua (%action.stub::as lua id))
test:
(swap %x and %y) parses as (..)
do:
@ -231,7 +236,7 @@ test:
i = i + 1
elseif k == "source" then
ret[#ret+1] = k.."= "..tostring(v):as_lua()
elseif lua_type_of(k) == 'string' and k:match("[_a-zA-Z][_a-zA-Z0-9]*") then
elseif lua_type_of(k) == 'string' and k:is_a_lua_id() then
ret[#ret+1] = k.."= "..make_tree(v)
else
ret[#ret+1] = "["..make_tree(k).."]= "..make_tree(v)
@ -247,7 +252,7 @@ test:
local \%new_body = LuaCode:from(\%body.source,
"local mangle = mangler()",
"\\nreturn ", make_tree(\%body))
local ret = \(what (%actions all compile to %new_body) compiles to)
local ret = \(\(%actions all compile to %new_body) as lua)
return ret"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -265,16 +270,13 @@ externally (%tree as lua expr) means:
externally [%var as lua identifier, %var as lua id] all mean:
lua> "\
..if lua_type_of(\%var) == 'string' then return \%var:as_lua_id()
elseif SyntaxTree:is_instance(\%var, 'Var') then return \%var[1]:as_lua_id()
elseif SyntaxTree:is_instance(\%var) then
local lua = \(%var as lua expr)
if not lua:text():match("^[_a-zA-Z][_a-zA-Z0-9]*$") then
compile_error(\%var, "This is not a valid Lua identifier.")
end
return lua
else error("Unknown type: "..tostring(\%var))
end"
..local lua = \(%var as lua)
if not lua:text():is_a_lua_id() then
compile_error(\%var,
"This is supposed to be something that compiles to a valid Lua identifier.",
"This should probably be a variable.")
end
return lua"
test:
(num args (*extra arguments*)) means (select "#" (*extra arguments*))

View File

@ -165,7 +165,7 @@ indented_text (Text):
indented_plain_text (Text):
{~
((("\" blank_lines =curr_indent "..") -> "") / ('\\' -> '\')
/ (!text_interpolation ((!("\n") escaped_char) / '\'))
/ (!text_interpolation (escaped_char / '\'))
/ (nonterminal_quote / text_char)+)+
(%nl+ (=curr_indent -> ""))*
~}

View File

@ -307,6 +307,7 @@ local compile = setmetatable({
return lua
elseif "Text" == _exp_0 then
local lua = LuaCode:from(tree.source)
local added = 0
local string_buffer = ""
for i, bit in ipairs(tree) do
local _continue_0 = false
@ -317,20 +318,29 @@ local compile = setmetatable({
break
end
if string_buffer ~= "" then
if #lua.bits > 0 then
string_buffer = string_buffer:as_lua()
if lua:trailing_line_len() + #string_buffer > MAX_LINE then
lua:append("\n ")
end
if added > 0 then
lua:append("..")
end
lua:append(string_buffer:as_lua())
lua:append(string_buffer)
added = added + 1
string_buffer = ""
end
local bit_lua = compile(bit)
if #lua.bits > 0 then
if lua:trailing_line_len() + #bit_lua:text() > MAX_LINE then
lua:append("\n ")
end
if added > 0 then
lua:append("..")
end
if bit.type ~= "Text" then
bit_lua = LuaCode:from(bit.source, "tostring(", bit_lua, ")")
end
lua:append(bit_lua)
added = added + 1
_continue_0 = true
until true
if not _continue_0 then
@ -338,10 +348,15 @@ local compile = setmetatable({
end
end
if string_buffer ~= "" or #lua.bits == 0 then
if #lua.bits > 0 then
string_buffer = string_buffer:as_lua()
if lua:trailing_line_len() + #string_buffer > MAX_LINE then
lua:append("\n ")
end
if added > 0 then
lua:append("..")
end
lua:append(string_buffer:as_lua())
lua:append(string_buffer)
added = added + 1
end
if #lua.bits > 1 then
lua:parenthesize()

View File

@ -213,24 +213,36 @@ compile = setmetatable({
when "Text"
lua = LuaCode\from(tree.source)
added = 0
string_buffer = ""
for i, bit in ipairs tree
if type(bit) == "string"
string_buffer ..= bit
continue
if string_buffer != ""
if #lua.bits > 0 then lua\append ".."
lua\append string_buffer\as_lua!
string_buffer = string_buffer\as_lua!
if lua\trailing_line_len! + #string_buffer > MAX_LINE
lua\append "\n "
if added > 0 then lua\append ".."
lua\append string_buffer
added += 1
string_buffer = ""
bit_lua = compile(bit)
if #lua.bits > 0 then lua\append ".."
if lua\trailing_line_len! + #bit_lua\text! > MAX_LINE
lua\append "\n "
if added > 0 then lua\append ".."
if bit.type != "Text"
bit_lua = LuaCode\from(bit.source, "tostring(",bit_lua,")")
lua\append bit_lua
added += 1
if string_buffer ~= "" or #lua.bits == 0
if #lua.bits > 0 then lua\append ".."
lua\append string_buffer\as_lua!
string_buffer = string_buffer\as_lua!
if lua\trailing_line_len! + #string_buffer > MAX_LINE
lua\append "\n "
if added > 0 then lua\append ".."
lua\append string_buffer
added += 1
if #lua.bits > 1
lua\parenthesize!