aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bitbucket@bruce-hill.com>2018-06-18 15:44:29 -0700
committerBruce Hill <bitbucket@bruce-hill.com>2018-06-18 15:44:35 -0700
commit16d127abb507751808eca65108710d3de1fd3cab (patch)
tree53a78ad2e88a95048eea76426e62c05c2c5102a5
parentfc71b0331b6122c774585c3ab93e6e55978ecaf2 (diff)
Initial working version.
-rw-r--r--code_obj.lua21
-rw-r--r--code_obj.moon14
-rw-r--r--core/collections.nom294
-rw-r--r--core/control_flow.nom668
-rw-r--r--core/errors.nom82
-rw-r--r--core/io.nom8
-rw-r--r--core/metaprogramming.nom328
-rw-r--r--core/operators.nom303
-rw-r--r--core/text.nom8
-rw-r--r--lib/object.nom107
-rw-r--r--nomsu.lua1970
-rwxr-xr-xnomsu.moon619
-rw-r--r--nomsu.peg10
-rw-r--r--nomsu_tree.lua4
-rw-r--r--nomsu_tree.moon3
-rw-r--r--tests/metaprogramming.nom36
-rw-r--r--tests/operators.nom15
-rw-r--r--tests/text.nom5
-rw-r--r--uuid.lua1
19 files changed, 2159 insertions, 2337 deletions
diff --git a/code_obj.lua b/code_obj.lua
index 426a973..f628fcc 100644
--- a/code_obj.lua
+++ b/code_obj.lua
@@ -3,7 +3,7 @@ do
local _obj_0 = table
insert, remove, concat = _obj_0.insert, _obj_0.remove, _obj_0.concat
end
-local Lua, Source
+local LuaCode, NomsuCode, Source
do
local _class_0
local _base_0 = {
@@ -242,7 +242,7 @@ do
if not (self.is_value) then
return self
end
- local statements = Lua(self.source)
+ local statements = LuaCode(self.source)
if prefix ~= "" then
statements:append(prefix)
end
@@ -272,7 +272,7 @@ do
local _list_1 = self.bits
for _index_0 = 1, #_list_1 do
local bit = _list_1[_index_0]
- if bit.__class == Lua then
+ if bit.__class == LuaCode then
gather_from(bit)
end
end
@@ -357,7 +357,7 @@ do
self.__str = nil
end,
__base = _base_0,
- __name = "Lua",
+ __name = "LuaCode",
__parent = _parent_0
}, {
__index = function(cls, name)
@@ -380,16 +380,15 @@ do
_base_0.__class = _class_0
local self = _class_0
self.Value = function(...)
- local lua = Lua(...)
+ local lua = LuaCode(...)
lua.is_value = true
return lua
end
if _parent_0.__inherited then
_parent_0.__inherited(_parent_0, _class_0)
end
- Lua = _class_0
+ LuaCode = _class_0
end
-local Nomsu
do
local _class_0
local _parent_0 = Code
@@ -423,7 +422,7 @@ do
return _class_0.__parent.__init(self, ...)
end,
__base = _base_0,
- __name = "Nomsu",
+ __name = "NomsuCode",
__parent = _parent_0
}, {
__index = function(cls, name)
@@ -447,11 +446,11 @@ do
if _parent_0.__inherited then
_parent_0.__inherited(_parent_0, _class_0)
end
- Nomsu = _class_0
+ NomsuCode = _class_0
end
return {
Code = Code,
- Nomsu = Nomsu,
- Lua = Lua,
+ NomsuCode = NomsuCode,
+ LuaCode = LuaCode,
Source = Source
}
diff --git a/code_obj.moon b/code_obj.moon
index d3de65c..3daed04 100644
--- a/code_obj.moon
+++ b/code_obj.moon
@@ -2,7 +2,7 @@
-- build up generated code, while keeping track of where it came from, and managing
-- indentation levels.
{:insert, :remove, :concat} = table
-local Lua, Source
+local LuaCode, NomsuCode, Source
export LINE_STARTS
class Source
@@ -99,7 +99,7 @@ class Code
else indents[i] = nil
@__str = nil
-class Lua extends Code
+class LuaCode extends Code
new: (...)=>
super ...
@free_vars = {}
@@ -107,7 +107,7 @@ class Lua extends Code
@__str = nil
@Value = (...)->
- lua = Lua(...)
+ lua = LuaCode(...)
lua.is_value = true
return lua
@@ -140,7 +140,7 @@ class Lua extends Code
as_statements: (prefix="", suffix=";")=>
unless @is_value
return self
- statements = Lua(@source)
+ statements = LuaCode(@source)
if prefix != ""
statements\append prefix
statements\append self
@@ -157,7 +157,7 @@ class Lua extends Code
seen[var] = true
to_declare[#to_declare+1] = var
for bit in *@bits
- if bit.__class == Lua
+ if bit.__class == LuaCode
gather_from bit
gather_from self
if #to_declare > 0
@@ -205,7 +205,7 @@ class Lua extends Code
else
error "Cannot parenthesize lua statements"
-class Nomsu extends Code
+class NomsuCode extends Code
__tostring: =>
if @__str == nil
buff, indents = {}, @indents
@@ -224,4 +224,4 @@ class Nomsu extends Code
@prepend "("
@append ")"
-return {:Code, :Nomsu, :Lua, :Source}
+return {:Code, :NomsuCode, :LuaCode, :Source}
diff --git a/core/collections.nom b/core/collections.nom
index 8a59852..69a51c7 100644
--- a/core/collections.nom
+++ b/core/collections.nom
@@ -9,162 +9,158 @@ use "core/operators.nom"
# List/dict functions:
# Indexing
-immediately
- compile [..]
- %index st to last in %list, %index nd to last in %list, %index rd to last in %list
- %index th to last in %list
- ..to: Lua value "utils.nth_to_last(\(%list as lua expr), \(%index as lua expr))"
+compile [..]
+ %index st to last in %list, %index nd to last in %list, %index rd to last in %list
+ %index th to last in %list
+..to: Lua value "utils.nth_to_last(\(%list as lua expr), \(%index as lua expr))"
-immediately
- parse [last in %list] as: 1st to last in %list
- parse [first in %list] as: %list.1
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+parse [last in %list] as: 1st to last in %list
+parse [first in %list] as: %list.1
# Membership testing
-immediately
- action [%item is in %list, %list contains %item, %list has %item]
- for %key = %value in %list
- if (%key is %item): return (yes)
- return (no)
-
- action [..]
- %item isn't in %list, %item is not in %list
- %list doesn't contain %item, %list does not contain %item
- %list doesn't have %item, %list does not have %item
- ..
- for %key = %value in %list
- if (%key is %item): return (no)
- return (yes)
-
-immediately
- parse [%list has key %index, %list has index %index] as
- %list.%index != (nil)
-
- parse [..]
- %list doesn't have key %index, %list does not have key %index
- %list doesn't have index %index, %list does not have index %index
- ..as
- %list.%index = (nil)
-
- compile [number of keys in %list] to
- Lua value "utils.size(\(%list as lua expr))"
-
- compile [append %item to %list, add %item to %list, to %list add %item, to %list append %item] to
- Lua "table.insert(\(%list as lua expr), \(%item as lua expr))"
-
- compile [pop from %list, remove last from %list] to
- Lua "table.remove(\(%list as lua expr))"
-
- compile [remove index %index from %list] to
- Lua "table.remove(\(%list as lua expr), \(%index as lua expr))"
+action [%item is in %list, %list contains %item, %list has %item]
+ for %key = %value in %list
+ if (%key is %item): return (yes)
+ return (no)
+
+action [..]
+ %item isn't in %list, %item is not in %list
+ %list doesn't contain %item, %list does not contain %item
+ %list doesn't have %item, %list does not have %item
+..
+ for %key = %value in %list
+ if (%key is %item): return (no)
+ return (yes)
+
+parse [%list has key %index, %list has index %index] as
+ %list.%index != (nil)
+
+parse [..]
+ %list doesn't have key %index, %list does not have key %index
+ %list doesn't have index %index, %list does not have index %index
+..as
+ %list.%index = (nil)
+
+compile [number of keys in %list] to
+ Lua value "utils.size(\(%list as lua expr))"
+
+compile [append %item to %list, add %item to %list, to %list add %item, to %list append %item] to
+ Lua "table.insert(\(%list as lua expr), \(%item as lua expr))"
+
+compile [pop from %list, remove last from %list] to
+ Lua "table.remove(\(%list as lua expr))"
+
+compile [remove index %index from %list] to
+ Lua "table.remove(\(%list as lua expr), \(%index as lua expr))"
# List Comprehension
-immediately
- parse [%expression for %item in %iterable] as
- result of
- %comprehension <- []
- for %item in %iterable
- add %expression to %comprehension
- return %comprehension
-
- parse [..]
- %expression for %index in %start to %stop via %step
- %expression for %index in %start to %stop by %step
- ..as
- result of
- %comprehension <- []
- for %index in %start to %stop via %step
- add %expression to %comprehension
- return %comprehension
-
- parse [%expression for %var in %start to %stop] as
- %expression for %var in %start to %stop via 1
-
- parse [..]
- %expression for %key = %value in %iterable
- %expression for (%key,%value) in %iterable
- ..as
- result of
- %comprehension <- []
- for %key = %value in %iterable
- add %expression to %comprehension
- return %comprehension
-
- # Dict comprehensions
- parse [..]
- %key = %value for %item in %iterable
- (%key,%value) for %item in %iterable
- ..as
- result of
- %comprehension <- {}
- for %item in %iterable
- %comprehension.%key <- %value
- return %comprehension
-
- parse [..]
- %key = %value for %src_key = %src_value in %iterable
- (%key,%value) for (%src_key,%src_value) in %iterable
- ..as
- result of
- %comprehension <- {}
- for %src_key = %src_value in %iterable
- %comprehension.%key <- %value
- return %comprehension
-
-immediately
- action [%lists flattened]
- %flat <- []
- for %list in %lists
- for %item in %list
- add %item to %flat
- return %flat
-
- parse [entries in %dict] as: {key:%k, value:%v} for %k = %v in %dict
- parse [keys in %dict, keys of %dict] as: %k for %k = %v in %dict
- parse [values in %dict, values of %dict] as: %v for %k = %v in %dict
+parse [%expression for %item in %iterable] as
+ result of
+ %comprehension <- []
+ for %item in %iterable
+ add %expression to %comprehension
+ return %comprehension
+
+parse [..]
+ %expression for %index in %start to %stop via %step
+ %expression for %index in %start to %stop by %step
+..as
+ result of
+ %comprehension <- []
+ for %index in %start to %stop via %step
+ add %expression to %comprehension
+ return %comprehension
+
+parse [%expression for %var in %start to %stop] as
+ %expression for %var in %start to %stop via 1
+
+parse [..]
+ %expression for %key = %value in %iterable
+ %expression for (%key,%value) in %iterable
+..as
+ result of
+ %comprehension <- []
+ for %key = %value in %iterable
+ add %expression to %comprehension
+ return %comprehension
+
+# Dict comprehensions
+parse [..]
+ %key = %value for %item in %iterable
+ (%key,%value) for %item in %iterable
+..as
+ result of
+ %comprehension <- {}
+ for %item in %iterable
+ %comprehension.%key <- %value
+ return %comprehension
+
+parse [..]
+ %key = %value for %src_key = %src_value in %iterable
+ (%key,%value) for (%src_key,%src_value) in %iterable
+..as
+ result of
+ %comprehension <- {}
+ for %src_key = %src_value in %iterable
+ %comprehension.%key <- %value
+ return %comprehension
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+action [%lists flattened]
+ %flat <- []
+ for %list in %lists
+ for %item in %list
+ add %item to %flat
+ return %flat
+
+parse [entries in %dict] as: {key:%k, value:%v} for %k = %v in %dict
+parse [keys in %dict, keys of %dict] as: %k for %k = %v in %dict
+parse [values in %dict, values of %dict] as: %v for %k = %v in %dict
# Metatable stuff
-immediately
- compile [set %dict's metatable to %metatable] to
- Lua "setmetatable(\(%dict as lua expr), \(%metatable as lua expr));"
-
- compile [%dict with fallback %key -> %value] to
- Lua value ".."
- setmetatable(\(%dict as lua expr), {__index=function(self, \(%key as lua expr))
- local value = \(%value as lua expr)
- self[\(%key as lua expr)] = value
- return value
- end})
+compile [set %dict's metatable to %metatable] to
+ Lua "setmetatable(\(%dict as lua expr), \(%metatable as lua expr));"
+
+compile [%dict with fallback %key -> %value] to
+ Lua value ".."
+ setmetatable(\(%dict as lua expr), {__index=function(self, \(%key as lua expr))
+ local value = \(%value as lua expr)
+ self[\(%key as lua expr)] = value
+ return value
+ end})
# Sorting
-immediately
- compile [sort %items] to: Lua "table.sort(\(%items as lua expr));"
- parse [..]
- sort %items by %item = %key_expr
- sort %items by %item -> %key_expr
- ..as
- do
- %keys <- ({} with fallback %item -> %key_expr)
- lua> "table.sort(\%items, function(x,y) return \%keys[x] < \%keys[y] end)"
-
-immediately
- action [%items sorted, sorted %items]
- %copy <- (% for % in %items)
- sort %copy
- return %copy
- action [..]
- %items sorted by %item = %key
- %items sorted by %item -> %key
- ..
- %copy <- (% for % in %items)
- sort %copy by %item = %key
- return %copy
-
- action [unique %items]
- %unique <- []
- %seen <- {}
- for % in %items
- unless: %seen.%
- add % to %unique
- %seen.% <- (yes)
- return %unique
+compile [sort %items] to: Lua "table.sort(\(%items as lua expr));"
+parse [..]
+ sort %items by %item = %key_expr
+ sort %items by %item -> %key_expr
+..as
+ do
+ %keys <- ({} with fallback %item -> %key_expr)
+ lua> "table.sort(\%items, function(x,y) return \%keys[x] < \%keys[y] end)"
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+action [%items sorted, sorted %items]
+ %copy <- (% for % in %items)
+ sort %copy
+ return %copy
+action [..]
+ %items sorted by %item = %key
+ %items sorted by %item -> %key
+..
+ %copy <- (% for % in %items)
+ sort %copy by %item = %key
+ return %copy
+
+action [unique %items]
+ %unique <- []
+ %seen <- {}
+ for % in %items
+ unless: %seen.%
+ add % to %unique
+ %seen.% <- (yes)
+ return %unique
diff --git a/core/control_flow.nom b/core/control_flow.nom
index 15c1ca1..fccdfca 100644
--- a/core/control_flow.nom
+++ b/core/control_flow.nom
@@ -8,387 +8,381 @@ use "core/operators.nom"
use "core/errors.nom"
# No-Op
-immediately
- compile [do nothing] to: Lua ""
+compile [do nothing] to: Lua ""
# Conditionals
-immediately
- compile [if %condition %if_body] to
- Lua ".."
- if \(%condition as lua expr) then
- \(%if_body as lua statements)
- end
- parse [unless %condition %unless_body] as: if (not %condition) %unless_body
-
- compile [if %condition %if_body else %else_body, unless %condition %else_body else %if_body] to
- Lua ".."
- if \(%condition as lua expr) then
- \(%if_body as lua statements)
- else
- \(%else_body as lua statements)
- end
+compile [if %condition %if_body] to
+ Lua ".."
+ if \(%condition as lua expr) then
+ \(%if_body as lua statements)
+ end
+parse [unless %condition %unless_body] as: if (not %condition) %unless_body
+
+compile [if %condition %if_body else %else_body, unless %condition %else_body else %if_body] to
+ Lua ".."
+ if \(%condition as lua expr) then
+ \(%if_body as lua statements)
+ else
+ \(%else_body as lua statements)
+ end
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Conditional expression (ternary operator)
# Note: this uses a function instead of "(condition and if_expr or else_expr)"
because that breaks if %if_expr is falsey, e.g. "x < 5 and false or 99"
-immediately
- compile [..]
- %when_true_expr if %condition else %when_false_expr
- %when_true_expr if %condition otherwise %when_false_expr
- %when_false_expr unless %condition else %when_true_expr
- %when_false_expr unless %condition then %when_true_expr
- ..to
- # If %when_true_expr is guaranteed to be truthy, we can use Lua's idiomatic
- equivalent of a conditional expression: (cond and if_true or if_false)
- if: {Text:yes, List:yes, Dict:yes, Number:yes}.(%when_true_expr.type)
- return
- Lua value ".."
- (\(%condition as lua expr) and \(%when_true_expr as lua expr) or \(%when_false_expr as lua expr))
- ..else
- # Otherwise, need to do an anonymous inline function (yuck, too bad lua
- doesn't have a proper ternary operator!)
- To see why this is necessary consider: (random()<.5 and false or 99)
- return
- Lua value ".."
- ((function()
- if \(%condition as lua expr) then
- return \(%when_true_expr as lua expr)
- else
- return \(%when_false_expr as lua expr)
- end
- end)())
+compile [..]
+ %when_true_expr if %condition else %when_false_expr
+ %when_true_expr if %condition otherwise %when_false_expr
+ %when_false_expr unless %condition else %when_true_expr
+ %when_false_expr unless %condition then %when_true_expr
+..to
+ # If %when_true_expr is guaranteed to be truthy, we can use Lua's idiomatic
+ equivalent of a conditional expression: (cond and if_true or if_false)
+ if: {Text:yes, List:yes, Dict:yes, Number:yes}.(%when_true_expr.type)
+ return
+ Lua value ".."
+ (\(%condition as lua expr) and \(%when_true_expr as lua expr) or \(%when_false_expr as lua expr))
+ ..else
+ # Otherwise, need to do an anonymous inline function (yuck, too bad lua
+ doesn't have a proper ternary operator!)
+ To see why this is necessary consider: (random()<.5 and false or 99)
+ return
+ Lua value ".."
+ ((function()
+ if \(%condition as lua expr) then
+ return \(%when_true_expr as lua expr)
+ else
+ return \(%when_false_expr as lua expr)
+ end
+ end)())
# GOTOs
-immediately
- compile [=== %label ===, --- %label ---, *** %label ***] to
- Lua "::label_\(%label as lua identifier)::"
- compile [go to %label] to
- Lua "goto label_\(%label as lua identifier)"
+compile [=== %label ===, --- %label ---, *** %label ***] to
+ Lua "::label_\(%label as lua identifier)::"
+compile [go to %label] to
+ Lua "goto label_\(%label as lua identifier)"
# Basic loop control
-immediately
- compile [do next] to: Lua "continue"
- compile [stop] to: Lua "break"
+compile [do next] to: Lua "continue"
+compile [stop] to: Lua "break"
# Helper function
-immediately
- compile [%tree has subtree %subtree where %condition] to
- Lua value ".."
- (function()
- for \(%subtree as lua expr) in coroutine.wrap(function() \(%tree as lua expr):map(coroutine.yield) end) do
- if \(%condition as lua expr) then
- return true
- end
+#TODO: do "using % compile %" instead so it's actually a helper function
+compile [%tree has subtree %subtree where %condition] to
+ Lua value ".."
+ (function()
+ for \(%subtree as lua expr) in coroutine.wrap(function() \(%tree as lua expr):map(coroutine.yield) end) do
+ if \(%condition as lua expr) then
+ return true
end
- return false
- end)()
+ end
+ return false
+ end)()
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# While loops
-immediately
- compile [do next repeat] to: Lua "goto continue_repeat"
- compile [stop repeating] to: Lua "goto stop_repeat"
- compile [repeat while %condition %body] to
+compile [do next repeat] to: Lua "goto continue_repeat"
+compile [stop repeating] to: Lua "goto stop_repeat"
+compile [repeat while %condition %body] to
+ %lua <-
+ Lua ".."
+ while \(%condition as lua expr) do
+ \(%body as lua statements)
+ if
+ %body has subtree % where: (%.type = "Action") and (%.stub is "do next repeat")
+ ..: to %lua write "\n ::continue_repeat::"
+ to %lua write "\nend --while-loop"
+ if
+ %body has subtree % where: (%.type = "Action") and (%.stub is "stop repeating")
+ ..
%lua <-
Lua ".."
- while \(%condition as lua expr) do
- \(%body as lua statements)
- if
- %body has subtree % where: (%.type = "Action") and (%.stub is "do next repeat")
- ..: to %lua write "\n ::continue_repeat::"
- to %lua write "\nend --while-loop"
- if
- %body has subtree % where: (%.type = "Action") and (%.stub is "stop repeating")
- ..
- %lua <-
- Lua ".."
- do -- scope of "stop repeating" label
- \%lua
- ::stop_repeat::
- end -- end of "stop repeating" label scope
- return %lua
- parse [repeat %body] as: repeat while (yes) %body
- parse [repeat until %condition %body] as: repeat while (not %condition) %body
-
- compile [..]
- repeat %n times %body
- ..to
+ do -- scope of "stop repeating" label
+ \%lua
+ ::stop_repeat::
+ end -- end of "stop repeating" label scope
+ return %lua
+parse [repeat %body] as: repeat while (yes) %body
+parse [repeat until %condition %body] as: repeat while (not %condition) %body
+
+compile [..]
+ repeat %n times %body
+..to
+ %lua <-
+ Lua ".."
+ for i=1,\(%n as lua expr) do
+ \(%body as lua statements)
+ if
+ %body has subtree % where: (%.type = "Action") and (%.stub is "do next repeat")
+ ..: to %lua write "\n ::continue_repeat::"
+ to %lua write "\nend --numeric for-loop"
+ if
+ %body has subtree % where: (%.type = "Action") and (%.stub is "stop repeating")
+ ..
%lua <-
Lua ".."
- for i=1,\(%n as lua expr) do
- \(%body as lua statements)
- if
- %body has subtree % where: (%.type = "Action") and (%.stub is "do next repeat")
- ..: to %lua write "\n ::continue_repeat::"
- to %lua write "\nend --numeric for-loop"
- if
- %body has subtree % where: (%.type = "Action") and (%.stub is "stop repeating")
- ..
- %lua <-
- Lua ".."
- do -- scope of "stop repeating" label
- \%lua
- ::stop_repeat::
- end -- end of "stop repeating" label scope
- return %lua
+ do -- scope of "stop repeating" label
+ \%lua
+ ::stop_repeat::
+ end -- end of "stop repeating" label scope
+ return %lua
# For loop control flow
-immediately
- compile [stop %var] to
- Lua "goto stop_\(%var as lua identifier)"
- compile [do next %var] to
- Lua "goto continue_\(%var as lua identifier)"
+compile [stop %var] to
+ Lua "goto stop_\(%var as lua identifier)"
+compile [do next %var] to
+ Lua "goto continue_\(%var as lua identifier)"
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Numeric range for loops
-immediately
- compile [..]
- for %var in %start to %stop by %step %body
- for %var in %start to %stop via %step %body
- ..to
- # This uses Lua's approach of only allowing loop-scoped variables in a loop
- assume (%var.type is "Var") or barf "Loop expected variable, not: \%var"
+compile [..]
+ for %var in %start to %stop by %step %body
+ for %var in %start to %stop via %step %body
+..to
+ # This uses Lua's approach of only allowing loop-scoped variables in a loop
+ assume (%var.type is "Var") or barf "Loop expected variable, not: \%var"
+ %lua <-
+ Lua ".."
+ for \(%var as lua expr)=\(%start as lua expr),\(%stop as lua expr),\(%step as lua expr) do
+ \(%body as lua statements)
+ if
+ %body has subtree % where
+ (%.type = "Action") and
+ (%.stub is "do next %") and
+ %.3 = %var
+ ..: to %lua write "\n ::continue_\(%var as lua identifier)::"
+ to %lua write "\nend --numeric for-loop"
+
+ if
+ %body has subtree % where
+ (%.type = "Action") and
+ (%.stub is "stop %") and
+ %.2 = %var
+ ..
%lua <-
Lua ".."
- for \(%var as lua expr)=\(%start as lua expr),\(%stop as lua expr),\(%step as lua expr) do
- \(%body as lua statements)
- if
- %body has subtree % where
- (%.type = "Action") and
- (%.stub is "do next %") and
- %.3 = %var
- ..: to %lua write "\n ::continue_\(%var as lua identifier)::"
- to %lua write "\nend --numeric for-loop"
-
- if
- %body has subtree % where
- (%.type = "Action") and
- (%.stub is "stop %") and
- %.2 = %var
- ..
- %lua <-
- Lua ".."
- do -- scope for stopping for-loop
- \%lua
- ::stop_\(%var as lua identifier)::
- end -- end of scope for stopping for-loop
+ do -- scope for stopping for-loop
+ \%lua
+ ::stop_\(%var as lua identifier)::
+ end -- end of scope for stopping for-loop
+
+ return %lua
- return %lua
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-immediately
- parse [for %var in %start to %stop %body] as: for %var in %start to %stop via 1 %body
+parse [for %var in %start to %stop %body] as: for %var in %start to %stop via 1 %body
# For-each loop (lua's "ipairs()")
-immediately
- compile [for %var in %iterable %body] to
- # This uses Lua's approach of only allowing loop-scoped variables in a loop
- assume (%var.type is "Var") or barf "Loop expected variable, not: \%var"
+compile [for %var in %iterable %body] to
+ # This uses Lua's approach of only allowing loop-scoped variables in a loop
+ assume (%var.type is "Var") or barf "Loop expected variable, not: \%var"
+ %lua <-
+ Lua ".."
+ for i,\(%var as lua identifier) in ipairs(\(%iterable as lua expr)) do
+ \(%body as lua statements)
+ if
+ %body has subtree % where
+ (%.type = "Action") and
+ (%.stub is "do next %") and
+ %.3.(1) = %var.(1)
+ ..: to %lua write (Lua "\n ::continue_\(%var as lua identifier)::")
+ to %lua write "\nend --foreach-loop"
+ if
+ %body has subtree % where
+ (%.type = "Action") and
+ (%.stub is "stop %") and
+ %.2.(1) = %var.(1)
+ ..
%lua <-
Lua ".."
- for i,\(%var as lua identifier) in ipairs(\(%iterable as lua expr)) do
- \(%body as lua statements)
- if
- %body has subtree % where
- (%.type = "Action") and
- (%.stub is "do next %") and
- %.3.(1) = %var.(1)
- ..: to %lua write (Lua "\n ::continue_\(%var as lua identifier)::")
- to %lua write "\nend --foreach-loop"
- if
- %body has subtree % where
- (%.type = "Action") and
- (%.stub is "stop %") and
- %.2.(1) = %var.(1)
- ..
- %lua <-
- Lua ".."
- do -- scope for stopping for-loop
- \%lua
- ::stop_\(%var as lua identifier)::
- end -- end of scope for stopping for-loop
- return %lua
+ do -- scope for stopping for-loop
+ \%lua
+ ::stop_\(%var as lua identifier)::
+ end -- end of scope for stopping for-loop
+ return %lua
# Dict iteration (lua's "pairs()")
-immediately
- compile [..]
- for %key = %value in %iterable %body
- for (%key,%value) in %iterable %body
- ..to
- # This uses Lua's approach of only allowing loop-scoped variables in a loop
- assume (%key.type is "Var") or barf "Loop expected variable, not: \%key"
- assume (%value.type is "Var") or barf "Loop expected variable, not: \%value"
+compile [..]
+ for %key = %value in %iterable %body
+ for (%key,%value) in %iterable %body
+..to
+ # This uses Lua's approach of only allowing loop-scoped variables in a loop
+ assume (%key.type is "Var") or barf "Loop expected variable, not: \%key"
+ assume (%value.type is "Var") or barf "Loop expected variable, not: \%value"
+ %lua <-
+ Lua ".."
+ for \(%key as lua identifier),\(%value as lua identifier) in pairs(\(%iterable as lua expr)) do
+ \(%body as lua statements)
+ if
+ %body has subtree % where
+ (%.type = "Action") and
+ (%.stub is "do next %") and
+ %.3.(1) = %key.(1)
+ ..: to %lua write (Lua "\n ::continue_\(%key as lua identifier)::")
+
+ if
+ %body has subtree % where
+ (%.type = "Action") and
+ (%.stub is "do next %") and
+ %.3.(1) = %value.(1)
+ ..: to %lua write (Lua "\n ::continue_\(%value as lua identifier)::")
+ to %lua write "\nend --foreach-loop"
+
+ %stop_labels <- (Lua "")
+ if
+ %body has subtree % where
+ (%.type = "Action") and
+ (%.stub is "stop %") and
+ %.2.(1) = %key.(1)
+ ..: to %stop_labels write "\n::stop_\(%key as lua identifier)::"
+
+ if
+ %body has subtree % where
+ (%.type = "Action") and
+ (%.stub is "stop %") and
+ %.2.(1) = %value.(1)
+ ..: to %stop_labels write "\n::stop_\(%value as lua identifier)::"
+
+ if: (length of %stop_labels) > 0
%lua <-
Lua ".."
- for \(%key as lua identifier),\(%value as lua identifier) in pairs(\(%iterable as lua expr)) do
- \(%body as lua statements)
- if
- %body has subtree % where
- (%.type = "Action") and
- (%.stub is "do next %") and
- %.3.(1) = %key.(1)
- ..: to %lua write (Lua "\n ::continue_\(%key as lua identifier)::")
-
- if
- %body has subtree % where
- (%.type = "Action") and
- (%.stub is "do next %") and
- %.3.(1) = %value.(1)
- ..: to %lua write (Lua "\n ::continue_\(%value as lua identifier)::")
- to %lua write "\nend --foreach-loop"
-
- %stop_labels <- (Lua "")
- if
- %body has subtree % where
- (%.type = "Action") and
- (%.stub is "stop %") and
- %.2.(1) = %key.(1)
- ..: to %stop_labels write "\n::stop_\(%key as lua identifier)::"
-
- if
- %body has subtree % where
- (%.type = "Action") and
- (%.stub is "stop %") and
- %.2.(1) = %value.(1)
- ..: to %stop_labels write "\n::stop_\(%value as lua identifier)::"
-
- if: (length of %stop_labels) > 0
- %lua <-
- Lua ".."
- do -- scope for stopping for % = % loop
- \%lua
- \%stop_labels
- end
- return %lua
+ do -- scope for stopping for % = % loop
+ \%lua
+ \%stop_labels
+ end
+ return %lua
-# Switch statement/multi-branch if
-immediately
- compile [when %body] to
- %code <- (Lua "")
- %fallthroughs <- []
- %is_first <- (yes)
- %seen_else <- (no)
- %branches <-
- %body if (%body.type = "Block") else [%body]
- for %func_call in %branches
- assume (%func_call.type is "Action") or barf ".."
- Invalid format for 'when' statement. Only '*' blocks are allowed.
- with {..}
- %star: %func_call.1
- %condition: %func_call.2
- %action: %func_call.3
- ..
- assume (%star = "*") or barf ".."
- Invalid format for 'when' statement. Lines must begin with '*'
- assume %condition or barf ".."
- Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else"
- if: %action is (nil)
- lua> "table.insert(\%fallthroughs, \(%condition as lua expr))"
- do next %func_call
-
- if: %condition = "else"
- assume (not %is_first) or barf "'else' clause cannot be first in 'when % = ?' block"
- to %code write "\nelse\n "
- to %code write: %action as lua statements
- %seen_else <- (yes)
- ..else
- assume (not %seen_else) or barf "'else' clause needs to be last in 'when' block"
- lua> "table.insert(\%fallthroughs, \(%condition as lua expr))"
- to %code write "\("if" if %is_first else "\nelseif") "
- for %i = %condition in %fallthroughs
- if (%i > 1): to %code write " or "
- to %code write %condition
- to %code write " then\n "
- to %code write (%action as lua statements)
-
- %fallthroughs <- []
- %is_first <- (no)
-
- assume (%fallthroughs = []) or barf "Unfinished fallthrough conditions in 'when' block"
- assume ((length of %code) > 0) or barf "Empty body for 'when' block"
- to %code write "\nend --when"
- return %code
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-# Switch statement
-immediately
- compile [when %branch_value = ? %body, when %branch_value is ? %body] to
- %code <- (Lua "")
- %fallthroughs <- []
- %is_first <- (yes)
- %seen_else <- (no)
- %branches <-
- %body if (%body.type = "Block") else [%body]
- for %func_call in %branches
- assume (%func_call.type is "Action") or barf ".."
- Invalid format for 'when' statement. Only '*' blocks are allowed.
- with {%star:%func_call.1, %condition:%func_call.2, %action:%func_call.3}
- assume (%star = "*") or barf ".."
- Invalid format for 'when' statement. Lines must begin with '*'
- assume %condition or barf ".."
- Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else"
- if: %action is (nil)
- lua> "table.insert(\%fallthroughs, \(%condition as lua expr))"
- do next %func_call
-
- if: %condition = "else"
- assume (not %is_first) or barf "'else' clause cannot be first in 'when % = ?' block"
- to %code write "\nelse\n "
- to %code write: %action as lua statements
- ..else
- assume (not %seen_else) or barf "'else' clause needs to be last in 'when % = ?' block"
- to %code write "\("if" if %is_first else "\nelseif") "
- lua> "table.insert(\%fallthroughs, \(%condition as lua expr))"
- for %i = % in %fallthroughs
- if: %i > 1
- to %code write " or "
- if: (%.type is "Text") or (%.type is "Number")
- to %code write "branch_value == \%"
- ..else
- to %code write "utils.equivalent(branch_value, \%)"
- to %code write "then\n "
- to %code write (%action as lua statements)
+# Switch statement/multi-branch if
+compile [when %body] to
+ %code <- (Lua "")
+ %fallthroughs <- []
+ %is_first <- (yes)
+ %seen_else <- (no)
+ %branches <-
+ %body if (%body.type = "Block") else [%body]
+ for %func_call in %branches
+ assume (%func_call.type is "Action") or barf ".."
+ Invalid format for 'when' statement. Only '*' blocks are allowed.
+ with {..}
+ %star: %func_call.1
+ %condition: %func_call.2
+ %action: %func_call.3
+ ..
+ assume (%star = "*") or barf ".."
+ Invalid format for 'when' statement. Lines must begin with '*'
+ assume %condition or barf ".."
+ Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else"
+ if: %action is (nil)
+ lua> "table.insert(\%fallthroughs, \(%condition as lua expr))"
+ do next %func_call
+
+ if: %condition = "else"
+ assume (not %is_first) or barf "'else' clause cannot be first in 'when % = ?' block"
+ to %code write "\nelse\n "
+ to %code write: %action as lua statements
+ %seen_else <- (yes)
+ ..else
+ assume (not %seen_else) or barf "'else' clause needs to be last in 'when' block"
+ lua> "table.insert(\%fallthroughs, \(%condition as lua expr))"
+ to %code write "\("if" if %is_first else "\nelseif") "
+ for %i = %condition in %fallthroughs
+ if (%i > 1): to %code write " or "
+ to %code write %condition
+ to %code write " then\n "
+ to %code write (%action as lua statements)
%fallthroughs <- []
%is_first <- (no)
-
- assume (%fallthroughs = []) or barf "Unfinished fallthrough conditions in 'when' block"
- assume ((length of %code) > 0) or barf "No body for 'when % = ?' block!"
- to %code write "\nend"
- %code <-
- Lua ".."
- do --when % = ?
- local branch_value = \(%branch_value as lua expr)
- \%code
- end --when % = ?
- return %code
+ assume (%fallthroughs = []) or barf "Unfinished fallthrough conditions in 'when' block"
+ assume ((length of %code) > 0) or barf "Empty body for 'when' block"
+ to %code write "\nend --when"
+ return %code
-# Do/finally
-immediately
- compile [do %action] to
- Lua ".."
- do
- \(%action as lua statements)
- end --do
+# Switch statement
+compile [when %branch_value = ? %body, when %branch_value is ? %body] to
+ %code <- (Lua "")
+ %fallthroughs <- []
+ %is_first <- (yes)
+ %seen_else <- (no)
+ %branches <-
+ %body if (%body.type = "Block") else [%body]
+ for %func_call in %branches
+ assume (%func_call.type is "Action") or barf ".."
+ Invalid format for 'when' statement. Only '*' blocks are allowed.
+ with {%star:%func_call.1, %condition:%func_call.2, %action:%func_call.3}
+ assume (%star = "*") or barf ".."
+ Invalid format for 'when' statement. Lines must begin with '*'
+ assume %condition or barf ".."
+ Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else"
+ if: %action is (nil)
+ lua> "table.insert(\%fallthroughs, \(%condition as lua expr))"
+ do next %func_call
+
+ if: %condition = "else"
+ assume (not %is_first) or barf "'else' clause cannot be first in 'when % = ?' block"
+ to %code write "\nelse\n "
+ to %code write: %action as lua statements
+ ..else
+ assume (not %seen_else) or barf "'else' clause needs to be last in 'when % = ?' block"
+ to %code write "\("if" if %is_first else "\nelseif") "
+ lua> "table.insert(\%fallthroughs, \(%condition as lua expr))"
+ for %i = % in %fallthroughs
+ if: %i > 1
+ to %code write " or "
+ if: (%.type is "Text") or (%.type is "Number")
+ to %code write "branch_value == \%"
+ ..else
+ to %code write "utils.equivalent(branch_value, \%)"
+ to %code write "then\n "
+ to %code write (%action as lua statements)
- compile [do %action then always %final_action] to
+ %fallthroughs <- []
+ %is_first <- (no)
+
+ assume (%fallthroughs = []) or barf "Unfinished fallthrough conditions in 'when' block"
+ assume ((length of %code) > 0) or barf "No body for 'when % = ?' block!"
+ to %code write "\nend"
+ %code <-
Lua ".."
- do
- local fell_through = false
- local ok, ret = pcall(function()
- \(%action as lua statements)
- fell_through = true
- end)
- \(%final_action as lua statements)
- if not ok then error(ret, 0) end
- if not fell_through then return ret end
- end
+ do --when % = ?
+ local branch_value = \(%branch_value as lua expr)
+ \%code
+ end --when % = ?
+ return %code
+
+# Do/finally
+compile [do %action] to
+ Lua ".."
+ do
+ \(%action as lua statements)
+ end --do
+
+compile [do %action then always %final_action] to
+ Lua ".."
+ do
+ local fell_through = false
+ local ok, ret = pcall(function()
+ \(%action as lua statements)
+ fell_through = true
+ end)
+ \(%final_action as lua statements)
+ if not ok then error(ret, 0) end
+ if not fell_through then return ret end
+ end
# Inline thunk:
-immediately
- compile [result of %body] to
- %body <- (%body as lua statements)
- declare locals in %body
- return
- Lua value ".."
- (function()
- \%body
- end)()
+compile [result of %body] to
+ %body <- (%body as lua statements)
+ declare locals in %body
+ return
+ Lua value ".."
+ (function()
+ \%body
+ end)()
diff --git a/core/errors.nom b/core/errors.nom
index 8c6261a..812052e 100644
--- a/core/errors.nom
+++ b/core/errors.nom
@@ -22,47 +22,47 @@ compile [assume %condition or barf %message] to
end
# Try/except
-immediately
- compile [..]
- try %action and if it succeeds %success or if it barfs %msg %fallback
- try %action and if it barfs %msg %fallback or if it succeeds %success
- ..to
- Lua ".."
- do
- local fell_through = false
- local err, erred = nil, false
- local ok, ret = xpcall(function()
- \(%action as lua statements)
- fell_through = true
- end, function(\(%msg as lua expr))
- local ok, ret = pcall(function()
- \(%fallback as lua statements)
- end)
- if not ok then err, erred = ret, true end
+compile [..]
+ try %action and if it succeeds %success or if it barfs %msg %fallback
+ try %action and if it barfs %msg %fallback or if it succeeds %success
+..to
+ Lua ".."
+ do
+ local fell_through = false
+ local err, erred = nil, false
+ local ok, ret = xpcall(function()
+ \(%action as lua statements)
+ fell_through = true
+ end, function(\(%msg as lua expr))
+ local ok, ret = pcall(function()
+ \(%fallback as lua statements)
end)
- if ok then
- \(%success as lua statements)
- if not fell_through then
- return ret
- end
- elseif erred then
- error(err, 0)
+ if not ok then err, erred = ret, true end
+ end)
+ if ok then
+ \(%success as lua statements)
+ if not fell_through then
+ return ret
end
+ elseif erred then
+ error(err, 0)
end
-immediately
- parse [..]
- try %action and if it succeeds %success or if it barfs %fallback
- try %action and if it barfs %fallback or if it succeeds %success
- ..as: try %action and if it succeeds %success or if it barfs (=lua "") %fallback
-immediately
- parse [try %action] as
- try %action and if it succeeds: do nothing
- ..or if it barfs: do nothing
- parse [try %action and if it barfs %fallback] as
- try %action and if it succeeds: do nothing
- ..or if it barfs %fallback
- parse [try %action and if it barfs %msg %fallback] as
- try %action and if it succeeds: do nothing
- ..or if it barfs %msg %fallback
- parse [try %action and if it succeeds %success] as
- try %action and if it succeeds %success or if it barfs: do nothing
+ end
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+parse [..]
+ try %action and if it succeeds %success or if it barfs %fallback
+ try %action and if it barfs %fallback or if it succeeds %success
+..as: try %action and if it succeeds %success or if it barfs (=lua "") %fallback
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+parse [try %action] as
+ try %action and if it succeeds: do nothing
+ ..or if it barfs: do nothing
+parse [try %action and if it barfs %fallback] as
+ try %action and if it succeeds: do nothing
+ ..or if it barfs %fallback
+parse [try %action and if it barfs %msg %fallback] as
+ try %action and if it succeeds: do nothing
+ ..or if it barfs %msg %fallback
+parse [try %action and if it succeeds %success] as
+ try %action and if it succeeds %success or if it barfs: do nothing
diff --git a/core/io.nom b/core/io.nom
index 4f12e57..751650d 100644
--- a/core/io.nom
+++ b/core/io.nom
@@ -6,15 +6,15 @@ use "core/metaprogramming.nom"
compile [say %message] to
lua> ".."
if \%message.type == "Text" then
- return Lua(tree.source, "io.write(", \(%message as lua expr), ", '\\\\n');");
+ return LuaCode(tree.source, "io.write(", \(%message as lua expr), ", '\\\\n');");
else
- return Lua(tree.source, "io.write(tostring(", \(%message as lua expr), "), '\\\\n');");
+ return LuaCode(tree.source, "io.write(tostring(", \(%message as lua expr), "), '\\\\n');");
end
compile [ask %prompt] to
lua> ".."
if \%prompt.type == "Text" then
- return Lua.Value(tree.source, "(io.write(", \(%prompt as lua expr), ") and io.read())");
+ return LuaCode.Value(tree.source, "(io.write(", \(%prompt as lua expr), ") and io.read())");
else
- return Lua.Value(tree.source, "(io.write(tostring(", \(%prompt as lua expr), ")) and io.read())");
+ return LuaCode.Value(tree.source, "(io.write(tostring(", \(%prompt as lua expr), ")) and io.read())");
end
diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom
index 82447b3..d04ced3 100644
--- a/core/metaprogramming.nom
+++ b/core/metaprogramming.nom
@@ -3,89 +3,122 @@
functions to make that easier.
# Compile-time action to make compile-time actions:
-immediately
- lua> ".."
- A_give_1_nickname_2 = compile_time(function(tree, \%action, \%nickname, is_compile_time)
- local function arg_to_string(a) return tostring(nomsu:tree_to_lua(a)) end
- local action_args = table.map(\%action:get_args(), arg_to_string)
- local nickname_args = table.map(\%nickname:get_args(), arg_to_string)
- if utils.equivalent(action_args, nickname_args) then
- return Lua(tree.source, "A", string.as_lua_id(\%nickname.stub), " = A", string.as_lua_id(\%action.stub))
- end
- local lua = Lua(tree.source, "A", string.as_lua_id(\%nickname.stub), " = ")
- if is_compile_time or COMPILE_TIME[_ENV["A"..string.as_lua_id(\%action.stub)]] then
- lua:append("compile_time")
- table.insert(action_args, 1, "tree")
- table.insert(nickname_args, 1, "tree")
+lua> ".."
+ nomsu.COMPILE_ACTIONS["give % nickname %"] = (function(nomsu, tree, \%action, \%nickname, is_compile_time)
+ local function arg_to_string(a) return tostring(nomsu:compile(a)) end
+ local action_args = table.map(\%action:get_args(), arg_to_string)
+ local nickname_args = table.map(\%nickname:get_args(), arg_to_string)
+ if utils.equivalent(action_args, nickname_args) then
+ if is_compile_time then
+ return LuaCode(tree.source, "nomsu.COMPILE_ACTIONS[", repr(\%nickname.stub), "] = nomsu.COMPILE_ACTIONS[", repr(\%action.stub), "]")
+ else
+ return LuaCode(tree.source, "A", string.as_lua_id(\%nickname.stub), " = A", string.as_lua_id(\%action.stub))
end
- lua:append("(function(")
- lua:concat_append(nickname_args, ", ")
+ end
+ local lua = LuaCode(tree.source)
+ if is_compile_time then
+ lua:append("nomsu.COMPILE_ACTIONS[", repr(\%nickname.stub), "] = ")
+ table.insert(action_args, 1, "nomsu")
+ table.insert(nickname_args, 1, "nomsu")
+ table.insert(action_args, 2, "tree")
+ table.insert(nickname_args, 2, "tree")
+ else
+ lua:append("A", string.as_lua_id(\%nickname.stub), " = ")
+ end
+ lua:append("(function(")
+ lua:concat_append(nickname_args, ", ")
+ if is_compile_time then
+ lua:append(")\n return nomsu.COMPILE_ACTIONS[", repr(\%action.stub), "](")
+ else
lua:append(")\n return A", string.as_lua_id(\%action.stub), "(")
- lua:concat_append(action_args, ", ")
- lua:append(")\nend)")
- return lua
- end)
-
- __MANGLE_INDEX = 0
- A_parse_1_as_2 = compile_time(function(tree, \%actions, \%body)
- local replacements = {}
- for i,arg in ipairs(\%actions[1]:get_args()) do
- replacements[arg[1]] = tostring(nomsu:tree_to_lua(arg))
- end
- local function make_tree(t)
- if not AST.is_syntax_tree(t) then
- return repr(t)
- elseif t.type ~= 'Var' then
- local args = table.map(t, make_tree)
- table.insert(args, 1, repr(tostring(t.source)))
- return t.type.."("..table.concat(args, ", ")..")"
- elseif replacements[t[1]] then
- return replacements[t[1]]
- else
- return t.type.."("..repr(tostring(t.source))..", "..repr(t[1].." \\0").."..('%X'):format(__MANGLE_INDEX))"
- end
- end
- local lua = Lua(tree.source, "A", string.as_lua_id(\%actions[1].stub), " = compile_time(function(tree")
- for _,arg in ipairs(\%actions[1]:get_args()) do
- lua:append(", ", nomsu:tree_to_lua(arg))
- end
- lua:append(")\n __MANGLE_INDEX = __MANGLE_INDEX + 1",
- "\n local tree = ", make_tree(\%body),
- "\n local lua = nomsu:tree_to_lua(tree)",
- "\n lua:remove_free_vars({")
- local vars = table.map(\%actions[1]:get_args(), function(a)
- return "Var("..repr(tostring(a.source))..", "..repr(a[1])..")"
- end)
- lua:concat_append(vars, ", ")
- lua:append("})\n return lua\nend)")
-
- for i=2,#\%actions do
- lua:append("\n", A_give_1_nickname_2(\%actions[i], \%actions[1], \%actions[i], true))
+ end
+ lua:concat_append(action_args, ", ")
+ lua:append(")\nend)")
+ if not is_compile_time then
+ lua:add_free_vars({"A"..string.as_lua_id(\%nickname.stub)})
+ end
+ return lua
+ end)
+
+ __MANGLE_INDEX = 0
+ nomsu.COMPILE_ACTIONS["parse % as %"] = (function(nomsu, tree, \%actions, \%body)
+ local replacements = {}
+ for i,arg in ipairs(\%actions[1]:get_args()) do
+ replacements[arg[1]] = tostring(nomsu:compile(arg))
+ end
+ local function make_tree(t)
+ if not AST.is_syntax_tree(t) then
+ return repr(t)
+ elseif t.type ~= 'Var' then
+ local args = table.map(t, make_tree)
+ table.insert(args, 1, repr(tostring(t.source)))
+ return t.type.."("..table.concat(args, ", ")..")"
+ elseif replacements[t[1]] then
+ return replacements[t[1]]
+ else
+ return t.type.."("..repr(tostring(t.source))..", "..repr(t[1].." \\0").."..('%X'):format(__MANGLE_INDEX))"
end
- return lua
- end)
-
- A_action_1_2 = compile_time(function(tree, \%actions, \%body, is_compile_time)
- local lua = Lua(tree.source, "A", string.as_lua_id(\%actions[1].stub), " = ")
- if is_compile_time then lua:append("compile_time") end
- lua:append("(function(")
- local args = \%actions[1]:get_args()
- local lua_args = table.map(args, function(a) return nomsu:tree_to_lua(a) end)
- if is_compile_time then table.insert(lua_args, 1, "tree") end
- lua:concat_append(lua_args, ", ")
- local body_lua = nomsu:tree_to_lua(\%body):as_statements("return ")
- body_lua:remove_free_vars(args)
- body_lua:declare_locals()
- lua:append(")\n ", body_lua, "\nend)")
- for i=2,#\%actions do
- lua:append("\n", A_give_1_nickname_2(\%actions[i], \%actions[1], \%actions[i], is_compile_time))
- end
- return lua
- end)
-
- A_compile_1_to_2 = compile_time(function(tree, \%actions, \%body)
- return A_action_1_2(tree, \%actions, \%body, true)
+ end
+ local lua = LuaCode(tree.source, "nomsu.COMPILE_ACTIONS[", repr(\%actions[1].stub), "] = (function(nomsu, tree")
+ lua:add_free_vars({"A"..string.as_lua_id(\%actions[1].stub)})
+ for _,arg in ipairs(\%actions[1]:get_args()) do
+ lua:append(", ", nomsu:compile(arg))
+ end
+ lua:append(")\n __MANGLE_INDEX = __MANGLE_INDEX + 1",
+ "\n local tree = ", make_tree(\%body),
+ "\n local lua = nomsu:compile(tree)",
+ "\n lua:remove_free_vars({")
+ local vars = table.map(\%actions[1]:get_args(), function(a)
+ return "Var("..repr(tostring(a.source))..", "..repr(a[1])..")"
end)
+ lua:concat_append(vars, ", ")
+ lua:append("})\n return lua\nend)")
+
+ for i=2,#\%actions do
+ lua:append("\n", nomsu.COMPILE_ACTIONS["give % nickname %"](nomsu, \%actions[i], \%actions[1], \%actions[i], true))
+ end
+ return lua
+ end)
+
+ nomsu.COMPILE_ACTIONS["local action % %"] = (function(nomsu, tree, \%actions, \%body, is_compile_time)
+ local lua = LuaCode(tree.source)
+ if is_compile_time then
+ lua:append("nomsu.COMPILE_ACTIONS[", repr(\%actions[1].stub), "] = ")
+ else
+ lua:append("A", string.as_lua_id(\%actions[1].stub), " = ")
+ lua:add_free_vars({"A"..string.as_lua_id(\%actions[1].stub)})
+ end
+ lua:append("(function(")
+ local args = \%actions[1]:get_args()
+ local lua_args = table.map(args, function(a) return nomsu:compile(a) end)
+ if is_compile_time then
+ table.insert(lua_args, 1, "nomsu")
+ table.insert(lua_args, 2, "tree")
+ end
+ lua:concat_append(lua_args, ", ")
+ local body_lua = nomsu:compile(\%body):as_statements("return ")
+ body_lua:remove_free_vars(args)
+ body_lua:declare_locals()
+ lua:append(")\n ", body_lua, "\nend)")
+ for i=2,#\%actions do
+ lua:append("\n", nomsu.COMPILE_ACTIONS["give % nickname %"](nomsu, \%actions[i], \%actions[1], \%actions[i], is_compile_time))
+ end
+ return lua
+ end)
+
+ -- Compile-time actions are always global, since they affect the state of the compiler
+ nomsu.COMPILE_ACTIONS["compile % to %"] = (function(nomsu, tree, \%actions, \%body)
+ local lua = nomsu.COMPILE_ACTIONS["local action % %"](nomsu, tree, \%actions, \%body, true)
+ return lua
+ end)
+
+ nomsu.COMPILE_ACTIONS["action % %"] = (function(nomsu, tree, \%actions, \%body)
+ local lua = nomsu.COMPILE_ACTIONS["local action % %"](nomsu, tree, \%actions, \%body)
+ lua:remove_free_vars(table.map(\%actions, function(a) return "A"..a.stub:as_lua_id() end))
+ return lua
+ end)
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compile [remove action %action] to
Lua ".."
@@ -93,90 +126,87 @@ compile [remove action %action] to
ARG_ORDERS[fn] = nil
COMPILE_TIME[fn] = nil
-immediately
- action [%tree as nomsu]
- =lua "nomsu:tree_to_nomsu(\%tree)"
+action [%tree as nomsu]
+ =lua "nomsu:tree_to_nomsu(\%tree)"
- action [%tree as inline nomsu]
- =lua "nomsu:tree_to_nomsu(\%tree, true)"
+action [%tree as inline nomsu]
+ =lua "nomsu:tree_to_nomsu(\%tree, true)"
- action [%tree as lua]
- =lua "nomsu:tree_to_lua(\%tree)"
+action [%tree as lua]
+ =lua "nomsu:compile(\%tree)"
- action [%tree as lua expr]
- lua> ".."
- local lua = nomsu:tree_to_lua(\%tree)
- if not lua.is_value then
- compile_error(\%tree, "Invalid thing to convert to lua expr:\n%s")
- end
- return lua
+action [%tree as lua expr]
+ lua> ".."
+ local lua = nomsu:compile(\%tree)
+ if not lua.is_value then
+ nomsu:compile_error(\%tree, "Invalid thing to convert to lua expr:\n%s")
+ end
+ return lua
- action [%tree as lua statements]
- =lua "nomsu:tree_to_lua(\%tree):as_statements()"
+action [%tree as lua statements]
+ =lua "nomsu:compile(\%tree):as_statements()"
- action [%tree as lua return]
- =lua "nomsu:tree_to_lua(\%tree):as_statements('return ')"
+action [%tree as lua return]
+ =lua "nomsu:compile(\%tree):as_statements('return ')"
- action [%var as lua identifier, %var as lua id]
- lua> ".."
- if type(\%var) == 'string' then return string.as_lua_id(\%var)
- elseif \%var.type == 'Var' then return string.as_lua_id(\%var[1])
- elseif \%var.type == 'Action' then return "A"..string.as_lua_id(\%var.stub)
- end
-
-immediately
- compile [%tree with %t -> %replacement] to
- Lua value ".."
- \(%tree as lua expr):map(function(\(%t as lua expr))
- \(%replacement as lua return)
- end)
-
- compile [declare locals in %code] to
- Lua value "\(%code as lua expr):declare_locals()"
-
- compile [declare locals %locals in %code] to
- Lua value "\(%code as lua expr):declare_locals(\(%locals as lua expr))"
+action [%var as lua identifier, %var as lua id]
+ lua> ".."
+ if type(\%var) == 'string' then return string.as_lua_id(\%var)
+ elseif \%var.type == 'Var' then return string.as_lua_id(\%var[1])
+ elseif \%var.type == 'Action' then return "A"..string.as_lua_id(\%var.stub)
+ end
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- compile [remove free vars %vars from %code] to
- Lua "\(%code as lua expr):remove_free_vars(\(%vars as lua expr));"
+compile [%tree with %t -> %replacement] to
+ Lua value ".."
+ \(%tree as lua expr):map(function(\(%t as lua expr))
+ \(%replacement as lua return)
+ end)
- parse [%lua <-write %code, to %lua write %code] as: lua> "\%lua:append(\%code);"
+compile [declare locals in %code] to
+ Lua value "\(%code as lua expr):declare_locals()"
-immediately
- compile [quote %s] to
- Lua value ".."
- ('"'..\(%s as lua expr):gsub("\\\\", "\\\\\\\\"):gsub("\n","\\\\n"):gsub('"', '\\\\"')..'"')
- compile [type of %obj] to: Lua value "type(\(%obj as lua expr))"
+compile [declare locals %locals in %code] to
+ Lua value "\(%code as lua expr):declare_locals(\(%locals as lua expr))"
-immediately
- compile [parse %text] to
- Lua value ".."
- nomsu:parse(Nomsu("\("\(%text.source)")", \(%text as lua expr)))
+compile [remove free vars %vars from %code] to
+ Lua "\(%code as lua expr):remove_free_vars(\(%vars as lua expr));"
- compile [run %nomsu_code] to
- Lua value "nomsu:run(Nomsu(\(quote "\(%nomsu_code.source)"), \(%nomsu_code as lua expr)))"
+parse [%lua <-write %code, to %lua write %code] as: lua> "\%lua:append(\%code);"
- action [run tree %tree, %tree as value]
- lua> ".."
- if \%tree.type == 'Text' and #\%tree == 1 and type(\%tree[1]) == 'string' then
- return \%tree[1]
- end
- local lua = Lua(\%tree.source, "return ",nomsu:tree_to_lua(\%tree))
- return nomsu:run_lua(lua)
+compile [quote %s] to
+ Lua value ".."
+ ('"'..\(%s as lua expr):gsub("\\\\", "\\\\\\\\"):gsub("\n","\\\\n"):gsub('"', '\\\\"')..'"')
+compile [type of %obj] to: Lua value "type(\(%obj as lua expr))"
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+compile [parse %text] to
+ Lua value ".."
+ nomsu:parse(NomsuCode("\("\(%text.source)")", \(%text as lua expr)))
+
+compile [run %nomsu_code] to
+ Lua value "nomsu:run(NomsuCode(\(quote "\(%nomsu_code.source)"), \(%nomsu_code as lua expr)))"
+
+action [run tree %tree, %tree as value]
+ lua> ".."
+ if \%tree.type == 'Text' and #\%tree == 1 and type(\%tree[1]) == 'string' then
+ return \%tree[1]
+ end
+ local lua = LuaCode(\%tree.source, "return ",nomsu:compile(\%tree))
+ return nomsu:run_lua(lua)
- compile [compile %block, compiled %block, %block compiled] to
- Lua value "nomsu:tree_to_lua(\(%block as lua))"
+compile [compile %block, compiled %block, %block compiled] to
+ Lua value "nomsu:compile(\(%block as lua))"
-# Return
-immediately
- # Return statement is wrapped in a do..end block because Lua is unhappy if you
- put code after a return statement, unless you wrap it in a block.
- compile [return] to: Lua "do return; end"
- compile [return %return_value] to: Lua "do return \(%return_value as lua expr); end"
+# Return statement is wrapped in a do..end block because Lua is unhappy if you
+ put code after a return statement, unless you wrap it in a block.
+compile [return] to: Lua "do return; end"
+compile [return %return_value] to: Lua "do return \(%return_value as lua expr); end"
# Literals
-immediately
- compile [yes] to: Lua value "true"
- compile [no] to: Lua value "false"
- compile [nothing, nil, null] to: Lua value "nil"
+compile [yes] to: Lua value "true"
+compile [no] to: Lua value "false"
+compile [nothing, nil, null] to: Lua value "nil"
diff --git a/core/operators.nom b/core/operators.nom
index f07ab3f..b4567b1 100644
--- a/core/operators.nom
+++ b/core/operators.nom
@@ -5,158 +5,175 @@ use "core/metaprogramming.nom"
use "core/errors.nom"
# Comparison Operators
-immediately
- compile [%x < %y] to: Lua value "(\(%x as lua expr) < \(%y as lua expr))"
- compile [%x > %y] to: Lua value "(\(%x as lua expr) > \(%y as lua expr))"
- compile [%x <= %y] to: Lua value "(\(%x as lua expr) <= \(%y as lua expr))"
- compile [%x >= %y] to: Lua value "(\(%x as lua expr) >= \(%y as lua expr))"
- compile [%a is %b, %a = %b, %a == %b] to
- Lua value "(\(%a as lua expr) == \(%b as lua expr))"
- compile [%a isn't %b, %a is not %b, %a not= %b, %a != %b] to
- Lua value "(\(%a as lua expr) ~= \(%b as lua expr))"
- # For strict identity checking, use (%x's id) is (%y's id)
- compile [%'s id, id of %] to: Lua value "nomsu.ids[\(% as lua expr)]"
+compile [%x < %y] to: Lua value "(\(%x as lua expr) < \(%y as lua expr))"
+compile [%x > %y] to: Lua value "(\(%x as lua expr) > \(%y as lua expr))"
+compile [%x <= %y] to: Lua value "(\(%x as lua expr) <= \(%y as lua expr))"
+compile [%x >= %y] to: Lua value "(\(%x as lua expr) >= \(%y as lua expr))"
+compile [%a is %b, %a = %b, %a == %b] to
+ Lua value "(\(%a as lua expr) == \(%b as lua expr))"
+compile [%a isn't %b, %a is not %b, %a not= %b, %a != %b] to
+ Lua value "(\(%a as lua expr) ~= \(%b as lua expr))"
+# For strict identity checking, use (%x's id) is (%y's id)
+lua> ".."
+ do
+ local new_uuid = require('uuid')
+ local NaN_surrogate = {}
+ local nil_surrogate = {}
+ IDS = setmetatable({}, {
+ __mode = "k",
+ __index = function(self, key)
+ if key == nil then return self[nil_surrogate]
+ elseif key ~= key then return self[NaN_surrogate] end
+ local id = new_uuid()
+ self[key] = id
+ return id
+ end
+ })
+ end
+compile [%'s id, id of %] to: Lua value "IDS[\(% as lua expr)]"
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Variable assignment operator
-immediately
- compile [%var <- %value] to
- lua> "local \%var_lua = \(%var as lua)"
- assume %var_lua.is_value or barf "Invalid target for assignment: \%var"
- lua> ".."
+compile [%var <- %value] to
+ lua> "local \%var_lua = \(%var as lua)"
+ assume %var_lua.is_value or barf "Invalid target for assignment: \%var"
+ lua> ".."
+ \%value = \%value:map(function(t)
+ if Action:is_instance(t) and t.stub == "?" then
+ return \%var
+ end
+ end)
+ local \%value_lua = \(%value as lua)
+
+ assume %value_lua.is_value or barf "Invalid value for assignment: \%value"
+ lua> ".."
+ local lua = LuaCode(tree.source, \%var_lua, ' = ', \%value_lua, ';')
+ if \%var.type == 'Var' then
+ lua:add_free_vars({\%var})
+ end
+ return lua
+
+# Simultaneous mutli-assignments like: x,y,z = 1,x,3;
+compile [<- %assignments, assign %assignments] to
+ assume (%assignments.type is "Dict") or barf ".."
+ Expected a Dict for the assignments part of '<- %' statement, not \%assignments
+ lua> ".."
+ local lhs, rhs = LuaCode(tree.source), LuaCode(tree.source)
+ for i, item in ipairs(\%assignments) do
+ local \%target, \%value = item[1], item[2]
\%value = \%value:map(function(t)
if Action:is_instance(t) and t.stub == "?" then
- return \%var
+ return \%target
end
end)
- local \%value_lua = \(%value as lua)
+ local target_lua = \(%target as lua)
+ if not target_lua.is_value then error("Invalid target for assignment: "..\(%target as text)) end
+ local value_lua = \(%value as lua)
+ if not value_lua.is_value then error("Invalid value for assignment: "..\(%value as text)) end
+ if \%target.type == "Var" then
+ lhs:add_free_vars({\%target})
+ end
+ if i > 1 then
+ lhs:append(", ")
+ rhs:append(", ")
+ end
+ lhs:append(target_lua)
+ rhs:append(value_lua)
+ end
+ return LuaCode(tree.source, lhs, " = ", rhs, ";")
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+compile [external %var <- %value] to
+ %var_lua <- (%var as lua)
+ assume %var_lua.is_value or barf "Invalid target for assignment: \%var"
+ %value_lua <- (%value as lua)
+ assume %value_lua.is_value or barf "Invalid value for assignment: \%value"
+ return: Lua "\%var_lua = \%value_lua;"
- assume %value_lua.is_value or barf "Invalid value for assignment: \%value"
- lua> ".."
- local lua = Lua(tree.source, \%var_lua, ' = ', \%value_lua, ';')
- if \%var.type == 'Var' then
- lua:add_free_vars({\%var})
+compile [with external %externs %body] to
+ %body_lua <- (%body as lua statements)
+ lua> "\%body_lua:remove_free_vars(\%externs);"
+ return %body_lua
+
+compile [with %assignments %body] to
+ %lua <- (%body as lua statements)
+ lua> ".."
+ local lhs, rhs = LuaCode(tree.source), LuaCode(tree.source)
+ local vars = {}
+ for i, item in ipairs(\%assignments) do
+ local \%target, \%value = item[1], item[2]
+ if not \%target.type == "Var" then
+ error("Invalid target for 'with' assignment: "..tostring(\%target))
end
- return lua;
-
-immediately
- # Simultaneous mutli-assignments like: x,y,z = 1,x,3;
- compile [<- %assignments, assign %assignments] to
- assume (%assignments.type is "Dict") or barf ".."
- Expected a Dict for the assignments part of '<- %' statement, not \%assignments
- lua> ".."
- local lhs, rhs = Lua(tree.source), Lua(tree.source)
- for i, item in ipairs(\%assignments) do
- local \%target, \%value = item[1], item[2]
- \%value = \%value:map(function(t)
- if Action:is_instance(t) and t.stub == "?" then
- return \%target
- end
- end)
- local target_lua = \(%target as lua)
- if not target_lua.is_value then error("Invalid target for assignment: "..\(%target as text)) end
- local value_lua = \(%value as lua)
- if not value_lua.is_value then error("Invalid value for assignment: "..\(%value as text)) end
- if \%target.type == "Var" then
- lhs:add_free_vars({\%target})
- end
- if i > 1 then
- lhs:append(", ")
- rhs:append(", ")
- end
- lhs:append(target_lua)
- rhs:append(value_lua)
+ local target_lua = \(%target as lua)
+ local value_lua = \(%value as lua)
+ if not value_lua.is_value then
+ error("Invalid value for assignment: "..tostring(\%value))
end
- return Lua(tree.source, lhs, " = ", rhs, ";")
-
-immediately
- compile [external %var <- %value] to
- %var_lua <- (%var as lua)
- assume %var_lua.is_value or barf "Invalid target for assignment: \%var"
- %value_lua <- (%value as lua)
- assume %value_lua.is_value or barf "Invalid value for assignment: \%value"
- return: Lua "\%var_lua = \%value_lua;"
-
- compile [with external %externs %body] to
- %body_lua <- (%body as lua statements)
- lua> "\%body_lua:remove_free_vars(\%externs);"
- return %body_lua
-
- compile [with %assignments %body] to
- %lua <- (%body as lua statements)
- lua> ".."
- local lhs, rhs = Lua(tree.source), Lua(tree.source)
- local vars = {}
- for i, item in ipairs(\%assignments) do
- local \%target, \%value = item[1], item[2]
- if not \%target.type == "Var" then
- error("Invalid target for 'with' assignment: "..tostring(\%target))
- end
- local target_lua = \(%target as lua)
- local value_lua = \(%value as lua)
- if not value_lua.is_value then
- error("Invalid value for assignment: "..tostring(\%value))
- end
- if \%target.type == "Var" then
- lhs:add_free_vars({\%target})
- end
- if i > 1 then
- lhs:append(", ")
- rhs:append(", ")
- end
- lhs:append(target_lua)
- rhs:append(value_lua)
- vars[i] = \%target
+ if \%target.type == "Var" then
+ lhs:add_free_vars({\%target})
+ end
+ if i > 1 then
+ lhs:append(", ")
+ rhs:append(", ")
end
- \%lua:remove_free_vars(vars)
- \%lua:prepend("local ", lhs, " = ", rhs, ";\n")
- return
- Lua ".."
- do
- \%lua
- end -- 'with' block
-
-immediately
- # Math Operators
- compile [%x wrapped around %y, %x mod %y] to: Lua value "(\(%x as lua expr) % \(%y as lua expr))"
-
- # 3-part chained comparisons
- # (uses a lambda to avoid re-evaluating middle value, while still being an expression)
- parse [%x < %y < %z] as: =lua "(function(x,y,z) return x < y and y < z; end)(\%x,\%y,\%z)"
- parse [%x <= %y < %z] as: =lua "(function(x,y,z) return x <= y and y < z; end)(\%x,\%y,\%z)"
- parse [%x < %y <= %z] as: =lua "(function(x,y,z) return x < y and y <= z; end)(\%x,\%y,\%z)"
- parse [%x <= %y <= %z] as: =lua "(function(x,y,z) return x <= y and y <= z; end)(\%x,\%y,\%z)"
- parse [%x > %y > %z] as: =lua "(function(x,y,z) return x > y and y > z; end)(\%x,\%y,\%z)"
- parse [%x >= %y > %z] as: =lua "(function(x,y,z) return x >= y and y > z; end)(\%x,\%y,\%z)"
- parse [%x > %y >= %z] as: =lua "(function(x,y,z) return x > y and y >= z; end)(\%x,\%y,\%z)"
- parse [%x >= %y >= %z] as: =lua "(function(x,y,z) return x >= y and y >= z; end)(\%x,\%y,\%z)"
- # TODO: optimize for common case where x,y,z are all either variables or number literals
-
- # Boolean Operators
- compile [%x and %y] to: Lua value "(\(%x as lua expr) and \(%y as lua expr))"
- compile [%x or %y] to: Lua value "(\(%x as lua expr) or \(%y as lua expr))"
-
- # Bitwise Operators
- compile [%a OR %b, %a | %b] to: Lua value "bit32.bor(\(%a as lua expr), \(%b as lua expr))"
- compile [%a XOR %b] to: Lua value "bit32.bxor(\(%a as lua expr), \(%b as lua expr))"
- compile [%a AND %b, %a & %b] to: Lua value "bit32.band(\(%a as lua expr), \(%b as lua expr))"
- compile [NOT %, ~ %] to: Lua value "bit32.bnot(\(% as lua expr))"
- compile [%x LSHIFT %shift, %x << %shift] to: Lua value "bit32.lshift(\(%x as lua expr), \(%shift as lua expr))"
- compile [%x RSHIFT %shift, %x >>> %shift] to: Lua value "bit32.rshift(\(%x as lua expr), \(%shift as lua expr))"
- compile [%x ARSHIFT %shift, %x >> %shift] to: Lua value "bit32.arshift(\(%x as lua expr), \(%shift as lua expr))"
- # TODO: implement OR, XOR, AND for multiple operands?
-
- # Unary operators
- compile [- %] to: Lua value "(- \(% as lua expr))"
- compile [not %] to: Lua value "(not \(% as lua expr))"
- compile [length of %list] to: Lua value "(#\(%list as lua expr))"
+ lhs:append(target_lua)
+ rhs:append(value_lua)
+ vars[i] = \%target
+ end
+ \%lua:remove_free_vars(vars)
+ \%lua:prepend("local ", lhs, " = ", rhs, ";\n")
+ return
+ Lua ".."
+ do
+ \%lua
+ end -- 'with' block
+
+# Math Operators
+compile [%x wrapped around %y, %x mod %y] to: Lua value "(\(%x as lua expr) % \(%y as lua expr))"
+
+# 3-part chained comparisons
+# (uses a lambda to avoid re-evaluating middle value, while still being an expression)
+parse [%x < %y < %z] as: =lua "(function(x,y,z) return x < y and y < z; end)(\%x,\%y,\%z)"
+parse [%x <= %y < %z] as: =lua "(function(x,y,z) return x <= y and y < z; end)(\%x,\%y,\%z)"
+parse [%x < %y <= %z] as: =lua "(function(x,y,z) return x < y and y <= z; end)(\%x,\%y,\%z)"
+parse [%x <= %y <= %z] as: =lua "(function(x,y,z) return x <= y and y <= z; end)(\%x,\%y,\%z)"
+parse [%x > %y > %z] as: =lua "(function(x,y,z) return x > y and y > z; end)(\%x,\%y,\%z)"
+parse [%x >= %y > %z] as: =lua "(function(x,y,z) return x >= y and y > z; end)(\%x,\%y,\%z)"
+parse [%x > %y >= %z] as: =lua "(function(x,y,z) return x > y and y >= z; end)(\%x,\%y,\%z)"
+parse [%x >= %y >= %z] as: =lua "(function(x,y,z) return x >= y and y >= z; end)(\%x,\%y,\%z)"
+# TODO: optimize for common case where x,y,z are all either variables or number literals
+
+# Boolean Operators
+compile [%x and %y] to: Lua value "(\(%x as lua expr) and \(%y as lua expr))"
+compile [%x or %y] to: Lua value "(\(%x as lua expr) or \(%y as lua expr))"
+
+# Bitwise Operators
+# TODO: support bit.???() for luajit and bit32.??? for lua 5.2
+compile [%a OR %b, %a | %b] to: Lua value "(\(%a as lua expr) | \(%b as lua expr))"
+compile [%a XOR %b] to: Lua value "(\(%a as lua expr) ^ \(%b as lua expr))"
+compile [%a AND %b, %a & %b] to: Lua value "(\(%a as lua expr) & \(%b as lua expr))"
+compile [NOT %, ~ %] to: Lua value "~(\(% as lua expr))"
+compile [%x LSHIFT %shift, %x << %shift] to: Lua value "(\(%x as lua expr) << \(%shift as lua expr))"
+compile [%x RSHIFT %shift, %x >>> %shift] to: Lua value "(\(%x as lua expr) >>> \(%shift as lua expr))"
+compile [%x ARSHIFT %shift, %x >> %shift] to: Lua value "(\(%x as lua expr) >> \(%shift as lua expr))"
+# TODO: implement OR, XOR, AND for multiple operands?
+
+# Unary operators
+compile [- %] to: Lua value "(- \(% as lua expr))"
+compile [not %] to: Lua value "(not \(% as lua expr))"
+compile [length of %list] to: Lua value "(#\(%list as lua expr))"
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Update operators
-immediately
- parse [%var + <- %, %var +<- %] as: %var <- (%var + %)
- parse [%var - <- %, %var -<- %] as: %var <- (%var - %)
- parse [%var * <- %, %var *<- %] as: %var <- (%var * %)
- parse [%var / <- %, %var /<- %] as: %var <- (%var / %)
- parse [%var ^ <- %, %var ^<- %] as: %var <- (%var ^ %)
- parse [%var and <- %] as: %var <- (%var and %)
- parse [%var or <- %] as: %var <- (%var or %)
- parse [wrap %var around %] as: %var <- (%var wrapped around %)
+parse [%var + <- %, %var +<- %] as: %var <- (%var + %)
+parse [%var - <- %, %var -<- %] as: %var <- (%var - %)
+parse [%var * <- %, %var *<- %] as: %var <- (%var * %)
+parse [%var / <- %, %var /<- %] as: %var <- (%var / %)
+parse [%var ^ <- %, %var ^<- %] as: %var <- (%var ^ %)
+parse [%var and <- %] as: %var <- (%var and %)
+parse [%var or <- %] as: %var <- (%var or %)
+parse [wrap %var around %] as: %var <- (%var wrapped around %)
diff --git a/core/text.nom b/core/text.nom
index 8b26ccb..b576127 100644
--- a/core/text.nom
+++ b/core/text.nom
@@ -35,7 +35,7 @@ lua> ".."
};
for name, e in pairs(escapes) do
local lua = "'"..e.."'"
- _ENV["A"..name:as_lua_id()] = compile_time(function(tree) return Lua.Value(tree.source, lua) end)
+ nomsu.COMPILE_ACTIONS[name] = (function(nomsu, tree) return LuaCode.Value(tree.source, lua) end)
end
local colors = {
["reset color"]="\\\\27[0m", bright="\\\\27[1m", dim="\\\\27[2m", underscore="\\\\27[4m",
@@ -50,9 +50,9 @@ lua> ".."
for name, c in pairs(colors) do
local color = "'"..c.."'";
local reset = "'"..colors["reset color"].."'";
- _ENV["A"..name:as_lua_id()] = compile_time(function(tree) return Lua.Value(tree.source, color) end)
- _ENV["A"..name:as_lua_id().."_1"] = compile_time(function(tree, text)
- return Lua.Value(tree.source, color, "..", nomsu:tree_to_lua(text), "..", reset);
+ nomsu.COMPILE_ACTIONS[name] = (function(nomsu, tree) return LuaCode.Value(tree.source, color) end)
+ nomsu.COMPILE_ACTIONS[name.." %"] = (function(nomsu, tree, text)
+ return LuaCode.Value(tree.source, color, "..", nomsu:tree_to_lua(text), "..", reset);
end)
end
end
diff --git a/lib/object.nom b/lib/object.nom
index 37f661c..c5c0091 100644
--- a/lib/object.nom
+++ b/lib/object.nom
@@ -3,57 +3,58 @@
use "core"
-immediately
- compile [@, me] to: Lua value "self"
- compile [set methods %methods] to
- %lua <- (Lua "")
- for %m in %methods
- to %lua write "\nclass.\(%m as lua id) = \(%m as lua id)"
- return %lua
-
-immediately
- parse [method %actions %body] as
- with local %actions
- action %actions %body
- set methods %actions
-
-immediately
- parse [as %instance %body] as
- result of
- %old_self <- (me)
- (me) <- %instance
- try
- %body
- ..and if it barfs %msg
- (me) <- %old_self
- barf %msg
- ..or if it succeeds
- (me) <- %old_self
-
- compile [object %classname extends %parent %class_body] to
- Lua ".."
- do
- local class = {name=\(%classname as lua expr)}
- setmetatable(class, {
- __index=\(%parent as lua expr),
- __tostring=function(cls) return cls.name end,
- __call=function(cls, inst)
- inst = setmetatable(inst or {}, cls)
- if cls.A_initialize_1 then
- cls.A_initialize_1(inst)
- end
- return inst
- end,
- })
- _ENV["A"..string.as_lua_id("new "..class.name)] = class
- _ENV["A"..string.as_lua_id("new "..class.name.." 1")] = class
- _ENV["A"..string.as_lua_id("class "..class.name)] = function() return class end
- class.__index = class
- class.class = class
-
- \(%class_body as lua statements)
-
- class.__tostring = class["A"..string.as_lua_id("as text")]
- end
-
+compile [@, me] to: Lua value "self"
+compile [set methods %methods] to
+ %lua <- (Lua "")
+ for %m in %methods
+ to %lua write "\nclass.\(%m as lua id) = \(%m as lua id)"
+ return %lua
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+parse [method %actions %body] as
+ with local %actions
+ action %actions %body
+ set methods %actions
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+parse [as %instance %body] as
+ result of
+ %old_self <- (me)
+ (me) <- %instance
+ try
+ %body
+ ..and if it barfs %msg
+ (me) <- %old_self
+ barf %msg
+ ..or if it succeeds
+ (me) <- %old_self
+
+compile [object %classname extends %parent %class_body] to
+ Lua ".."
+ do
+ local class = {name=\(%classname as lua expr)}
+ setmetatable(class, {
+ __index=\(%parent as lua expr),
+ __tostring=function(cls) return cls.name end,
+ __call=function(cls, inst)
+ inst = setmetatable(inst or {}, cls)
+ if cls.A_initialize_1 then
+ cls.A_initialize_1(inst)
+ end
+ return inst
+ end,
+ })
+ _ENV["A"..string.as_lua_id("new "..class.name)] = class
+ _ENV["A"..string.as_lua_id("new "..class.name.." 1")] = class
+ _ENV["A"..string.as_lua_id("class "..class.name)] = function() return class end
+ class.__index = class
+ class.class = class
+
+ \(%class_body as lua statements)
+
+ class.__tostring = class["A"..string.as_lua_id("as text")]
+ end
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
parse [object %classname %class_body] as: object %classname extends (nil) %class_body
diff --git a/nomsu.lua b/nomsu.lua
index 80f7f01..1ea73ec 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -1,16 +1,9 @@
-local _pairs, _ipairs = pairs, ipairs
-if jit then
- package.cpath = "./luajit_lpeg/?.so;" .. package.cpath
- package.path = "./luajit_lpeg/?.lua;" .. package.path
- bit32 = require('bit')
-end
-lpeg = require('lpeg')
-re = require('re')
+local lpeg = require('lpeg')
+local re = require('re')
lpeg.setmaxstack(10000)
local P, R, V, S, Cg, C, Cp, B, Cmt, Carg
P, R, V, S, Cg, C, Cp, B, Cmt, Carg = lpeg.P, lpeg.R, lpeg.V, lpeg.S, lpeg.Cg, lpeg.C, lpeg.Cp, lpeg.B, lpeg.Cmt, lpeg.Carg
local utils = require('utils')
-local new_uuid = require('uuid')
local repr, stringify, min, max, equivalent, set, is_list, sum
repr, stringify, min, max, equivalent, set, is_list, sum = utils.repr, utils.stringify, utils.min, utils.max, utils.equivalent, utils.set, utils.is_list, utils.sum
local colors = setmetatable({ }, {
@@ -30,16 +23,17 @@ do
local _obj_0 = table
insert, remove, concat = _obj_0.insert, _obj_0.remove, _obj_0.concat
end
+local unpack = unpack or table.unpack
local match, sub, rep, gsub, format, byte, find
do
local _obj_0 = string
match, sub, rep, gsub, format, byte, match, find = _obj_0.match, _obj_0.sub, _obj_0.rep, _obj_0.gsub, _obj_0.format, _obj_0.byte, _obj_0.match, _obj_0.find
end
local debug_getinfo = debug.getinfo
-local Nomsu, Lua, Source
+local NomsuCode, LuaCode, Source
do
local _obj_0 = require("code_obj")
- Nomsu, Lua, Source = _obj_0.Nomsu, _obj_0.Lua, _obj_0.Source
+ NomsuCode, LuaCode, Source = _obj_0.NomsuCode, _obj_0.LuaCode, _obj_0.Source
end
local STDIN, STDOUT, STDERR = "/dev/fd/0", "/dev/fd/1", "/dev/fd/2"
string.as_lua_id = function(str)
@@ -165,288 +159,414 @@ do
end
end
local AST = require("nomsu_tree")
-local NOMSU_DEFS
-do
- local _with_0 = { }
- _with_0.nl = P("\r") ^ -1 * P("\n")
- _with_0.ws = S(" \t")
- _with_0.tonumber = tonumber
- local string_escapes = {
- n = "\n",
- t = "\t",
- b = "\b",
- a = "\a",
- v = "\v",
- f = "\f",
- r = "\r"
- }
- local digit, hex = R('09'), R('09', 'af', 'AF')
- _with_0.escaped_char = (P("\\") * S("xX") * C(hex * hex)) / function(self)
- return string.char(tonumber(self, 16))
- end
- _with_0.escaped_char = _with_0.escaped_char + ((P("\\") * C(digit * (digit ^ -2))) / function(self)
- return string.char(tonumber(self))
- end)
- _with_0.escaped_char = _with_0.escaped_char + ((P("\\") * C(S("ntbavfr"))) / string_escapes)
- _with_0.operator_char = S("'~`!@$^&*-+=|<>?/")
- _with_0.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"))
- _with_0.ident_char = R("az", "AZ", "09") + P("_") + _with_0.utf8_char
- _with_0.indent = Cmt(Carg(1), function(self, start, userdata)
- local indented = userdata.indent .. ' '
- if sub(self, start, start + #indented - 1) == indented then
- userdata.indent = indented
- return start + #indented
- end
- end)
- _with_0.dedent = Cmt(Carg(1), function(self, start, userdata)
- local dedented = sub(userdata.indent, 1, -5)
- if #match(self, "^[ ]*", start) <= #dedented then
- userdata.indent = dedented
- return start
- end
- end)
- _with_0.nodent = Cmt(Carg(1), function(self, start, userdata)
- if sub(self, start, start + #userdata.indent - 1) == userdata.indent then
- return start + #userdata.indent
- end
- end)
- _with_0.userdata = Carg(1)
- _with_0.error = function(src, end_pos, start_pos, err_msg, userdata)
- local seen_errors = userdata.errors
- if seen_errors[start_pos] then
- return true
- end
- if utils.size(seen_errors) >= 10 then
- seen_errors[start_pos + 1] = colored.bright(colored.yellow(colored.onred("Too many errors, canceling parsing...")))
- return #src + 1
- end
- local err_pos = start_pos
- local line_no = pos_to_line(src, err_pos)
- src = FILE_CACHE[userdata.source.filename]
- local line_starts = LINE_STARTS[src]
- local prev_line = line_no == 1 and "" or src:sub(line_starts[line_no - 1] or 1, line_starts[line_no] - 2)
- local err_line = src:sub(line_starts[line_no], (line_starts[line_no + 1] or 0) - 2)
- local next_line = src:sub(line_starts[line_no + 1] or -1, (line_starts[line_no + 2] or 0) - 2)
- local i = err_pos - line_starts[line_no]
- local pointer = ("-"):rep(i) .. "^"
- err_msg = colored.bright(colored.yellow(colored.onred((err_msg or "Parse error") .. " at " .. tostring(userdata.source.filename) .. ":" .. tostring(line_no) .. ":")))
- if #prev_line > 0 then
- err_msg = err_msg .. ("\n" .. colored.dim(prev_line))
- end
- err_line = colored.white(err_line:sub(1, i)) .. colored.bright(colored.red(err_line:sub(i + 1, i + 1))) .. colored.dim(err_line:sub(i + 2, -1))
- err_msg = err_msg .. "\n" .. tostring(err_line) .. "\n" .. tostring(colored.red(pointer))
- if #next_line > 0 then
- err_msg = err_msg .. ("\n" .. colored.dim(next_line))
- end
- seen_errors[start_pos] = err_msg
- return true
+local _list_mt = {
+ __eq = utils.equivalent,
+ __tostring = function(self)
+ return "[" .. concat((function()
+ local _accum_0 = { }
+ local _len_0 = 1
+ for _index_0 = 1, #self do
+ local b = self[_index_0]
+ _accum_0[_len_0] = repr(b)
+ _len_0 = _len_0 + 1
+ end
+ return _accum_0
+ end)(), ", ") .. "]"
end
- NOMSU_DEFS = _with_0
+}
+local list
+list = function(t)
+ return setmetatable(t, _list_mt)
end
-setmetatable(NOMSU_DEFS, {
- __index = function(self, key)
- local make_node
- make_node = function(start, value, stop, userdata)
- local source
- do
- local _with_0 = userdata.source
- source = Source(_with_0.filename, _with_0.start + start - 1, _with_0.start + stop - 1)
+local _dict_mt = {
+ __eq = utils.equivalent,
+ __tostring = function(self)
+ return "{" .. concat((function()
+ local _accum_0 = { }
+ local _len_0 = 1
+ for k, v in pairs(self) do
+ _accum_0[_len_0] = tostring(repr(k)) .. ": " .. tostring(repr(v))
+ _len_0 = _len_0 + 1
end
- value.source = source
- setmetatable(value, AST[key])
- if value.__init then
- value:__init()
- end
- for i = 1, #value do
- assert(value[i])
+ return _accum_0
+ end)(), ", ") .. "}"
+ end
+}
+local dict
+dict = function(t)
+ return setmetatable(t, _dict_mt)
+end
+local MAX_LINE = 80
+local NomsuCompiler = setmetatable({ }, {
+ __index = function(self, k)
+ do
+ local _self = rawget(self, "self")
+ if _self then
+ return _self[k]
+ else
+ return nil
end
- return value
end
- self[key] = make_node
- return make_node
end
})
-local NOMSU_PATTERN
do
- local peg_tidier = re.compile([[ 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 <- (({} %3 {} %%userdata) -> %2)"
- ident <- [a-zA-Z_][a-zA-Z0-9_]*
- comment <- "--" [^%nl]*
- ]])
- local nomsu_peg = peg_tidier:match(FILE_CACHE["nomsu.peg"])
- NOMSU_PATTERN = re.compile(nomsu_peg, NOMSU_DEFS)
-end
-local NomsuCompiler
-do
- local _class_0
- local compile_error, _running_files, MAX_LINE, math_expression
- local _base_0 = {
- parse = function(self, nomsu_code)
- assert(type(nomsu_code) ~= 'string')
- local userdata = {
- source_code = nomsu_code,
- indent = "",
- errors = { },
- source = nomsu_code.source
- }
- local tree = NOMSU_PATTERN:match(tostring(nomsu_code), nil, userdata)
- if not (tree) then
- error("In file " .. tostring(colored.blue(filename)) .. " failed to parse:\n" .. tostring(colored.onyellow(colored.black(nomsu_code))))
+ NomsuCompiler._ENV = NomsuCompiler
+ NomsuCompiler.nomsu = NomsuCompiler
+ local parse = require("parser")
+ NomsuCompiler.parse = function(self, ...)
+ return parse(...)
+ end
+ NomsuCompiler.source_map = { }
+ local to_add = {
+ repr = repr,
+ stringify = stringify,
+ utils = utils,
+ lpeg = lpeg,
+ re = re,
+ next = next,
+ unpack = unpack,
+ setmetatable = setmetatable,
+ coroutine = coroutine,
+ rawequal = rawequal,
+ getmetatable = getmetatable,
+ pcall = pcall,
+ error = error,
+ package = package,
+ os = os,
+ require = require,
+ tonumber = tonumber,
+ tostring = tostring,
+ string = string,
+ xpcall = xpcall,
+ module = module,
+ print = print,
+ loadfile = loadfile,
+ rawset = rawset,
+ _VERSION = _VERSION,
+ collectgarbage = collectgarbage,
+ rawget = rawget,
+ rawlen = rawlen,
+ table = table,
+ assert = assert,
+ dofile = dofile,
+ loadstring = loadstring,
+ type = type,
+ select = select,
+ debug = debug,
+ math = math,
+ io = io,
+ load = load,
+ pairs = pairs,
+ ipairs = ipairs,
+ list = list,
+ dict = dict
+ }
+ for k, v in pairs(to_add) do
+ NomsuCompiler[k] = v
+ end
+ for k, v in pairs(AST) do
+ NomsuCompiler[k] = v
+ end
+ NomsuCompiler.LuaCode = LuaCode
+ NomsuCompiler.NomsuCode = NomsuCode
+ NomsuCompiler.Source = Source
+ NomsuCompiler.ARG_ORDERS = setmetatable({ }, {
+ __mode = "k"
+ })
+ NomsuCompiler.ALIASES = setmetatable({ }, {
+ __mode = "k"
+ })
+ NomsuCompiler.LOADED = { }
+ NomsuCompiler.AST = AST
+ NomsuCompiler.compile_error = function(self, tok, err_format_string, ...)
+ local file = FILE_CACHE[tok.source.filename]
+ local line_no = pos_to_line(file, tok.source.start)
+ local line_start = LINE_STARTS[file][line_no]
+ local src = colored.dim(file:sub(line_start, tok.source.start - 1))
+ src = src .. colored.underscore(colored.bright(colored.red(file:sub(tok.source.start, tok.source.stop - 1))))
+ local end_of_line = (LINE_STARTS[file][pos_to_line(file, tok.source.stop) + 1] or 0) - 1
+ src = src .. colored.dim(file:sub(tok.source.stop, end_of_line - 1))
+ src = ' ' .. src:gsub('\n', '\n ')
+ local err_msg = err_format_string:format(src, ...)
+ return error(tostring(tok.source.filename) .. ":" .. tostring(line_no) .. ": " .. err_msg, 0)
+ end
+ local math_expression = re.compile([[ ([+-] " ")* "%" (" " [*/^+-] (" " [+-])* " %")+ !. ]])
+ local add_lua_bits
+ add_lua_bits = function(self, lua, code)
+ for _index_0 = 1, #code do
+ local bit = code[_index_0]
+ if type(bit) == "string" then
+ lua:append(bit)
+ else
+ local bit_lua = self:compile(bit)
+ if not (bit_lua.is_value) then
+ self:compile_error(bit, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.")
+ end
+ lua:append(bit_lua)
end
- if next(userdata.errors) then
- local keys = utils.keys(userdata.errors)
- table.sort(keys)
- local errors
- do
- local _accum_0 = { }
- local _len_0 = 1
- for _index_0 = 1, #keys do
- local k = keys[_index_0]
- _accum_0[_len_0] = userdata.errors[k]
- _len_0 = _len_0 + 1
+ end
+ return lua
+ end
+ local add_lua_string_bits
+ add_lua_string_bits = function(self, lua, code)
+ local line_len = 0
+ if code.type ~= "Text" then
+ lua:append(", ", self:compile(code))
+ return
+ end
+ for _index_0 = 1, #code do
+ local bit = code[_index_0]
+ local bit_lua
+ if type(bit) == "string" then
+ bit_lua = repr(bit)
+ else
+ bit_lua = self:compile(bit)
+ if not (bit_lua.is_value) then
+ self:compile_error(bit, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.")
+ end
+ bit_lua = bit_lua
+ end
+ line_len = line_len + #tostring(bit_lua)
+ if line_len > MAX_LINE then
+ lua:append(",\n ")
+ line_len = 4
+ else
+ lua:append(", ")
+ end
+ lua:append(bit_lua)
+ end
+ end
+ NomsuCompiler.COMPILE_ACTIONS = setmetatable({
+ compile_math_expr = function(self, tree, ...)
+ local lua = LuaCode.Value(tree.source)
+ for i, tok in ipairs(tree) do
+ if type(tok) == 'string' then
+ lua:append(tok)
+ else
+ local tok_lua = self:compile(tok)
+ if not (tok_lua.is_value) then
+ self:compile_error(tok, "Non-expression value inside math expression:\n%s")
+ end
+ if tok.type == "Action" then
+ tok_lua:parenthesize()
end
- errors = _accum_0
+ lua:append(tok_lua)
+ end
+ if i < #tree then
+ lua:append(" ")
end
- io.stderr:write(concat(errors, "\n\n") .. "\n")
- os.exit()
end
- return tree
+ return lua
end,
- run = function(self, nomsu_code)
- local tree = assert(self:parse(nomsu_code))
- if type(tree) == 'number' then
- return nil
+ ["Lua %"] = function(self, tree, _code)
+ local lua = LuaCode.Value(_code.source, "LuaCode(", repr(tostring(_code.source)))
+ add_lua_string_bits(self, lua, _code)
+ lua:append(")")
+ return lua
+ end,
+ ["Lua value %"] = function(self, tree, _code)
+ local lua = LuaCode.Value(_code.source, "LuaCode.Value(", repr(tostring(_code.source)))
+ add_lua_string_bits(self, lua, _code)
+ lua:append(")")
+ return lua
+ end,
+ ["lua > %"] = function(self, tree, _code)
+ if _code.type ~= "Text" then
+ return LuaCode(tree.source, "nomsu:run_lua(", self:compile(_code), ");")
end
- local lua = self:tree_to_lua(tree):as_statements()
- lua:declare_locals()
- lua:prepend("-- File: " .. tostring(nomsu_code.source or "") .. "\n")
- if self.compile_fn then
- self.compile_fn(lua, nomsu_code.source.filename)
+ return add_lua_bits(self, LuaCode(tree.source), _code)
+ end,
+ ["= lua %"] = function(self, tree, _code)
+ if _code.type ~= "Text" then
+ return LuaCode.Value(tree.source, "nomsu:run_lua(", self:compile(_code), ":as_statements('return '))")
end
- return self:run_lua(lua)
+ return add_lua_bits(self, LuaCode.Value(tree.source), _code)
end,
- run_file = function(self, filename)
- local loaded = self.environment.LOADED
- if loaded[filename] then
- return loaded[filename]
+ ["use %"] = function(self, tree, _path)
+ if not (_path.type == 'Text' and #_path == 1 and type(_path[1]) == 'string') then
+ return LuaCode(tree.source, "nomsu:run_file(" .. tostring(self:compile(_path)) .. ");")
+ end
+ local path = _path[1]
+ self:run_file(path)
+ return LuaCode(tree.source, "nomsu:run_file(" .. tostring(repr(path)) .. ");")
+ end
+ }, {
+ __index = function(self, stub)
+ if math_expression:match(stub) then
+ return self.compile_math_expr
end
+ end
+ })
+ NomsuCompiler.fork = function(self)
+ return setmetatable({
+ COMPILE_ACTIONS = setmetatable({ }, {
+ __index = self.COMPILE_ACTIONS
+ })
+ }, {
+ __index = self
+ })
+ end
+ NomsuCompiler.run = function(self, to_run, source)
+ if source == nil then
+ source = nil
+ end
+ local tree
+ if AST.is_syntax_tree(to_run) then
+ tree = tree
+ else
+ tree = self:parse(to_run, source or to_run.source)
+ end
+ if tree == nil then
+ return nil
+ end
+ if tree.type == "FileChunks" then
local ret = nil
- for filename in all_files(filename) do
- local _continue_0 = false
- repeat
- if loaded[filename] then
- ret = loaded[filename]
- _continue_0 = true
- break
- end
- for i, running in ipairs(_running_files) do
- if running == filename then
- local loop
- do
- local _accum_0 = { }
- local _len_0 = 1
- for j = i, #_running_files do
- _accum_0[_len_0] = _running_files[j]
- _len_0 = _len_0 + 1
- end
- loop = _accum_0
+ local all_lua = { }
+ for _index_0 = 1, #tree do
+ local chunk = tree[_index_0]
+ local lua = self:compile(chunk):as_statements()
+ lua:declare_locals()
+ lua:prepend("-- File: " .. tostring(chunk.source or "") .. "\n")
+ insert(all_lua, tostring(lua))
+ ret = self:run_lua(lua)
+ end
+ if self.on_compile then
+ self.on_compile(concat(all_lua, "\n"), (source or to_run.source).filename)
+ end
+ return ret
+ else
+ local lua = self:compile(tree, compile_actions):as_statements()
+ lua:declare_locals()
+ lua:prepend("-- File: " .. tostring(source or to_run.source or "") .. "\n")
+ if self.on_compile then
+ self.on_compile(lua, (source or to_run.source).filename)
+ end
+ return self:run_lua(lua)
+ end
+ end
+ local _running_files = { }
+ NomsuCompiler.run_file = function(self, filename)
+ if self.LOADED[filename] then
+ return self.LOADED[filename]
+ end
+ local ret = nil
+ for filename in all_files(filename) do
+ local _continue_0 = false
+ repeat
+ if self.LOADED[filename] then
+ ret = self.LOADED[filename]
+ _continue_0 = true
+ break
+ end
+ for i, running in ipairs(_running_files) do
+ if running == filename then
+ local loop
+ do
+ local _accum_0 = { }
+ local _len_0 = 1
+ for j = i, #_running_files do
+ _accum_0[_len_0] = _running_files[j]
+ _len_0 = _len_0 + 1
end
- insert(loop, filename)
- error("Circular import, this loops forever: " .. tostring(concat(loop, " -> ")))
+ loop = _accum_0
end
+ insert(loop, filename)
+ error("Circular import, this loops forever: " .. tostring(concat(loop, " -> ")))
end
- insert(_running_files, filename)
- if match(filename, "%.lua$") then
- local file = assert(FILE_CACHE[filename], "Could not find file: " .. tostring(filename))
- ret = self:run_lua(Lua(Source(filename, 1, #file), file))
- elseif match(filename, "%.nom$") or match(filename, "^/dev/fd/[012]$") then
- if not self.skip_precompiled then
- local lua_filename = gsub(filename, "%.nom$", ".lua")
- local file = FILE_CACHE[lua_filename]
- if file then
- ret = self:run_lua(Lua(Source(filename, 1, #file), file))
- remove(_running_files)
- _continue_0 = true
- break
- end
- end
- local file = file or FILE_CACHE[filename]
- if not file then
- error("File does not exist: " .. tostring(filename), 0)
+ end
+ insert(_running_files, filename)
+ if match(filename, "%.lua$") then
+ local file = assert(FILE_CACHE[filename], "Could not find file: " .. tostring(filename))
+ ret = self:run_lua(file, Source(filename, 1, #file))
+ elseif match(filename, "%.nom$") or match(filename, "^/dev/fd/[012]$") then
+ if not self.skip_precompiled then
+ local lua_filename = gsub(filename, "%.nom$", ".lua")
+ local file = FILE_CACHE[lua_filename]
+ if file then
+ ret = self:run_lua(file, Source(filename, 1, #file))
+ remove(_running_files)
+ _continue_0 = true
+ break
end
- ret = self:run(Nomsu(Source(filename, 1, #file), file))
- else
- error("Invalid filetype for " .. tostring(filename), 0)
end
- loaded[filename] = ret or true
- remove(_running_files)
- _continue_0 = true
- until true
- if not _continue_0 then
- break
+ local file = file or FILE_CACHE[filename]
+ if not file then
+ error("File does not exist: " .. tostring(filename), 0)
+ end
+ ret = self:run(file, Source(filename, 1, #file))
+ else
+ error("Invalid filetype for " .. tostring(filename), 0)
end
+ self.LOADED[filename] = ret or true
+ remove(_running_files)
+ _continue_0 = true
+ until true
+ if not _continue_0 then
+ break
end
- loaded[filename] = ret or true
- return ret
- end,
- run_lua = function(self, lua)
- assert(type(lua) ~= 'string', "Attempt to run lua string instead of Lua (object)")
- local lua_string = tostring(lua)
- local run_lua_fn, err = load(lua_string, tostring(lua.source), "t", self.environment)
- if not run_lua_fn then
- local n = 1
- local fn
- fn = function()
- n = n + 1
- return ("\n%-3d|"):format(n)
- end
- local line_numbered_lua = "1 |" .. lua_string:gsub("\n", fn)
- error("Failed to compile generated code:\n" .. tostring(colored.bright(colored.blue(colored.onblack(line_numbered_lua)))) .. "\n\n" .. tostring(err), 0)
+ end
+ self.LOADED[filename] = ret or true
+ return ret
+ end
+ NomsuCompiler.run_lua = function(self, lua, source)
+ if source == nil then
+ source = nil
+ end
+ assert(type(lua) ~= 'string', "Attempt to run lua string instead of Lua (object)")
+ local lua_string = tostring(lua)
+ local run_lua_fn, err = load(lua_string, nil and tostring(source or lua.source), "t", self)
+ if not run_lua_fn then
+ local n = 1
+ local fn
+ fn = function()
+ n = n + 1
+ return ("\n%-3d|"):format(n)
end
- local source_key = tostring(lua.source)
- if not (self.source_map[source_key]) then
- local map = { }
- local offset = 1
- local source = lua.source
- local nomsu_str = tostring(FILE_CACHE[source.filename]:sub(source.start, source.stop))
- local lua_line = 1
- local nomsu_line = pos_to_line(nomsu_str, lua.source.start)
- local fn
- fn = function(s)
- if type(s) == 'string' then
- for nl in s:gmatch("\n") do
- map[lua_line] = map[lua_line] or nomsu_line
- lua_line = lua_line + 1
- end
- else
- local old_line = nomsu_line
- if s.source then
- nomsu_line = pos_to_line(nomsu_str, s.source.start)
- end
- local _list_0 = s.bits
- for _index_0 = 1, #_list_0 do
- local b = _list_0[_index_0]
- fn(b)
- end
+ local line_numbered_lua = "1 |" .. lua_string:gsub("\n", fn)
+ error("Failed to compile generated code:\n" .. tostring(colored.bright(colored.blue(colored.onblack(line_numbered_lua)))) .. "\n\n" .. tostring(err), 0)
+ end
+ local source_key = tostring(source or lua.source)
+ if not (self.source_map[source_key]) then
+ local map = { }
+ local offset = 1
+ source = source or lua.source
+ local nomsu_str = tostring(FILE_CACHE[source.filename]:sub(source.start, source.stop))
+ local lua_line = 1
+ local nomsu_line = pos_to_line(nomsu_str, source.start)
+ local fn
+ fn = function(s)
+ if type(s) == 'string' then
+ for nl in s:gmatch("\n") do
+ map[lua_line] = map[lua_line] or nomsu_line
+ lua_line = lua_line + 1
+ end
+ else
+ local old_line = nomsu_line
+ if s.source then
+ nomsu_line = pos_to_line(nomsu_str, s.source.start)
+ end
+ local _list_0 = s.bits
+ for _index_0 = 1, #_list_0 do
+ local b = _list_0[_index_0]
+ fn(b)
end
end
- fn(lua)
- map[lua_line] = map[lua_line] or nomsu_line
- map[0] = 0
- self.source_map[source_key] = map
end
- return run_lua_fn()
- end,
- tree_to_lua = function(self, tree)
- local _exp_0 = tree.type
- if "Action" == _exp_0 then
- local stub = tree.stub
- local action = self.environment['A' .. string.as_lua_id(stub)]
- if action and self.environment.COMPILE_TIME[action] then
+ fn(lua)
+ map[lua_line] = map[lua_line] or nomsu_line
+ map[0] = 0
+ self.source_map[source_key] = map
+ end
+ return run_lua_fn()
+ end
+ NomsuCompiler.compile = function(self, tree)
+ assert(LuaCode)
+ local _exp_0 = tree.type
+ if "Action" == _exp_0 then
+ local stub = tree.stub
+ do
+ local compile_action = self.COMPILE_ACTIONS[stub]
+ if compile_action then
local args
do
local _accum_0 = { }
@@ -461,7 +581,7 @@ do
args = _accum_0
end
do
- local arg_orders = self.environment.ARG_ORDERS[stub]
+ local arg_orders = self.ARG_ORDERS[stub]
if arg_orders then
do
local _accum_0 = { }
@@ -475,883 +595,631 @@ do
end
end
end
- local ret = action(tree, unpack(args))
+ local ret = compile_action(self, tree, unpack(args))
if not ret then
- compile_error(tree, "Compile-time action:\n%s\nfailed to produce any Lua")
+ self:compile_error(tree, "Compile-time action:\n%s\nfailed to produce any Lua")
end
return ret
end
- local lua = Lua.Value(tree.source)
- if not action and math_expression:match(stub) then
- for i, tok in ipairs(tree) do
- if type(tok) == 'string' then
- lua:append(tok)
- else
- local tok_lua = self:tree_to_lua(tok)
- if not (tok_lua.is_value) then
- compile_error(tok, "Non-expression value inside math expression:\n%s")
- end
- if tok.type == "Action" then
- tok_lua:parenthesize()
- end
- lua:append(tok_lua)
+ end
+ local action = self['A' .. string.as_lua_id(stub)]
+ local lua = LuaCode.Value(tree.source)
+ if not action and math_expression:match(stub) then
+ for i, tok in ipairs(tree) do
+ if type(tok) == 'string' then
+ lua:append(tok)
+ else
+ local tok_lua = self:compile(tok)
+ if not (tok_lua.is_value) then
+ self:compile_error(tok, "Non-expression value inside math expression:\n%s")
end
- if i < #tree then
- lua:append(" ")
+ if tok.type == "Action" then
+ tok_lua:parenthesize()
end
+ lua:append(tok_lua)
+ end
+ if i < #tree then
+ lua:append(" ")
end
- return lua
end
- local args = { }
- for i, tok in ipairs(tree) do
- local _continue_0 = false
- repeat
- if type(tok) == "string" then
- _continue_0 = true
- break
- end
- local arg_lua = self:tree_to_lua(tok)
- if not (arg_lua.is_value) then
- compile_error(tok, "Cannot use:\n%s\nas an argument to %s, since it's not an expression, it produces: %s", stub, repr(arg_lua))
- end
- insert(args, arg_lua)
+ return lua
+ end
+ local args = { }
+ for i, tok in ipairs(tree) do
+ local _continue_0 = false
+ repeat
+ if type(tok) == "string" then
_continue_0 = true
- until true
- if not _continue_0 then
break
end
+ local arg_lua = self:compile(tok)
+ if not (arg_lua.is_value) then
+ self:compile_error(tok, "Cannot use:\n%s\nas an argument to %s, since it's not an expression, it produces: %s", stub, repr(arg_lua))
+ end
+ insert(args, arg_lua)
+ _continue_0 = true
+ until true
+ if not _continue_0 then
+ break
end
- if action then
- do
- local arg_orders = self.environment.ARG_ORDERS[stub]
- if arg_orders then
- do
- local _accum_0 = { }
- local _len_0 = 1
- for _index_0 = 1, #arg_orders do
- local p = arg_orders[_index_0]
- _accum_0[_len_0] = args[p]
- _len_0 = _len_0 + 1
- end
- args = _accum_0
+ end
+ if action then
+ do
+ local arg_orders = self.ARG_ORDERS[stub]
+ if arg_orders then
+ do
+ local _accum_0 = { }
+ local _len_0 = 1
+ for _index_0 = 1, #arg_orders do
+ local p = arg_orders[_index_0]
+ _accum_0[_len_0] = args[p]
+ _len_0 = _len_0 + 1
end
+ args = _accum_0
end
end
end
- lua:append("A", string.as_lua_id(stub), "(")
- for i, arg in ipairs(args) do
- lua:append(arg)
- if i < #args then
- lua:append(", ")
- end
+ end
+ lua:append("A", string.as_lua_id(stub), "(")
+ for i, arg in ipairs(args) do
+ lua:append(arg)
+ if i < #args then
+ lua:append(", ")
end
- lua:append(")")
- return lua
- elseif "EscapedNomsu" == _exp_0 then
- local make_tree
- make_tree = function(t)
- if not (AST.is_syntax_tree(t)) then
- return repr(t)
- end
- local bits
- do
- local _accum_0 = { }
- local _len_0 = 1
- for _index_0 = 1, #t do
- local bit = t[_index_0]
- _accum_0[_len_0] = make_tree(bit)
- _len_0 = _len_0 + 1
- end
- bits = _accum_0
- end
- return t.type .. "(" .. repr(tostring(t.source)) .. ", " .. table.concat(bits, ", ") .. ")"
+ end
+ lua:append(")")
+ return lua
+ elseif "EscapedNomsu" == _exp_0 then
+ local make_tree
+ make_tree = function(t)
+ if not (AST.is_syntax_tree(t)) then
+ return repr(t)
end
- return Lua.Value(tree.source, make_tree(tree[1]))
- elseif "Block" == _exp_0 then
- local lua = Lua(tree.source)
- for i, line in ipairs(tree) do
- local line_lua = self:tree_to_lua(line)
- if i > 1 then
- lua:append("\n")
+ local bits
+ do
+ local _accum_0 = { }
+ local _len_0 = 1
+ for _index_0 = 1, #t do
+ local bit = t[_index_0]
+ _accum_0[_len_0] = make_tree(bit)
+ _len_0 = _len_0 + 1
end
- lua:append(line_lua:as_statements())
+ bits = _accum_0
end
- return lua
- elseif "Text" == _exp_0 then
- local lua = Lua.Value(tree.source)
- local string_buffer = ""
- for i, bit in ipairs(tree) do
- local _continue_0 = false
- repeat
- if type(bit) == "string" then
- string_buffer = string_buffer .. bit
- _continue_0 = true
- break
- end
- if string_buffer ~= "" then
- if #lua.bits > 0 then
- lua:append("..")
- end
- lua:append(repr(string_buffer))
- string_buffer = ""
- end
- local bit_lua = self:tree_to_lua(bit)
- if not (bit_lua.is_value) then
- local src = ' ' .. gsub(tostring(self:tree_to_nomsu(bit)), '\n', '\n ')
- local line = tostring(bit.source.filename) .. ":" .. tostring(pos_to_line(FILE_CACHE[bit.source.filename], bit.source.start))
- compile_error(bit, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.")
- end
+ return t.type .. "(" .. repr(tostring(t.source)) .. ", " .. table.concat(bits, ", ") .. ")"
+ end
+ return LuaCode.Value(tree.source, make_tree(tree[1]))
+ elseif "Block" == _exp_0 then
+ local lua = LuaCode(tree.source)
+ for i, line in ipairs(tree) do
+ local line_lua = self:compile(line)
+ if i > 1 then
+ lua:append("\n")
+ end
+ lua:append(line_lua:as_statements())
+ end
+ return lua
+ elseif "Text" == _exp_0 then
+ local lua = LuaCode.Value(tree.source)
+ local string_buffer = ""
+ for i, bit in ipairs(tree) do
+ local _continue_0 = false
+ repeat
+ if type(bit) == "string" then
+ string_buffer = string_buffer .. bit
+ _continue_0 = true
+ break
+ end
+ if string_buffer ~= "" then
if #lua.bits > 0 then
lua:append("..")
end
- if bit.type ~= "Text" then
- bit_lua = Lua.Value(bit.source, "stringify(", bit_lua, ")")
- end
- lua:append(bit_lua)
- _continue_0 = true
- until true
- if not _continue_0 then
- break
+ lua:append(repr(string_buffer))
+ string_buffer = ""
+ end
+ local bit_lua = self:compile(bit)
+ if not (bit_lua.is_value) then
+ local src = ' ' .. gsub(tostring(self:tree_to_nomsu(bit)), '\n', '\n ')
+ local line = tostring(bit.source.filename) .. ":" .. tostring(pos_to_line(FILE_CACHE[bit.source.filename], bit.source.start))
+ self:compile_error(bit, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.")
end
- end
- if string_buffer ~= "" or #lua.bits == 0 then
if #lua.bits > 0 then
lua:append("..")
end
- lua:append(repr(string_buffer))
+ if bit.type ~= "Text" then
+ bit_lua = LuaCode.Value(bit.source, "stringify(", bit_lua, ")")
+ end
+ lua:append(bit_lua)
+ _continue_0 = true
+ until true
+ if not _continue_0 then
+ break
end
- if #lua.bits > 1 then
- lua:parenthesize()
+ end
+ if string_buffer ~= "" or #lua.bits == 0 then
+ if #lua.bits > 0 then
+ lua:append("..")
end
- return lua
- elseif "List" == _exp_0 then
- local lua = Lua.Value(tree.source, "list{")
- local line_length = 0
- for i, item in ipairs(tree) do
- local item_lua = self:tree_to_lua(item)
- if not (item_lua.is_value) then
- compile_error(item, "Cannot use:\n%s\nas a list item, since it's not an expression.")
- end
- lua:append(item_lua)
- local item_string = tostring(item_lua)
- local last_line = match(item_string, "[^\n]*$")
- if match(item_string, "\n") then
- line_length = #last_line
+ lua:append(repr(string_buffer))
+ end
+ if #lua.bits > 1 then
+ lua:parenthesize()
+ end
+ return lua
+ elseif "List" == _exp_0 then
+ local lua = LuaCode.Value(tree.source, "list{")
+ local line_length = 0
+ for i, item in ipairs(tree) do
+ local item_lua = self:compile(item)
+ if not (item_lua.is_value) then
+ self:compile_error(item, "Cannot use:\n%s\nas a list item, since it's not an expression.")
+ end
+ lua:append(item_lua)
+ local item_string = tostring(item_lua)
+ local last_line = match(item_string, "[^\n]*$")
+ if match(item_string, "\n") then
+ line_length = #last_line
+ else
+ line_length = line_length + #last_line
+ end
+ if i < #tree then
+ if line_length >= MAX_LINE then
+ lua:append(",\n ")
+ line_length = 0
else
- line_length = line_length + #last_line
- end
- if i < #tree then
- if line_length >= MAX_LINE then
- lua:append(",\n ")
- line_length = 0
- else
- lua:append(", ")
- line_length = line_length + 2
- end
+ lua:append(", ")
+ line_length = line_length + 2
end
end
- lua:append("}")
- return lua
- elseif "Dict" == _exp_0 then
- local lua = Lua.Value(tree.source, "dict{")
- local line_length = 0
- for i, entry in ipairs(tree) do
- local entry_lua = self:tree_to_lua(entry)
- lua:append(entry_lua)
- local entry_lua_str = tostring(entry_lua)
- local last_line = match(entry_lua_str, "\n([^\n]*)$")
- if last_line then
- line_length = #last_line
+ end
+ lua:append("}")
+ return lua
+ elseif "Dict" == _exp_0 then
+ local lua = LuaCode.Value(tree.source, "dict{")
+ local line_length = 0
+ for i, entry in ipairs(tree) do
+ local entry_lua = self:compile(entry)
+ lua:append(entry_lua)
+ local entry_lua_str = tostring(entry_lua)
+ local last_line = match(entry_lua_str, "\n([^\n]*)$")
+ if last_line then
+ line_length = #last_line
+ else
+ line_length = line_length + #entry_lua_str
+ end
+ if i < #tree then
+ if line_length >= MAX_LINE then
+ lua:append(",\n ")
+ line_length = 0
else
- line_length = line_length + #entry_lua_str
- end
- if i < #tree then
- if line_length >= MAX_LINE then
- lua:append(",\n ")
- line_length = 0
- else
- lua:append(", ")
- line_length = line_length + 2
- end
+ lua:append(", ")
+ line_length = line_length + 2
end
end
- lua:append("}")
- return lua
- elseif "DictEntry" == _exp_0 then
- local key, value = tree[1], tree[2]
- local key_lua = self:tree_to_lua(key)
+ end
+ lua:append("}")
+ return lua
+ elseif "DictEntry" == _exp_0 then
+ local key, value = tree[1], tree[2]
+ local key_lua = self:compile(key)
+ if not (key_lua.is_value) then
+ self:compile_error(tree[1], "Cannot use:\n%s\nas a dict key, since it's not an expression.")
+ end
+ local value_lua = value and self:compile(value) or LuaCode.Value(key.source, "true")
+ if not (value_lua.is_value) then
+ self:compile_error(tree[2], "Cannot use:\n%s\nas a dict value, since it's not an expression.")
+ end
+ local key_str = match(tostring(key_lua), [=[["']([a-zA-Z_][a-zA-Z0-9_]*)['"]]=])
+ if key_str then
+ return LuaCode(tree.source, key_str, "=", value_lua)
+ elseif sub(tostring(key_lua), 1, 1) == "[" then
+ return LuaCode(tree.source, "[ ", key_lua, "]=", value_lua)
+ else
+ return LuaCode(tree.source, "[", key_lua, "]=", value_lua)
+ end
+ elseif "IndexChain" == _exp_0 then
+ local lua = self:compile(tree[1])
+ if not (lua.is_value) then
+ self:compile_error(tree[1], "Cannot index:\n%s\nsince it's not an expression.")
+ end
+ local first_char = sub(tostring(lua), 1, 1)
+ if first_char == "{" or first_char == '"' or first_char == "[" then
+ lua:parenthesize()
+ end
+ for i = 2, #tree do
+ local key = tree[i]
+ local key_lua = self:compile(key)
if not (key_lua.is_value) then
- compile_error(tree[1], "Cannot use:\n%s\nas a dict key, since it's not an expression.")
- end
- local value_lua = value and self:tree_to_lua(value) or Lua.Value(key.source, "true")
- if not (value_lua.is_value) then
- compile_error(tree[2], "Cannot use:\n%s\nas a dict value, since it's not an expression.")
+ self:compile_error(key, "Cannot use:\n%s\nas an index, since it's not an expression.")
end
- local key_str = match(tostring(key_lua), [=[["']([a-zA-Z_][a-zA-Z0-9_]*)['"]]=])
- if key_str then
- return Lua(tree.source, key_str, "=", value_lua)
- elseif sub(tostring(key_lua), 1, 1) == "[" then
- return Lua(tree.source, "[ ", key_lua, "]=", value_lua)
- else
- return Lua(tree.source, "[", key_lua, "]=", value_lua)
- end
- elseif "IndexChain" == _exp_0 then
- local lua = self:tree_to_lua(tree[1])
- if not (lua.is_value) then
- compile_error(tree[1], "Cannot index:\n%s\nsince it's not an expression.")
- end
- local first_char = sub(tostring(lua), 1, 1)
- if first_char == "{" or first_char == '"' or first_char == "[" then
- lua:parenthesize()
- end
- for i = 2, #tree do
- local key = tree[i]
- local key_lua = self:tree_to_lua(key)
- if not (key_lua.is_value) then
- compile_error(key, "Cannot use:\n%s\nas an index, since it's not an expression.")
+ local key_lua_str = tostring(key_lua)
+ do
+ local lua_id = match(key_lua_str, "^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$")
+ if lua_id then
+ lua:append("." .. tostring(lua_id))
+ elseif sub(key_lua_str, 1, 1) == '[' then
+ lua:append("[ ", key_lua, " ]")
+ else
+ lua:append("[", key_lua, "]")
end
- local key_lua_str = tostring(key_lua)
- do
- local lua_id = match(key_lua_str, "^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$")
- if lua_id then
- lua:append("." .. tostring(lua_id))
- elseif sub(key_lua_str, 1, 1) == '[' then
- lua:append("[ ", key_lua, " ]")
- else
- lua:append("[", key_lua, "]")
+ end
+ end
+ return lua
+ elseif "Number" == _exp_0 then
+ return LuaCode.Value(tree.source, tostring(tree[1]))
+ elseif "Var" == _exp_0 then
+ return LuaCode.Value(tree.source, string.as_lua_id(tree[1]))
+ else
+ return error("Unknown type: " .. tostring(tree.type))
+ end
+ end
+ NomsuCompiler.tree_to_nomsu = function(self, tree, inline, can_use_colon)
+ if inline == nil then
+ inline = false
+ end
+ if can_use_colon == nil then
+ can_use_colon = false
+ end
+ local _exp_0 = tree.type
+ if "Action" == _exp_0 then
+ if inline then
+ local nomsu = NomsuCode(tree.source)
+ for i, bit in ipairs(tree) do
+ if type(bit) == "string" then
+ if i > 1 then
+ nomsu:append(" ")
end
+ nomsu:append(bit)
+ else
+ local arg_nomsu = self:tree_to_nomsu(bit, true)
+ if not (arg_nomsu) then
+ return nil
+ end
+ if not (i == 1) then
+ nomsu:append(" ")
+ end
+ if bit.type == "Action" or bit.type == "Block" then
+ arg_nomsu:parenthesize()
+ end
+ nomsu:append(arg_nomsu)
end
end
- return lua
- elseif "Number" == _exp_0 then
- return Lua.Value(tree.source, tostring(tree[1]))
- elseif "Var" == _exp_0 then
- return Lua.Value(tree.source, string.as_lua_id(tree[1]))
+ return nomsu
else
- return error("Unknown type: " .. tostring(tree.type))
- end
- end,
- tree_to_nomsu = function(self, tree, inline, can_use_colon)
- if inline == nil then
- inline = false
- end
- if can_use_colon == nil then
- can_use_colon = false
- end
- local _exp_0 = tree.type
- if "Action" == _exp_0 then
- if inline then
- local nomsu = Nomsu(tree.source)
- for i, bit in ipairs(tree) do
- if type(bit) == "string" then
- if i > 1 then
- nomsu:append(" ")
- end
- nomsu:append(bit)
+ local nomsu = NomsuCode(tree.source)
+ local next_space = ""
+ local line_len, last_colon = 0, nil
+ for i, bit in ipairs(tree) do
+ if type(bit) == "string" then
+ line_len = line_len + #next_space + #bit
+ nomsu:append(next_space, bit)
+ next_space = " "
+ else
+ local arg_nomsu
+ if last_colon == i - 1 and bit.type == "Action" then
+ arg_nomsu = nil
+ elseif bit.type == "Block" then
+ arg_nomsu = nil
else
- local arg_nomsu = self:tree_to_nomsu(bit, true)
- if not (arg_nomsu) then
- return nil
- end
- if not (i == 1) then
- nomsu:append(" ")
- end
- if bit.type == "Action" or bit.type == "Block" then
- arg_nomsu:parenthesize()
- end
- nomsu:append(arg_nomsu)
+ arg_nomsu = self:tree_to_nomsu(bit, true)
end
- end
- return nomsu
- else
- local nomsu = Nomsu(tree.source)
- local next_space = ""
- local line_len, last_colon = 0, nil
- for i, bit in ipairs(tree) do
- if type(bit) == "string" then
- line_len = line_len + #next_space + #bit
- nomsu:append(next_space, bit)
- next_space = " "
- else
- local arg_nomsu
- if last_colon == i - 1 and bit.type == "Action" then
- arg_nomsu = nil
- elseif bit.type == "Block" then
- arg_nomsu = nil
- else
- arg_nomsu = self:tree_to_nomsu(bit, true)
- end
- if arg_nomsu and line_len + #tostring(arg_nomsu) < MAX_LINE then
- if bit.type == "Action" then
- if can_use_colon and i > 1 then
- nomsu:append(match(next_space, "[^ ]*"), ": ", arg_nomsu)
- next_space = "\n.."
- line_len = 2
- last_colon = i
- else
- nomsu:append(next_space, "(", arg_nomsu, ")")
- line_len = line_len + #next_space + 2 + #tostring(arg_nomsu)
- next_space = " "
- end
+ if arg_nomsu and line_len + #tostring(arg_nomsu) < MAX_LINE then
+ if bit.type == "Action" then
+ if can_use_colon and i > 1 then
+ nomsu:append(match(next_space, "[^ ]*"), ": ", arg_nomsu)
+ next_space = "\n.."
+ line_len = 2
+ last_colon = i
else
- nomsu:append(next_space, arg_nomsu)
- line_len = line_len + #next_space + #tostring(arg_nomsu)
+ nomsu:append(next_space, "(", arg_nomsu, ")")
+ line_len = line_len + #next_space + 2 + #tostring(arg_nomsu)
next_space = " "
end
else
- arg_nomsu = self:tree_to_nomsu(bit, nil, true)
- if not (nomsu) then
- return nil
- end
- if bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" then
- if i == 1 then
- arg_nomsu = Nomsu(bit.source, "(..)\n ", arg_nomsu)
- else
- arg_nomsu = Nomsu(bit.source, "\n ", arg_nomsu)
- end
- end
- if last_colon == i - 1 and (bit.type == "Action" or bit.type == "Block") then
- next_space = ""
- end
nomsu:append(next_space, arg_nomsu)
- next_space = "\n.."
- line_len = 2
+ line_len = line_len + #next_space + #tostring(arg_nomsu)
+ next_space = " "
end
- if next_space == " " and #(match(tostring(nomsu), "[^\n]*$")) > MAX_LINE then
- next_space = "\n.."
+ else
+ arg_nomsu = self:tree_to_nomsu(bit, nil, true)
+ if not (nomsu) then
+ return nil
end
+ if bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" then
+ if i == 1 then
+ arg_nomsu = NomsuCode(bit.source, "(..)\n ", arg_nomsu)
+ else
+ arg_nomsu = NomsuCode(bit.source, "\n ", arg_nomsu)
+ end
+ end
+ if last_colon == i - 1 and (bit.type == "Action" or bit.type == "Block") then
+ next_space = ""
+ end
+ nomsu:append(next_space, arg_nomsu)
+ next_space = "\n.."
+ line_len = 2
end
- end
- return nomsu
- end
- elseif "EscapedNomsu" == _exp_0 then
- local nomsu = self:tree_to_nomsu(tree[1], true)
- if nomsu == nil and not inline then
- nomsu = self:tree_to_nomsu(tree[1])
- return nomsu and Nomsu(tree.source, "\\:\n ", nomsu)
- end
- return nomsu and Nomsu(tree.source, "\\(", nomsu, ")")
- elseif "Block" == _exp_0 then
- if inline then
- local nomsu = Nomsu(tree.source)
- for i, line in ipairs(tree) do
- if i > 1 then
- nomsu:append("; ")
- end
- local line_nomsu = self:tree_to_nomsu(line, true)
- if not (line_nomsu) then
- return nil
+ if next_space == " " and #(match(tostring(nomsu), "[^\n]*$")) > MAX_LINE then
+ next_space = "\n.."
end
- nomsu:append(line_nomsu)
end
- return nomsu
end
- local nomsu = Nomsu(tree.source)
+ return nomsu
+ end
+ elseif "EscapedNomsu" == _exp_0 then
+ local nomsu = self:tree_to_nomsu(tree[1], true)
+ if nomsu == nil and not inline then
+ nomsu = self:tree_to_nomsu(tree[1])
+ return nomsu and NomsuCode(tree.source, "\\:\n ", nomsu)
+ end
+ return nomsu and NomsuCode(tree.source, "\\(", nomsu, ")")
+ elseif "Block" == _exp_0 then
+ if inline then
+ local nomsu = NomsuCode(tree.source)
for i, line in ipairs(tree) do
- line = assert(self:tree_to_nomsu(line, nil, true), "Could not convert line to nomsu")
- nomsu:append(line)
- if i < #tree then
- nomsu:append("\n")
- if match(tostring(line), "\n") then
- nomsu:append("\n")
- end
+ if i > 1 then
+ nomsu:append("; ")
+ end
+ local line_nomsu = self:tree_to_nomsu(line, true)
+ if not (line_nomsu) then
+ return nil
end
+ nomsu:append(line_nomsu)
end
return nomsu
- elseif "Text" == _exp_0 then
- if inline then
- local nomsu = Nomsu(tree.source, '"')
- for _index_0 = 1, #tree do
- local bit = tree[_index_0]
- if type(bit) == 'string' then
- nomsu:append((gsub(gsub(gsub(bit, "\\", "\\\\"), "\n", "\\n"), '"', '\\"')))
- else
- local interp_nomsu = self:tree_to_nomsu(bit, true)
- if interp_nomsu then
- if bit.type ~= "Var" and bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" then
- interp_nomsu:parenthesize()
- end
- nomsu:append("\\", interp_nomsu)
- else
- return nil
+ end
+ local nomsu = NomsuCode(tree.source)
+ for i, line in ipairs(tree) do
+ line = assert(self:tree_to_nomsu(line, nil, true), "Could not convert line to nomsu")
+ nomsu:append(line)
+ if i < #tree then
+ nomsu:append("\n")
+ if match(tostring(line), "\n") then
+ nomsu:append("\n")
+ end
+ end
+ end
+ return nomsu
+ elseif "Text" == _exp_0 then
+ if inline then
+ local nomsu = NomsuCode(tree.source, '"')
+ for _index_0 = 1, #tree do
+ local bit = tree[_index_0]
+ if type(bit) == 'string' then
+ nomsu:append((gsub(gsub(gsub(bit, "\\", "\\\\"), "\n", "\\n"), '"', '\\"')))
+ else
+ local interp_nomsu = self:tree_to_nomsu(bit, true)
+ if interp_nomsu then
+ if bit.type ~= "Var" and bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" then
+ interp_nomsu:parenthesize()
end
+ nomsu:append("\\", interp_nomsu)
+ else
+ return nil
end
end
- nomsu:append('"')
- return nomsu
- else
- local inline_version = self:tree_to_nomsu(tree, true)
- if inline_version and #inline_version <= MAX_LINE then
- return inline_version
- end
- local nomsu = Nomsu(tree.source, '".."\n ')
- for i, bit in ipairs(tree) do
- if type(bit) == 'string' then
- local bit_lines = get_lines:match(bit)
- for j, line in ipairs(bit_lines) do
- if j > 1 then
- nomsu:append("\n ")
- end
- if #line > 1.25 * MAX_LINE then
- local remainder = line
- while #remainder > 0 do
- local split = find(remainder, " ", MAX_LINE, true)
- if split then
- local chunk
- chunk, remainder = sub(remainder, 1, split), sub(remainder, split + 1, -1)
- nomsu:append(chunk)
- elseif #remainder > 1.75 * MAX_LINE then
- split = math.floor(1.5 * MAX_LINE)
- local chunk
- chunk, remainder = sub(remainder, 1, split), sub(remainder, split + 1, -1)
- nomsu:append(chunk)
- else
- nomsu:append(remainder)
- break
- end
- if #remainder > 0 then
- nomsu:append("\\\n ..")
- end
- end
- else
- nomsu:append(line)
- end
+ end
+ nomsu:append('"')
+ return nomsu
+ else
+ local inline_version = self:tree_to_nomsu(tree, true)
+ if inline_version and #inline_version <= MAX_LINE then
+ return inline_version
+ end
+ local nomsu = NomsuCode(tree.source, '".."\n ')
+ for i, bit in ipairs(tree) do
+ if type(bit) == 'string' then
+ local bit_lines = get_lines:match(bit)
+ for j, line in ipairs(bit_lines) do
+ if j > 1 then
+ nomsu:append("\n ")
end
- else
- local interp_nomsu = self:tree_to_nomsu(bit, true)
- if interp_nomsu then
- if bit.type ~= "Var" and bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" then
- interp_nomsu:parenthesize()
+ if #line > 1.25 * MAX_LINE then
+ local remainder = line
+ while #remainder > 0 do
+ local split = find(remainder, " ", MAX_LINE, true)
+ if split then
+ local chunk
+ chunk, remainder = sub(remainder, 1, split), sub(remainder, split + 1, -1)
+ nomsu:append(chunk)
+ elseif #remainder > 1.75 * MAX_LINE then
+ split = math.floor(1.5 * MAX_LINE)
+ local chunk
+ chunk, remainder = sub(remainder, 1, split), sub(remainder, split + 1, -1)
+ nomsu:append(chunk)
+ else
+ nomsu:append(remainder)
+ break
+ end
+ if #remainder > 0 then
+ nomsu:append("\\\n ..")
+ end
end
- nomsu:append("\\", interp_nomsu)
else
- interp_nomsu = assert(self:tree_to_nomsu(bit))
- if not (interp_nomsu) then
- return nil
- end
- nomsu:append("\\\n ", interp_nomsu)
- if i < #tree then
- nomsu:append("\n ..")
- end
+ nomsu:append(line)
end
end
- end
- return nomsu
- end
- elseif "List" == _exp_0 then
- if inline then
- local nomsu = Nomsu(tree.source, "[")
- for i, item in ipairs(tree) do
- local item_nomsu = self:tree_to_nomsu(item, true)
- if not (item_nomsu) then
- return nil
- end
- if i > 1 then
- nomsu:append(", ")
- end
- nomsu:append(item_nomsu)
- end
- nomsu:append("]")
- return nomsu
- else
- local inline_version = self:tree_to_nomsu(tree, true)
- if inline_version and #inline_version <= MAX_LINE then
- return inline_version
- end
- local nomsu = Nomsu(tree.source, "[..]")
- local line = Nomsu(tree.source, "\n ")
- for _index_0 = 1, #tree do
- local item = tree[_index_0]
- local item_nomsu = self:tree_to_nomsu(item, true)
- if item_nomsu and #line + #", " + #item_nomsu <= MAX_LINE then
- if #line.bits > 1 then
- line:append(", ")
+ else
+ local interp_nomsu = self:tree_to_nomsu(bit, true)
+ if interp_nomsu then
+ if bit.type ~= "Var" and bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" then
+ interp_nomsu:parenthesize()
end
- line:append(item_nomsu)
+ nomsu:append("\\", interp_nomsu)
else
- if not (item_nomsu) then
- item_nomsu = self:tree_to_nomsu(item)
- if not (item_nomsu) then
- return nil
- end
+ interp_nomsu = assert(self:tree_to_nomsu(bit))
+ if not (interp_nomsu) then
+ return nil
end
- if #line.bits > 1 then
- nomsu:append(line)
- line = Nomsu(line.source, "\n ")
+ nomsu:append("\\\n ", interp_nomsu)
+ if i < #tree then
+ nomsu:append("\n ..")
end
- line:append(item_nomsu)
end
end
- if #line.bits > 1 then
- nomsu:append(line)
- end
- return nomsu
end
- elseif "Dict" == _exp_0 then
- if inline then
- local nomsu = Nomsu(tree.source, "{")
- for i, entry in ipairs(tree) do
- local entry_nomsu = self:tree_to_nomsu(entry, true)
- if not (entry_nomsu) then
- return nil
- end
- if i > 1 then
- nomsu:append(", ")
- end
- nomsu:append(entry_nomsu)
+ return nomsu
+ end
+ elseif "List" == _exp_0 then
+ if inline then
+ local nomsu = NomsuCode(tree.source, "[")
+ for i, item in ipairs(tree) do
+ local item_nomsu = self:tree_to_nomsu(item, true)
+ if not (item_nomsu) then
+ return nil
end
- nomsu:append("}")
- return nomsu
- else
- local inline_version = self:tree_to_nomsu(tree, true)
- if inline_version then
- return inline_version
+ if i > 1 then
+ nomsu:append(", ")
end
- local nomsu = Nomsu(tree.source, "{..}")
- local line = Nomsu(tree.source, "\n ")
- for _index_0 = 1, #tree do
- local entry = tree[_index_0]
- local entry_nomsu = self:tree_to_nomsu(entry)
- if not (entry_nomsu) then
- return nil
+ nomsu:append(item_nomsu)
+ end
+ nomsu:append("]")
+ return nomsu
+ else
+ local inline_version = self:tree_to_nomsu(tree, true)
+ if inline_version and #inline_version <= MAX_LINE then
+ return inline_version
+ end
+ local nomsu = NomsuCode(tree.source, "[..]")
+ local line = NomsuCode(tree.source, "\n ")
+ for _index_0 = 1, #tree do
+ local item = tree[_index_0]
+ local item_nomsu = self:tree_to_nomsu(item, true)
+ if item_nomsu and #line + #", " + #item_nomsu <= MAX_LINE then
+ if #line.bits > 1 then
+ line:append(", ")
end
- if #line + #tostring(entry_nomsu) <= MAX_LINE then
- if #line.bits > 1 then
- line:append(", ")
- end
- line:append(entry_nomsu)
- else
- if #line.bits > 1 then
- nomsu:append(line)
- line = Nomsu(line.source, "\n ")
+ line:append(item_nomsu)
+ else
+ if not (item_nomsu) then
+ item_nomsu = self:tree_to_nomsu(item)
+ if not (item_nomsu) then
+ return nil
end
- line:append(entry_nomsu)
end
+ if #line.bits > 1 then
+ nomsu:append(line)
+ line = NomsuCode(line.source, "\n ")
+ end
+ line:append(item_nomsu)
end
- if #line.bits > 1 then
- nomsu:append(line)
- end
- return nomsu
- end
- elseif "DictEntry" == _exp_0 then
- local key, value = tree[1], tree[2]
- local key_nomsu = self:tree_to_nomsu(key, true)
- if not (key_nomsu) then
- return nil
- end
- if key.type == "Action" or key.type == "Block" then
- key_nomsu:parenthesize()
end
- local value_nomsu
- if value then
- value_nomsu = self:tree_to_nomsu(value, true)
- else
- value_nomsu = Nomsu(tree.source, "")
- end
- if inline and not value_nomsu then
- return nil
+ if #line.bits > 1 then
+ nomsu:append(line)
end
- if not value_nomsu then
- if inline then
- return nil
- end
- value_nomsu = self:tree_to_nomsu(value)
- if not (value_nomsu) then
+ return nomsu
+ end
+ elseif "Dict" == _exp_0 then
+ if inline then
+ local nomsu = NomsuCode(tree.source, "{")
+ for i, entry in ipairs(tree) do
+ local entry_nomsu = self:tree_to_nomsu(entry, true)
+ if not (entry_nomsu) then
return nil
end
- end
- return Nomsu(tree.source, key_nomsu, ":", value_nomsu)
- elseif "IndexChain" == _exp_0 then
- local nomsu = Nomsu(tree.source)
- for i, bit in ipairs(tree) do
if i > 1 then
- nomsu:append(".")
+ nomsu:append(", ")
end
- local bit_nomsu
- if bit.type == "Text" and #bit == 1 and type(bit[1]) == 'string' then
- if (NOMSU_DEFS.ident_char ^ 1):match(bit[1]) then
- bit_nomsu = bit[1]
- end
- end
- if not (bit_nomsu) then
- bit_nomsu = self:tree_to_nomsu(bit, true)
- end
- if not (bit_nomsu) then
+ nomsu:append(entry_nomsu)
+ end
+ nomsu:append("}")
+ return nomsu
+ else
+ local inline_version = self:tree_to_nomsu(tree, true)
+ if inline_version then
+ return inline_version
+ end
+ local nomsu = NomsuCode(tree.source, "{..}")
+ local line = NomsuCode(tree.source, "\n ")
+ for _index_0 = 1, #tree do
+ local entry = tree[_index_0]
+ local entry_nomsu = self:tree_to_nomsu(entry)
+ if not (entry_nomsu) then
return nil
end
- local _exp_1 = bit.type
- if "Action" == _exp_1 or "Block" == _exp_1 or "IndexChain" == _exp_1 then
- bit_nomsu:parenthesize()
- elseif "Number" == _exp_1 then
- if i < #tree then
- bit_nomsu:parenthesize()
+ if #line + #tostring(entry_nomsu) <= MAX_LINE then
+ if #line.bits > 1 then
+ line:append(", ")
end
+ line:append(entry_nomsu)
+ else
+ if #line.bits > 1 then
+ nomsu:append(line)
+ line = NomsuCode(line.source, "\n ")
+ end
+ line:append(entry_nomsu)
end
- nomsu:append(bit_nomsu)
+ end
+ if #line.bits > 1 then
+ nomsu:append(line)
end
return nomsu
- elseif "Number" == _exp_0 then
- return Nomsu(tree.source, tostring(tree[1]))
- elseif "Var" == _exp_0 then
- return Nomsu(tree.source, "%", tree[1])
+ end
+ elseif "DictEntry" == _exp_0 then
+ local key, value = tree[1], tree[2]
+ local key_nomsu = self:tree_to_nomsu(key, true)
+ if not (key_nomsu) then
+ return nil
+ end
+ if key.type == "Action" or key.type == "Block" then
+ key_nomsu:parenthesize()
+ end
+ local value_nomsu
+ if value then
+ value_nomsu = self:tree_to_nomsu(value, true)
else
- return error("Unknown type: " .. tostring(tree.type))
+ value_nomsu = NomsuCode(tree.source, "")
end
- end,
- initialize_core = function(self)
- local nomsu = self
- do
- local _with_0 = nomsu.environment
- _with_0.A_immediately_1 = _with_0.compile_time(function(self, _block)
- local lua = nomsu:tree_to_lua(_block):as_statements()
- lua:declare_locals()
- nomsu:run_lua(lua)
- return Lua(_block.source, "if IMMEDIATE then\n ", lua, "\nend")
- end)
- local add_lua_string_bits
- add_lua_string_bits = function(lua, code)
- local line_len = 0
- if code.type ~= "Text" then
- lua:append(", ", nomsu:tree_to_lua(code))
- return
- end
- for _index_0 = 1, #code do
- local bit = code[_index_0]
- local bit_lua
- if type(bit) == "string" then
- bit_lua = repr(bit)
- else
- bit_lua = nomsu:tree_to_lua(bit)
- if not (bit_lua.is_value) then
- compile_error(bit, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.")
- end
- bit_lua = bit_lua
- end
- line_len = line_len + #tostring(bit_lua)
- if line_len > MAX_LINE then
- lua:append(",\n ")
- line_len = 4
- else
- lua:append(", ")
- end
- lua:append(bit_lua)
- end
+ if inline and not value_nomsu then
+ return nil
+ end
+ if not value_nomsu then
+ if inline then
+ return nil
end
- _with_0.A_Lua_1 = _with_0.compile_time(function(self, _code)
- local lua = Lua.Value(_code.source, "Lua(", repr(tostring(_code.source)))
- add_lua_string_bits(lua, _code)
- lua:append(")")
- return lua
- end)
- _with_0.A_Lua_value_1 = _with_0.compile_time(function(self, _code)
- local lua = Lua.Value(_code.source, "Lua.Value(", repr(tostring(_code.source)))
- add_lua_string_bits(lua, _code)
- lua:append(")")
- return lua
- end)
- local add_lua_bits
- add_lua_bits = function(lua, code)
- for _index_0 = 1, #code do
- local bit = code[_index_0]
- if type(bit) == "string" then
- lua:append(bit)
- else
- local bit_lua = nomsu:tree_to_lua(bit)
- if not (bit_lua.is_value) then
- compile_error(bit, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.")
- end
- lua:append(bit_lua)
- end
- end
- return lua
+ value_nomsu = self:tree_to_nomsu(value)
+ if not (value_nomsu) then
+ return nil
end
- nomsu.environment["A" .. string.as_lua_id("lua > 1")] = _with_0.compile_time(function(self, _code)
- if _code.type ~= "Text" then
- return Lua(self.source, "nomsu:run_lua(", nomsu:tree_to_lua(_code), ");")
- end
- return add_lua_bits(Lua(self.source), _code)
- end)
- nomsu.environment["A" .. string.as_lua_id("= lua 1")] = _with_0.compile_time(function(self, _code)
- if _code.type ~= "Text" then
- return Lua.Value(self.source, "nomsu:run_lua(", nomsu:tree_to_lua(_code), ":as_statements('return '))")
- end
- return add_lua_bits(Lua.Value(self.source), _code)
- end)
- _with_0.A_use_1 = _with_0.compile_time(function(self, _path)
- if not (_path.type == 'Text' and #_path == 1 and type(_path[1]) == 'string') then
- return Lua(_path.source, "nomsu:run_file(" .. tostring(nomsu:tree_to_lua(_path)) .. ");")
- end
- local path = _path[1]
- nomsu:run_file(path)
- return Lua(_path.source, "nomsu:run_file(" .. tostring(repr(path)) .. ");")
- end)
- return _with_0
end
- end
- }
- _base_0.__index = _base_0
- _class_0 = setmetatable({
- __init = function(self)
- local NaN_surrogate = { }
- local nil_surrogate = { }
- self.ids = setmetatable({ }, {
- __mode = "k",
- __index = function(self, key)
- if key == nil then
- return self[nil_surrogate]
- elseif key ~= key then
- return self[NaN_surrogate]
+ return NomsuCode(tree.source, key_nomsu, ":", value_nomsu)
+ elseif "IndexChain" == _exp_0 then
+ local nomsu = NomsuCode(tree.source)
+ for i, bit in ipairs(tree) do
+ if i > 1 then
+ nomsu:append(".")
+ end
+ local bit_nomsu
+ if bit.type == "Text" and #bit == 1 and type(bit[1]) == 'string' then
+ if bit[1]:match("[_a-zA-Z][_a-zA-Z0-9]*") then
+ bit_nomsu = bit[1]
end
- local id = new_uuid()
- self[key] = id
- return id
end
- })
- self.source_map = { }
- local _list_mt = {
- __eq = utils.equivalent,
- __tostring = function(self)
- return "[" .. concat((function()
- local _accum_0 = { }
- local _len_0 = 1
- for _index_0 = 1, #self do
- local b = self[_index_0]
- _accum_0[_len_0] = repr(b)
- _len_0 = _len_0 + 1
- end
- return _accum_0
- end)(), ", ") .. "]"
+ if not (bit_nomsu) then
+ bit_nomsu = self:tree_to_nomsu(bit, true)
end
- }
- local list
- list = function(t)
- return setmetatable(t, _list_mt)
- end
- local _dict_mt = {
- __eq = utils.equivalent,
- __tostring = function(self)
- return "{" .. concat((function()
- local _accum_0 = { }
- local _len_0 = 1
- for k, v in pairs(self) do
- _accum_0[_len_0] = tostring(repr(k)) .. ": " .. tostring(repr(v))
- _len_0 = _len_0 + 1
- end
- return _accum_0
- end)(), ", ") .. "}"
+ if not (bit_nomsu) then
+ return nil
end
- }
- local dict
- dict = function(t)
- return setmetatable(t, _dict_mt)
- end
- self.environment = {
- nomsu = self,
- repr = repr,
- stringify = stringify,
- utils = utils,
- lpeg = lpeg,
- re = re,
- compile_error = compile_error,
- next = next,
- unpack = unpack,
- setmetatable = setmetatable,
- coroutine = coroutine,
- rawequal = rawequal,
- getmetatable = getmetatable,
- pcall = pcall,
- error = error,
- package = package,
- os = os,
- require = require,
- tonumber = tonumber,
- tostring = tostring,
- string = string,
- xpcall = xpcall,
- module = module,
- print = print,
- loadfile = loadfile,
- rawset = rawset,
- _VERSION = _VERSION,
- collectgarbage = collectgarbage,
- rawget = rawget,
- bit32 = bit32,
- rawlen = rawlen,
- table = table,
- assert = assert,
- dofile = dofile,
- loadstring = loadstring,
- type = type,
- select = select,
- debug = debug,
- math = math,
- io = io,
- load = load,
- pairs = pairs,
- ipairs = ipairs,
- list = list,
- dict = dict
- }
- for k, v in pairs(AST) do
- self.environment[k] = v
- end
- self.environment.Lua = Lua
- self.environment.Nomsu = Nomsu
- self.environment.Source = Source
- self.environment.ARG_ORDERS = setmetatable({ }, {
- __mode = "k"
- })
- self.environment.ALIASES = setmetatable({ }, {
- __mode = "k"
- })
- self.environment.compile_time = function(fn)
- self.environment.COMPILE_TIME[fn] = true
- return fn
- end
- self.environment.COMPILE_TIME = { }
- self.environment.LOADED = { }
- self.environment.AST = AST
- self.environment._ENV = self.environment
- setmetatable(self.environment, {
- __index = function(self, k)
- do
- local _self = rawget(self, "self")
- if _self then
- return _self[k]
- end
+ local _exp_1 = bit.type
+ if "Action" == _exp_1 or "Block" == _exp_1 or "IndexChain" == _exp_1 then
+ bit_nomsu:parenthesize()
+ elseif "Number" == _exp_1 then
+ if i < #tree then
+ bit_nomsu:parenthesize()
end
end
- })
- return self:initialize_core()
- end,
- __base = _base_0,
- __name = "NomsuCompiler"
- }, {
- __index = _base_0,
- __call = function(cls, ...)
- local _self_0 = setmetatable({}, _base_0)
- cls.__init(_self_0, ...)
- return _self_0
+ nomsu:append(bit_nomsu)
+ end
+ return nomsu
+ elseif "Number" == _exp_0 then
+ return NomsuCode(tree.source, tostring(tree[1]))
+ elseif "Var" == _exp_0 then
+ return NomsuCode(tree.source, "%", tree[1])
+ else
+ return error("Unknown type: " .. tostring(tree.type))
end
- })
- _base_0.__class = _class_0
- local self = _class_0
- compile_error = function(tok, err_format_string, ...)
- local file = FILE_CACHE[tok.source.filename]
- local line_no = pos_to_line(file, tok.source.start)
- local line_start = LINE_STARTS[file][line_no]
- local src = colored.dim(file:sub(line_start, tok.source.start - 1))
- src = src .. colored.underscore(colored.bright(colored.red(file:sub(tok.source.start, tok.source.stop - 1))))
- local end_of_line = (LINE_STARTS[file][pos_to_line(file, tok.source.stop) + 1] or 0) - 1
- src = src .. colored.dim(file:sub(tok.source.stop, end_of_line - 1))
- src = ' ' .. src:gsub('\n', '\n ')
- local err_msg = err_format_string:format(src, ...)
- return error(tostring(tok.source.filename) .. ":" .. tostring(line_no) .. ": " .. err_msg, 0)
end
- _running_files = { }
- MAX_LINE = 80
- math_expression = re.compile([[ ([+-] " ")* "%" (" " [*/^+-] (" " [+-])* " %")+ !. ]])
- NomsuCompiler = _class_0
end
if arg and debug_getinfo(2).func ~= require then
colors = require('consolecolors')
@@ -1391,8 +1259,8 @@ OPTIONS
]=])
os.exit()
end
- local nomsu = NomsuCompiler()
- nomsu.environment.arg = args.nomsu_args
+ local nomsu = NomsuCompiler
+ nomsu.arg = args.nomsu_args
local ok, to_lua = pcall(function()
return require('moonscript.base').to_lua
end)
@@ -1427,7 +1295,7 @@ OPTIONS
end
if info.short_src or info.source or info.linedefine or info.currentline then
do
- local arg_orders = nomsu.environment.ARG_ORDERS[info.func]
+ local arg_orders = nomsu.ARG_ORDERS[info.func]
if arg_orders then
info.name = next(arg_orders)
end
@@ -1517,7 +1385,7 @@ OPTIONS
local err_line = get_line(file, calling_fn.currentline):sub(1, -2)
local offending_statement = colored.bright(colored.red(err_line:match("^[ ]*(.*)")))
do
- local arg_orders = nomsu.environment.ARG_ORDERS[calling_fn.func]
+ local arg_orders = nomsu.ARG_ORDERS[calling_fn.func]
if arg_orders then
name = "action '" .. tostring(next(arg_orders)) .. "'"
else
@@ -1627,9 +1495,9 @@ OPTIONS
end
nomsu.skip_precompiled = not args.optimized
if print_file == nil then
- nomsu.environment.print = function() end
+ nomsu.print = function() end
elseif print_file ~= io.stdout then
- nomsu.environment.print = function(...)
+ nomsu.print = function(...)
local N = select("#", ...)
if N > 0 then
print_file:write(tostring(select(1, ...)))
@@ -1652,7 +1520,7 @@ OPTIONS
end
end
if args.compile or args.verbose then
- nomsu.compile_fn = function(code, from_file)
+ nomsu.on_compile = function(code, from_file)
if to_run[from_file] then
if args.verbose then
io.write(tostring(code), "\n")
@@ -1660,7 +1528,7 @@ OPTIONS
if args.compile and from_file:match("%.nom$") then
local output_filename = from_file:gsub("%.nom$", ".lua")
local output_file = io.open(output_filename, 'w')
- output_file:write("local IMMEDIATE = true;\n", tostring(code))
+ output_file:write(tostring(code))
output_file:flush()
print(("Compiled %-25s -> %s"):format(from_file, output_filename))
return output_file:close()
@@ -1668,14 +1536,15 @@ OPTIONS
end
end
else
- nomsu.compile_fn = nil
+ nomsu.on_compile = nil
end
local parse_errs = { }
for _index_0 = 1, #input_files do
local filename = input_files[_index_0]
if args.syntax then
+ local file_contents = io.open(filename):read('*a')
local err
- ok, err = pcall(nomsu.parse, nomsu, Nomsu(filename, io.open(filename):read("*a")))
+ ok, err = pcall(nomsu.parse, nomsu, file_contents, Source(filename, 1, #file_contents))
if not ok then
insert(parse_errs, err)
elseif print_file then
@@ -1687,7 +1556,7 @@ OPTIONS
if not file then
error("File does not exist: " .. tostring(filename), 0)
end
- local tree = nomsu:parse(Nomsu(Source(filename, 1, #file), file))
+ local tree = nomsu:parse(file, Source(filename, 1, #file))
local formatted = tostring(nomsu:tree_to_nomsu(tree))
if print_file then
print_file:write(formatted, "\n")
@@ -1696,7 +1565,7 @@ OPTIONS
elseif filename == STDIN then
local file = io.input():read("*a")
FILE_CACHE.stdin = file
- nomsu:run(Nomsu(Source('stdin', 1, #file), file))
+ nomsu:run(file, Source('stdin', 1, #file))
else
nomsu:run_file(filename)
end
@@ -1729,13 +1598,12 @@ OPTIONS
end
buff = concat(buff)
FILE_CACHE["REPL#" .. repl_line] = buff
- local code = Nomsu(Source("REPL#" .. repl_line, 1, #buff), buff)
local err_hand
err_hand = function(error_message)
return print_err_msg(error_message)
end
local ret
- ok, ret = xpcall(nomsu.run, err_hand, nomsu, code)
+ ok, ret = xpcall(nomsu.run, err_hand, nomsu, buff, Source("REPL#" .. repl_line, 1, #buff))
if ok and ret ~= nil then
print("= " .. repr(ret))
elseif not ok then
diff --git a/nomsu.moon b/nomsu.moon
index 459ad7c..b99d6f4 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -10,29 +10,20 @@
-- nomsu:run(your_nomsu_code)
-- Or from the command line:
-- lua nomsu.lua your_file.nom
-export lpeg, re
-_pairs, _ipairs = pairs, ipairs
-if jit
- package.cpath = "./luajit_lpeg/?.so;"..package.cpath
- package.path = "./luajit_lpeg/?.lua;"..package.path
-
- export bit32
- bit32 = require('bit')
-
lpeg = require 'lpeg'
re = require 're'
lpeg.setmaxstack 10000
{:P,:R,:V,:S,:Cg,:C,:Cp,:B,:Cmt,:Carg} = lpeg
utils = require 'utils'
-new_uuid = require 'uuid'
{:repr, :stringify, :min, :max, :equivalent, :set, :is_list, :sum} = utils
colors = setmetatable({}, {__index:->""})
export colored
colored = setmetatable({}, {__index:(_,color)-> ((msg)-> colors[color]..tostring(msg or '')..colors.reset)})
{:insert, :remove, :concat} = table
+unpack or= table.unpack
{:match, :sub, :rep, :gsub, :format, :byte, :match, :find} = string
debug_getinfo = debug.getinfo
-{:Nomsu, :Lua, :Source} = require "code_obj"
+{:NomsuCode, :LuaCode, :Source} = require "code_obj"
STDIN, STDOUT, STDERR = "/dev/fd/0", "/dev/fd/1", "/dev/fd/2"
string.as_lua_id = (str)->
@@ -138,103 +129,53 @@ do
AST = require "nomsu_tree"
-NOMSU_DEFS = with {}
- -- Newline supports either windows-style CR+LF or unix-style LF
- .nl = P("\r")^-1 * P("\n")
- .ws = S(" \t")
- .tonumber = tonumber
- string_escapes = n:"\n", t:"\t", b:"\b", a:"\a", v:"\v", f:"\f", r:"\r"
- digit, hex = R('09'), R('09','af','AF')
- .escaped_char = (P("\\")*S("xX")*C(hex*hex)) / => string.char(tonumber(@, 16))
- .escaped_char += (P("\\")*C(digit*(digit^-2))) / => string.char(tonumber @)
- .escaped_char += (P("\\")*C(S("ntbavfr"))) / string_escapes
- .operator_char = S("'~`!@$^&*-+=|<>?/")
- .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"))
- .ident_char = R("az","AZ","09") + P("_") + .utf8_char
-
- -- If the line begins with #indent+4 spaces, the pattern matches *those* spaces
- -- and adds them to the current indent (not any more).
- .indent = Cmt Carg(1), (start, userdata)=>
- indented = userdata.indent..' '
- if sub(@, start, start+#indented-1) == indented
- userdata.indent = indented
- return start + #indented
- -- If the number of leading space characters is <= the number of spaces in the current
- -- indent minus 4, this pattern matches and decrements the current indent exactly once.
- .dedent = Cmt Carg(1), (start, userdata)=>
- dedented = sub(userdata.indent, 1, -5)
- if #match(@, "^[ ]*", start) <= #dedented
- userdata.indent = dedented
- return start
- -- If the number of leading space characters is >= the number of spaces in the current
- -- indent, this pattern matches and does not modify the indent.
- .nodent = Cmt Carg(1), (start, userdata)=>
- if sub(@, start, start+#userdata.indent-1) == userdata.indent
- return start + #userdata.indent
-
- .userdata = Carg(1)
-
- .error = (src,end_pos,start_pos,err_msg,userdata)->
- seen_errors = userdata.errors
- if seen_errors[start_pos]
- return true
- if utils.size(seen_errors) >= 10
- seen_errors[start_pos+1] = colored.bright colored.yellow colored.onred "Too many errors, canceling parsing..."
- return #src+1
- err_pos = start_pos
- line_no = pos_to_line(src, err_pos)
- src = FILE_CACHE[userdata.source.filename]
- line_starts = LINE_STARTS[src]
- prev_line = line_no == 1 and "" or src\sub(line_starts[line_no-1] or 1, line_starts[line_no]-2)
- err_line = src\sub(line_starts[line_no], (line_starts[line_no+1] or 0)-2)
- next_line = src\sub(line_starts[line_no+1] or -1, (line_starts[line_no+2] or 0)-2)
- i = err_pos-line_starts[line_no]
- pointer = ("-")\rep(i) .. "^"
- err_msg = colored.bright colored.yellow colored.onred (err_msg or "Parse error").." at #{userdata.source.filename}:#{line_no}:"
- if #prev_line > 0 then err_msg ..= "\n"..colored.dim(prev_line)
- err_line = colored.white(err_line\sub(1, i))..colored.bright(colored.red(err_line\sub(i+1,i+1)))..colored.dim(err_line\sub(i+2,-1))
- err_msg ..= "\n#{err_line}\n#{colored.red pointer}"
- if #next_line > 0 then err_msg ..= "\n"..colored.dim(next_line)
- --error(err_msg)
- seen_errors[start_pos] = err_msg
- return true
-
-setmetatable(NOMSU_DEFS, {__index:(key)=>
- make_node = (start, value, stop, userdata)->
- local source
- with userdata.source
- source = Source(.filename, .start + start-1, .start + stop-1)
- value.source = source
- setmetatable(value, AST[key])
- if value.__init then value\__init!
- for i=1,#value do assert(value[i])
- return value
-
- self[key] = make_node
- return make_node
-})
-
-NOMSU_PATTERN = do
- -- Just for cleanliness, I put the language spec in its own file using a slightly modified
- -- version of the lpeg.re syntax.
- peg_tidier = re.compile [[
- 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 <- (({} %3 {} %%userdata) -> %2)"
- ident <- [a-zA-Z_][a-zA-Z0-9_]*
- comment <- "--" [^%nl]*
- ]]
- nomsu_peg = peg_tidier\match(FILE_CACHE["nomsu.peg"])
- re.compile(nomsu_peg, NOMSU_DEFS)
-
-class NomsuCompiler
- compile_error = (tok, err_format_string, ...)->
+_list_mt =
+ __eq:utils.equivalent
+ -- Could consider adding a __newindex to enforce list-ness, but would hurt performance
+ __tostring: =>
+ "["..concat([repr(b) for b in *@], ", ").."]"
+list = (t)-> setmetatable(t, _list_mt)
+
+_dict_mt =
+ __eq:utils.equivalent
+ __tostring: =>
+ "{"..concat(["#{repr(k)}: #{repr(v)}" for k,v in pairs @], ", ").."}"
+dict = (t)-> setmetatable(t, _dict_mt)
+
+MAX_LINE = 80 -- For beautification purposes, try not to make lines much longer than this value
+NomsuCompiler = setmetatable({}, {__index: (k)=> if _self = rawget(@, "self") then _self[k] else nil})
+with NomsuCompiler
+ ._ENV = NomsuCompiler
+ .nomsu = NomsuCompiler
+ parse = require("parser")
+ .parse = (...)=> parse(...)
+
+ -- Mapping from source string (e.g. "@core/metaprogramming.nom[1:100]") to a mapping
+ -- from lua line number to nomsu line number
+ .source_map = {}
+ -- Discretionary/convenience stuff
+ to_add = {
+ repr:repr, stringify:stringify, utils:utils, lpeg:lpeg, re:re,
+ -- Lua stuff:
+ :next, :unpack, :setmetatable, :coroutine, :rawequal, :getmetatable, :pcall,
+ :error, :package, :os, :require, :tonumber, :tostring, :string, :xpcall, :module,
+ :print, :loadfile, :rawset, :_VERSION, :collectgarbage, :rawget, :rawlen,
+ :table, :assert, :dofile, :loadstring, :type, :select, :debug, :math, :io, :load,
+ :pairs, :ipairs,
+ -- Nomsu types:
+ :list, :dict,
+ }
+ for k,v in pairs(to_add) do NomsuCompiler[k] = v
+ for k,v in pairs(AST) do NomsuCompiler[k] = v
+ .LuaCode = LuaCode
+ .NomsuCode = NomsuCode
+ .Source = Source
+ .ARG_ORDERS = setmetatable({}, {__mode:"k"})
+ .ALIASES = setmetatable({}, {__mode:"k"})
+ .LOADED = {}
+ .AST = AST
+
+ .compile_error = (tok, err_format_string, ...)=>
file = FILE_CACHE[tok.source.filename]
line_no = pos_to_line(file, tok.source.start)
line_start = LINE_STARTS[file][line_no]
@@ -245,105 +186,132 @@ class NomsuCompiler
src = ' '..src\gsub('\n', '\n ')
err_msg = err_format_string\format(src, ...)
error("#{tok.source.filename}:#{line_no}: "..err_msg, 0)
- new: =>
- -- Weak-key mapping from objects to randomly generated unique IDs
- NaN_surrogate = {}
- nil_surrogate = {}
- @ids = setmetatable({}, {
- __mode: "k"
- __index: (key)=>
- if key == nil then return @[nil_surrogate]
- elseif key != key then return @[NaN_surrogate]
- id = new_uuid!
- @[key] = id
- return id
- })
- -- Mapping from source string (e.g. "@core/metaprogramming.nom[1:100]") to a mapping
- -- from lua line number to nomsu line number
- @source_map = {}
-
- _list_mt =
- __eq:utils.equivalent
- -- Could consider adding a __newindex to enforce list-ness, but would hurt performance
- __tostring: =>
- "["..concat([repr(b) for b in *@], ", ").."]"
- list = (t)-> setmetatable(t, _list_mt)
- _dict_mt =
- __eq:utils.equivalent
- __tostring: =>
- "{"..concat(["#{repr(k)}: #{repr(v)}" for k,v in pairs @], ", ").."}"
- dict = (t)-> setmetatable(t, _dict_mt)
- @environment = {
- -- Discretionary/convenience stuff
- nomsu:self, repr:repr, stringify:stringify, utils:utils, lpeg:lpeg, re:re,
- :compile_error
- -- Lua stuff:
- :next, :unpack, :setmetatable, :coroutine, :rawequal, :getmetatable, :pcall,
- :error, :package, :os, :require, :tonumber, :tostring, :string, :xpcall, :module,
- :print, :loadfile, :rawset, :_VERSION, :collectgarbage, :rawget, :bit32, :rawlen,
- :table, :assert, :dofile, :loadstring, :type, :select, :debug, :math, :io, :load,
- :pairs, :ipairs,
- -- Nomsu types:
- :list, :dict,
- }
- for k,v in pairs(AST) do @environment[k] = v
- @environment.Lua = Lua
- @environment.Nomsu = Nomsu
- @environment.Source = Source
- @environment.ARG_ORDERS = setmetatable({}, {__mode:"k"})
- @environment.ALIASES = setmetatable({}, {__mode:"k"})
- @environment.compile_time = (fn)->
- @environment.COMPILE_TIME[fn] = true
- return fn
- @environment.COMPILE_TIME = {}
- @environment.LOADED = {}
- @environment.AST = AST
- @environment._ENV = @environment
- setmetatable @environment,
- __index: (k)=>
- if _self = rawget(@, "self")
- return _self[k]
- @initialize_core!
+
+ -- This is a bit of a hack, but this code handles arbitrarily complex
+ -- math expressions like 2*x + 3^2 without having to define a single
+ -- action for every possibility.
+ math_expression = re.compile [[ ([+-] " ")* "%" (" " [*/^+-] (" " [+-])* " %")+ !. ]]
+ add_lua_bits = (lua, code)=>
+ for bit in *code
+ if type(bit) == "string"
+ lua\append bit
+ else
+ bit_lua = @compile(bit)
+ unless bit_lua.is_value
+ @compile_error bit,
+ "Cannot use:\n%s\nas a string interpolation value, since it's not an expression."
+ lua\append bit_lua
+ return lua
+
+ add_lua_string_bits = (lua, code)=>
+ line_len = 0
+ if code.type != "Text"
+ lua\append ", ", @compile(code)
+ return
+ for bit in *code
+ bit_lua = if type(bit) == "string"
+ repr(bit)
+ else
+ bit_lua = @compile(bit)
+ unless bit_lua.is_value
+ @compile_error bit,
+ "Cannot use:\n%s\nas a string interpolation value, since it's not an expression."
+ bit_lua
+ line_len += #tostring(bit_lua)
+ if line_len > MAX_LINE
+ lua\append ",\n "
+ line_len = 4
+ else
+ lua\append ", "
+ lua\append bit_lua
+
+ .COMPILE_ACTIONS = setmetatable {
+ compile_math_expr: (tree, ...)=>
+ lua = LuaCode.Value(tree.source)
+ for i,tok in ipairs tree
+ if type(tok) == 'string'
+ lua\append tok
+ else
+ tok_lua = @compile(tok)
+ unless tok_lua.is_value
+ @compile_error tok,
+ "Non-expression value inside math expression:\n%s"
+ if tok.type == "Action"
+ tok_lua\parenthesize!
+ lua\append tok_lua
+ if i < #tree
+ lua\append " "
+ return lua
+
+ ["Lua %"]: (tree, _code)=>
+ lua = LuaCode.Value(_code.source, "LuaCode(", repr(tostring _code.source))
+ add_lua_string_bits(@, lua, _code)
+ lua\append ")"
+ return lua
- parse: (nomsu_code)=>
- assert(type(nomsu_code) != 'string')
- userdata = {
- source_code:nomsu_code, indent: "", errors: {},
- source: nomsu_code.source,
- }
- tree = NOMSU_PATTERN\match(tostring(nomsu_code), nil, userdata)
- unless tree
- error "In file #{colored.blue filename} failed to parse:\n#{colored.onyellow colored.black nomsu_code}"
-
- if next(userdata.errors)
- keys = utils.keys(userdata.errors)
- table.sort(keys)
- errors = [userdata.errors[k] for k in *keys]
- io.stderr\write(concat(errors, "\n\n").."\n")
- os.exit!
-
- return tree
-
- run: (nomsu_code)=>
- tree = assert(@parse(nomsu_code))
- if type(tree) == 'number' -- Happens if pattern matches, but there are no captures, e.g. an empty string
+ ["Lua value %"]: (tree, _code)=>
+ lua = LuaCode.Value(_code.source, "LuaCode.Value(", repr(tostring _code.source))
+ add_lua_string_bits(@, lua, _code)
+ lua\append ")"
+ return lua
+
+ ["lua > %"]: (tree, _code)=>
+ if _code.type != "Text"
+ return LuaCode tree.source, "nomsu:run_lua(", @compile(_code), ");"
+ return add_lua_bits(@, LuaCode(tree.source), _code)
+
+ ["= lua %"]: (tree, _code)=>
+ if _code.type != "Text"
+ return LuaCode.Value tree.source, "nomsu:run_lua(", @compile(_code), ":as_statements('return '))"
+ return add_lua_bits(@, LuaCode.Value(tree.source), _code)
+
+ ["use %"]: (tree, _path)=>
+ unless _path.type == 'Text' and #_path == 1 and type(_path[1]) == 'string'
+ return LuaCode(tree.source, "nomsu:run_file(#{@compile(_path)});")
+ path = _path[1]
+ @run_file(path)
+ return LuaCode(tree.source, "nomsu:run_file(#{repr path});")
+ }, {
+ __index: (stub)=>
+ if math_expression\match(stub)
+ return @compile_math_expr
+ }
+
+ .fork = =>
+ setmetatable({COMPILE_ACTIONS:setmetatable({}, {__index:@COMPILE_ACTIONS})}, {__index:@})
+
+ .run = (to_run, source=nil)=>
+ tree = if AST.is_syntax_tree(to_run) then tree else @parse(to_run, source or to_run.source)
+ if tree == nil -- Happens if pattern matches, but there are no captures, e.g. an empty string
return nil
- lua = @tree_to_lua(tree)\as_statements!
- lua\declare_locals!
- lua\prepend "-- File: #{nomsu_code.source or ""}\n"
- if @compile_fn
- self.compile_fn(lua, nomsu_code.source.filename)
- return @run_lua(lua)
+ if tree.type == "FileChunks"
+ ret = nil
+ all_lua = {}
+ for chunk in *tree
+ lua = @compile(chunk)\as_statements!
+ lua\declare_locals!
+ lua\prepend "-- File: #{chunk.source or ""}\n"
+ insert all_lua, tostring(lua)
+ ret = @run_lua(lua)
+ if @on_compile
+ self.on_compile(concat(all_lua, "\n"), (source or to_run.source).filename)
+ return ret
+ else
+ lua = @compile(tree, compile_actions)\as_statements!
+ lua\declare_locals!
+ lua\prepend "-- File: #{source or to_run.source or ""}\n"
+ if @on_compile
+ self.on_compile(lua, (source or to_run.source).filename)
+ return @run_lua(lua)
_running_files = {} -- For detecting circular imports
- run_file: (filename)=>
- loaded = @environment.LOADED
- if loaded[filename]
- return loaded[filename]
+ .run_file = (filename)=>
+ if @LOADED[filename]
+ return @LOADED[filename]
ret = nil
for filename in all_files(filename)
- if loaded[filename]
- ret = loaded[filename]
+ if @LOADED[filename]
+ ret = @LOADED[filename]
continue
for i,running in ipairs _running_files
@@ -355,31 +323,31 @@ class NomsuCompiler
insert _running_files, filename
if match(filename, "%.lua$")
file = assert(FILE_CACHE[filename], "Could not find file: #{filename}")
- ret = @run_lua(Lua(Source(filename, 1, #file), file))
+ ret = @run_lua file, Source(filename, 1, #file)
elseif match(filename, "%.nom$") or match(filename, "^/dev/fd/[012]$")
if not @skip_precompiled -- Look for precompiled version
lua_filename = gsub(filename, "%.nom$", ".lua")
file = FILE_CACHE[lua_filename]
if file
- ret = @run_lua(Lua(Source(filename, 1, #file), file))
+ ret = @run_lua file, Source(filename, 1, #file)
remove _running_files
continue
file = file or FILE_CACHE[filename]
if not file
error("File does not exist: #{filename}", 0)
- ret = @run(Nomsu(Source(filename,1,#file), file))
+ ret = @run file, Source(filename,1,#file)
else
error("Invalid filetype for #{filename}", 0)
- loaded[filename] = ret or true
+ @LOADED[filename] = ret or true
remove _running_files
- loaded[filename] = ret or true
+ @LOADED[filename] = ret or true
return ret
- run_lua: (lua)=>
+ .run_lua = (lua, source=nil)=>
assert(type(lua) != 'string', "Attempt to run lua string instead of Lua (object)")
lua_string = tostring(lua)
- run_lua_fn, err = load(lua_string, tostring(lua.source), "t", @environment)
+ run_lua_fn, err = load(lua_string, nil and tostring(source or lua.source), "t", self)
if not run_lua_fn
n = 1
fn = ->
@@ -387,14 +355,14 @@ class NomsuCompiler
("\n%-3d|")\format(n)
line_numbered_lua = "1 |"..lua_string\gsub("\n", fn)
error("Failed to compile generated code:\n#{colored.bright colored.blue colored.onblack line_numbered_lua}\n\n#{err}", 0)
- source_key = tostring(lua.source)
+ source_key = tostring(source or lua.source)
unless @source_map[source_key]
map = {}
offset = 1
- source = lua.source
+ source or= lua.source
nomsu_str = tostring(FILE_CACHE[source.filename]\sub(source.start, source.stop))
lua_line = 1
- nomsu_line = pos_to_line(nomsu_str, lua.source.start)
+ nomsu_line = pos_to_line(nomsu_str, source.start)
fn = (s)->
if type(s) == 'string'
for nl in s\gmatch("\n")
@@ -413,26 +381,26 @@ class NomsuCompiler
return run_lua_fn!
- MAX_LINE = 80 -- For beautification purposes, try not to make lines much longer than this value
- math_expression = re.compile [[ ([+-] " ")* "%" (" " [*/^+-] (" " [+-])* " %")+ !. ]]
- tree_to_lua: (tree)=>
+ .compile = (tree)=>
+ assert(LuaCode)
switch tree.type
when "Action"
stub = tree.stub
- action = @environment['A'..string.as_lua_id(stub)]
- if action and @environment.COMPILE_TIME[action]
+ if compile_action = @COMPILE_ACTIONS[stub]
args = [arg for arg in *tree when type(arg) != "string"]
- -- Force all compile-time actions to take a tree location
- if arg_orders = @environment.ARG_ORDERS[stub]
+ if arg_orders = @ARG_ORDERS[stub]
args = [args[p] for p in *arg_orders]
-- Force Lua to avoid tail call optimization for debugging purposes
- -- TODO: use tail call
- ret = action(tree, unpack(args))
+ -- TODO: use tail call?
+ ret = compile_action(@, tree, unpack(args))
if not ret
- compile_error tree,
+ @compile_error tree,
"Compile-time action:\n%s\nfailed to produce any Lua"
return ret
- lua = Lua.Value(tree.source)
+
+ action = @['A'..string.as_lua_id(stub)]
+
+ lua = LuaCode.Value(tree.source)
if not action and math_expression\match(stub)
-- This is a bit of a hack, but this code handles arbitrarily complex
-- math expressions like 2*x + 3^2 without having to define a single
@@ -441,9 +409,9 @@ class NomsuCompiler
if type(tok) == 'string'
lua\append tok
else
- tok_lua = @tree_to_lua(tok)
+ tok_lua = @compile(tok)
unless tok_lua.is_value
- compile_error tok,
+ @compile_error tok,
"Non-expression value inside math expression:\n%s"
if tok.type == "Action"
tok_lua\parenthesize!
@@ -455,15 +423,15 @@ class NomsuCompiler
args = {}
for i, tok in ipairs tree
if type(tok) == "string" then continue
- arg_lua = @tree_to_lua(tok)
+ arg_lua = @compile(tok)
unless arg_lua.is_value
- compile_error tok,
+ @compile_error tok,
"Cannot use:\n%s\nas an argument to %s, since it's not an expression, it produces: %s",
stub, repr arg_lua
insert args, arg_lua
if action
- if arg_orders = @environment.ARG_ORDERS[stub]
+ if arg_orders = @ARG_ORDERS[stub]
args = [args[p] for p in *arg_orders]
lua\append "A",string.as_lua_id(stub),"("
@@ -479,19 +447,19 @@ class NomsuCompiler
return repr(t)
bits = [make_tree(bit) for bit in *t]
return t.type.."("..repr(tostring t.source)..", "..table.concat(bits, ", ")..")"
- Lua.Value tree.source, make_tree(tree[1])
+ LuaCode.Value tree.source, make_tree(tree[1])
when "Block"
- lua = Lua(tree.source)
+ lua = LuaCode(tree.source)
for i,line in ipairs tree
- line_lua = @tree_to_lua(line)
+ line_lua = @compile(line)
if i > 1
lua\append "\n"
lua\append line_lua\as_statements!
return lua
when "Text"
- lua = Lua.Value(tree.source)
+ lua = LuaCode.Value(tree.source)
string_buffer = ""
for i, bit in ipairs tree
if type(bit) == "string"
@@ -501,15 +469,15 @@ class NomsuCompiler
if #lua.bits > 0 then lua\append ".."
lua\append repr(string_buffer)
string_buffer = ""
- bit_lua = @tree_to_lua(bit)
+ bit_lua = @compile(bit)
unless bit_lua.is_value
src = ' '..gsub(tostring(@tree_to_nomsu(bit)), '\n','\n ')
line = "#{bit.source.filename}:#{pos_to_line(FILE_CACHE[bit.source.filename], bit.source.start)}"
- compile_error bit,
+ @compile_error bit,
"Cannot use:\n%s\nas a string interpolation value, since it's not an expression."
if #lua.bits > 0 then lua\append ".."
if bit.type != "Text"
- bit_lua = Lua.Value(bit.source, "stringify(",bit_lua,")")
+ bit_lua = LuaCode.Value(bit.source, "stringify(",bit_lua,")")
lua\append bit_lua
if string_buffer ~= "" or #lua.bits == 0
@@ -521,12 +489,12 @@ class NomsuCompiler
return lua
when "List"
- lua = Lua.Value tree.source, "list{"
+ lua = LuaCode.Value tree.source, "list{"
line_length = 0
for i, item in ipairs tree
- item_lua = @tree_to_lua(item)
+ item_lua = @compile(item)
unless item_lua.is_value
- compile_error item,
+ @compile_error item,
"Cannot use:\n%s\nas a list item, since it's not an expression."
lua\append item_lua
item_string = tostring(item_lua)
@@ -546,10 +514,10 @@ class NomsuCompiler
return lua
when "Dict"
- lua = Lua.Value tree.source, "dict{"
+ lua = LuaCode.Value tree.source, "dict{"
line_length = 0
for i, entry in ipairs tree
- entry_lua = @tree_to_lua(entry)
+ entry_lua = @compile(entry)
lua\append entry_lua
entry_lua_str = tostring(entry_lua)
-- TODO: maybe make this more accurate? It's only a heuristic, so eh...
@@ -570,29 +538,29 @@ class NomsuCompiler
when "DictEntry"
key, value = tree[1], tree[2]
- key_lua = @tree_to_lua(key)
+ key_lua = @compile(key)
unless key_lua.is_value
- compile_error tree[1],
+ @compile_error tree[1],
"Cannot use:\n%s\nas a dict key, since it's not an expression."
- value_lua = value and @tree_to_lua(value) or Lua.Value(key.source, "true")
+ value_lua = value and @compile(value) or LuaCode.Value(key.source, "true")
unless value_lua.is_value
- compile_error tree[2],
+ @compile_error tree[2],
"Cannot use:\n%s\nas a dict value, since it's not an expression."
key_str = match(tostring(key_lua), [=[["']([a-zA-Z_][a-zA-Z0-9_]*)['"]]=])
return if key_str
- Lua tree.source, key_str,"=",value_lua
+ LuaCode tree.source, key_str,"=",value_lua
elseif sub(tostring(key_lua),1,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 tree.source, "[ ",key_lua,"]=",value_lua
+ LuaCode tree.source, "[ ",key_lua,"]=",value_lua
else
- Lua tree.source, "[",key_lua,"]=",value_lua
+ LuaCode tree.source, "[",key_lua,"]=",value_lua
when "IndexChain"
- lua = @tree_to_lua(tree[1])
+ lua = @compile(tree[1])
unless lua.is_value
- compile_error tree[1],
+ @compile_error tree[1],
"Cannot index:\n%s\nsince it's not an expression."
first_char = sub(tostring(lua),1,1)
if first_char == "{" or first_char == '"' or first_char == "["
@@ -600,9 +568,9 @@ class NomsuCompiler
for i=2,#tree
key = tree[i]
- key_lua = @tree_to_lua(key)
+ key_lua = @compile(key)
unless key_lua.is_value
- compile_error key,
+ @compile_error key,
"Cannot use:\n%s\nas an index, since it's not an expression."
key_lua_str = tostring(key_lua)
if lua_id = match(key_lua_str, "^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$")
@@ -617,19 +585,19 @@ class NomsuCompiler
return lua
when "Number"
- Lua.Value(tree.source, tostring(tree[1]))
+ LuaCode.Value(tree.source, tostring(tree[1]))
when "Var"
- Lua.Value(tree.source, string.as_lua_id(tree[1]))
+ LuaCode.Value(tree.source, string.as_lua_id(tree[1]))
else
error("Unknown type: #{tree.type}")
- tree_to_nomsu: (tree, inline=false, can_use_colon=false)=>
+ .tree_to_nomsu = (tree, inline=false, can_use_colon=false)=>
switch tree.type
when "Action"
if inline
- nomsu = Nomsu(tree.source)
+ nomsu = NomsuCode(tree.source)
for i,bit in ipairs tree
if type(bit) == "string"
if i > 1
@@ -645,7 +613,7 @@ class NomsuCompiler
nomsu\append arg_nomsu
return nomsu
else
- nomsu = Nomsu(tree.source)
+ nomsu = NomsuCode(tree.source)
next_space = ""
line_len, last_colon = 0, nil
for i,bit in ipairs tree
@@ -679,9 +647,9 @@ class NomsuCompiler
-- These types carry their own indentation
if bit.type != "List" and bit.type != "Dict" and bit.type != "Text"
if i == 1
- arg_nomsu = Nomsu(bit.source, "(..)\n ", arg_nomsu)
+ arg_nomsu = NomsuCode(bit.source, "(..)\n ", arg_nomsu)
else
- arg_nomsu = Nomsu(bit.source, "\n ", arg_nomsu)
+ arg_nomsu = NomsuCode(bit.source, "\n ", arg_nomsu)
if last_colon == i-1 and (bit.type == "Action" or bit.type == "Block")
next_space = ""
@@ -697,12 +665,12 @@ class NomsuCompiler
nomsu = @tree_to_nomsu(tree[1], true)
if nomsu == nil and not inline
nomsu = @tree_to_nomsu(tree[1])
- return nomsu and Nomsu tree.source, "\\:\n ", nomsu
- return nomsu and Nomsu tree.source, "\\(", nomsu, ")"
+ return nomsu and NomsuCode tree.source, "\\:\n ", nomsu
+ return nomsu and NomsuCode tree.source, "\\(", nomsu, ")"
when "Block"
if inline
- nomsu = Nomsu(tree.source)
+ nomsu = NomsuCode(tree.source)
for i,line in ipairs tree
if i > 1
nomsu\append "; "
@@ -710,7 +678,7 @@ class NomsuCompiler
return nil unless line_nomsu
nomsu\append line_nomsu
return nomsu
- nomsu = Nomsu(tree.source)
+ nomsu = NomsuCode(tree.source)
for i, line in ipairs tree
line = assert(@tree_to_nomsu(line, nil, true), "Could not convert line to nomsu")
nomsu\append line
@@ -722,7 +690,7 @@ class NomsuCompiler
when "Text"
if inline
- nomsu = Nomsu(tree.source, '"')
+ nomsu = NomsuCode(tree.source, '"')
for bit in *tree
if type(bit) == 'string'
-- TODO: unescape better?
@@ -740,7 +708,7 @@ class NomsuCompiler
inline_version = @tree_to_nomsu(tree, true)
if inline_version and #inline_version <= MAX_LINE
return inline_version
- nomsu = Nomsu(tree.source, '".."\n ')
+ nomsu = NomsuCode(tree.source, '".."\n ')
for i, bit in ipairs tree
if type(bit) == 'string'
bit_lines = get_lines\match(bit)
@@ -779,7 +747,7 @@ class NomsuCompiler
when "List"
if inline
- nomsu = Nomsu(tree.source, "[")
+ nomsu = NomsuCode(tree.source, "[")
for i, item in ipairs tree
item_nomsu = @tree_to_nomsu(item, true)
return nil unless item_nomsu
@@ -792,8 +760,8 @@ class NomsuCompiler
inline_version = @tree_to_nomsu(tree, true)
if inline_version and #inline_version <= MAX_LINE
return inline_version
- nomsu = Nomsu(tree.source, "[..]")
- line = Nomsu(tree.source, "\n ")
+ nomsu = NomsuCode(tree.source, "[..]")
+ line = NomsuCode(tree.source, "\n ")
for item in *tree
item_nomsu = @tree_to_nomsu(item, true)
if item_nomsu and #line + #", " + #item_nomsu <= MAX_LINE
@@ -806,7 +774,7 @@ class NomsuCompiler
return nil unless item_nomsu
if #line.bits > 1
nomsu\append line
- line = Nomsu(line.source, "\n ")
+ line = NomsuCode(line.source, "\n ")
line\append item_nomsu
if #line.bits > 1
nomsu\append line
@@ -814,7 +782,7 @@ class NomsuCompiler
when "Dict"
if inline
- nomsu = Nomsu(tree.source, "{")
+ nomsu = NomsuCode(tree.source, "{")
for i, entry in ipairs tree
entry_nomsu = @tree_to_nomsu(entry, true)
return nil unless entry_nomsu
@@ -826,8 +794,8 @@ class NomsuCompiler
else
inline_version = @tree_to_nomsu(tree, true)
if inline_version then return inline_version
- nomsu = Nomsu(tree.source, "{..}")
- line = Nomsu(tree.source, "\n ")
+ nomsu = NomsuCode(tree.source, "{..}")
+ line = NomsuCode(tree.source, "\n ")
for entry in *tree
entry_nomsu = @tree_to_nomsu(entry)
return nil unless entry_nomsu
@@ -838,7 +806,7 @@ class NomsuCompiler
else
if #line.bits > 1
nomsu\append line
- line = Nomsu(line.source, "\n ")
+ line = NomsuCode(line.source, "\n ")
line\append entry_nomsu
if #line.bits > 1
nomsu\append line
@@ -852,22 +820,23 @@ class NomsuCompiler
key_nomsu\parenthesize!
value_nomsu = if value
@tree_to_nomsu(value, true)
- else Nomsu(tree.source, "")
+ else NomsuCode(tree.source, "")
if inline and not value_nomsu then return nil
if not value_nomsu
return nil if inline
value_nomsu = @tree_to_nomsu(value)
return nil unless value_nomsu
- return Nomsu tree.source, key_nomsu, ":", value_nomsu
+ return NomsuCode tree.source, key_nomsu, ":", value_nomsu
when "IndexChain"
- nomsu = Nomsu(tree.source)
+ nomsu = NomsuCode(tree.source)
for i, bit in ipairs tree
if i > 1
nomsu\append "."
local bit_nomsu
if bit.type == "Text" and #bit == 1 and type(bit[1]) == 'string'
- if (NOMSU_DEFS.ident_char^1)\match(bit[1])
+ -- TODO: support arbitrary words here, including operators and unicode
+ if bit[1]\match("[_a-zA-Z][_a-zA-Z0-9]*")
bit_nomsu = bit[1]
unless bit_nomsu then bit_nomsu = @tree_to_nomsu(bit, true)
return nil unless bit_nomsu
@@ -881,86 +850,22 @@ class NomsuCompiler
return nomsu
when "Number"
- return Nomsu(tree.source, tostring(tree[1]))
+ return NomsuCode(tree.source, tostring(tree[1]))
when "Var"
- return Nomsu(tree.source, "%", tree[1])
+ return NomsuCode(tree.source, "%", tree[1])
else
error("Unknown type: #{tree.type}")
- initialize_core: =>
- -- Sets up some core functionality
- nomsu = self
- with nomsu.environment
- .A_immediately_1 = .compile_time (_block)=>
- lua = nomsu\tree_to_lua(_block)\as_statements!
- lua\declare_locals!
- nomsu\run_lua(lua)
- return Lua(_block.source, "if IMMEDIATE then\n ", lua, "\nend")
-
- add_lua_string_bits = (lua, code)->
- line_len = 0
- if code.type != "Text"
- lua\append ", ", nomsu\tree_to_lua(code)
- return
- for bit in *code
- bit_lua = if type(bit) == "string"
- repr(bit)
- else
- bit_lua = nomsu\tree_to_lua(bit)
- unless bit_lua.is_value
- compile_error bit,
- "Cannot use:\n%s\nas a string interpolation value, since it's not an expression."
- bit_lua
- line_len += #tostring(bit_lua)
- if line_len > MAX_LINE
- lua\append ",\n "
- line_len = 4
- else
- lua\append ", "
- lua\append bit_lua
- .A_Lua_1 = .compile_time (_code)=>
- lua = Lua.Value(_code.source, "Lua(", repr(tostring _code.source))
- add_lua_string_bits(lua, _code)
- lua\append ")"
- return lua
-
- .A_Lua_value_1 = .compile_time (_code)=>
- lua = Lua.Value(_code.source, "Lua.Value(", repr(tostring _code.source))
- add_lua_string_bits(lua, _code)
- lua\append ")"
- return lua
- add_lua_bits = (lua, code)->
- for bit in *code
- if type(bit) == "string"
- lua\append bit
- else
- bit_lua = nomsu\tree_to_lua(bit)
- unless bit_lua.is_value
- compile_error bit,
- "Cannot use:\n%s\nas a string interpolation value, since it's not an expression."
- lua\append bit_lua
- return lua
- nomsu.environment["A"..string.as_lua_id("lua > 1")] = .compile_time (_code)=>
- if _code.type != "Text"
- return Lua @source, "nomsu:run_lua(", nomsu\tree_to_lua(_code), ");"
- return add_lua_bits(Lua(@source), _code)
- nomsu.environment["A"..string.as_lua_id("= lua 1")] = .compile_time (_code)=>
- if _code.type != "Text"
- return Lua.Value @source, "nomsu:run_lua(", nomsu\tree_to_lua(_code), ":as_statements('return '))"
- return add_lua_bits(Lua.Value(@source), _code)
- .A_use_1 = .compile_time (_path)=>
- unless _path.type == 'Text' and #_path == 1 and type(_path[1]) == 'string'
- return Lua(_path.source, "nomsu:run_file(#{nomsu\tree_to_lua(_path)});")
- path = _path[1]
- nomsu\run_file(path)
- return Lua(_path.source, "nomsu:run_file(#{repr path});")
+-- Command line interface:
+
+
-- Only run this code if this file was run directly with command line arguments, and not require()'d:
if arg and debug_getinfo(2).func != require
@@ -1000,8 +905,8 @@ OPTIONS
]=]
os.exit!
- nomsu = NomsuCompiler!
- nomsu.environment.arg = args.nomsu_args
+ nomsu = NomsuCompiler
+ nomsu.arg = args.nomsu_args
ok, to_lua = pcall -> require('moonscript.base').to_lua
if not ok then to_lua = nil
@@ -1022,7 +927,7 @@ OPTIONS
else debug_getinfo(thread,f,what)
if not info or not info.func then return info
if info.short_src or info.source or info.linedefine or info.currentline
- if arg_orders = nomsu.environment.ARG_ORDERS[info.func]
+ if arg_orders = nomsu.ARG_ORDERS[info.func]
info.name = next(arg_orders)
if map = nomsu.source_map[info.source]
if info.currentline
@@ -1077,7 +982,7 @@ OPTIONS
file = FILE_CACHE[filename]\sub(tonumber(start),tonumber(stop))
err_line = get_line(file, calling_fn.currentline)\sub(1,-2)
offending_statement = colored.bright(colored.red(err_line\match("^[ ]*(.*)")))
- if arg_orders = nomsu.environment.ARG_ORDERS[calling_fn.func]
+ if arg_orders = nomsu.ARG_ORDERS[calling_fn.func]
name = "action '#{next(arg_orders)}'"
else
name = "main chunk"
@@ -1145,9 +1050,9 @@ OPTIONS
nomsu.skip_precompiled = not args.optimized
if print_file == nil
- nomsu.environment.print = ->
+ nomsu.print = ->
elseif print_file != io.stdout
- nomsu.environment.print = (...)->
+ nomsu.print = (...)->
N = select("#",...)
if N > 0
print_file\write(tostring(select(1,...)))
@@ -1163,7 +1068,7 @@ OPTIONS
input_files[#input_files+1] = f
to_run[f] = true
- nomsu.compile_fn = if args.compile or args.verbose
+ nomsu.on_compile = if args.compile or args.verbose
(code, from_file)->
if to_run[from_file]
if args.verbose
@@ -1171,7 +1076,7 @@ OPTIONS
if args.compile and from_file\match("%.nom$")
output_filename = from_file\gsub("%.nom$", ".lua")
output_file = io.open(output_filename, 'w')
- output_file\write("local IMMEDIATE = true;\n", tostring(code))
+ output_file\write(tostring(code))
output_file\flush!
print ("Compiled %-25s -> %s")\format(from_file, output_filename)
output_file\close!
@@ -1181,7 +1086,8 @@ OPTIONS
for filename in *input_files
if args.syntax
-- Check syntax:
- ok,err = pcall nomsu.parse, nomsu, Nomsu(filename, io.open(filename)\read("*a"))
+ file_contents = io.open(filename)\read('*a')
+ ok,err = pcall nomsu.parse, nomsu, file_contents, Source(filename, 1, #file_contents)
if not ok
insert parse_errs, err
elseif print_file
@@ -1192,7 +1098,7 @@ OPTIONS
file = FILE_CACHE[filename]
if not file
error("File does not exist: #{filename}", 0)
- tree = nomsu\parse(Nomsu(Source(filename,1,#file), file))
+ tree = nomsu\parse(file, Source(filename,1,#file))
formatted = tostring(nomsu\tree_to_nomsu(tree))
if print_file
print_file\write(formatted, "\n")
@@ -1200,7 +1106,7 @@ OPTIONS
elseif filename == STDIN
file = io.input!\read("*a")
FILE_CACHE.stdin = file
- nomsu\run(Nomsu(Source('stdin',1,#file), file))
+ nomsu\run(file, Source('stdin',1,#file))
else
nomsu\run_file(filename)
@@ -1230,10 +1136,9 @@ OPTIONS
buff = concat(buff)
FILE_CACHE["REPL#"..repl_line] = buff
- code = Nomsu(Source("REPL#"..repl_line, 1, #buff), buff)
err_hand = (error_message)->
print_err_msg error_message
- ok, ret = xpcall(nomsu.run, err_hand, nomsu, code)
+ ok, ret = xpcall(nomsu.run, err_hand, nomsu, buff, Source("REPL#"..repl_line, 1, #buff))
if ok and ret != nil
print "= "..repr(ret)
elseif not ok
diff --git a/nomsu.peg b/nomsu.peg
index 2654f21..a137675 100644
--- a/nomsu.peg
+++ b/nomsu.peg
@@ -1,13 +1,17 @@
file:
(ignored_line %nl)*
- (block / action / expression)?
+ (file_chunks / block / action / expression)?
(%nl ignored_line)*
(!. / (({} (.* -> "Parse error") %userdata) => error))
+file_chunks (FileChunks):
+ {| (block/action/expression) (nodent chunk_delimeter nodent (block/action/expression))+ |}
+chunk_delimeter: "~~~" (("~")*)
+
inline_block (Block):
{| inline_statement (%ws* ";" %ws* inline_statement)+ |}
block (Block):
- {| statement (nodent (statement / (({} ([^%nl]* -> "Unexpected character while parsing block line") %userdata) => error)))+ |}
+ {| statement (nodent !("~") (statement / (({} ([^%nl]* -> "Unexpected character while parsing block line") %userdata) => error)))+ |}
statement: (action / expression) (eol / (({} ([^%nl]* -> "Unexpected character while parsing line") %userdata) => error))
inline_statement: inline_action / inline_expression
@@ -49,6 +53,7 @@ index_chain (IndexChain):
-- Actions need either at least 1 word, or at least 2 tokens
inline_action (Action):
+ !chunk_delimeter
{|
( (inline_expression (%ws* (inline_expression / word))+)
/ (word (%ws* (inline_expression / word))*))
@@ -56,6 +61,7 @@ inline_action (Action):
/ (({} ('' -> "Missing expression after the ':'") %userdata) => error)))?
|}
action (Action):
+ !chunk_delimeter
{|
(expression ((nodent "..")? %ws* (expression / word))+)
/ (word ((nodent "..")? %ws* (expression / word))*)
diff --git a/nomsu_tree.lua b/nomsu_tree.lua
index 7288613..05fb22c 100644
--- a/nomsu_tree.lua
+++ b/nomsu_tree.lua
@@ -7,6 +7,7 @@ do
end
local Source
Source = require("code_obj").Source
+local unpack = unpack or table.unpack
local AST = { }
AST.is_syntax_tree = function(n)
return type(n) == 'table' and getmetatable(n) and AST[n.type] == getmetatable(n)
@@ -21,7 +22,8 @@ local types = {
"Dict",
"DictEntry",
"IndexChain",
- "Action"
+ "Action",
+ "FileChunks"
}
for _index_0 = 1, #types do
local name = types[_index_0]
diff --git a/nomsu_tree.moon b/nomsu_tree.moon
index 0c6e925..71bcff9 100644
--- a/nomsu_tree.moon
+++ b/nomsu_tree.moon
@@ -3,13 +3,14 @@
{:repr} = require 'utils'
{:insert, :remove, :concat} = table
{:Source} = require "code_obj"
+unpack or= table.unpack
AST = {}
AST.is_syntax_tree = (n)->
type(n) == 'table' and getmetatable(n) and AST[n.type] == getmetatable(n)
types = {"Number", "Var", "Block", "EscapedNomsu", "Text", "List", "Dict", "DictEntry",
- "IndexChain", "Action"}
+ "IndexChain", "Action", "FileChunks"}
for name in *types
cls = {}
with cls
diff --git a/tests/metaprogramming.nom b/tests/metaprogramming.nom
index af43269..e7e22c5 100644
--- a/tests/metaprogramming.nom
+++ b/tests/metaprogramming.nom
@@ -3,22 +3,22 @@
use "core"
-immediately
- compile [five] to: Lua value "5"
+compile [five] to: Lua value "5"
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
assume ((five) = 5) or barf "Compile to expression failed."
-immediately
- compile [loc x] to: Lua "local _x = 99;"
+compile [loc x] to: Lua "local _x = 99;"
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
lua> "do"
loc x
assume (%x is 99) or barf "Compile to statements with locals failed."
lua> "end"
assume (%x is (nil)) or barf "Failed to properly localize a variable."
-immediately
- compile [asdf] to
- %tmp <- ""
- return: Lua %tmp
+compile [asdf] to
+ %tmp <- ""
+ return: Lua %tmp
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
asdf
assume (%tmp is (nil)) or barf "compile to is leaking variables"
@@ -28,20 +28,20 @@ action [foo %x]
assume ((foo 10) = 11) or barf "Action didn't work."
assume (%y is (nil)) or barf "Action leaked a local into globals."
-immediately
- parse [baz %] as: foo %
+parse [baz %] as: foo %
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
assume ((baz 10) = 11) or barf "Parse as action failed."
-immediately
- parse [V] as: five
+parse [V] as: five
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
assume ((V) = 5) or barf "Parse as compile action failed."
-immediately
- parse [swap %x and %y] as
- do
- %tmp <- %x
- %x <- %y
- %y <- %tmp
+parse [swap %x and %y] as
+ do
+ %tmp <- %x
+ %x <- %y
+ %y <- %tmp
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<- {%1:1, %2:2}
swap %1 and %2
assume ((%1 = 2) and (%2 = 1)) or barf "'parse % as %' failed on 'swap % and %'"
diff --git a/tests/operators.nom b/tests/operators.nom
index 7cdf964..4b0d6ad 100644
--- a/tests/operators.nom
+++ b/tests/operators.nom
@@ -51,13 +51,14 @@ assume (((no) and (barfer)) = (no))
assume ((no) or (yes))
assume ((yes) or (barfer))
-assume ((1 OR 2) = 3)
-assume ((3 XOR 2) = 1)
-assume ((3 AND 2) = 2)
-assume ((NOT (NOT 6)) = 6)
-assume ((1<<1) = 2)
-assume ((2>>1) = 1)
-assume ((2>>>1) = 1)
+# Disabled because luajit doesn't have bitops
+ assume ((1 OR 2) = 3)
+ assume ((3 XOR 2) = 1)
+ assume ((3 AND 2) = 2)
+ assume ((NOT (NOT 6)) = 6)
+ assume ((1<<1) = 2)
+ assume ((2>>1) = 1)
+ assume ((2>>>1) = 1)
#.. Ugh, Lua is stupid when it comes to bitwise arithmetic on negative numbers, so I'm
skipping the tests for those.
diff --git a/tests/text.nom b/tests/text.nom
index a74ac5b..025e793 100644
--- a/tests/text.nom
+++ b/tests/text.nom
@@ -12,8 +12,9 @@ assume ("\n" = (newline)) or barf "Text literals failed."
assume (("x" + "y") = "xy")
assume ((lines in "one\ntwo") = ["one", "two"])
-immediately
- parse [アクション %spec %body] as: action %spec %body
+parse [アクション %spec %body] as: action %spec %body
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%こんにちは <- "こんにちは"
アクション [% と言う]
diff --git a/uuid.lua b/uuid.lua
index 563b950..ac4df1e 100644
--- a/uuid.lua
+++ b/uuid.lua
@@ -1,4 +1,5 @@
-- A simple UUID function based on RFC 4122: http://www.ietf.org/rfc/rfc4122.txt
+local unpack = unpack or table.unpack
local function uuid()
local r = math.random
-- Set all the other bits to randomly (or pseudo-randomly) chosen values.