diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2018-09-21 00:30:28 -0700 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2018-09-21 00:30:44 -0700 |
| commit | f2048235f5cc7ff02db39a0e2fe5c79c7f390e0b (patch) | |
| tree | 738faa0d4692e53d0fe2deb61399b6d7a9eedc9f /nomnom/decompile.nom | |
| parent | 79d4bd5125de7ff220fbf8a8a5493d437ed16963 (diff) | |
Incremental checkin, currently not working, just saving progress.
Diffstat (limited to 'nomnom/decompile.nom')
| -rw-r--r-- | nomnom/decompile.nom | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/nomnom/decompile.nom b/nomnom/decompile.nom new file mode 100644 index 0000000..27ef406 --- /dev/null +++ b/nomnom/decompile.nom @@ -0,0 +1,339 @@ +# This file contains the code to convert syntax trees to Nomsu code +use "nomnom/code_obj.nom" +use "nomnom/parser.nom" + +# TODO: maybe re-implement the fancy coroutine checker that aborts early if nomsu gets too long +action [decompile %tree inline]: + assume (%tree is a "Syntax Tree") + if %tree.type is: + "Action": + %nomsu = (Nomsu Code from %tree) + if %tree.target: + %target_nomsu = (decompile %tree.target inline) + if %tree.target.type is: + ("Action", "Block"): + %target_nomsu::parenthesize + %nomsu::add [%target_nomsu, "::"] + + for %bit in %tree at %i: + if (%bit is text): + unless (..) + any of [..] + %i == 1, + %tree.(%i - 1) isn't text, + (%bit::is a nomsu operator) == (%tree.(%i - 1)::is a nomsu operator) + ..: %nomsu::add " " + %nomsu::add %bit + ..else: + %arg_nomsu = (decompile %bit inline) + unless ((%i == (size of %tree)) and (%bit.type == "Block")): + %nomsu::add " " + if ((%bit.type == "Action") or (%bit.type == "Block")): + %arg_nomsu::parenthesize + %nomsu::add %arg_nomsu + return %nomsu + + "EscapedNomsu": + %inner_nomsu = (decompile %tree.1 inline) + unless (..) + any of [..] + %tree.1.type == "List", %tree.1.type == "Dict", + %tree.1.type == "Var" + ..: %inner_nomsu::parenthesize + %nomsu = (Nomsu Code from %tree ["\\", %inner_nomsu]) + return %nomsu + + "Block": + %nomsu = (Nomsu Code from %tree [":"]) + for i,line in ipairs tree + %nomsu::add(i == 1 and " " or "; ") + %nomsu::add recurse(line, nomsu, i == 1 or i < #tree) + return %nomsu + + "Text": + %nomsu = (Nomsu Code from %tree ["\""]) + for %text in recursive %tree: + for %bit in %text at %i: + if: + (%bit is text): + %nomsu::add %bit + if %bit.type is: + "Text": + recurse %text on %bit + "Var": + %interp_nomsu = (decompile %bit inline) + # Make sure "...\(%x)y..." isn't confused with "...\(%xy)..." + # TODO: make this more robust against "...\%x\("y").." + if (..) + (%tree.(%i + 1) is text) and (..) + not (%tree.(%i + 1)::matches "^[ \n\t,.:;#(){}%[%]]") + ..: %interp_nomsu::parenthesize + %nomsu::add ["\\", %interp_nomsu] + ("List", "Dict"): + %nomsu::add ["\\", decompile %bit inline] + else: + %nomsu::add ["\\(", decompile %bit inline, ")"] + return (Nomsu Code from %tree ["\"", %nomsu, "\""]) + + ("List", "Dict"): + %nomsu = (Nomsu Code from %tree ["[" if (%tree.type == "List") else "{"]) + for %item in %tree at %i: + if (%i > 1): %nomsu::add ", " + %nomsu::add (decompile %item inline) + %nomsu::add ("]" if (%tree.type == "List") else "}") + return %nomsu + + "DictEntry": + set {%key:%tree.1, %value:%tree.2} + if (all of [%key.type == "Text", (size of %key) == 1, %key.1::is a nomsu identifier]): + %nomsu = (Nomsu Code from %key [key.1]) + ..else: + %nomsu = (decompile %key inline) + + if (%key.type == "Action"): + %nomsu::parenthesize + %nomsu::add ":" + if %value: + %nomsu::add (decompile %value inline) + return %nomsu + + "IndexChain": + %nomsu = (Nomsu Code from %tree) + for %bit in %tree at %i: + if (%i > 1): nomsu::add "." + if (..) + all of [..] + %i > 1, %bit.type == "Text", (size of %bit) == 1, %bit.1 is text, + %bit.1::is a nomsu identifier + %nomsu::add %bit.1 + ..else: + %bit_nomsu = (decompile %bit inline) + if (..) + any of [..] + %bit.type == "Action" + %bit.type == "Block" + %bit.type == "IndexChain" + (%bit.type == "Number") and (%i < (size of %tree)) + ..: %bit_nomsu::parenthesize + %nomsu::add %bit_nomsu + return %nomsu + + "Number": + return (Nomsu Code from %tree [(%tree.1 as hex) if %tree.hex else "\(%tree.1)"]) + + "Var": + return (Nomsu Code from %tree ["%\(%tree.1)"]) + + "Comment": + return (nil) + + "FileChunks": + barf "Can't inline a FileChunks" + + "Error": + barf "Can't compile errors" + + else: + barf "Unknown type: \(%tree.type)" + +%MAX_LINE = 90 +action [decompile %tree]: + %nomsu = (Nomsu Code from %tree) + # For concision: + local action [recurse on %t]: + %space = (%MAX_LINE - (%nomsu::trailing line length)) + if (%space <= 0): go to (Indented) + for %subtree in recursive %tree: + if %subtree.type is: + "Block": + if ((size of %subtree) > 1): + go to (Use Indented) + if ((size of "\(decompile %subtree inline)") > 20): + go to (Use Indented) + for %k = %v in %subtree: + if (%v is a "Syntax Tree"): + recurse %subtree on %v + + %inline_nomsu = (decompile %t inline) + if (%inline_nomsu and ((size of "\%inline_nomsu") <= %space)): + return %inline_nomsu + + === (Use Indented) === + %indented = (decompile %t) + if (%t.type == "Action"): + %indented = (Nomsu Code from %t ["(..)\n ", %indented]) + return %indented + + if %tree.type is: + "FileChunks": + local action [%1 and %2 should clump]: + if ((%1.type == "Action") and (%2.type == "Action")): + if (%1.stub == "use 1"): return (%2.stub == "use 1") + if (%1.stub == "test 1"): return (yes) + if (%2.stub == "test 1"): return (no) + return (not ((recurse on %1)::is multi-line)) + for %chunk in %tree at %chunk_no: + if (%chunk_no > 1): + %nomsu::add "\n\n\("~"::* 80)\n\n" + %nomsu::add (pop comments at %chunk.source.start) + if (%chunk.type == "Block"): + for %line in %chunk at %line_no: + if (%line_no > 1): + if (%chunk.(%line_no - 1) and %line should clump): + %nomsu::add ["\n", pop comments at %line.source.start "\n"] + ..else: + %nomsu::add ["\n\n", pop comments at %line.source.start] + %nomsu::add (decompile %line %pop_comments) + %nomsu::add (pop comments at %chunk.source.stop "\n") + ..else: + %nomsu::add (decompile %chunk %pop_comments) + %nomsu::add (pop comments at %tree.source.stop "\n") + unless ("\%nomsu"::matches "\n$"): + %nomsu::add "\n" + return %nomsu + + "Action": + %pos = %tree.source.start + %next_space = "" + if %tree.target: + %target_nomsu = (recurse on %tree.target) + if ((%tree.target.type == "Action") and (%target_nomsu::is one line)): + %target_nomsu::parenthesize + %nomsu::add %target_nomsu + %pos = %tree.target.source.stop + %next_space = ("\n..::" if (%target_nomsu::is multi-line) else "::") + + for %bit in %tree at %i: + if ((%next_space == " ") and ((%nomsu::trailing line length) > %MAX_LINE)): + %next_space = " \\\n" + + %nomsu::add %next_space + + if (%bit is text): + unless (..) + all of [..] + %tree.(%i - 1) is text + (%tree.(%i - 1)::is a nomsu operator) != (%bit::is a nomsu operator) + ..: %nomsu::add %next_space + %nomsu::add %bit + %next_space = " " + do next %bit + + %bit_nomsu = (recurse on %bit) + if (%bit.type == "Comment"): + %next_space = "\n" + ..else: + %next_space = (" " if (%bit_nomsu::is one line) else "\n..") + if (%bit.type == "Action"): + %bit_nomsu::parenthesize + + return %nomsu + + "EscapedNomsu": + %nomsu::add "\\" + %val_nomsu = (recurse on %tree.1) + if ((%tree.(1).type == "Action") and (%val_nomsu::is one line)): + %val_nomsu::parenthesize + %nomsu::add %val_nomsu + return %nomsu + + "Block": + for %line in %tree at %i: + if ((%i > 1) and (%line.type == "Comment")): + %nomsu::add "\n" + %line_nomsu = (recurse on %line) + %nomsu::add + if (%i < (size of %tree)): + if ((%line_nomsu::number of lines) > 2): + %nomsu::add "\n\n" + ..else: + %nomsu::add "\n" + return (Nomsu Code from %tree [":\n ", %nomsu]) + + "Text": + # Multi-line text has more generous wrap margins + %max_line = ((1.5 * %MAX_LINE) rounded down) + %nomsu = (Nomsu Code from %tree) + local action [add text from %tree]: + for %bit in %tree at %i: + if (%bit is text): + # TODO: escape properly? + %bit = (escape text %bit) + for %line in (%bit::lines) at %j: + if: + (%j > 1): nomsu::add "\n" + (((size of %line) > 10) and ((%nomsu::trailing line length) > %max_line)): + %nomsu::add "\\\n.." + + while ((size of %line) > 0): + %space = (%max_line - (%nomsu::trailing line length)) + %split = (%line::position of "[%p%s]" after %space) + if ((not %split) or (%split > %space + 10)): + %split = (%space + 10) + if ((%line - %split) < 10): + %split = (size of %line) + set {%bite:%line.[1, %split], %line:%line.[%split + 1, -1]} + %nomsu::add %bite + if ((size of %line) > 0): + %nomsu::add "\\\n.." + if (%bit.type == "Text"): + add text from %bit + ..else: + %nomsu::add "\\" + %interp_nomsu = (recurse on %bit) + unless (%interp_nomsu::is multi-line): + if %bit.type is: + "Var": + if ((%tree.(%i+1) is text) and (not (%tree.(%i+1)::matches "^[ \n\t,.:#(){}[%]]"))): + %interp_nomsu::parenthesize + ("List", "Dict"): + %interp_nomsu::parenthesize + %nomsu::add %interp_nomsu + if (%interp_nomsu::is multi-line): + %nomsu::add "\n.." + add text from %tree + return (Nomsu Code from %tree ["\"\\\n ..", %nomsu, "\""]) + + ("List", "Dict"): + if ((size of %tree) == 0): + %nomsu::add ("[]" if (%tree.type == "List") else "{}") + return %nomsu + for %item in %tree at %i: + %item_nomsu = (decompile %item inline) + if ((not %item_nomsu) or ((size of "\%item_nomsu") > %MAX_LINE)): + %item_nomsu = (recurse on %item_nomsu) + %nomsu::add %item_nomsu + if (%i < (size of %tree)): + if (..) + (%item_nomsu::is multi-line) or (..) + (%nomsu::trailing line length) + (size of "\%item_nomsu")) >= %MAX_LINE + ..: %nomsu::add "\n" + ..else: %nomsu::add ", " + return (..) + Nomsu Code from %tree [..] + "[..]\n " if tree.type == "List" else "{..}\n " + %nomsu + + "DictEntry": + set {%key:%tree.1, %value:%tree.2} + if (all of [%key.type == "Text", (size of %key) == 1, %key.1::is a nomsu identifier]): + %nomsu::add %key.1 + ..else: + %nomsu::add (decompile %key inline) + if ((%key.type == "Action") or (%key.type == "Block")): + %nomsu::parenthesize + %nomsu::add [": ", recurse on %value] + return %nomsu + + "Comment": + %nomsu::add ["#", %tree.1::with "\n" -> "\n "] + return %nomsu + + ("IndexChain", "Number", "Var"): + return (decompile %tree inline) + + "Error": + barf "Cannot decompile an error" + + else: + barf "Unknown type: \(%tree.type)" |
