aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2018-11-11 15:05:18 -0800
committerBruce Hill <bruce@bruce-hill.com>2018-11-11 15:05:56 -0800
commit9a75d25c843b03e3671b71384fd48deb0607db43 (patch)
tree8baf212544a15fde2150fe790b4414d608a55663
parent65ec3f597f0f39e01fa44a14ea4971c797a015c2 (diff)
Lots of fixes to the upgrading and codegen/autoformatting pipeline, also
deleted nomnom files, since they're mostly not needed anymore.
-rw-r--r--compatibility/2.4.nom16
-rw-r--r--compatibility/2.nom6
-rw-r--r--compatibility/4.10.12.7.nom49
-rw-r--r--compatibility/4.9.nom60
-rw-r--r--nomnom/ast.nom90
-rw-r--r--nomnom/code_obj.nom212
-rw-r--r--nomnom/compile.nom278
-rw-r--r--nomnom/decompile.nom348
-rw-r--r--nomnom/files.nom110
-rw-r--r--nomnom/parser.nom91
-rw-r--r--nomnom/pretty_errors.nom85
-rw-r--r--nomnom/source.nom56
-rw-r--r--nomsu.4.peg4
-rw-r--r--nomsu_decompiler.lua38
-rw-r--r--nomsu_decompiler.moon42
-rw-r--r--nomsu_environment.lua3
-rw-r--r--nomsu_environment.moon2
17 files changed, 123 insertions, 1367 deletions
diff --git a/compatibility/2.4.nom b/compatibility/2.4.nom
index 1f87a98..2b39dd5 100644
--- a/compatibility/2.4.nom
+++ b/compatibility/2.4.nom
@@ -9,7 +9,9 @@ use "compatibility/compatibility.nom"
upgrade %tree to "2.4" as:
unless (%tree is "Action" syntax tree): return
if %tree.stub is:
- "when":
+ "when" "if":
+ if ((size of %tree) == 3):
+ return %tree
%conditions = []
%new_lines = []
%body = (..)
@@ -29,15 +31,15 @@ upgrade %tree to "2.4" as:
%conditions::add %line.2
%action = %line.3
unless (%action is "Block" syntax tree):
- %action = (=lua "Block(\%action.source, \%action)")
+ %action = (=lua "SyntaxTree{type='Block', source=\%action.source, \%action}")
%conditions::add %action
- %new_lines::add (=lua "Action(\%conditions[1].source, unpack(\%conditions))")
+ %new_lines::add (=lua "SyntaxTree{type='Action', source=\%conditions[1].source, unpack(\%conditions)}")
%conditions = []
return (..)
- \(when %body) with vars {body:=lua "Block(\%tree[2].source, unpack(\%new_lines))"}
+ \(when %body) with vars {body:=lua "SyntaxTree{type='Block', source=\%tree[2].source, unpack(\%new_lines)}"}
- "when 1 is ?" "when 1 = ?":
+ "if 1 is ?" "if 1 = ?":
%values = []
%new_lines = []
%body = (..)
@@ -59,9 +61,9 @@ upgrade %tree to "2.4" as:
unless (%action is "Block" syntax tree):
%action = \(: %action)
%values::add %action
- %new_lines::add (=lua "Action(\%values[1].source, unpack(\%values))")
+ %new_lines::add (=lua "SyntaxTree{type='Action', source=\%values[1].source, unpack(\%values)}")
%values = []
return (..)
\(if %var is %body) with vars {..}
- var:%tree.2 upgraded, body:=lua "Block(\%tree[5].source, unpack(\%new_lines))"
+ var:%tree.2 upgraded, body:=lua "SyntaxTree{type='Block', source=\%tree[5].source, unpack(\%new_lines)}"
diff --git a/compatibility/2.nom b/compatibility/2.nom
index 5c78e29..84331a6 100644
--- a/compatibility/2.nom
+++ b/compatibility/2.nom
@@ -23,13 +23,13 @@ upgrade %tree to "2" as:
"if", "unless", "for 1 in", "for 1 = 2 in", "repeat while 1"
"repeat 1 times", "repeat", "repeat until 1", "for 1 in 2 to 3 by"
"for 1 in 2 to 3 via", "for 1 in 2 to", "for 1 2 in"
- "do", "for 1 in recursive", "test", "with", "result of"
+ "do", "for 1 in recursive", "test", "with", "result of", "when"
for %n in %need_blocks:
if (%tree.stub is %n):
%bits = (((% upgraded) if (% is syntax tree) else %) for % in %tree)
unless ((%bits::last) is "Block" syntax tree):
%body = (%bits::last)
- %bits.(size of %bits) = (=lua "Block(\%body.source, \%body)")
+ %bits.(size of %bits) = (=lua "SyntaxTree{type='Block', source=\%body.source, \%body}")
- return (=lua "Action(\%tree.source, unpack(\%bits))")
+ return (=lua "SyntaxTree{type='Action', source=\%tree.source, unpack(\%bits)}")
diff --git a/compatibility/4.10.12.7.nom b/compatibility/4.10.12.7.nom
new file mode 100644
index 0000000..c314b68
--- /dev/null
+++ b/compatibility/4.10.12.7.nom
@@ -0,0 +1,49 @@
+#!/usr/bin/env nomsu -V4.10.12.7
+#
+ This file defines upgrades from Nomsu <4.10.12.7 to 4.10.12.7
+use "compatibility/compatibility.nom"
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+upgrade action (% as lua statements) to "4.10.12.7" as (% as lua)
+upgrade action (% as lua return) to "4.10.12.7" as (..)
+ =lua "\%.type == 'Block' and \(% as lua) or 'return '..\(% as lua expr)"
+upgrade action (Lua value %) to "4.10.12.7" as (Lua %)
+
+upgrade action (%e for % in %items) to "4.10.12.7" as [:for % in %items: add %e]
+upgrade action (%e for %k = %v in %items) to "4.10.12.7" as [:for %k = %v in %items: add %e]
+upgrade action (%e for %i in %start to %stop) to "4.10.12.7" as [:for %i in %start to %stop: add %e]
+upgrade action (%e for %i in %start to %stop by %step) to "4.10.12.7" as (..)
+ [:for %i in %start to %stop by %step: add %e]
+upgrade action (%e for %i in %start to %stop via %step) to "4.10.12.7" as (..)
+ [:for %i in %start to %stop by %step: add %e]
+
+upgrade action (%k = %v for % in %items) to "4.10.12.7" as {:for % in %items: add %k = %v}
+upgrade action (%k = %v for %k0 = %v0 in %items) to "4.10.12.7" as {:for %k0 = %v0 in %items: add %k = %v}
+upgrade action (%k = %v for %i in %start to %stop) to "4.10.12.7" as {:for %i in %start to %stop: add %k = %v}
+upgrade action (%k = %v for %i in %start to %stop by %step) to "4.10.12.7" as (..)
+ {:for %i in %start to %stop by %step: add %k = %v}
+upgrade action (%k = %v for %i in %start to %stop via %step) to "4.10.12.7" as (..)
+ {:for %i in %start to %stop by %step: add %k = %v}
+
+upgrade action (% as lua statements) to "4.10.12.7" as (% as lua)
+
+upgrade %tree to "4.10.12.7" as:
+ if (%tree.type == "FileChunks"):
+ %first_chunk = %tree.1
+ %first_has_use = (no)
+ %i = 1
+ repeat while (%i < (size of %first_chunk)):
+ if %first_has_use:
+ if ((%first_chunk.%i.type != "Action") or (%first_chunk.%i.stub != "use")):
+ %chunk2 = (%SyntaxTree {type:"Block"})
+ for %j in %i to (size of %first_chunk.%i):
+ %chunk2.((size of %chunk2) + 1) = %first_chunk.%i.%j
+ for %j in %i to (size of %first_chunk.%i):
+ %first_chunk.%i.%j = (nil)
+ %table.insert %tree 2 %chunk2
+ return %tree
+ ..else:
+ if ((%first_chunk.type == "Action") and (%first_chunk.stub == "use")):
+ %first_has_use = (yes)
+ %i += 1
diff --git a/compatibility/4.9.nom b/compatibility/4.9.nom
index 7eb54d4..76df07b 100644
--- a/compatibility/4.9.nom
+++ b/compatibility/4.9.nom
@@ -3,61 +3,9 @@
This file defines upgrades from Nomsu <4.9 to 4.9
use "compatibility/compatibility.nom"
-upgrade action "local action" to "4.9" via (..)
- [%tree, %end_version] ->:
- %spec = %tree.3
- %body = %tree.4
- if %spec.type is:
- "List":
- if ((size of %spec) == 1):
- return \(%spec.1 means %body)
- ..else:
- return \(%spec all mean %body)
- else:
- return \(%spec means %body)
-
-upgrade action "action" to "4.9" via (..)
- [%tree, %end_version] ->:
- %spec = %tree.2
- %body = %tree.3
- if %body:
- if %spec.type is:
- "List":
- if ((size of %spec) == 1):
- return \(externally %spec.1 means %body)
- ..else:
- return \(externally %spec all mean %body)
- else:
- return \(externally %spec means %body)
- ..else:
- return \(%spec's meaning)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-upgrade action "compile 1 to" to "4.9" via (..)
+upgrade action "if" to "4.9" via (..)
[%tree, %end_version] ->:
- %spec = %tree.2
- %body = %tree.4
- if %spec.type is:
- "List":
- if ((size of %spec) == 1):
- return \(%spec.1 compiles to %body)
- ..else:
- return \(%spec all compile to %body)
- else:
- return \(%spec compiles to %body)
-
-upgrade action "parse 1 as" to "4.9" via (..)
- [%tree, %end_version] ->:
- %spec = %tree.2
- %body = %tree.4
- if %spec.type is:
- "List":
- if ((size of %spec) == 1):
- return \(%spec.1 parses as %body)
- ..else:
- return \(%spec all parse as %body)
- else:
- return \(%spec parse as %body)
-
-upgrade action (compile as %) to "4.9" as (what % compiles to)
-upgrade action (remove action %) to "4.9" as ((%'s meaning) = (nil))
-upgrade action (if %) to "4.9" as (when %)
+ if ((size of %tree) > 2): return %tree
+ return \(when %tree.2)
diff --git a/nomnom/ast.nom b/nomnom/ast.nom
deleted file mode 100644
index 935b0c5..0000000
--- a/nomnom/ast.nom
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/usr/bin/env nomsu -V4.8.10
-use "lib/object.nom"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-# The types are [..]
- "Number", "Var", "Block", "EscapedNomsu", "Text", "List", "Dict", "DictEntry",
- "IndexChain", "Action", "FileChunks", "Error", "Comment"
-object (Syntax Tree):
- my action [set up]:
- if (%me.type == "Action"):
- %stub_bits = []
- %argnum = 1
- for %bit in %me:
- if:
- (%bit is text):
- %stub_bits::add %bit
- (%bit.type != "Comment"):
- %stub_bits::add "\%argnum"
- %argnum += 1
-
- %me.stub = (%stub_bits::joined with " ")
- if (%me.stub == "Lua Code 1 2"):
- lua> "require('ldt').breakpoint()"
-
- (Syntax Tree).source_code_for_tree = (..)
- {} with fallback % -> (read file %.source.filename)
- my action [children]:
- %children = []
- for % in %me:
- if ((% is a "Syntax Tree") and (%.type != "Comment")): %children::add %
- if ((%me.type == "Action") and %me.target):
- %children::add %me.target
- return %children
-
- my action [as lua] "\
- ..a_Syntax_Tree_with(\(call ({} 's metatable).as_lua with [%me]))"
- my action [as nomsu] "\
- ..(a Syntax Tree with \(call ({} 's metatable).as_nomsu with [%me]))"
- my action [as text] "\
- ..(Syntax Tree \(call ({} 's metatable).__tostring with [%me]))"
- my action [get source code] (Syntax Tree).source_code_for_tree.%me
- my action [map %fn]:
- %replacement = (call %fn with [%me])
- if %replacement:
- if (%replacement is a "Syntax Tree"):
- %replacement = (%k = %v for %k = %v in %replacement)
- %replacement.source = %me.source
- return (Syntax Tree %replacement)
- return %replacement
- ..else:
- %replacement = {}
- %changes = (no)
- for %k = %v in %me:
- %replacement.%k = %v
- if (%v is a "Syntax Tree"):
- %r = (%v::map %fn)
- if ((%r == %v) or (%r == (nil))): do next %k
- %changes = (yes)
- %replacement.%k = %r
-
- unless %changes: return %me
- return (Syntax Tree %replacement)
-
- my action [with %overrides]:
- %new = (%k = %v for %k = %v in %me)
- for %k = %v in %overrides: %new.%k = %v
- return (Syntax Tree %new)
-
- my action [== %other]:
- unless (..)
- all of [..]
- (type of %me) == (type of %other), (%me 's metatable) == (%other 's metatable)
- (size of %me) == (size of %other), %me.type == %other.type
- ..: return (no)
-
- for %item in %me at %i:
- if (%other.%i != %item): return (no)
- if (%me.type == "Action"):
- if (%me.target != %other.target): return (no)
- return (yes)
-
- my action [get args]:
- assume (%me.type == "Action") or barf "\
- ..Only actions have arguments, not \(%me.type)"
- %args = []
- for % in %me:
- unless ((% is text) or (%.type == "Comment")): %args::add %
- return %args
-
diff --git a/nomnom/code_obj.nom b/nomnom/code_obj.nom
deleted file mode 100644
index 2c78ace..0000000
--- a/nomnom/code_obj.nom
+++ /dev/null
@@ -1,212 +0,0 @@
-#!/usr/bin/env nomsu -V4.8.10
-# This file contains objects that are used to track code positions and incrementally
- build up generated code, while keeping track of where it came from, and managing
- indentation levels.
-use "lib/things.nom"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-a (Code Buffer) is a thing:
- that can (set up) by:
- assume %its.source
- %old_bits = (%its.bits if (%its.bits is a "List") else [%its.bits])
- %its.bits = []
- if (type of %its.source) is:
- "Text":
- %its.source = (Source from text %its.source)
- "Syntax Tree":
- %its.source = %its.source.source
-
- for % in %old_bits: %its::add %
-
- whose (text) means:
- if (%its._text == (nil)):
- %buff = []
- %indent = 0
- for %bit in %its.bits:
- if (%bit is text):
- %spaces = (%bit::matching "\n([ ]*)[^\n]*$")
- if %spaces: %indent = (size of %spaces.1)
- ..else:
- %bit = (%bit::text)
- if (%indent > 0):
- %bit = (%bit::with "\n" -> "\n\(" "::* %indent)")
- %buff::add %bit
- %its._text = (%buff::joined)
- return %its._text
-
- whose (lua code) means "\
- ..a_\(%its.class.name::as lua id)_with{source=\(..)
- (%its.source::as lua) if %its.source else "nil"
- .., \(%its.bits::as lua)}"
-
- whose (nomsu code) means "\
- ..(a \(%its.class.name) with {source: \((%its.source::as nomsu) if %its.source else "(nil)"), bits: \(..)
- %its.bits::as nomsu
- ..})"
-
- whose (size) means (size of (%its::text))
-
- that can (mark as dirty) by:
- %its._text = (nil)
- %its._trailing_line_len = (nil)
- %its._num_lines = (nil)
-
- that can (add %new_bits) by:
- unless (%new_bits is a "List"):
- %new_bits = [%new_bits]
- for % in %new_bits:
- if (% == ""): do next %
- #if ((% isn't text) and (% isn't a (Code))):
- % = (%::as lua)
- %its.bits::add %
- %its::mark as dirty
-
- whose (trailing line length) means:
- if (%its._trailing_line_len == (nil)):
- %its._trailing_line_len = (size of ((%its::text)::matching "[^\n]*$"))
- return %its._trailing_line_len
-
- whose (number of lines) means:
- unless %its._num_lines:
- %num_lines = 1
- for % in %its:
- if (% is text):
- %num_lines += (size of (%::all matches of "\n"))
- ..else:
- %num_lines += ((%::number of lines) - 1)
-
- %its._num_lines = %num_lines
-
- return %its._num_lines
-
- whose [is multiline, is multi-line] all mean ((%its::number of lines) > 1)
- whose [is one line, is single line] all mean ((%its::number of lines) == 1)
- that can (add %values joined with %joiner) by:
- %its::add %values joined with %joiner or %joiner
- that can [add %values joined with %joiner or %wrapping_joiner] by:
- %line_len = 0
- %bits = %its.bits
- for %value in %values at %i:
- if (%i > 1):
- if (%line_len > 80):
- %bits::add %wrapping_joiner
- %line_len = 0
- ..else: %bits::add %joiner
-
- %bits::add %value
- unless (%value is text):
- %value = (%value::text)
- %line = (%value::matching "\n([^\n]*)$")
- if %line:
- %line_len = (size of %line)
- ..else:
- %line_len += (size of %value)
- %its::mark as dirty
-
- that can (prepend %) by:
- #if ((% isn't text) and (% isn't a %its.__type)):
- % = (%::as lua)
- %its.bits::add % at index 1
- %its::mark as dirty
-
- that can (parenthesize) by:
- %its.bits::add "(" at index 1
- %its.bits::add ")"
- %its::mark as dirty
-
-a (Lua Buffer) is a thing:
- that has [..]
- text, lua code, nomsu code, trailing line length, size, number of lines,
- is multiline, is multi-line, is one line, is single line,
- ..like a (Code Buffer)
- that can [..]
- set up, mark as dirty, add %, prepend %, parenthesize,
- add % joined with %, add % joined with % or %,
- ..like a (Code Buffer)
-
- that can (add free vars %vars) by:
- if ((size of %vars) == 0): return
- %seen = (%v = (yes) for %v in %its.free_vars)
- for %var in %vars:
- assume (%var is text)
- unless %seen.%var:
- %its.free_vars::add %var
- %seen.%var = (yes)
-
- %its::mark as dirty
-
- that can (remove free vars %vars) by:
- if ((size of %vars) == 0): return
- %removals = {}
- for %var in %vars:
- assume (%var is text)
- %removals.%var = (yes)
-
- %stack = [%its]
- repeat while ((size of %stack) > 0):
- %lua = (%stack::pop)
- for %i in (size of %lua.free_vars) to 1 by -1:
- if %removals.(%lua.free_vars.%i):
- %lua.free_vars::remove at index %i
-
- for % in %lua.bits:
- unless (% is text): %stack::add %
-
- %its::mark as dirty
-
- that can (declare locals) by (%its::declare locals (nil))
- that can (declare locals %to_declare) by:
- unless %to_declare:
- %to_declare = []
- %seen = {}
- for %lua in recursive %its:
- for %var in %lua.free_vars:
- unless %seen.%var:
- %seen.%var = (yes)
- %to_declare::add %var
-
- for % in %lua.bits:
- unless (% is text): recurse %lua on %
-
- if ((size of %to_declare) > 0):
- %its::remove free vars %to_declare
- %its::prepend "local \(%to_declare::joined with ", ");\n"
- return %to_declare
-
- whose (as statements) means (%its::as statements with "")
- whose (as statements with %prefix) means:
- unless %its.is_value: return %its
- %statements = (a Lua Buffer with {source:%its.source})
- if ((%prefix or "") != ""):
- %statements::add %prefix
- %statements::add %its
- %statements::add ";"
- return %statements
-
- that can (mark as value) by:
- %its.is_value = (yes)
-
- that can (mark as variable) by:
- %its.is_variable = (yes)
- %its.is_value = (yes)
-
- that can (variables) by:
- %vars = []
- for %code in recursive %its:
- if %code.is_variable:
- %vars::add (%code::text)
- for % in %code.bits:
- unless (% is text): recurse %code on %
-
- return %vars
-
-a (Nomsu Buffer) is a thing:
- that has [..]
- text, lua code, nomsu code, trailing line length, size, number of lines,
- is multiline, is multi-line, is one line, is single line,
- ..like a (Code Buffer)
- that can [..]
- set up, mark as dirty, add %, prepend %, parenthesize,
- add % joined with %, add % joined with % or %,
- ..like a (Code Buffer)
diff --git a/nomnom/compile.nom b/nomnom/compile.nom
deleted file mode 100644
index ad38b69..0000000
--- a/nomnom/compile.nom
+++ /dev/null
@@ -1,278 +0,0 @@
-#!/usr/bin/env nomsu -V4.8.10
-# This file contains the code to convert syntax trees to Lua code
-use "nomnom/code_obj.nom"
-use "nomnom/parser.nom"
-use "nomnom/pretty_errors.nom"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-externally (report compile error at %tree %err) means:
- barf (pretty "Compile Error" error at %tree %err)
-
-externally (report compile error at %pos %err hint %hint) means:
- barf (pretty "Compile Error" error at %tree %err hint %hint)
-
-externally (barf any errors in %t) means:
- assume (%t is a "Syntax Tree")
- %errs = []
- for % in recursive %t:
- if (%.type == "Error"): %errs::add %
- for %k = %v in %:
- if (%v is a "Syntax Tree"): recurse % on %v
-
- sort %errs by % -> %.source
- %errs = ((% as a pretty error) for % in %errs)
- if ((size of %errs) > 0):
- if ((size of %errs) > 3):
- %n = ((size of %errs) - 3)
- for %i in 4 to (size of %errs): %errs.%i = (nil)
- %errs::add "\027[31;1m +\%n additional errors...\027[0m\n"
- barf (%errs::joined with "\n\n")
-
-externally (%tree compiled with %compile_actions) means:
- assume (%tree is a "Syntax Tree")
- if all of [..]
- %tree.version, ((Nomsu version)'s meaning) != (nil), %tree.version != (Nomsu version)
- ((1 upgraded from 2 to 3)'s meaning) != (nil)
- ..then:
- %tree = (upgrade %tree from %tree.version to (Nomsu version))
-
- if %tree.type is:
- "Action":
- %stub = %tree.stub
- %compile_action = %compile_actions.%stub
-
- # Don't apply compiler actions to methods
- if (%compile_action and (not %tree.target)):
- # TODO: restore this:
- #%args = [%tree, %compile_actions]
- %args = [%nomsu, %tree]
- for % in (%tree::arguments): %args::add %
- %result = (call %compile_action with %args)
- if (%result == (nil)):
- report compile error at %tree "\
- ..The compile-time action here (\(%tree.stub)) failed to return any value."
- ..hint "\
- ..Look at the implementation of (\(%tree.stub)) and make sure it's returning something."
-
- if (%result is a "Syntax Tree"):
- if (%result == %tree):
- report compile error at %tree "\
- ..The compile-time action here (\(%tree.stub)) is producing an endless loop."
- ..hint "\
- ..Look at the implementation of (\(%tree.stub)) and make sure it's not just returning the original tree."
-
- return (%result compiled with %compile_actions)
-
- return %result
-
- %lua = (a Lua Buffer with {source:%tree})
- if %tree.target:
- # Method call
- %target_lua = (%tree.target compiled with %compile_actions)
- if (..)
- ((%target_lua::text)::matches "^%(.*%)$") or (..)
- (%target_lua::text)::matches "^[_a-zA-Z][_a-zA-Z0-9]*$"
- ..:
- %lua::add [%target_lua, ":"]
- ..else:
- %lua::add ["(", %target_lua, "):"]
-
- %lua::add [%stub as lua id, "("]
- %args = []
- for %tok in %tree at %i:
- if (%tok is text): do next %tok
-
- # TODO: maybe don't translate Lua comments
- #if (%tok.type == "Comment"): do next %tok
- if (%tok.type == "Block"):
- %values = []
- for %line in %tok:
- #unless (%line.type == "Comment"):
- %values::add (%line compiled with %compile_actions)
-
- if all of (%.is_value for % in %values):
- if ((size of %values) == 1):
- %arg_lua = %values.1
- ..else:
- %arg_lua = (a Lua Buffer with {source:%tok, is_value:yes, bits:["("]})
- %arg_lua::add %values joined with " and nil or "
- %arg_lua::add ")"
- ..else:
- %arg_lua = (a Lua Buffer with {source:%tok, is_value:yes, bits:["((function()"]})
- for %v in %values at %i:
- if %v.is_value:
- %v = (%v::as statements with ("return " if (%i == (size of %values) else "")))
- %arg_lua::add ["\n ", %v]
-
- %arg_lua::add "\nend)())"
- ..else:
- %arg_lua = (%tok compiled with %compile_actions)
- unless %arg_lua.is_value:
- if (%tok.type == "Action"):
- report compile error at %tok "\
- ..Can't use this as an argument to (\%stub), since it's not an expression, it produces: \%arg_lua"
- ..hint "\
- ..Check the implementation of (\(%tok.stub)) to see if it is actually meant to produce an expression."
- ..else:
- report compile error at %tok "\
- ..Can't use this as an argument to (\%stub), since it's not an expression, it produces: \%arg_lua"
-
- assume (%arg_lua != %lua) or barf "Huh? \%tree .\%i = \%tok -> \%arg_lua"
- %args::add %arg_lua
-
- %lua::add %args joined with ", "
- %lua::add ")"
- return %lua
-
- "EscapedNomsu":
- %lua = (a Lua Buffer with {source:%tree, is_value:yes, bits:["a_Syntax_Tree_with{type=", quote %tree.(1).type]})
- set {%needs_comma:no, %i:1}
- (% as shmua) means:
- if (% is a "Lua number"): return "\%"
- if (% is a "Syntax Tree"):
- return (% compiled with %compile_actions)
- if (% is text): return (quote %)
- return (%::as lua)
-
- for %k = %v in (((%tree.(1).type == "EscapedNomsu") and %tree) or %tree.1):
- %lua::add ", "
- if:
- (%k == %i): %i += 1
- ((%k is text) and (%k::is a lua identifier)):
- %lua::add [%k, "= "]
- else:
- %lua::add ["[", % as shmua, "]= "]
-
- if (%k == "source"):
- %lua::add (quote "\%v")
- ..else:
- %lua::add (%v as shmua)
-
- %lua::add "}"
- return %lua
-
- "Block":
- %lua = (a Lua Buffer with {source:%tree})
- %lua::add (..)
- ((%line compiled with %compile_actions)::as statements) for %line in %tree
- ..joined with "\n"
-
- return %lua
-
- "Text":
- %lua = (a Lua Buffer with {source:%tree})
- %lua_bits = []
- %string_buffer = ""
- for % in %tree:
- if (% is text):
- %string_buffer = "\%string_buffer\%"
- do next %
-
- if (%string_buffer != ""):
- %lua_bits::add (%string_buffer::as lua)
- %string_buffer = ""
-
- %bit_lua = (% compiled with %compile_actions)
- unless %bit_lua.is_value:
- report compile error at % "\
- ..Can't use this as a string interpolation value, since it doesn't have a value."
-
- if (%.type != "Text"):
- %bit_lua = (a Lua Buffer with {source:%, is_value:yes, bits:["tostring(", %bit_lua, ")"]})
- %lua_bits::add %bit_lua
-
- if ((%string_buffer != "") or ((size of %lua_bits) == 0)):
- %lua_bits::add (%string_buffer::as lua)
- %lua::add %lua_bits joined with ".."
- if ((size of %lua_bits) > 1): %lua::parenthesize
- return %lua
-
- "List":
- %lua = (a Lua Buffer with {source:%tree, is_value:yes, bits:["List{"]})
- %lua::add ((% compiled with %compile_actions) for % in %tree) joined with ", " or ",\n "
- %lua::add "}"
- return %lua
-
- "Dict":
- %lua = (a Lua Buffer with {source:%tree, is_value:yes, bits:["Dict{"]})
- %lua::add ((% compiled with %compile_actions) for % in %tree) joined with ", " or ",\n "
- %lua::add "}"
- return %lua
-
- "DictEntry":
- set {%key:%tree.1, %value:%tree.2}
- %key_lua = (%key compiled with %compile_actions)
- unless %key_lua.is_value:
- report compile error at %tree.1 "\
- ..Can't use this as a dict key, since it's not an expression."
-
- %value_lua = (..)
- (%value compiled with %compile_actions) if %value else (..)
- a Lua Buffer with {source:%key, is_value:yes, bits:["true"]}
-
- unless %value_lua.is_value:
- report compile error at %tree.2 "\
- ..Can't use this as a dict value, since it's not an expression."
-
- %key_str = ((%key_lua::text)::matching "^[\"']([a-zA-Z_][a-zA-Z0-9_]*)['\"]$")
- if:
- %key_str:
- return (a Lua Buffer with {source:%tree, bits:[%key_str, "=", %value_lua]})
- ((%key_lua::text).1 == "["):
- # NOTE: this *must* use a space after the [ to avoid freaking out
- Lua's parser if the inner expression is a long string. Lua
- parses x[[[y]]] as x("[y]"), not as x["y"]
- return (a Lua Buffer with {source:%tree, bits:["[ ", %key_lua, "]=", %value_lua]})
-
- else:
- return (a Lua Buffer with {source:%tree, bits:["[", %key_lua, "]=", %value_lua]})
-
- "IndexChain":
- %lua = (%tree.1 compiled with %compile_actions)
- unless %lua.is_value:
- report compile error at %tree.1 "\
- ..Can't index into this, since it's not an expression."
-
- %first_char = (%lua::text).1
- if (any of [%first_char == "{", %first_char == "\"", %first_char == "["]):
- %lua::parenthesize
- for %i in 2 to (size of %tree):
- %key = %tree.%i
- %key_lua = (%key compiled with %compile_actions)
- unless %key_lua.is_value:
- report compile error at %key "\
- ..Can't use this as an index, since it's not an expression."
-
- %key_lua_str = (%key_lua::text)
- %lua_id = (%key_lua_str::matching "^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$")
- if:
- %lua_id:
- %lua::add [".", %lua_id]
- (%key_lua_str.1 == "["):
- # NOTE: this *must* use a space after the [ to avoid freaking out
- Lua's parser if the inner expression is a long string. Lua
- parses x[[[y]]] as x("[y]"), not as x["y"]
- %lua::add ["[ ", %key_lua, " ]"]
-
- else:
- %lua::add ["[", %key_lua, "]"]
-
- return %lua
-
- "Number":
- return (a Lua Buffer with {source:%tree, is_value:yes, bits:["\(%tree.1)"]})
- "Var":
- return (a Lua Buffer with {source:%tree, is_value:yes, is_variable:yes, bits:[%tree.1::as lua id]})
- "FileChunks":
- barf "\
- ..Can't convert FileChunks to a single block of lua, since each chunk's compilation depends on the earlier chunks"
-
- "Comment":
- # TODO: de-implement?
- return (a Lua Buffer with {source:%tree, bits:["-- \(%tree.1::with "\n" -> "\n-- ")"]})
-
- "Error":
- barf (%tree as a pretty error)
- else:
- barf "Unknown type: \(%tree.type)"
diff --git a/nomnom/decompile.nom b/nomnom/decompile.nom
deleted file mode 100644
index c958280..0000000
--- a/nomnom/decompile.nom
+++ /dev/null
@@ -1,348 +0,0 @@
-#!/usr/bin/env nomsu -V4.8.10
-# 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
-externally (%tree decompiled inline) means:
- assume (%tree is a "Syntax Tree")
- if %tree.type is:
- "Action":
- %nomsu = (a Nomsu Buffer with {source: %tree})
- if %tree.target:
- %target_nomsu = (%tree.target decompiled 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 = (%bit decompiled 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 = (%tree.1 decompiled inline)
- unless (..)
- any of [..]
- %tree.(1).type == "List", %tree.(1).type == "Dict", %tree.(1).type == "Var"
- ..:
- %inner_nomsu::parenthesize
-
- %nomsu = (a Nomsu Buffer with {source: %tree, bits: ["\\", %inner_nomsu]})
- return %nomsu
-
- "Block":
- %nomsu = (a Nomsu Buffer with {source: %tree, bits: [":"]})
- for %line in %tree at %i:
- %nomsu::add [" " if (%i == 1) else "; ", %line decompiled inline]
- return %nomsu
-
- "Text":
- %nomsu = (a Nomsu Buffer with {source: %tree, bits: []})
- for %text in recursive %tree:
- for %bit in %text at %i:
- if (%bit is text): %nomsu::add %bit
- ..else:
- if %bit.type is:
- "Text":
- recurse %text on %bit
- "Var":
- %interp_nomsu = (%bit decompiled 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 ["\\", %bit decompiled inline]
- else:
- %nomsu::add ["\\(", %bit decompiled inline, ")"]
-
- return (a Nomsu Buffer with {source: %tree, bits: ["\"", %nomsu, "\""]})
-
- "List" "Dict":
- %nomsu = (a Nomsu Buffer with {source: %tree, bits: ["[" if (%tree.type == "List") else "{"]})
- for %item in %tree at %i:
- if (%i > 1): %nomsu::add ", "
- %nomsu::add (%item decompiled 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 = (a Nomsu Buffer with {source: %key, bits: [%key.1]})
- ..else:
- %nomsu = (%key decompiled inline)
-
- if (%key.type == "Action"):
- %nomsu::parenthesize
- if %value:
- %nomsu::add ":"
- %nomsu::add (%value decompiled inline)
-
- return %nomsu
-
- "IndexChain":
- %nomsu = (a Nomsu Buffer with {source: %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 = (%bit decompiled 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 (a Nomsu Buffer with {source: %tree, bits: [(%tree.1 as hex) if %tree.hex else "\(%tree.1)"]})
- "Var":
- return (a Nomsu Buffer with {source: %tree, bits: ["%\(%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
-externally (%tree decompiled) means:
- %nomsu = (a Nomsu Buffer with {source: %tree})
-
- # For concision:
- (recurse on %t) means:
- %space = (%MAX_LINE - (%nomsu::trailing line length))
- if (%space <= 0):
- go to (Use Indented)
- for %subtree in recursive %tree:
- if %subtree.type is:
- "Block":
- if ((size of %subtree) > 1):
- go to (Use Indented)
- if ((size of "\(%subtree decompiled inline)") > 20):
- go to (Use Indented)
-
- for %k = %v in %subtree:
- if (%v is a "Syntax Tree"):
- recurse %subtree on %v
-
- %inline_nomsu = (%t decompiled inline)
- if (%inline_nomsu and ((size of "\%inline_nomsu") <= %space)):
- return %inline_nomsu
- === (Use Indented) ===
- %indented = (%t decompiled)
- if (%t.type == "Action"):
- %indented = (..)
- a Nomsu Buffer with {source: %t, bits: ["(..)\n ", %indented]}
-
- return %indented
-
- if %tree.type is:
- "FileChunks":
- (%1 and %2 should clump) means:
- if ((%1.type == "Action") and (%2.type == "Action")):
- if (%1.stub == "use"):
- return (%2.stub == "use")
- if (%1.stub == "test"): return (yes)
- if (%2.stub == "test"): 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"
- 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"
- ..else: %nomsu::add "\n\n"
-
- %nomsu::add (%line decompiled)
- ..else:
- %nomsu::add (%chunk decompiled)
-
- unless ("\%nomsu"::matches "\n$"): %nomsu::add "\n"
- return %nomsu
-
- "Action":
- %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
- %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 (..)
- a Nomsu Buffer with {source: %tree, bits: [":\n ", %nomsu]}
-
- "Text":
- # Multi-line text has more generous wrap margins
- %max_line = ((1.5 * %MAX_LINE) rounded down)
- %nomsu = (a Nomsu Buffer with {source: %tree})
- (add text from %tree) means:
- 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.."
-
- repeat 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":
- do nothing
- else:
- %interp_nomsu::parenthesize
-
- %nomsu::add %interp_nomsu
- if (%interp_nomsu::is multi-line): %nomsu::add "\n.."
-
- add text from %tree
- return (..)
- a Nomsu Buffer with {source: %tree, bits: ["\"\\\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 = (%item decompiled 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 any of [..]
- %item_nomsu::is multi-line, ((%nomsu::trailing line length) + (size of "\%item_nomsu")) >= %MAX_LINE
- ..: %nomsu::add "\n"
- ..else: %nomsu::add ", "
-
- return (..)
- a Nomsu Buffer with {..}
- source: %tree, bits: [..]
- "[..]\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 (%key decompiled 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 (%tree decompiled inline)
- "Error":
- barf "Cannot decompile an error"
- else:
- barf "Unknown type: \(%tree.type)"
diff --git a/nomnom/files.nom b/nomnom/files.nom
deleted file mode 100644
index 61119c0..0000000
--- a/nomnom/files.nom
+++ /dev/null
@@ -1,110 +0,0 @@
-#!/usr/bin/env nomsu -V4.8.10
-# Some file utilities for searching for files recursively and using package.nomsupath
-use "lib/os.nom"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-%_SPOOFED_FILES = {}
-%_FILE_CACHE = ({} with fallback % -> %_SPOOFED_FILES.%)
-%_BROWSE_CACHE = {}
-
-# Create a fake file and put it in the cache
-externally (spoof file %filename %contents) means:
- %_SPOOFED_FILES.%filename = %contents
- return %contents
-
-# Read a file's contents
-externally (read file %filename) means:
- %contents = %_FILE_CACHE.%filename
- if %contents: return %contents
- if (%filename == "stdin"):
- return (spoof file "stdin" (=lua "io.read('*a')"))
- %file = (=lua "io.open(\%filename)")
- unless %file: return (nil)
- %contents = (call %file.read with [%file, "*a"])
- %file::close
- %_FILE_CACHE.%filename = %contents
- return %contents
-
-externally (%path sanitized) means:
- %path = (%path::with "\\" -> "\\\\")
- %path = (%path::with "`" -> "")
- %path = (%path::with "\"" -> "\\\"")
- %path = (%path::with "$" -> "")
- %path = (%path::with "%.%." -> "\\..")
- return %path
-
-try:
- %lfs = (=lua "require('lfs')")
-..and if it succeeds:
- (filesystem has %filename) means:
- %mode = (call %lfs.attributes with [%filename, "mode"])
- if %mode is:
- "file" "directory" "link" "char device": return (yes)
- else: return (no)
-
- externally (file %path exists) means:
- if (any of [%_SPOOFED_FILES.%path, %path == "stdin", filesystem has %path]):
- return (yes)
- for %nomsupath in (%package.nomsupath::all matches of "[^;]+"):
- if (filesystem has "\(%nomsupath)/\%path"): return (yes)
- return (no)
-
- externally (files in %path) means:
- unless %_BROWSE_CACHE.%path:
- if (%_SPOOFED_FILES.%path or (%filename == "stdin")):
- %_BROWSE_CACHE.%path = [%path]
- ..else:
- if (call %lfs.attributes with [%filename, "mode"]) is:
- "file" "char device":
- %_BROWSE_CACHE.%path = [%filename]
- "directory" "link":
- for %nomsupath in (%package.nomsupath::all matches of "[^;]+"):
- %files = []
- for %member in (call %lfs.dir with ["\(%nomsupath)/\%filename"]):
- if ((%member == ".") or (%member == "..")): do next %member
- for % in (files in %member): %files::add %
-
- if ((size of %files) > 0):
- %_BROWSE_CACHE.%path = %files
- go to (Found Files)
-
- %_BROWSE_CACHE.%path = []
-
- else:
- %_BROWSE_CACHE.%path = []
-
- === (Found Files) ===
- return %_BROWSE_CACHE.%filename
-..or if it barfs:
- # LFS not found! Fall back to shell commands, if available.
- unless (sh> "find . -maxdepth 0"):
- barf "\
- ..Could not find 'luafilesystem' module and couldn't run system command 'find' (this might happen on Windows). Please install \
- ..'luafilesystem' (which can be found at \(..)
- "https://github.com/spacewander/luafilesystem" if %jit else "\
- ..https://github.com/keplerproject/luafilesystem"
- .. or obtained through `luarocks install luafilesystem`)"
-
- externally (file %path exists) means:
- if (any of [%_SPOOFED_FILES.%path, %path == "stdin", sh> "ls \(%path sanitized)"]) \
- ..: return (yes)
- for %nomsupath in (%package.nomsupath::all matches of "[^;]+"):
- if (sh> "ls \(%nomsupath)/\%path"): return (yes)
- return (no)
-
- externally (files in %path) means:
- unless %_BROWSE_CACHE.%path:
- if %_SPOOFED_FILES.%path:
- %_BROWSE_CACHE.%path = [%_SPOOFED_FILES.%path]
- ..else:
- for %nomsupath in (%package.nomsupath::all matches of "[^;]+"):
- %files = (sh> "find -L '\(%path)' -not -path '*/\\.*' -type f'")
- if %files:
- %_BROWSE_CACHE.%path = (%files::lines)
- go to (Found Files)
-
- %_BROWSE_CACHE.%path = []
-
- === (Found Files) ===
- return %_BROWSE_CACHE.%path
diff --git a/nomnom/parser.nom b/nomnom/parser.nom
deleted file mode 100644
index fe237e8..0000000
--- a/nomnom/parser.nom
+++ /dev/null
@@ -1,91 +0,0 @@
-#!/usr/bin/env nomsu -V4.8.10
-# This file contains the parser, which converts text into abstract syntax trees
-#use "nomonom/ast.nom"
-%lpeg = (=lua "require('lpeg')")
-%re = (=lua "require('re')")
-call %lpeg.setmaxstack with [20000]
-set {..}
- ((P 1)'s meaning):%lpeg.P, ((R 1)'s meaning):%lpeg.R
- ((Carg 1)'s meaning):%lpeg.Carg, ((S 1)'s meaning):%lpeg.S
- ((Cc 1)'s meaning):%lpeg.Cc, ((lpeg re pattern 1)'s meaning):%re.compile
- ((lpeg re pattern 1 using 2)'s meaning):%re.compile
- ((lpeg pattern 1's match of 2)'s meaning):%lpeg.match
- ((lpeg pattern 1's match of 2 with 3)'s meaning): (..)
- [%1, %2, %3] -> (call %lpeg.match with [%1, %2, nil, %3])
-
-%source_code_for_tree = {}
-%defs = (..)
- {..}
- nl: (P "\r")^(-1) * (P "\n")
- tab: P "\t"
- tonumber: %tonumber
- tochar: %string.char
- unpack: %unpack
- nil: Cc (nil)
- userdata: Carg 1
- utf8_char: (..)
- (R "\194\223")*(R "\128\191") +
- ..(R "\224\239")*(R "\128\191")*(R "\128\191") +
- ..(R "\240\244")*(R "\128\191")*(R "\128\191")*(R "\128\191")
-
- Tree: [%t, %userdata] ->:
- %source = (..)
- Source {filename:%userdata.filename, start:%t.start, stop:%t.stop}
- set {%t.start: nil, %t.stop: nil, %t.source: %source}
- %t = (a Syntax Tree with %t)
- (Syntax Tree).source_code_for_tree.%t = %userdata.source
- return %t
- ..with fallback %key ->:
- if:
- (%key::matches "^ascii_(%d+)$"):
- %i = (%key::matching "^ascii_(%d+)$")
- return (call %string.char with [%i as a number])
-
- (%key::matches "^number_(%d+)$"):
- %i = (%key::matching "^number_(%d+)$")
- return (Cc (%i as a number))
-
-%id_patt = (..)
- ((P "") - (R "09")) * (..)
- (%defs.utf8_char + (R "az") + (R "AZ") + (P "_") + (R "09")) ^ 1 * -1
-
-%operator_patt = ((S "'`~!@$^&*+=|<>?/-") ^ 1 * -1)
-externally [%text is a nomsu id, %text is a nomsu identifier] all mean (..)
- lpeg pattern %id_patt's match of %text
-
-externally (%text is a nomsu operator) means (..)
- lpeg pattern %operator_patt's match of %text
-
-%peg_tidier = (..)
- lpeg re pattern "\
- ..file <- %nl* {~ (def/comment) (%nl+ (def/comment))* %nl* ~}
- def <- anon_def / captured_def
- anon_def <-
- ({ident} (" "*) ":" {[^%nl]* (%nl+ " "+ [^%nl]*)*})
- -> "%1 <- %2"
- captured_def <-
- ({ident} (" "*) "(" {ident} ")" (" "*) ":" {[^%nl]* (%nl+ " "+ [^%nl]*)*})
- -> "%1 <- ({| {:start:{}:} %3 {:stop:{}:} {:type: (''->'%2') :} |} %%userdata) -> Tree"
- ident <- [a-zA-Z_][a-zA-Z0-9_]*
- comment <- "--" [^%nl]*
- "
-
-externally (make parser from %peg) means (make parser from %peg using (nil))
-externally (make parser from %peg using %make_tree) means:
- %peg = (lpeg pattern %peg_tidier's match of %peg)
- %peg = (lpeg re pattern %peg using %defs)
- (%input from %filename parsed) means:
- %input = "\%input"
- %tree_mt = {__index:{source:%input, filename:%filename}}
- %userdata = {..}
- make_tree:%make_tree or ([%] -> (: set %'s metatable to %tree_mt; return %))
- filename:%filename, source:%input
-
- %tree = (lpeg pattern %peg's match of %input with %userdata)
- assume %tree or barf "\
- ..File \%filename failed to parse:
- \%input"
-
- return %tree
-
- return ((1 from 2 parsed)'s meaning)
diff --git a/nomnom/pretty_errors.nom b/nomnom/pretty_errors.nom
deleted file mode 100644
index db4be5a..0000000
--- a/nomnom/pretty_errors.nom
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env nomsu -V4.8.10
-# This file has code for converting errors to user-friendly format, with colors,
- line numbers, code excerpts, and so on.
-(visible size of %text) means:
- return (size of (%text::with "\027%[[0-9;]*m" -> ""))
-
-(%text boxed) means:
- %max_line = (max of ((visible size of %line) for %line in (%text::lines)))
- %ret = (..)
- "\n\%text"::with "\n([^\n]*)" -> (..)
- [%] -> (..)
- "\n\%\(" "::* (%max_line - (visible size of %))) \027[0m"
- return %ret.[2,-1]
-
-%CONTEXT = 2
-externally (pretty %title error at %tree %err hint %hint) means:
- %source_code = (%tree::get source code)
- %start = %tree.source.start
- %stop = %tree.source.stop
- %filename = (%tree.source.filename or "???")
- %err_line = (%source_code::line at %start)
- %err_linenum = (%source_code::line number at %start)
- %err_linepos = (%source_code::line position at %start)
-
- # TODO: better handle multi-line errors
- %err_size = (min of [%stop - %start, (size of %err_line) - %err_linepos + 1])
- %nl_indicator = (" " if (%err_linepos > (size of %err_line)) else "")
- %fmt_str = " %\(size of "\(%err_linenum + %CONTEXT)")d|"
- (num %i) means (%fmt_str::formatted with %i)
- %linenum_size = (size of (num 0))
- %pointer = "\(" "::* (%err_linepos + %linenum_size - 1))"
- if (%err_size >= 2):
- %pointer += "╚\("═"::* (%err_size - 2))╝"
- ..else: %pointer += "⬆"
-
- %err_msg = "\
- ..\027[33;41;1m\(%title or "Error") at \%filename:\%err_linenum\027[0m"
- for %i in (%err_linenum - %CONTEXT) to (%err_linenum - 1):
- %line = (%source_code::line %i)
- if %line:
- %err_msg += "\n\027[2m\(num %i)\027[0m\(%line)\027[0m"
-
- if %err_line:
- %before = %err_line.[1, %err_linepos - 1]
- %during = %err_line.[%err_linepos, %err_linepos + %err_size - 1]
- %after = %err_line.[%err_linepos + %err_size, -1]
- %err_line = "\027[0m\(%before)\027[41;30m\%during\(%nl_indicator)\027[0m\%after"
- %err_msg += "\n\027[2m\(num %err_linenum)\(%err_line)\027[0m"
-
- %err_linenum_end = (%source_code::line number at %stop)
- %err_linepos_end = (%source_code::line position at %stop)
- %err_linenum_end or= %err_linenum
- if (%err_linenum_end == %err_linenum):
- %err_msg += "\n\%pointer"
- ..else:
- for %i in (%err_linenum + 1) to %err_linenum_end:
- %line = (%source_code::line %i)
- if %line:
- if (%i == %err_linenum_end):
- %during = %line.[1, %err_linepos_end - 1]
- %after = %line.[%err_linepos_end, -1]
- %err_msg += "\n\027[2m\(num %i)\027[0;41;30m\(%during)\027[0m\%after"
- ..else:
- %err_msg += "\n\027[2m\(num %i)\027[0;41;30m\(%line)\027[0m"
-
- %box_width = 70
- %err_text = "\
- ..\027[47;31;1m\((" \%err"::wrapped to %box_width)::with "\n" -> "\n\027[47;31;1m ")"
- if %hint:
- %err_text += "\n\027[47;30m\((" Suggestion: \(%hint)"::wrapped to %box_width)::with "\n" -> "\n\027[47;30m ")"
- %err_msg += "\n\027[33;1m \((%err_text boxed)::with "\n" -> "\n ")"
-
- %err_msg += "\n\027[33;1m \((%err_text boxed)::with "\n" -> "\n ")"
- for %i in (%err_linenum_end + 1) to (%err_linenum_end + %CONTEXT):
- %line = (%source_code::line %i)
- if %line:
- %err_msg += "\n\027[2m\(num %i)\027[0m\(%line)\027[0m"
-
- return %err_msg
-
-externally (pretty %title error at %tree %err) means (..)
- pretty %title error at %tree %err (nil)
-
-externally (%err_tree as a pretty error) means (..)
- pretty %err_tree.title error at %err_tree %err_tree.error hint %err_tree.hint
diff --git a/nomnom/source.nom b/nomnom/source.nom
deleted file mode 100644
index bff8d8d..0000000
--- a/nomnom/source.nom
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/env nomsu -V4.8.10
-use "lib/object.nom"
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-object (Source):
- externally (Source from text %text) means:
- %match = (%text::matching groups "^@(.-)%[(%d+):(%d+)%]$")
- set {%filename:%match.1, %start:%match.2, %stop:%match.3}
- unless %filename:
- %match = (%text::matching groups "^@(.-)%[(%d+)%]$")
- set {%filename:%match.1, %start:%match.2}
-
- return (..)
- Source {filename:%filename, start:(%start or 1) as number, stop:%stop as number}
-
- my action [as text] "\
- ..@\(%me.filename)[\(%me.start)\(":\(%me.stop)" if %me.stop else "")]"
- my action [as lua] "\
- ..Source{filename=\(%me.filename::as lua), start=\(%me.start)\(..)
- ", stop=\(%me.stop)" if %stop else ""
- ..}"
-
- my action [as nomsu] "\
- ..(Source {filename:\(%me.filename::as nomsu), start:\(%me.start)\(..)
- ", stop:\(%me.stop)" if %stop else ""
- ..})"
-
- my action [== %other] (..)
- all of [..]
- (%me's metatable) == (%other's metatable)
- %me.filename == %other.filename
- %me.start == %other.start
- %me.stop == %other.stop
-
- my action [< %other]:
- assume %me.filename == %other.filename
- if (%start == %other.start):
- return ((%me.stop or %me.start) < (%other.stop or %other.start))
- ..else:
- return (%me.start < %other.start)
-
- my action [<= %other]:
- assume %me.filename == %other.filename
- if (%start == %other.start):
- return ((%me.stop or %me.start) <= (%other.stop or %other.start))
- ..else:
- return (%me.start <= %other.start)
-
- my action [+ %offset]:
- if ((type of %me) == "number"):
- set {%me:%offset, %offset:%me}
- ..else:
- assume (type of %offset) == "number"
-
- return (Source {filename:%me.filename, start:%me.start + %offset, stop:%me.stop})
diff --git a/nomsu.4.peg b/nomsu.4.peg
index bbff67d..e7fc09a 100644
--- a/nomsu.4.peg
+++ b/nomsu.4.peg
@@ -6,7 +6,7 @@ file:
{:curr_indent: %nil :}
!.
-shebang: "#!" (!"nomsu" [^%nl])* "nomsu" ws+ "-V" ws* {:version: [0-9.]+ :} [^%nl]* (%nl / !.)
+shebang: "#!" (!"nomsu" [^%nl])* "nomsu" ws+ "-V" ws* [0-9.]+ [^%nl]* (%nl / !.)
eof: !.
@@ -37,7 +37,7 @@ 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+ (indent -> '') [^%nl]*)* (%nl &%nl)* ~}
eol_comment (Comment):
"#" {[^%nl]*}
diff --git a/nomsu_decompiler.lua b/nomsu_decompiler.lua
index 9880014..46b769e 100644
--- a/nomsu_decompiler.lua
+++ b/nomsu_decompiler.lua
@@ -11,7 +11,8 @@ do
R, P, S = _obj_0.R, _obj_0.P, _obj_0.S
end
local re = require('re')
-local MAX_LINE = 90
+local MAX_LINE = 80
+local GOLDEN_RATIO = ((1 + math.sqrt(5)) / 2)
local utf8_char_patt = (R("\194\223") * R("\128\191") + R("\224\239") * R("\128\191") * R("\128\191") + R("\240\244") * R("\128\191") * R("\128\191") * R("\128\191"))
local operator_patt = S("'`~!@$^&*+=|<>?/-") ^ 1 * -1
local identifier_patt = (R("az", "AZ", "09") + P("_") + utf8_char_patt) ^ 1 * -1
@@ -149,7 +150,7 @@ tree_to_inline_nomsu = function(tree)
nomsu:parenthesize()
end
assert(value.type ~= "Block", "Didn't expect to find a Block as a value in a dict")
- nomsu:append(":")
+ nomsu:append(": ")
if value then
local value_nomsu = tree_to_inline_nomsu(value)
if value.type == "Block" then
@@ -197,19 +198,20 @@ tree_to_nomsu = function(tree)
local recurse
recurse = function(t)
local space = MAX_LINE - nomsu:trailing_line_len()
- local inline = true
+ local try_inline = true
for subtree in coroutine.wrap(function()
return (t:map(coroutine.yield) and nil)
end) do
if subtree.type == "Block" then
if #subtree > 1 then
- inline = false
+ try_inline = false
end
end
end
- if inline then
- local inline_nomsu = tree_to_inline_nomsu(t)
- if #inline_nomsu:text() <= space then
+ local inline_nomsu
+ 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
inline_nomsu:parenthesize()
end
@@ -224,6 +226,9 @@ tree_to_nomsu = function(tree)
indented:parenthesize()
end
end
+ if inline_nomsu and indented:text():match("^[^\n]*\n[^\n]*$") and nomsu:trailing_line_len() <= 8 then
+ return inline_nomsu
+ end
return indented
end
local _exp_0 = tree.type
@@ -270,7 +275,7 @@ tree_to_nomsu = function(tree)
if #word_buffer > 0 then
local words = table.concat(word_buffer)
if next_space == " " then
- if nomsu:trailing_line_len() + #words > MAX_LINE then
+ if nomsu:trailing_line_len() + #words > MAX_LINE and nomsu:trailing_line_len() > 8 then
next_space = " \\\n.."
elseif word_buffer[1] == "'" then
next_space = ""
@@ -282,11 +287,11 @@ tree_to_nomsu = function(tree)
end
local bit_nomsu = recurse(bit)
if bit.type == "Block" and not bit_nomsu:is_multiline() then
- if #bit_nomsu:text() > nomsu:trailing_line_len() then
+ if #bit_nomsu:text() > nomsu:trailing_line_len() * GOLDEN_RATIO and #bit_nomsu:text() > 8 then
bit_nomsu = tree_to_nomsu(bit)
end
end
- if next_space == " " and not bit_nomsu:is_multiline() and nomsu:trailing_line_len() + #bit_nomsu:text() > MAX_LINE then
+ 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
bit_nomsu = NomsuCode:from(bit.source, "(..)\n ", tree_to_nomsu(bit))
else
@@ -307,7 +312,7 @@ tree_to_nomsu = function(tree)
if #word_buffer > 0 then
local words = table.concat(word_buffer)
if next_space == " " then
- if nomsu:trailing_line_len() + #words > MAX_LINE then
+ if nomsu:trailing_line_len() + #words > MAX_LINE and nomsu:trailing_line_len() > 8 then
next_space = " \\\n.."
elseif word_buffer[1] == "'" then
next_space = ""
@@ -397,14 +402,21 @@ tree_to_nomsu = function(tree)
nomsu:append(tree.type == "List" and "[]" or "{}")
return nomsu
end
+ local sep = ''
for i, item in ipairs(tree) do
local item_nomsu = tree_to_inline_nomsu(item)
if #item_nomsu:text() > MAX_LINE then
item_nomsu = recurse(item)
end
+ if item.type == 'Comment' then
+ item_nomsu = tree_to_nomsu(item)
+ end
+ nomsu:append(sep)
nomsu:append(item_nomsu)
- if i < #tree then
- nomsu:append((item_nomsu:is_multiline() or nomsu:trailing_line_len() + #tostring(item_nomsu) >= MAX_LINE) and '\n' or ', ')
+ if item_nomsu:is_multiline() or item.type == 'Comment' or nomsu:trailing_line_len() + #tostring(item_nomsu) >= MAX_LINE then
+ sep = '\n'
+ else
+ sep = ', '
end
end
if tree.type == "List" then
diff --git a/nomsu_decompiler.moon b/nomsu_decompiler.moon
index fa50eb2..99dce3e 100644
--- a/nomsu_decompiler.moon
+++ b/nomsu_decompiler.moon
@@ -3,7 +3,8 @@
{:R,:P,:S} = require 'lpeg'
re = require 're'
-MAX_LINE = 90
+MAX_LINE = 80
+GOLDEN_RATIO = ((1+math.sqrt(5))/2)
-- Parsing helper functions
utf8_char_patt = (
@@ -107,7 +108,7 @@ tree_to_inline_nomsu = (tree)->
else tree_to_inline_nomsu(key)
nomsu\parenthesize! if key.type == "Action" or key.type == "Block"
assert(value.type != "Block", "Didn't expect to find a Block as a value in a dict")
- nomsu\append ":"
+ nomsu\append ": "
if value
value_nomsu = tree_to_inline_nomsu(value)
value_nomsu\parenthesize! if value.type == "Block"
@@ -153,15 +154,16 @@ tree_to_nomsu = (tree)->
-- For concision:
recurse = (t)->
space = MAX_LINE - nomsu\trailing_line_len!
- inline = true
+ try_inline = true
for subtree in coroutine.wrap(-> (t\map(coroutine.yield) and nil))
if subtree.type == "Block"
if #subtree > 1
- inline = false
+ try_inline = false
- if inline
+ local inline_nomsu
+ if try_inline
inline_nomsu = tree_to_inline_nomsu(t)
- if #inline_nomsu\text! <= space
+ if #inline_nomsu\text! <= space or #inline_nomsu\text! <= 8
if t.type == "Action"
inline_nomsu\parenthesize!
return inline_nomsu
@@ -170,6 +172,8 @@ tree_to_nomsu = (tree)->
if indented\is_multiline!
return NomsuCode\from(t.source, "(..)\n ", indented)
else indented\parenthesize!
+ if inline_nomsu and indented\text!\match("^[^\n]*\n[^\n]*$") and nomsu\trailing_line_len! <= 8
+ return inline_nomsu
return indented
switch tree.type
@@ -207,7 +211,7 @@ tree_to_nomsu = (tree)->
if #word_buffer > 0
words = table.concat(word_buffer)
if next_space == " "
- if nomsu\trailing_line_len! + #words > MAX_LINE
+ if nomsu\trailing_line_len! + #words > MAX_LINE and nomsu\trailing_line_len! > 8
next_space = " \\\n.."
elseif word_buffer[1] == "'"
next_space = ""
@@ -217,14 +221,14 @@ tree_to_nomsu = (tree)->
bit_nomsu = recurse(bit)
if bit.type == "Block" and not bit_nomsu\is_multiline!
- -- Rule of thumb: one-liner block arguments should be shorter
- -- than the proceeding part of the line
- if #bit_nomsu\text! > nomsu\trailing_line_len!
+ -- Rule of thumb: nontrivial one-liner block arguments should be no more
+ -- than golden ratio * the length of the proceeding part of the line
+ if #bit_nomsu\text! > nomsu\trailing_line_len! * GOLDEN_RATIO and #bit_nomsu\text! > 8
bit_nomsu = tree_to_nomsu(bit)
- --else
- -- bit_nomsu\parenthesize!
- if next_space == " " and not bit_nomsu\is_multiline! and nomsu\trailing_line_len! + #bit_nomsu\text! > MAX_LINE
+ 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'
bit_nomsu = NomsuCode\from bit.source, "(..)\n ", tree_to_nomsu(bit)
else
@@ -238,7 +242,7 @@ tree_to_nomsu = (tree)->
if #word_buffer > 0
words = table.concat(word_buffer)
if next_space == " "
- if nomsu\trailing_line_len! + #words > MAX_LINE
+ if nomsu\trailing_line_len! + #words > MAX_LINE and nomsu\trailing_line_len! > 8
next_space = " \\\n.."
elseif word_buffer[1] == "'"
next_space = ""
@@ -312,13 +316,19 @@ tree_to_nomsu = (tree)->
if #tree == 0
nomsu\append(tree.type == "List" and "[]" or "{}")
return nomsu
+ sep = ''
for i, item in ipairs tree
item_nomsu = tree_to_inline_nomsu(item)
if #item_nomsu\text! > MAX_LINE
item_nomsu = recurse(item)
+ if item.type == 'Comment'
+ item_nomsu = tree_to_nomsu(item)
+ nomsu\append sep
nomsu\append item_nomsu
- if i < #tree
- nomsu\append((item_nomsu\is_multiline! or nomsu\trailing_line_len! + #tostring(item_nomsu) >= MAX_LINE) and '\n' or ', ')
+ if item_nomsu\is_multiline! or item.type == 'Comment' or nomsu\trailing_line_len! + #tostring(item_nomsu) >= MAX_LINE
+ sep = '\n'
+ else
+ sep = ', '
return if tree.type == "List" then
NomsuCode\from(tree.source, "[..]\n ", nomsu)
else
diff --git a/nomsu_environment.lua b/nomsu_environment.lua
index ac99246..a4ade61 100644
--- a/nomsu_environment.lua
+++ b/nomsu_environment.lua
@@ -122,6 +122,9 @@ local nomsu_environment = Importer({
local syntax_version = version and tonumber(version:match("^[0-9]+")) or max_parser_version
local parse = Parsers[syntax_version] or Parsers[max_parser_version]
local tree = parse(nomsu_code, source.filename)
+ if tree.shebang then
+ tree.version = tree.shebang:match("nomsu %-V[ ]*([%d.]*)")
+ end
local find_errors
find_errors = function(t)
if t.type == "Error" then
diff --git a/nomsu_environment.moon b/nomsu_environment.moon
index 4c8ba28..0d80e0d 100644
--- a/nomsu_environment.moon
+++ b/nomsu_environment.moon
@@ -65,6 +65,8 @@ nomsu_environment = Importer{
syntax_version = version and tonumber(version\match("^[0-9]+")) or max_parser_version
parse = Parsers[syntax_version] or Parsers[max_parser_version]
tree = parse(nomsu_code, source.filename)
+ if tree.shebang
+ tree.version = tree.shebang\match("nomsu %-V[ ]*([%d.]*)")
find_errors = (t)->
if t.type == "Error"
coroutine.yield t