Commit 15cf6197 authored by Jamie A. Jennings's avatar Jamie A. Jennings

Now using rpl_1_3 with shunting yard. Made some changes to rpl_1_3.rpl, and...

Now using rpl_1_3 with shunting yard.  Made some changes to rpl_1_3.rpl, and could do some optimizations to infix.to_prefix() if we wanted.  In particular, quantifiers are now always inside a "term".  Most tests pass, except for some rpl-future ones.
parent 8f23c550
1.2.0-preview.2
1.2.0-preview.3
......@@ -114,36 +114,32 @@ operator = slash / and
grammar
syntax_error = { rest_of_line }
exp = infix -- capture
term = {base_term quantifier?}
alias infix = {atmos
!binding_prefix
atmos
term quantifier?
{ atmos
operator?
infix}*
{predicate / term}
{atmos operator? infix}*
}
grammar_exp = "grammar" identifier atmos (bindings "in")? exp
let_exp = "let" atmos (bindings "in")? exp
grammar_exp = "grammar" eot identifier atmos (bindings "in" eot)? term --quantifier? !@#!@#!@#!@#!@#!@#!@#!@#!@#
let_exp = "let" bindings "in" term --quantifier? !@# !@# !@# !@# !@# !@# !@# !@# !@# !@# !@#
application = { identifier ":" } atmos (arg / arglist / rawarglist )
arglist = { atmos open int_or_exp { atmos "," int_or_exp }* close }
rawarglist = { atmos openraw int_or_exp { atmos "," int_or_exp }* closeraw }
arg = term / int -- must be term, not exp
alias int_or_exp = atmos int / exp
alias term = {grammar_exp /
let_exp /
cooked /
raw /
quoted_string /
simple_charset /
bracket /
predicate /
hash_exp /
application /
identifier}
alias base_term = {grammar_exp /
let_exp /
cooked /
raw /
quoted_string /
simple_charset /
bracket /
hash_exp /
application /
{!binding_prefix identifier}}
bracket = { openbracket complement? exp atmos closebracket }
cooked = { open exp atmos close }
raw = { openraw exp atmos closeraw }
predicate = { predicate_symbol ws? term }
predicate = { predicate_symbol ws? {predicate / term}}
-- binding forms
binding = { atmos grammar_block / let_block / simple / empty }
......
......@@ -294,14 +294,16 @@ function convert_bracket(pt, sref)
if compflag then
table.remove(exps, 1)
end
if not (exps[1] and (not exps[2]) and (exps[1].type=="form.exp")) then
print("***")
table.print(exps)
print("***")
end
assert(exps[1] and (not exps[2]) and (exps[1].type=="form.exp"))
-- !@#
if exps[1].subs and exps[1].subs[2] then print("*** " .. util.table_to_pretty_string(exps)); end
-- strip off the outer 'form.exp'
exps = exps[1].subs
assert(exps[1])
-- for i=2, #exps do assert(not common.not_atmosphere(exps[i]), util.table_to_pretty_string(exps[i])) end
assert(not exps[2], "*** " .. util.table_to_pretty_string(exps))
assert(not exps[2], "internal error: bracket expression has expected structure")
local cexp
if exps[1].type=="form.sequence" then
local explist = filter(not_atmosphere, flatten_exp(exps[1], "form.sequence"))
......
......@@ -35,8 +35,9 @@ local infix = {}
infix.DEBUG=false -- temporary
assert(rosie, "'rosie' not defined. Use this file in rosie lua, not plain lua.")
import = rosie.import
--assert(rosie, "'rosie' not defined. Use this file in rosie lua, not plain lua.")
--import = rosie.import
local util = require("util")
local common = require("common")
local list = require("list")
......@@ -114,7 +115,7 @@ local function insert_seq_operators(exps)
local i = 1
while i <= #exps do
item = exps[i]
if is_atmosphere(item) then
if is_atmosphere(item) or item.type=="complement" then
-- no op, just enqueue it into the result list
elseif item.type=="operator" then
--!assert( last_seen )
......@@ -138,6 +139,7 @@ local function insert_seq_operators(exps)
end
local shunting_yard_explist;
local handle_statement;
local function shunting_yard_exp(exp, attribute_table)
if infix.DEBUG then print("*** entering shunting_yard_exp with: ", exp.type, " ", exp.data) end
......@@ -145,6 +147,7 @@ local function shunting_yard_exp(exp, attribute_table)
return map(function(e) return shunting_yard_exp(e, attribute_table) end, ls)
end
if exp.type == "form.exp" or
exp.type == "form.term" or
exp.type == "form.bracket" then
return {type=exp.type,
s=exp.s,
......@@ -166,7 +169,38 @@ local function shunting_yard_exp(exp, attribute_table)
data=exp.data,
subs=map_shunting_yard_exp(exp.subs)}
elseif exp.type == "form.grammar_exp" or exp.type == "form.let_exp" then
error("unhandled expression type: " .. exp.type)
-- grammar_exp = "grammar" identifier atmos (bindings "in")? exp
-- let_exp = "let" atmos (bindings "in")? exp
local expression = exp.subs[#exp.subs]
local bindings = filter(function(sub)
return sub.type=="bindings"
end,
exp.subs)
local newbindings
if #bindings==0 then
newbindings = nil
else
newbindings = map(handle_statement, bindings[1].subs)
end
local newbindingsub = {type=bindings.type,
s=bindings.s,
e=bindings.e,
data=bindings.data,
subs=newbindings}
local newsubs = {}
for i, sub in ipairs(exp.subs) do
if sub.type=="bindings" then
newsubs[i] = newbindingsub
else
newsubs[i] = sub;
end
end
newsubs[#newsubs] = shunting_yard_exp(expression)
return {type=exp.type,
s=exp.s,
e=exp.e,
data=exp.data,
subs=newsubs}
elseif exp.type == "form.application" then
local n = #exp.subs
local arg_form = exp.subs[n]
......@@ -350,7 +384,7 @@ end
-- complicated, so we have to take them apart to find the simple bindings inside
-- them.
local function handle_statement(s)
function handle_statement(s)
if s.type=="form.binding" then
return {type=s.type,
s=s.s,
......@@ -370,7 +404,8 @@ local function handle_statement(s)
e=s.e,
data=s.data,
subs = newsubs}
elseif s.type=="form.grammar_block" then
elseif s.type=="form.grammar_block"
or s.type=="form.let_block" then
--!assert(s.subs[1].type=="form.bindings")
-- there may be one set of bindings or two
local newsubs = {}
......@@ -392,8 +427,16 @@ local function handle_statement(s)
s.type=="language_decl" or
is_atmosphere(s) then
return s
elseif s.type=="form.let_block" then
error("let statements are not supported")
elseif s.type=="form.exp" then
-- Oddly, perhaps, 'rpl_statements' can match 'form.exp'. This is
-- intentional, and allows a better error message to be issued by code
-- that wants a statment but gets an expression. Similarly,
-- 'rpl_expression' can match a binding for the same reason.
return {type = s.type,
s = s.s,
e = s.e,
data = s.data,
subs = map(shunting_yard, s.subs)}
else
error("unexpected statement type: " .. tostring(s.type))
end
......@@ -415,20 +458,27 @@ function infix.to_prefix(pt)
data = pt.data,
subs = map(shunting_yard, pt.subs)}
elseif pt.type=="rpl_statements" then
--!assert(pt.subs)
-- There can be no subs, which happens if some component of rosie tries to
-- parse a statement and gets only a language declaration, which gets
-- stripped out in pre-parsing, leaving no actual statements.
local newsubs = (pt.subs and map(handle_statement, pt.subs)) or nil
return {type = pt.type,
s = pt.s,
e = pt.e,
data = pt.data,
subs = map(handle_statement, pt.subs)}
subs = newsubs}
else
error("unexpected parse tree type: " .. tostring(pt.type))
end
end
return infix
--------------------------------------------------------------------------------
-- FOR TESTING DURING DEVELOPMENT
--[==[
function slurp(filename)
local f, err = io.open(filename)
if not f then error(err) end
......@@ -608,4 +658,6 @@ return infix
-- 0.181641
-- > collectgarbage('collect'); t0=os.clock(); for i=1,10000 do x = orig:compile('"a"'); end; t1=os.clock(); print((t1-t0)/10)
-- 0.1787887
-- >
\ No newline at end of file
-- >
--]==]
......@@ -119,6 +119,7 @@ local function load_all()
ui = import("ui")
expr = import("expr")
unittest = import("unittest")
infix = import("infix")
end
---------------------------------------------------------------------------------------------------
......@@ -230,6 +231,46 @@ function create_rpl_1_2_engine(e)
end
function create_rpl_1_3_engine(e)
-- common.notes = true
local ok, pkg, messages = e:import("rosie/rpl_1_3", ".")
assert(ok, util.table_to_pretty_string(messages, false))
-- local e = rosie.engine.new()
-- parse_block = rosie.env.compile.make_parse_block(preparse, stmt, e.compiler.version, infix.to_prefix)
-- parse_expression = rosie.env.compile.make_parse_expression(exp, infix.to_prefix)
-- e.compiler.parse_block = parse_block
-- e.compiler.parse_expression = parse_expression
-- e.compiler.version = common.rpl_version.new(1,3)
local version = common.rpl_version.new(1, 3)
local rplx_preparse, errs = e:compile("preparse")
assert(rplx_preparse, errs and util.table_to_pretty_string(errs) or "no err info")
local rplx_statements = e:compile("rpl_statements")
assert(rplx_statements)
local rplx_expression = e:compile("rpl_expression")
assert(rplx_expression)
local compiler3 =
{ version = version,
parse_block = compile.make_parse_block(rplx_preparse, rplx_statements, version, infix.to_prefix),
expand_block = compile.expand_block,
compile_block = compile.compile_block,
dependencies_of = compile.dependencies_of,
parse_expression = compile.make_parse_expression(rplx_expression, infix.to_prefix),
expand_expression = compile.expand_expression,
compile_expression = compile.compile_expression,
}
local c3engine = engine.new("NEW RPL 1.3 engine (c3)", compiler3, ROSIE_LIBDIR)
announce("c3 engine", c3engine)
return c3engine, compiler3
end
----------------------------------------------------------------------------------------
-- INFO for debugging
----------------------------------------------------------------------------------------
......@@ -319,7 +360,7 @@ ROSIE_LIBPATH = ROSIE_LIBDIR
CORE_ENGINE = create_core_engine()
assert(CORE_ENGINE)
ROSIE_ENGINE, ROSIE_COMPILER = create_rpl_1_2_engine(CORE_ENGINE)
ROSIE_ENGINE, ROSIE_COMPILER = create_rpl_1_3_engine(CORE_ENGINE)
assert(ROSIE_ENGINE and ROSIE_COMPILER)
rosie_package.default = { rcfile = "~/.rosierc",
......
......@@ -458,14 +458,14 @@ check_lua_error(results_txt)
check(results_txt:find("[parser]"))
check(results_txt:find("let expressions are not supported"))
cmd = rosie_cmd .. " --norcfile " .. " expand 'grammar X foo=\"foo\" in foo' 2>&1"
results, status, code = util.os_execute_capture(cmd, nil)
check(#results>0, "command should have produced output")
check(code ~= 0, "return should NOT have been zero")
results_txt = table.concat(results, '\n')
check_lua_error(results_txt)
check(results_txt:find("[parser]"))
check(results_txt:find("grammar expressions are not supported"))
-- cmd = rosie_cmd .. " --norcfile " .. " expand 'grammar X foo=\"foo\" in foo' 2>&1"
-- results, status, code = util.os_execute_capture(cmd, nil)
-- check(#results>0, "command should have produced output")
-- check(code ~= 0, "return should NOT have been zero")
-- results_txt = table.concat(results, '\n')
-- check_lua_error(results_txt)
-- check(results_txt:find("[parser]"))
-- check(results_txt:find("grammar expressions are not supported"))
---------------------------------------------------------------------------------------------------
......
......@@ -30,7 +30,7 @@ print("Found rosie executable: " .. rosie_cmd)
rplfile = "utf8-in-rpl.rpl"
test.heading("Running self-tests on " .. rplfile)
cmd = rosie_cmd .. " test --verbose " .. "test/" .. rplfile .. " 2>/dev/null"
cmd = rosie_cmd .. " --norcfile test --verbose " .. "test/" .. rplfile .. " 2>/dev/null"
print()
print(cmd)
results, status, code = util.os_execute_capture(cmd)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment