aboutsummaryrefslogtreecommitdiff
path: root/nomnom/decompile.nom
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2018-09-21 00:30:28 -0700
committerBruce Hill <bruce@bruce-hill.com>2018-09-21 00:30:44 -0700
commitf2048235f5cc7ff02db39a0e2fe5c79c7f390e0b (patch)
tree738faa0d4692e53d0fe2deb61399b6d7a9eedc9f /nomnom/decompile.nom
parent79d4bd5125de7ff220fbf8a8a5493d437ed16963 (diff)
Incremental checkin, currently not working, just saving progress.
Diffstat (limited to 'nomnom/decompile.nom')
-rw-r--r--nomnom/decompile.nom339
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)"