Initial setup work for syntax version 5.
This commit is contained in:
parent
0d88091f8d
commit
6ba84a0f50
12
Makefile
12
Makefile
@ -1,6 +1,6 @@
|
||||
# Nomsu makefile
|
||||
# To build, run `make`
|
||||
# To install,
|
||||
# To install, run `make install`
|
||||
|
||||
# ========= User-controlled variables ========
|
||||
LUA= lua
|
||||
@ -23,10 +23,10 @@ LIB_LUA_FILES= $(patsubst %.nom,%.lua,$(LIB_NOM_FILES))
|
||||
PEG_FILES= $(wildcard nomsu.*.peg)
|
||||
GET_VERSION= $(LUA_BIN) nomsu.lua --version
|
||||
|
||||
all: build optimize
|
||||
all: lua optimize
|
||||
|
||||
.PHONY: test
|
||||
test: build optimize
|
||||
test: lua optimize
|
||||
@echo "\033[1;4mRunning unoptimized tests...\033[0m"
|
||||
@$(LUA_BIN) nomsu.lua -O0 tools/test.nom $(CORE_NOM_FILES) $(LIB_NOM_FILES)
|
||||
@echo "\n\033[1;4mRunning optimized tests...\033[0m"
|
||||
@ -42,10 +42,10 @@ test: build optimize
|
||||
version: $(LUA_FILES) $(CORE_NOM_FILES) $(LIB_NOM_FILES)
|
||||
@$(LUA_BIN) nomsu.lua --version > version || exit
|
||||
|
||||
build: $(LUA_FILES)
|
||||
lua: $(LUA_FILES)
|
||||
|
||||
.PHONY: optimize
|
||||
optimize: build $(CORE_LUA_FILES) $(LIB_LUA_FILES)
|
||||
optimize: lua $(CORE_LUA_FILES) $(LIB_LUA_FILES)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@ -53,7 +53,7 @@ clean:
|
||||
@rm -rvf version core/*.lua lib/*.lua tools/*.lua compatibility/*.lua
|
||||
|
||||
.PHONY: install
|
||||
install: build version optimize
|
||||
install: lua version optimize
|
||||
@prefix="$(PREFIX)"; \
|
||||
if [[ ! $$prefix ]]; then \
|
||||
read -p $$'\033[1mWhere do you want to install Nomsu? (default: /usr/local) \033[0m' prefix; \
|
||||
|
@ -26,7 +26,8 @@ lua> "\
|
||||
local body_lua = SyntaxTree:is_instance(\%body) and compile(\%body) or \%body
|
||||
if SyntaxTree:is_instance(\%body) and \%body.type ~= "Block" then body_lua:prepend("return ") end
|
||||
local lua = LuaCode("(function(")
|
||||
if SyntaxTree:is_instance(\%args) and \%args.type == "Action" then \%args = \%args:get_args()
|
||||
if SyntaxTree:is_instance(\%args) and (\%args.type == "Action" or \%args.type == "MethodCall") then
|
||||
\%args = \%args:get_args()
|
||||
elseif SyntaxTree:is_instance(\%args) and \%args.type == "Var" then \%args = {\%args} end
|
||||
for i, arg in ipairs(\%args) do
|
||||
local arg_lua = SyntaxTree:is_instance(arg) and compile(arg):text() or arg
|
||||
@ -38,7 +39,7 @@ lua> "\
|
||||
elseif not arg_lua:is_lua_id() then
|
||||
compile_error_at(SyntaxTree:is_instance(arg) and arg or nil,
|
||||
"This does not compile to a Lua identifier, so it can't be used as a function argument.",
|
||||
"This should probably be a Nomsu variable instead (like %x).")
|
||||
"This should probably be a Nomsu variable instead (like $x).")
|
||||
end
|
||||
lua:add(i > 1 and ", " or "", arg_lua)
|
||||
body_lua:remove_free_vars({arg_lua})
|
||||
@ -136,34 +137,38 @@ test:
|
||||
lua> "\
|
||||
..
|
||||
local lua = LuaCode()
|
||||
local fn_name = \%action.stub:as_lua_id()
|
||||
if \%action.target then lua:add(compile(\%action.target), ".")
|
||||
else lua:add_free_vars({fn_name}) end
|
||||
lua:add(fn_name, " = ", \(\(%action -> %body) as lua), ";")
|
||||
if \%action.type == "MethodCall" then
|
||||
lua:add(compile(\%action[1]), ".", \%action[2].stub:as_lua_id())
|
||||
elseif \%action.type == "Action" then
|
||||
lua:add(\%action.stub:as_lua_id())
|
||||
lua:add_free_vars({\%action.stub:as_lua_id()})
|
||||
else
|
||||
compile_error_at(\%action, "Expected an action or method call here")
|
||||
end
|
||||
lua:add(" = ", \(\(%action -> %body) as lua), ";")
|
||||
return lua"
|
||||
|
||||
(%actions all mean %body) compiles to:
|
||||
lua> "\
|
||||
..local fn_name = \%actions[1].stub:as_lua_id()
|
||||
local target = \%actions[1].target and compile(\%actions[1].target) or nil
|
||||
..local lua = \(\(%actions.1 means %body) as lua)
|
||||
local first_def = (\%actions[1].type == "MethodCall"
|
||||
and LuaCode(compile(\%actions[1][1]), ".", \%actions[1].stub:as_lua_id())
|
||||
or LuaCode(\%actions[1].stub:as_lua_id()))
|
||||
local \%args = List(\%actions[1]:get_args())
|
||||
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()
|
||||
local \%alias_args = List(alias:get_args())
|
||||
lua:add("\\n")
|
||||
if alias.target then
|
||||
lua:add(compile(alias.target), ".")
|
||||
if alias.type == "MethodCall" then
|
||||
lua:add(compile(alias[1]), ".", alias.stub:as_lua_id())
|
||||
else
|
||||
lua:add(alias.stub:as_lua_id())
|
||||
lua:add_free_vars({alias_name})
|
||||
end
|
||||
lua:add(alias_name, " = ")
|
||||
if \%args == \%alias_args then
|
||||
if target then lua:add(target, ".") end
|
||||
lua:add(fn_name, ";")
|
||||
lua:add(" = ", first_def, ";")
|
||||
else
|
||||
lua:add(\(\(%alias_args -> %actions.1) as lua), ";")
|
||||
lua:add(" = ", \(\(%alias_args -> %actions.1) as lua), ";")
|
||||
end
|
||||
end
|
||||
return lua"
|
||||
|
@ -35,8 +35,7 @@ test:
|
||||
# Variable assignment operator
|
||||
(%var = %value) compiles to:
|
||||
lua> "\
|
||||
..
|
||||
local lua = LuaCode()
|
||||
..local lua = LuaCode()
|
||||
if \%var.type == "List" then
|
||||
for i, \%assignment in ipairs(\%var) do
|
||||
if i > 1 then lua:add(", ") end
|
||||
|
13
nomsu.3.peg
13
nomsu.3.peg
@ -101,17 +101,22 @@ indented_nomsu (EscapedNomsu):
|
||||
index_chain (IndexChain):
|
||||
noindex_inline_expression ("." (text_word / noindex_inline_expression))+
|
||||
|
||||
inline_action: inline_methodcall / _inline_action
|
||||
inline_methodcall:
|
||||
inline_arg ws* "::" ws* _inline_action
|
||||
-- Actions need either at least 1 word, or at least 2 tokens
|
||||
inline_action (Action):
|
||||
_inline_action (Action):
|
||||
!section_division
|
||||
({:target: inline_arg :} ws* "::" ws*)?
|
||||
( (inline_arg (ws* (inline_arg / word))+)
|
||||
/ (word (ws* (inline_arg / word))*))
|
||||
(ws* inline_block)?
|
||||
inline_arg: inline_expression / inline_block
|
||||
action (Action):
|
||||
|
||||
action: methodcall / _action
|
||||
methodcall:
|
||||
arg (nl_nodent "..")? ws* "::" (nl_nodent "..")? ws* _action
|
||||
_action (Action):
|
||||
!section_division
|
||||
({:target: arg :} (nl_nodent "..")? ws* "::" (nl_nodent "..")? ws*)?
|
||||
( (arg ((nl_nodent "..")? ws* (arg / word))+)
|
||||
/ (word ((nl_nodent "..")? ws* (arg / word))*))
|
||||
arg: expression / inline_block / indented_block
|
||||
|
16
nomsu.4.peg
16
nomsu.4.peg
@ -111,18 +111,24 @@ indented_nomsu (EscapedNomsu):
|
||||
index_chain (IndexChain):
|
||||
noindex_inline_expression ("." (text_word / noindex_inline_expression))+
|
||||
|
||||
inline_action: inline_methodcall / _inline_action
|
||||
inline_methodcall (MethodCall):
|
||||
(inline_expression / "(" inline_block ")") ws* "::" ws* _inline_action
|
||||
-- Actions need either at least 1 word, or at least 2 tokens
|
||||
inline_action (Action):
|
||||
_inline_action (Action):
|
||||
!section_division
|
||||
({:target: (inline_expression / "(" inline_block ")") :} ws* "::" ws*)?
|
||||
( (inline_arg (ws* (inline_arg / word))+)
|
||||
/ (word (ws* (inline_arg / word))*))
|
||||
(ws* inline_block)?
|
||||
inline_arg: inline_expression / inline_block / "(" ws* ")"
|
||||
action (Action):
|
||||
|
||||
action: methodcall / _action
|
||||
methodcall (MethodCall):
|
||||
(expression / "(" inline_block ")" / indented_block)
|
||||
((ws* "\")? eol nl_nodent "..")? ws* "::" ((ws* "\")? eol nl_nodent "..")? ws*
|
||||
_action
|
||||
_action (Action):
|
||||
!section_division
|
||||
({:target: (expression / "(" inline_block ")" / indented_block) :}
|
||||
((ws* "\")? eol nl_nodent "..")? ws* "::" ((ws* "\")? eol nl_nodent "..")? ws*)?
|
||||
( (arg (((ws* "\")? eol nl_nodent "..")? ws* (arg / word))+)
|
||||
/ (word (((ws* "\")? eol nl_nodent "..")? ws* (arg / word))*))
|
||||
arg: expression / inline_block / indented_block / "(" ws* ")"
|
||||
|
245
nomsu.5.peg
Normal file
245
nomsu.5.peg
Normal file
@ -0,0 +1,245 @@
|
||||
-- Nomsu version 5
|
||||
file:
|
||||
{:curr_indent: ' '* :}
|
||||
(((methodcall / action / expression / inline_block / indented_block) eol !.)
|
||||
/ file_chunks / empty_block)
|
||||
{:curr_indent: %nil :}
|
||||
!.
|
||||
|
||||
shebang: "#!" (!"nomsu" [^%nl])* "nomsu" ws+ "-V" ws* [0-9.]+ [^%nl]* (%nl / !.)
|
||||
|
||||
eof: !.
|
||||
|
||||
file_chunks (FileChunks):
|
||||
{:curr_indent: ' '* :}
|
||||
{:shebang: shebang :}?
|
||||
(top_block (nl_nodent section_division top_block)*)
|
||||
blank_lines?
|
||||
ws* unexpected_chunk?
|
||||
{:curr_indent: %nil :}
|
||||
|
||||
top_block (Block):
|
||||
{:curr_indent: ' '* :}
|
||||
comment? blank_lines? statement (nl_nodent statement)*
|
||||
{:curr_indent: %nil :}
|
||||
|
||||
empty_block (Block):
|
||||
{:curr_indent: ' '* :}
|
||||
comment? blank_lines?
|
||||
{:curr_indent: %nil :}
|
||||
|
||||
nodent: (unexpected_indent [^%nl]* / =curr_indent)
|
||||
indent: {~ =curr_indent (ws / (%tab -> ' '))+ ~}
|
||||
blank_lines: %nl ((nodent comment / ws*) %nl)*
|
||||
eol: ws* eol_comment? (!. / &%nl)
|
||||
|
||||
nl_nodent: blank_lines nodent
|
||||
nl_indent: blank_lines tab_error? {:curr_indent: indent :} (comment nl_nodent)*
|
||||
|
||||
comment (Comment):
|
||||
"#" {~ [^%nl]* (%nl+ (indent -> '') [^%nl]*)* (%nl &%nl)* ~}
|
||||
eol_comment (Comment):
|
||||
"#" {[^%nl]*}
|
||||
|
||||
unexpected_code: ws* _unexpected_code
|
||||
_unexpected_code (Error):
|
||||
{:error: {~ [^%nl]+ -> "Couldn't parse this code" ~} :}
|
||||
unexpected_chunk (Error):
|
||||
{:error: {~ .+ -> "Couldn't parse this code" ~} :}
|
||||
unexpected_indent (Error):
|
||||
{:error: {~ (=curr_indent ws+) -> "Messed up indentation" ~} :}
|
||||
{:hint: {~ '' -> 'Either make sure this line is aligned with the one above it, or make sure the previous line ends with something that uses indentation, like ":" or "(..)"' ~} :}
|
||||
missing_paren_err (Error):
|
||||
{:error: {~ eol -> 'Line ended without finding a closing )-parenthesis' ~} :}
|
||||
{:hint: {~ '' -> 'Put a ")" here' ~} :}
|
||||
missing_quote_err (Error):
|
||||
{:error: {~ eol -> "Line ended without finding a closing quotation mark." ~} :}
|
||||
{:hint: {~ "" -> "Put a quotation mark here." ~} :}
|
||||
missing_indented_quote_err (Error):
|
||||
{:error: {~ eol -> "This text doesn't have a closing quotation mark." ~} :}
|
||||
{:hint: {~ "" -> "Put a quotation mark here on its own line." ~} :}
|
||||
missing_bracket_error (Error):
|
||||
{:error: {~ eol -> "Line ended before finding a closing ]-bracket" ~} :}
|
||||
{:hint: {~ '' -> 'Put a "]" here' ~} :}
|
||||
missing_brace_error (Error):
|
||||
{:error: {~ eol -> "Line ended before finding a closing }-brace" ~} :}
|
||||
{:hint: {~ '' -> 'Put a "}" here' ~} :}
|
||||
tab_error (Error):
|
||||
&(=curr_indent %tab)
|
||||
{:error: {~ '' -> 'Tabs are not allowed for indentation.' ~} :}
|
||||
{:hint: {~ '' -> 'Use spaces instead of tabs.' ~} :}
|
||||
|
||||
section_division: ("~")^+3 eol
|
||||
|
||||
inline_block:
|
||||
"(" ws* inline_block ws* (eof / ")") / raw_inline_block
|
||||
raw_inline_block (Block):
|
||||
(!"::") ":" ws* ((inline_statement (ws* ";" ws* inline_statement)*) / !(eol nl_indent))
|
||||
indented_block (Block):
|
||||
":" eol nl_indent statement (nl_nodent statement)*
|
||||
(%nl (ws* %nl)* nodent (comment / eol / unexpected_code))*
|
||||
{:curr_indent: %nil :}
|
||||
|
||||
statement:
|
||||
(methodcall / action / expression) (eol / unexpected_code)
|
||||
|
||||
inline_statement: (inline_methodcall / inline_action / inline_expression)
|
||||
|
||||
noindex_inline_expression:
|
||||
number / variable / inline_text / inline_list / inline_dict / inline_nomsu
|
||||
/ ( "("
|
||||
ws* (inline_methodcall / inline_action / inline_expression) ws*
|
||||
(")" / eof / missing_paren_err / unexpected_code)
|
||||
)
|
||||
inline_expression: index_chain / noindex_inline_expression
|
||||
indented_expression:
|
||||
indented_text / indented_nomsu / indented_list / indented_dict / ({|
|
||||
"(..)" eol nl_indent
|
||||
(methodcall / action / expression) (eol / unexpected_code)
|
||||
(%nl (ws* %nl)* nodent (comment / eol / unexpected_code))*
|
||||
{:curr_indent: %nil :}
|
||||
|} -> unpack)
|
||||
expression:
|
||||
inline_expression / indented_expression
|
||||
|
||||
inline_nomsu (EscapedNomsu): "\" (inline_expression / inline_block)
|
||||
indented_nomsu (EscapedNomsu):
|
||||
"\" (noindex_inline_expression / inline_block / indented_expression / indented_block)
|
||||
|
||||
index_chain (IndexChain):
|
||||
noindex_inline_expression
|
||||
("." (hex_integer / integer / text_word / noindex_inline_expression))+
|
||||
|
||||
index_chain_before_method (IndexChain):
|
||||
noindex_inline_expression
|
||||
("." (hex_integer / integer / text_word / noindex_inline_expression) &".")+
|
||||
|
||||
-- Actions need 1 argument and either another argument or a word.
|
||||
inline_action (Action):
|
||||
!section_division
|
||||
( (word (ws* (inline_arg / word))*)
|
||||
/(inline_arg (ws* (inline_arg / word))+))
|
||||
inline_arg: inline_expression / inline_block
|
||||
inline_methodcall (MethodCall):
|
||||
(index_chain / noindex_inline_expression / "(" inline_block ")")
|
||||
"|" inline_action
|
||||
|
||||
action (Action):
|
||||
!section_division
|
||||
( (word ((linesplit / ws*) (arg / word))*)
|
||||
/(arg ((linesplit / ws*) (arg / word))+))
|
||||
linesplit: (ws* "\")? eol nl_nodent ".." ws*
|
||||
arg: expression / inline_block / indented_block
|
||||
methodcall (MethodCall):
|
||||
(index_chain / noindex_inline_expression / indented_expression / "(" inline_block ")" / indented_block)
|
||||
linesplit? "|" linesplit? action
|
||||
|
||||
word: !number { operator_char+ / ident_char+ }
|
||||
|
||||
text_word (Text): word
|
||||
|
||||
inline_text (Text):
|
||||
!(indented_text)
|
||||
'"' _inline_text* ('"' / eof / missing_quote_err / unexpected_code)
|
||||
_inline_text:
|
||||
{~ (('\"' -> '"') / ('\\' -> '\') / escaped_char / text_char+)+ ~}
|
||||
/ inline_text_interpolation / illegal_char
|
||||
inline_text_interpolation:
|
||||
"\" (
|
||||
variable / inline_list / inline_dict
|
||||
/ ("("
|
||||
ws* ((inline_methodcall / inline_action / inline_expression) ws*)?
|
||||
(")" / eof / missing_paren_err / unexpected_code))
|
||||
)
|
||||
|
||||
text_char: %utf8_char / !["\] %print / %tab
|
||||
illegal_char (Error):
|
||||
{:error: {~ (!(%nl / %tab / %print) .) -> "Illegal unprintable character here (it may not be visible, but it's there)" ~} :}
|
||||
{:hint: {~ '' -> "This sort of thing can happen when copying and pasting code. Try deleting and retyping the code." ~} :}
|
||||
|
||||
terminal_quote: '"' !([^%nl] / (%nl (ws* eol)?)+ =curr_indent [^%nl])
|
||||
nonterminal_quote: !terminal_quote '"'
|
||||
indented_text (Text):
|
||||
'"' %nl {%nl*} {:curr_indent: indent :}
|
||||
(indented_plain_text / text_interpolation / illegal_char / blank_text_lines)*
|
||||
(terminal_quote eol / eof / missing_indented_quote_err)
|
||||
{:curr_indent: %nil :}
|
||||
-- Tracking text-lines-within-indented-text as separate objects allows for better debugging line info
|
||||
indented_plain_text (Text):
|
||||
{~
|
||||
((("\" blank_lines =curr_indent "..") -> "") / ('\\' -> '\')
|
||||
/ (!text_interpolation ((!("\n") escaped_char) / '\'))
|
||||
/ (nonterminal_quote / text_char)+)+
|
||||
blank_text_lines?
|
||||
~}
|
||||
blank_text_lines:
|
||||
{~ (%nl ((ws* -> '') eol / (=curr_indent -> '') &[^%nl]))+ ~}
|
||||
|
||||
text_interpolation:
|
||||
("\" indented_expression (blank_lines =curr_indent "..")?) / inline_text_interpolation
|
||||
|
||||
number:
|
||||
hex_integer / real_number / integer
|
||||
|
||||
integer (Number):
|
||||
(("-"? [0-9]+)-> tonumber)
|
||||
|
||||
hex_integer (Number):
|
||||
(("-"? "0x" [0-9a-fA-F]+)-> tonumber)
|
||||
{:hex: '' -> 'yes' :}
|
||||
|
||||
real_number (Number):
|
||||
(("-"? ([0-9]+ "." [0-9]+) / ("." [0-9]+))-> tonumber)
|
||||
|
||||
variable (Var): "$" ({ident_char+} / "(" {(ws+ / operator_char+ / ident_char+)*} ")" / {''})
|
||||
|
||||
inline_list (List):
|
||||
!('[..]')
|
||||
"[" ws*
|
||||
(inline_list_item (ws* ',' ws* inline_list_item)* (ws* ',')?)? ws*
|
||||
("]" / eof / (","? (missing_bracket_error / unexpected_code)))
|
||||
indented_list (List):
|
||||
"[..]" eol nl_indent
|
||||
list_line (nl_nodent list_line)*
|
||||
(%nl (ws* %nl)* nodent (comment / eol / unexpected_code))*
|
||||
(","? unexpected_code)?
|
||||
list_line:
|
||||
(inline_list_item ws* "," ws*)+ eol
|
||||
/ (inline_list_item ws* "," ws*)* (methodcall / action / expression / inline_block / indented_block) eol
|
||||
inline_list_item: inline_methodcall / inline_action / inline_expression / inline_block
|
||||
|
||||
inline_dict (Dict):
|
||||
!('{..}')
|
||||
"{" ws*
|
||||
(inline_dict_entry (ws* ',' ws* inline_dict_entry)*)? ws*
|
||||
("}" / eof / (","? (missing_brace_error / unexpected_code)))
|
||||
indented_dict (Dict):
|
||||
"{..}" eol nl_indent
|
||||
dict_line (nl_nodent dict_line)*
|
||||
(%nl (ws* %nl)* nodent (comment / eol / unexpected_code))*
|
||||
(","? unexpected_code)?
|
||||
dict_line:
|
||||
(inline_dict_entry ws* "," ws*)+ eol
|
||||
/ (inline_dict_entry ws* "," ws*)* dict_entry eol
|
||||
_dict_entry(DictEntry):
|
||||
dict_key (ws* ":" ws* (methodcall / action / expression))?
|
||||
dict_entry:
|
||||
_dict_entry / inline_block / indented_block
|
||||
_inline_dict_entry(DictEntry):
|
||||
dict_key (ws* ":" ws* (inline_methodcall / inline_action / inline_expression)?)?
|
||||
inline_dict_entry:
|
||||
_inline_dict_entry / inline_block
|
||||
dict_key:
|
||||
text_word / inline_expression
|
||||
|
||||
operator_char: ['`~@^&*+=|<>?/%!-]
|
||||
ident_char: [a-zA-Z0-9_] / %utf8_char
|
||||
ws: " "
|
||||
|
||||
escaped_char:
|
||||
("\"->'') (
|
||||
(([xX]->'') ((({[0-9a-fA-F]^2} %number_16) -> tonumber) -> tochar))
|
||||
/ ((([0-9] [0-9]^-2) -> tonumber) -> tochar)
|
||||
/ ("a"->ascii_7) / ("b"->ascii_8) / ("t"->ascii_9) / ("n"->ascii_10)
|
||||
/ ("v"->ascii_11) / ("f"->ascii_12) / ("r"->ascii_13)
|
||||
)
|
@ -188,7 +188,7 @@ local compile = setmetatable({
|
||||
if "Action" == _exp_0 then
|
||||
local stub = tree.stub
|
||||
local compile_action = compile.action[stub]
|
||||
if not compile_action and not tree.target and math_expression:match(stub) then
|
||||
if not compile_action and math_expression:match(stub) then
|
||||
local lua = LuaCode:from(tree.source)
|
||||
for i, tok in ipairs(tree) do
|
||||
if type(tok) == 'string' then
|
||||
@ -206,7 +206,7 @@ local compile = setmetatable({
|
||||
end
|
||||
return lua
|
||||
end
|
||||
if compile_action and not tree.target then
|
||||
if compile_action then
|
||||
local args
|
||||
do
|
||||
local _accum_0 = { }
|
||||
@ -235,39 +235,42 @@ local compile = setmetatable({
|
||||
end
|
||||
end
|
||||
local lua = LuaCode:from(tree.source)
|
||||
if tree.target then
|
||||
local target_lua = compile(tree.target)
|
||||
local target_text = target_lua:text()
|
||||
if target_text:match("^%(.*%)$") or target_text:match("^[_a-zA-Z][_a-zA-Z0-9.]*$") or tree.target.type == "IndexChain" then
|
||||
lua:add(target_lua, ":")
|
||||
else
|
||||
lua:add("(", target_lua, "):")
|
||||
end
|
||||
end
|
||||
lua:add((stub):as_lua_id(), "(")
|
||||
local arg_count = 0
|
||||
for i, tok in ipairs(tree) do
|
||||
local _continue_0 = false
|
||||
repeat
|
||||
if type(tok) == "string" then
|
||||
_continue_0 = true
|
||||
break
|
||||
end
|
||||
arg_count = arg_count + 1
|
||||
local arg_lua = compile(tok)
|
||||
if tok.type == "Block" then
|
||||
arg_lua = LuaCode:from(tok.source, "(function()\n ", arg_lua, "\nend)()")
|
||||
end
|
||||
if arg_count > 1 then
|
||||
lua:add(",")
|
||||
end
|
||||
lua:add(lua:trailing_line_len() + #arg_lua:text() > MAX_LINE and "\n " or " ")
|
||||
lua:add(arg_lua)
|
||||
_continue_0 = true
|
||||
until true
|
||||
if not _continue_0 then
|
||||
break
|
||||
for i, arg in ipairs(tree:get_args()) do
|
||||
local arg_lua = compile(arg)
|
||||
if arg.type == "Block" then
|
||||
arg_lua = LuaCode:from(arg.source, "(function()\n ", arg_lua, "\nend)()")
|
||||
end
|
||||
if i > 1 then
|
||||
lua:add(",")
|
||||
end
|
||||
lua:add(lua:trailing_line_len() + #arg_lua:text() > MAX_LINE and "\n " or " ")
|
||||
lua:add(arg_lua)
|
||||
end
|
||||
lua:add(")")
|
||||
return lua
|
||||
elseif "MethodCall" == _exp_0 then
|
||||
local stub = tree[2].stub
|
||||
local lua = LuaCode:from(tree.source)
|
||||
local target_lua = compile(tree[1])
|
||||
local target_text = target_lua:text()
|
||||
if target_text:match("^%(.*%)$") or target_text:match("^[_a-zA-Z][_a-zA-Z0-9.]*$") or tree[1].type == "IndexChain" then
|
||||
lua:add(target_lua, ":")
|
||||
else
|
||||
lua:add("(", target_lua, "):")
|
||||
end
|
||||
assert(tree[2].type == "Action")
|
||||
lua:add((stub):as_lua_id(), "(")
|
||||
for i, arg in ipairs(tree[2]:get_args()) do
|
||||
local arg_lua = compile(arg)
|
||||
if arg.type == "Block" then
|
||||
arg_lua = LuaCode:from(arg.source, "(function()\n ", arg_lua, "\nend)()")
|
||||
end
|
||||
if i > 1 then
|
||||
lua:add(",")
|
||||
end
|
||||
lua:add(lua:trailing_line_len() + #arg_lua:text() > MAX_LINE and "\n " or " ")
|
||||
lua:add(arg_lua)
|
||||
end
|
||||
lua:add(")")
|
||||
return lua
|
||||
|
@ -143,7 +143,7 @@ compile = setmetatable({
|
||||
when "Action"
|
||||
stub = tree.stub
|
||||
compile_action = compile.action[stub]
|
||||
if not compile_action and not tree.target and math_expression\match(stub)
|
||||
if not compile_action and math_expression\match(stub)
|
||||
lua = LuaCode\from(tree.source)
|
||||
for i,tok in ipairs tree
|
||||
if type(tok) == 'string'
|
||||
@ -155,7 +155,7 @@ compile = setmetatable({
|
||||
lua\add " " if i < #tree
|
||||
return lua
|
||||
|
||||
if compile_action and not tree.target
|
||||
if compile_action
|
||||
args = [arg for arg in *tree when type(arg) != "string"]
|
||||
-- Force Lua to avoid tail call optimization for debugging purposes
|
||||
-- TODO: use tail call?
|
||||
@ -173,25 +173,37 @@ compile = setmetatable({
|
||||
return compile(ret)
|
||||
|
||||
lua = LuaCode\from(tree.source)
|
||||
if tree.target -- Method call
|
||||
target_lua = compile tree.target
|
||||
target_text = target_lua\text!
|
||||
-- TODO: this parenthesizing is maybe overly conservative
|
||||
if target_text\match("^%(.*%)$") or target_text\match("^[_a-zA-Z][_a-zA-Z0-9.]*$") or
|
||||
tree.target.type == "IndexChain"
|
||||
lua\add target_lua, ":"
|
||||
else
|
||||
lua\add "(", target_lua, "):"
|
||||
lua\add((stub)\as_lua_id!,"(")
|
||||
arg_count = 0
|
||||
for i, tok in ipairs tree
|
||||
if type(tok) == "string" then continue
|
||||
arg_count += 1
|
||||
arg_lua = compile(tok)
|
||||
if tok.type == "Block"
|
||||
arg_lua = LuaCode\from(tok.source, "(function()\n ", arg_lua, "\nend)()")
|
||||
if arg_count > 1
|
||||
lua\add ","
|
||||
for i, arg in ipairs tree\get_args!
|
||||
arg_lua = compile(arg)
|
||||
if arg.type == "Block"
|
||||
arg_lua = LuaCode\from(arg.source, "(function()\n ", arg_lua, "\nend)()")
|
||||
lua\add "," if i > 1
|
||||
lua\add(lua\trailing_line_len! + #arg_lua\text! > MAX_LINE and "\n " or " ")
|
||||
lua\add arg_lua
|
||||
lua\add ")"
|
||||
return lua
|
||||
|
||||
when "MethodCall"
|
||||
stub = tree[2].stub
|
||||
lua = LuaCode\from tree.source
|
||||
target_lua = compile tree[1]
|
||||
target_text = target_lua\text!
|
||||
-- TODO: this parenthesizing is maybe overly conservative
|
||||
if target_text\match("^%(.*%)$") or target_text\match("^[_a-zA-Z][_a-zA-Z0-9.]*$") or
|
||||
tree[1].type == "IndexChain"
|
||||
lua\add target_lua, ":"
|
||||
else
|
||||
lua\add "(", target_lua, "):"
|
||||
|
||||
-- TODO: de-duplicate this code
|
||||
assert tree[2].type == "Action"
|
||||
lua\add((stub)\as_lua_id!,"(")
|
||||
for i, arg in ipairs tree[2]\get_args!
|
||||
arg_lua = compile(arg)
|
||||
if arg.type == "Block"
|
||||
arg_lua = LuaCode\from(arg.source, "(function()\n ", arg_lua, "\nend)()")
|
||||
lua\add "," if i > 1
|
||||
lua\add(lua\trailing_line_len! + #arg_lua\text! > MAX_LINE and "\n " or " ")
|
||||
lua\add arg_lua
|
||||
lua\add ")"
|
||||
|
@ -49,13 +49,7 @@ tree_to_inline_nomsu = function(tree)
|
||||
local _exp_0 = tree.type
|
||||
if "Action" == _exp_0 then
|
||||
local nomsu = NomsuCode:from(tree.source)
|
||||
if tree.target then
|
||||
local inline_target = tree_to_inline_nomsu(tree.target)
|
||||
if tree.target.type == "Action" then
|
||||
inline_target:parenthesize()
|
||||
end
|
||||
nomsu:add(inline_target, "::")
|
||||
end
|
||||
local num_args = 0
|
||||
for i, bit in ipairs(tree) do
|
||||
if type(bit) == "string" then
|
||||
local clump_words
|
||||
@ -69,6 +63,7 @@ tree_to_inline_nomsu = function(tree)
|
||||
end
|
||||
nomsu:add(bit)
|
||||
else
|
||||
num_args = num_args + 1
|
||||
local arg_nomsu = tree_to_inline_nomsu(bit)
|
||||
if bit.type == "Block" then
|
||||
if i > 1 and i < #tree then
|
||||
@ -81,17 +76,16 @@ tree_to_inline_nomsu = function(tree)
|
||||
if i > 1 then
|
||||
nomsu:add(" ")
|
||||
end
|
||||
if bit.type == "Action" then
|
||||
if bit.type == "Action" or bit.type == "MethodCall" then
|
||||
arg_nomsu:parenthesize()
|
||||
end
|
||||
end
|
||||
nomsu:add(arg_nomsu)
|
||||
end
|
||||
end
|
||||
if #tree == 1 and type(tree[1]) ~= "string" then
|
||||
nomsu:add("()")
|
||||
end
|
||||
return nomsu
|
||||
elseif "MethodCall" == _exp_0 then
|
||||
return NomsuCode:from(tree.source, tree_to_inline_nomsu(tree[1]), "|", tree_to_inline_nomsu(tree[2]))
|
||||
elseif "EscapedNomsu" == _exp_0 then
|
||||
local inner_nomsu = tree_to_inline_nomsu(tree[1])
|
||||
if not (tree[1].type == "List" or tree[1].type == "Dict" or tree[1].type == "Var") then
|
||||
@ -149,7 +143,7 @@ tree_to_inline_nomsu = function(tree)
|
||||
else
|
||||
nomsu = tree_to_inline_nomsu(key)
|
||||
end
|
||||
if key.type == "Action" or key.type == "Block" then
|
||||
if key.type == "Action" or key.type == "MethodCall" or key.type == "Block" then
|
||||
nomsu:parenthesize()
|
||||
end
|
||||
if value then
|
||||
@ -174,8 +168,13 @@ tree_to_inline_nomsu = function(tree)
|
||||
bit_nomsu = tree_to_inline_nomsu(bit)
|
||||
end
|
||||
assert(bit.type ~= "Block")
|
||||
if bit.type == "Action" or bit.type == "IndexChain" or (bit.type == "Number" and i < #tree) then
|
||||
local _exp_1 = bit.type
|
||||
if "Action" == _exp_1 or "MethodCall" == _exp_1 or "IndexChain" == _exp_1 then
|
||||
bit_nomsu:parenthesize()
|
||||
elseif "Number" == _exp_1 then
|
||||
if bit_nomsu:text():match("%.") then
|
||||
bit_nomsu:parenthesize()
|
||||
end
|
||||
end
|
||||
nomsu:add(bit_nomsu)
|
||||
end
|
||||
@ -191,7 +190,12 @@ tree_to_inline_nomsu = function(tree)
|
||||
end
|
||||
return NomsuCode:from(tree.source, s)
|
||||
elseif "Var" == _exp_0 then
|
||||
return NomsuCode:from(tree.source, "%", tree[1])
|
||||
local varname = tree[1]:gsub("_", " ")
|
||||
if varname == "" or is_identifier(varname) then
|
||||
return NomsuCode:from(tree.source, "$", varname)
|
||||
else
|
||||
return NomsuCode:from(tree.source, "$(", varname, ")")
|
||||
end
|
||||
elseif "FileChunks" == _exp_0 then
|
||||
return error("Can't inline a FileChunks")
|
||||
elseif "Comment" == _exp_0 then
|
||||
@ -222,14 +226,17 @@ tree_to_nomsu = function(tree)
|
||||
if try_inline then
|
||||
inline_nomsu = tree_to_inline_nomsu(t)
|
||||
if #inline_nomsu:text() <= space or #inline_nomsu:text() <= 8 then
|
||||
if t.type == "Action" then
|
||||
if t.type == "Action" or t.type == "MethodCall" then
|
||||
inline_nomsu:parenthesize()
|
||||
end
|
||||
return inline_nomsu
|
||||
end
|
||||
if t.type == "Text" and #inline_nomsu:text() + 2 < MAX_LINE then
|
||||
return inline_nomsu
|
||||
end
|
||||
end
|
||||
local indented = tree_to_nomsu(t)
|
||||
if t.type == "Action" then
|
||||
if t.type == "Action" or t.type == "MethodCall" then
|
||||
if indented:is_multiline() then
|
||||
return NomsuCode:from(t.source, "(..)\n ", indented)
|
||||
else
|
||||
@ -262,15 +269,8 @@ tree_to_nomsu = function(tree)
|
||||
return nomsu
|
||||
elseif "Action" == _exp_0 then
|
||||
local next_space = ""
|
||||
if tree.target then
|
||||
local target_nomsu = recurse(tree.target)
|
||||
if tree.target.type == "Block" and not target_nomsu:is_multiline() then
|
||||
target_nomsu:parenthesize()
|
||||
end
|
||||
nomsu:add(target_nomsu)
|
||||
nomsu:add(target_nomsu:is_multiline() and "\n..::" or "::")
|
||||
end
|
||||
local word_buffer = { }
|
||||
local num_args = 0
|
||||
for i, bit in ipairs(tree) do
|
||||
local _continue_0 = false
|
||||
repeat
|
||||
@ -295,6 +295,7 @@ tree_to_nomsu = function(tree)
|
||||
word_buffer = { }
|
||||
next_space = " "
|
||||
end
|
||||
num_args = num_args + 1
|
||||
local bit_nomsu = recurse(bit)
|
||||
if bit.type == "Block" and not bit_nomsu:is_multiline() then
|
||||
if #bit_nomsu:text() > nomsu:trailing_line_len() * GOLDEN_RATIO and #bit_nomsu:text() > 8 then
|
||||
@ -302,7 +303,7 @@ tree_to_nomsu = function(tree)
|
||||
end
|
||||
end
|
||||
if (next_space == " " and not bit_nomsu:is_multiline() and nomsu:trailing_line_len() + #bit_nomsu:text() > MAX_LINE and nomsu:trailing_line_len() > 8) then
|
||||
if bit.type == 'Action' then
|
||||
if bit.type == 'Action' or bit.type == "MethodCall" then
|
||||
bit_nomsu = NomsuCode:from(bit.source, "(..)\n ", tree_to_nomsu(bit))
|
||||
else
|
||||
next_space = " \\\n.."
|
||||
@ -331,12 +332,14 @@ tree_to_nomsu = function(tree)
|
||||
nomsu:add(next_space, words)
|
||||
next_space = " "
|
||||
end
|
||||
if #tree == 1 and type(tree[1]) ~= "string" then
|
||||
if next_space == " " then
|
||||
next_space = ""
|
||||
end
|
||||
nomsu:add(next_space, "()")
|
||||
return nomsu
|
||||
elseif "MethodCall" == _exp_0 then
|
||||
local target_nomsu = recurse(tree[1])
|
||||
if tree[1].type == "Block" and not target_nomsu:is_multiline() then
|
||||
target_nomsu:parenthesize()
|
||||
end
|
||||
nomsu:add(target_nomsu)
|
||||
nomsu:add(target_nomsu:is_multiline() and " \\\n..|" or "|")
|
||||
return nomsu
|
||||
elseif "EscapedNomsu" == _exp_0 then
|
||||
nomsu = recurse(tree[1])
|
||||
@ -413,7 +416,7 @@ tree_to_nomsu = function(tree)
|
||||
end
|
||||
end
|
||||
add_text(tree)
|
||||
return NomsuCode:from(tree.source, '"\\\n ..', nomsu, '"')
|
||||
return NomsuCode:from(tree.source, '"\n ', nomsu, '"')
|
||||
elseif "List" == _exp_0 or "Dict" == _exp_0 then
|
||||
if #tree == 0 then
|
||||
nomsu:add(tree.type == "List" and "[]" or "{}")
|
||||
|
@ -33,12 +33,7 @@ tree_to_inline_nomsu = (tree)->
|
||||
switch tree.type
|
||||
when "Action"
|
||||
nomsu = NomsuCode\from(tree.source)
|
||||
if tree.target
|
||||
inline_target = tree_to_inline_nomsu(tree.target)
|
||||
if tree.target.type == "Action"
|
||||
inline_target\parenthesize!
|
||||
nomsu\add inline_target, "::"
|
||||
|
||||
num_args = 0
|
||||
for i,bit in ipairs tree
|
||||
if type(bit) == "string"
|
||||
clump_words = if type(tree[i-1]) == 'string'
|
||||
@ -47,6 +42,7 @@ tree_to_inline_nomsu = (tree)->
|
||||
nomsu\add " " if i > 1 and not clump_words
|
||||
nomsu\add bit
|
||||
else
|
||||
num_args += 1
|
||||
arg_nomsu = tree_to_inline_nomsu(bit)
|
||||
if bit.type == "Block"
|
||||
if i > 1 and i < #tree
|
||||
@ -55,13 +51,14 @@ tree_to_inline_nomsu = (tree)->
|
||||
arg_nomsu\parenthesize!
|
||||
else
|
||||
nomsu\add " " if i > 1
|
||||
if bit.type == "Action"
|
||||
if bit.type == "Action" or bit.type == "MethodCall"
|
||||
arg_nomsu\parenthesize!
|
||||
nomsu\add arg_nomsu
|
||||
if #tree == 1 and type(tree[1]) != "string"
|
||||
nomsu\add "()"
|
||||
return nomsu
|
||||
|
||||
when "MethodCall"
|
||||
return NomsuCode\from(tree.source, tree_to_inline_nomsu(tree[1]), "|", tree_to_inline_nomsu(tree[2]))
|
||||
|
||||
when "EscapedNomsu"
|
||||
inner_nomsu = tree_to_inline_nomsu(tree[1])
|
||||
unless tree[1].type == "List" or tree[1].type == "Dict" or tree[1].type == "Var"
|
||||
@ -108,7 +105,7 @@ tree_to_inline_nomsu = (tree)->
|
||||
nomsu = if key.type == "Text" and #key == 1 and is_identifier(key[1])
|
||||
NomsuCode\from(key.source, key[1])
|
||||
else tree_to_inline_nomsu(key)
|
||||
nomsu\parenthesize! if key.type == "Action" or key.type == "Block"
|
||||
nomsu\parenthesize! if key.type == "Action" or key.type == "MethodCall" or key.type == "Block"
|
||||
if value
|
||||
nomsu\add ": "
|
||||
value_nomsu = tree_to_inline_nomsu(value)
|
||||
@ -125,8 +122,11 @@ tree_to_inline_nomsu = (tree)->
|
||||
bit[1]
|
||||
else tree_to_inline_nomsu(bit)
|
||||
assert bit.type != "Block"
|
||||
if bit.type == "Action" or bit.type == "IndexChain" or (bit.type == "Number" and i < #tree)
|
||||
bit_nomsu\parenthesize!
|
||||
switch bit.type
|
||||
when "Action", "MethodCall", "IndexChain"
|
||||
bit_nomsu\parenthesize!
|
||||
when "Number"
|
||||
bit_nomsu\parenthesize! if bit_nomsu\text!\match("%.")
|
||||
nomsu\add bit_nomsu
|
||||
return nomsu
|
||||
|
||||
@ -139,7 +139,12 @@ tree_to_inline_nomsu = (tree)->
|
||||
return NomsuCode\from(tree.source, s)
|
||||
|
||||
when "Var"
|
||||
return NomsuCode\from(tree.source, "%", tree[1])
|
||||
-- TODO: remove this hack:
|
||||
varname = tree[1]\gsub("_", " ")
|
||||
if varname == "" or is_identifier(varname)
|
||||
return NomsuCode\from(tree.source, "$", varname)
|
||||
else
|
||||
return NomsuCode\from(tree.source, "$(", varname, ")")
|
||||
|
||||
when "FileChunks"
|
||||
error("Can't inline a FileChunks")
|
||||
@ -170,11 +175,13 @@ tree_to_nomsu = (tree)->
|
||||
if try_inline
|
||||
inline_nomsu = tree_to_inline_nomsu(t)
|
||||
if #inline_nomsu\text! <= space or #inline_nomsu\text! <= 8
|
||||
if t.type == "Action"
|
||||
if t.type == "Action" or t.type == "MethodCall"
|
||||
inline_nomsu\parenthesize!
|
||||
return inline_nomsu
|
||||
if t.type == "Text" and #inline_nomsu\text! + 2 < MAX_LINE
|
||||
return inline_nomsu
|
||||
indented = tree_to_nomsu(t)
|
||||
if t.type == "Action"
|
||||
if t.type == "Action" or t.type == "MethodCall"
|
||||
if indented\is_multiline!
|
||||
return NomsuCode\from(t.source, "(..)\n ", indented)
|
||||
else indented\parenthesize!
|
||||
@ -199,14 +206,8 @@ tree_to_nomsu = (tree)->
|
||||
|
||||
when "Action"
|
||||
next_space = ""
|
||||
if tree.target
|
||||
target_nomsu = recurse(tree.target)
|
||||
if tree.target.type == "Block" and not target_nomsu\is_multiline!
|
||||
target_nomsu\parenthesize!
|
||||
nomsu\add target_nomsu
|
||||
nomsu\add(target_nomsu\is_multiline! and "\n..::" or "::")
|
||||
|
||||
word_buffer = {}
|
||||
num_args = 0
|
||||
for i,bit in ipairs tree
|
||||
if type(bit) == "string"
|
||||
if #word_buffer > 0 and is_operator(bit) == is_operator(word_buffer[#word_buffer])
|
||||
@ -225,6 +226,7 @@ tree_to_nomsu = (tree)->
|
||||
word_buffer = {}
|
||||
next_space = " "
|
||||
|
||||
num_args += 1
|
||||
bit_nomsu = recurse(bit)
|
||||
if bit.type == "Block" and not bit_nomsu\is_multiline!
|
||||
-- Rule of thumb: nontrivial one-liner block arguments should be no more
|
||||
@ -235,7 +237,7 @@ tree_to_nomsu = (tree)->
|
||||
if (next_space == " " and not bit_nomsu\is_multiline! and
|
||||
nomsu\trailing_line_len! + #bit_nomsu\text! > MAX_LINE and
|
||||
nomsu\trailing_line_len! > 8)
|
||||
if bit.type == 'Action'
|
||||
if bit.type == 'Action' or bit.type == "MethodCall"
|
||||
bit_nomsu = NomsuCode\from bit.source, "(..)\n ", tree_to_nomsu(bit)
|
||||
else
|
||||
next_space = " \\\n.."
|
||||
@ -255,10 +257,14 @@ tree_to_nomsu = (tree)->
|
||||
nomsu\add next_space, words
|
||||
next_space = " "
|
||||
|
||||
if #tree == 1 and type(tree[1]) != "string"
|
||||
if next_space == " " then next_space = ""
|
||||
nomsu\add next_space, "()"
|
||||
return nomsu
|
||||
|
||||
when "MethodCall"
|
||||
target_nomsu = recurse(tree[1])
|
||||
if tree[1].type == "Block" and not target_nomsu\is_multiline!
|
||||
target_nomsu\parenthesize!
|
||||
nomsu\add target_nomsu
|
||||
nomsu\add(target_nomsu\is_multiline! and " \\\n..|" or "|")
|
||||
return nomsu
|
||||
|
||||
when "EscapedNomsu"
|
||||
@ -321,7 +327,7 @@ tree_to_nomsu = (tree)->
|
||||
if interp_nomsu\is_multiline!
|
||||
nomsu\add "\n.."
|
||||
add_text(tree)
|
||||
return NomsuCode\from(tree.source, '"\\\n ..', nomsu, '"')
|
||||
return NomsuCode\from(tree.source, '"\n ', nomsu, '"')
|
||||
|
||||
when "List", "Dict"
|
||||
if #tree == 0
|
||||
|
@ -59,9 +59,6 @@ do
|
||||
return false
|
||||
end
|
||||
end
|
||||
if self.target ~= other.target then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end,
|
||||
as_lua = function(self)
|
||||
@ -146,19 +143,31 @@ do
|
||||
return replacement
|
||||
end,
|
||||
get_args = function(self)
|
||||
assert(self.type == "Action", "Only actions have arguments")
|
||||
local args = {
|
||||
self.target
|
||||
}
|
||||
for _index_0 = 1, #self do
|
||||
local tok = self[_index_0]
|
||||
if type(tok) ~= 'string' then
|
||||
args[#args + 1] = tok
|
||||
assert(self.type == "Action" or self.type == "MethodCall", "Only actions and method calls have arguments")
|
||||
local args = { }
|
||||
if self.type == "MethodCall" then
|
||||
args[1] = self[1]
|
||||
local _list_0 = self[2]
|
||||
for _index_0 = 1, #_list_0 do
|
||||
local tok = _list_0[_index_0]
|
||||
if type(tok) ~= 'string' then
|
||||
args[#args + 1] = tok
|
||||
end
|
||||
end
|
||||
else
|
||||
for _index_0 = 1, #self do
|
||||
local tok = self[_index_0]
|
||||
if type(tok) ~= 'string' then
|
||||
args[#args + 1] = tok
|
||||
end
|
||||
end
|
||||
end
|
||||
return args
|
||||
end,
|
||||
get_stub = function(self)
|
||||
if self.type == "MethodCall" then
|
||||
return self[2]:get_stub()
|
||||
end
|
||||
local stub_bits = { }
|
||||
local arg_i = 1
|
||||
for _index_0 = 1, #self do
|
||||
@ -213,6 +222,8 @@ getmetatable(SyntaxTree).__call = function(self, t)
|
||||
setmetatable(t, self.__base)
|
||||
if t.type == 'Action' then
|
||||
t.stub = t:get_stub()
|
||||
elseif t.type == 'MethodCall' then
|
||||
t.stub = t[2]:get_stub()
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
@ -29,7 +29,6 @@ class SyntaxTree
|
||||
return false if type(@) != type(other) or #@ != #other or getmetatable(@) != getmetatable(other)
|
||||
for i=1,#@
|
||||
return false if @[i] != other[i]
|
||||
return false if @target != other.target
|
||||
return true
|
||||
|
||||
as_lua: =>
|
||||
@ -74,13 +73,20 @@ class SyntaxTree
|
||||
return replacement
|
||||
|
||||
get_args: =>
|
||||
assert(@type == "Action", "Only actions have arguments")
|
||||
args = {@target}
|
||||
for tok in *@
|
||||
if type(tok) != 'string' then args[#args+1] = tok
|
||||
assert(@type == "Action" or @type == "MethodCall", "Only actions and method calls have arguments")
|
||||
args = {}
|
||||
if @type == "MethodCall"
|
||||
args[1] = @[1]
|
||||
for tok in *@[2]
|
||||
if type(tok) != 'string' then args[#args+1] = tok
|
||||
else
|
||||
for tok in *@
|
||||
if type(tok) != 'string' then args[#args+1] = tok
|
||||
return args
|
||||
|
||||
get_stub: =>
|
||||
if @type == "MethodCall"
|
||||
return @[2]\get_stub!
|
||||
stub_bits = {}
|
||||
arg_i = 1
|
||||
for a in *@
|
||||
@ -103,6 +109,8 @@ getmetatable(SyntaxTree).__call = (t)=>
|
||||
setmetatable(t, @__base)
|
||||
if t.type == 'Action'
|
||||
t.stub = t\get_stub!
|
||||
elseif t.type == 'MethodCall'
|
||||
t.stub = t[2]\get_stub!
|
||||
return t
|
||||
|
||||
return SyntaxTree
|
||||
|
@ -11,14 +11,15 @@ externally (print tree %t at indent %indent) means:
|
||||
if %t.type is:
|
||||
"Action":
|
||||
say "\(%indent)Action (\(%t.stub)):"
|
||||
if %t.target:
|
||||
say "\%indent Target:"
|
||||
print tree %t.target at indent "\%indent "
|
||||
|
||||
for %arg in %t:
|
||||
if (%arg is syntax tree):
|
||||
print tree %arg at indent "\%indent "
|
||||
|
||||
"MethodCall":
|
||||
say "\(%indent)MethodCall on:"
|
||||
print tree %t.1 at indent "\%indent "
|
||||
print tree %t.2 at indent "\%indent "
|
||||
|
||||
"Number":
|
||||
say "\%indent\(%t.1)"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user