aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bitbucket@bruce-hill.com>2018-04-18 15:28:46 -0700
committerBruce Hill <bitbucket@bruce-hill.com>2018-04-18 15:28:59 -0700
commit16f3a189fd9b32f599d1271c772e6d4287f95d20 (patch)
treed40c600e0ea0c1de66a170057027b37219d0219c
parentb589c23741c3111c151c0fecc7e299fd321c13a1 (diff)
More working, shifting towards having Lua and Nomsu objects instead of
just strings.
-rw-r--r--core/metaprogramming.nom4
-rw-r--r--lua_obj.lua243
-rw-r--r--lua_obj.moon139
-rw-r--r--nomsu.lua83
-rwxr-xr-xnomsu.moon74
-rw-r--r--nomsu_tree.moon2
6 files changed, 393 insertions, 152 deletions
diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom
index 1b65890..011d44d 100644
--- a/core/metaprogramming.nom
+++ b/core/metaprogramming.nom
@@ -78,13 +78,13 @@ immediately:
for i, line in ipairs(\%longhand.value) do lines[i] = line.source:get_text(); end
template = repr(table.concat(lines, "\\n"));
else
- template = repr(\%longhand.source:get_text());
+ template = repr(tostring(\%longhand.source:get_text()));
end
local replacements = {};
for i, a in ipairs(args) do replacements[i] = a.."="..a; end
replacements = "{"..table.concat(replacements, ", ").."}";
lua:append([[)
- local template = nomsu:parse(]]..template..[[, ]]..repr(tree.source.filename)..[[);
+ local template = nomsu:parse(Nomsu(]]..repr(tree.source)..[[, ]]..template..[[));
local replacement = nomsu:tree_with_replaced_vars(template, ]]..replacements..[[);
return replacement:as_lua(nomsu);
end);
diff --git a/lua_obj.lua b/lua_obj.lua
index ba8277c..eca0bf1 100644
--- a/lua_obj.lua
+++ b/lua_obj.lua
@@ -4,23 +4,30 @@ do
insert, remove, concat = _obj_0.insert, _obj_0.remove, _obj_0.concat
end
local immutable = require('immutable')
-local Lua, Location
-Location = immutable({
+local Lua, Source
+Source = immutable({
"filename",
"start",
"stop"
}, {
- name = "Location",
+ name = "Source",
__new = function(self, filename, start, stop)
- return filename, start, stop or start
+ if stop then
+ assert(start <= stop, "Invalid range: " .. tostring(start) .. ", " .. tostring(stop))
+ end
+ return filename, start, stop
end,
__tostring = function(self)
- return "Location(\"" .. tostring(self.filename) .. "\", " .. tostring(self.start) .. ", " .. tostring(self.stop) .. ")"
+ if self.stop then
+ return "Source(\"" .. tostring(self.filename) .. "\", " .. tostring(self.start) .. ", " .. tostring(self.stop) .. ")"
+ else
+ return "Source(\"" .. tostring(self.filename) .. "\", " .. tostring(self.start) .. ")"
+ end
end,
__lt = function(self, other)
assert(self.filename == other.filename, "Cannot compare sources from different files")
if self.start == other.start then
- return self.stop < other.stop
+ return (self.stop or self.start) < (other.stop or other.start)
else
return self.start < other.start
end
@@ -28,11 +35,36 @@ Location = immutable({
__le = function(self, other)
assert(self.filename == other.filename, "Cannot compare sources from different files")
if self.start == other.start then
- return self.stop <= other.stop
+ return (self.stop or self.start) <= (other.stop or other.start)
else
return self.start <= other.start
end
end,
+ __add = function(self, offset)
+ if type(self) == 'number' then
+ offset, self = self, offset
+ else
+ assert(type(offset) == 'number', "Cannot add Source and " .. tostring(type(offset)))
+ end
+ return Source(self.filename, self.start + offset, self.stop)
+ end,
+ sub = function(self, start, stop)
+ if not self.stop then
+ assert(not stop, "cannot subscript non-range with range")
+ assert(start > 0, "cannot subscript non-range with negative index")
+ return Source(self.filename, self.start + (start or 0))
+ else
+ start = start or 1
+ if start < 0 then
+ start = self.stop + start + 1
+ end
+ stop = stop or -1
+ if stop < 0 then
+ stop = self.stop + stop + 1
+ end
+ return Source(self.filename, self.start + start - 1, self.start + stop - 1)
+ end
+ end,
get_text = function(self)
return FILE_CACHE[self.filename]:sub(self.start, self.stop)
end,
@@ -61,19 +93,88 @@ Location = immutable({
end
end
})
+local Code
do
local _class_0
local _base_0 = {
clone = function(self)
- local copy = Lua(self.source, {
- unpack(self.bits)
- })
+ local cls = self.__class
+ local copy = cls(self.source, unpack(self.bits))
copy.is_value = self.is_value
for k, v in pairs(self.free_vars) do
copy.free_vars[k] = v
end
return copy
end,
+ __tostring = function(self)
+ local buff = { }
+ for i, b in ipairs(self.bits) do
+ buff[#buff + 1] = tostring(b)
+ end
+ local ret = concat(buff, "")
+ return ret
+ end,
+ __len = function(self)
+ local len = 0
+ local _list_0 = self.bits
+ for _index_0 = 1, #_list_0 do
+ local b = _list_0[_index_0]
+ len = len + #b
+ end
+ return len
+ end,
+ sub = function(self, start, stop)
+ local str = tostring(self):sub(start, stop)
+ local cls = self.__class
+ return cls(self.source:sub(start - self.source.start + 1, stop - self.source.stop + 1), str)
+ end,
+ append = function(self, ...)
+ local n = select("#", ...)
+ local bits = self.bits
+ for i = 1, n do
+ bits[#bits + 1] = select(i, ...)
+ end
+ end,
+ prepend = function(self, ...)
+ local n = select("#", ...)
+ local bits = self.bits
+ for i = #bits + n, n + 1, -1 do
+ bits[i] = bits[i - n]
+ end
+ for i = 1, n do
+ bits[i] = select(i, ...)
+ end
+ end
+ }
+ _base_0.__index = _base_0
+ _class_0 = setmetatable({
+ __init = function(self, source, ...)
+ self.source = source
+ if type(self.source) == 'string' then
+ local filename, start, stop = self.source:match("^(.-)[(%d+):(%d+)]$")
+ self.source = Source(filename, tonumber(start), tonumber(stop))
+ end
+ self.bits = {
+ ...
+ }
+ end,
+ __base = _base_0,
+ __name = "Code"
+ }, {
+ __index = _base_0,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ Code = _class_0
+end
+do
+ local _class_0
+ local _parent_0 = Code
+ local _base_0 = {
add_free_vars = function(self, ...)
local seen
do
@@ -150,9 +251,6 @@ do
local buff = { }
for i, b in ipairs(self.bits) do
buff[#buff + 1] = tostring(b)
- if i < #self.bits and type(b) ~= 'string' and not b.is_value then
- buff[#buff + 1] = "\n"
- end
end
local ret = concat(buff, "")
return ret
@@ -166,30 +264,33 @@ do
end
return len
end,
- __add = function(self, other)
- return Lua(nil, self, other)
- end,
- __concat = function(self, other)
- return Lua(nil, self, other)
- end,
append = function(self, ...)
local n = select("#", ...)
local bits = self.bits
for i = 1, n do
- bits[#bits + 1] = select(i, ...)
+ local bit = select(i, ...)
+ bits[#bits + 1] = bit
+ if type(bit) ~= 'string' and not bit.is_value and #self.bits > 0 then
+ bits[#bits + 1] = "\n"
+ end
end
end,
prepend = function(self, ...)
local n = select("#", ...)
local bits = self.bits
- for i = #bits + n, n + 1, -1 do
- bits[i] = bits[i - n]
- end
+ local insert_index = 1
for i = 1, n do
- bits[i] = select(i, ...)
+ local bit = select(i, ...)
+ insert(bits, insert_index, bit)
+ insert_index = insert_index + 1
+ if type(bit) ~= 'string' and not bit.is_value and insert_index < #self.bits + 1 then
+ insert(bits, insert_index, "\n")
+ insert_index = insert_index + 1
+ end
end
end,
- make_offset_table = function(self, lua_chunkname)
+ make_offset_table = function(self)
+ local lua_chunkname = tostring(self.source) .. ".lua"
local lua_str = tostring(self)
local metadata = {
nomsu_filename = self.source.filename,
@@ -211,7 +312,7 @@ do
walk(b)
end
local lua_stop = lua_offset
- local nomsu_src, lua_src = lua.source, Location(lua_chunkname, lua_start, lua_stop)
+ local nomsu_src, lua_src = lua.source, Source(lua_chunkname, lua_start, lua_stop)
metadata.lua_to_nomsu[lua_src] = nomsu_src
metadata.nomsu_to_lua[nomsu_src] = lua_src
end
@@ -229,23 +330,28 @@ do
end
}
_base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
_class_0 = setmetatable({
- __init = function(self, source, ...)
- self.source = source
- if type(self.source) == 'string' then
- local filename, start, stop = self.source:match("^(.-)[(%d+):(%d+)]$")
- self.source = Location(filename, tonumber(start), tonumber(stop))
- end
- self.bits = {
- ...
- }
+ __init = function(self, ...)
+ _class_0.__parent.__init(self, ...)
self.free_vars = { }
self.is_value = false
end,
__base = _base_0,
- __name = "Lua"
+ __name = "Lua",
+ __parent = _parent_0
}, {
- __index = _base_0,
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
@@ -259,9 +365,70 @@ do
lua.is_value = true
return lua
end
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
Lua = _class_0
end
+local Nomsu
+do
+ local _class_0
+ local _parent_0 = Code
+ local _base_0 = {
+ __tostring = function(self)
+ local buff = { }
+ for i, b in ipairs(self.bits) do
+ buff[#buff + 1] = tostring(b)
+ end
+ local ret = concat(buff, "")
+ return ret
+ end,
+ __len = function(self)
+ local len = 0
+ local _list_0 = self.bits
+ for _index_0 = 1, #_list_0 do
+ local b = _list_0[_index_0]
+ len = len + #b
+ end
+ return len
+ end
+ }
+ _base_0.__index = _base_0
+ setmetatable(_base_0, _parent_0.__base)
+ _class_0 = setmetatable({
+ __init = function(self, ...)
+ return _class_0.__parent.__init(self, ...)
+ end,
+ __base = _base_0,
+ __name = "Nomsu",
+ __parent = _parent_0
+ }, {
+ __index = function(cls, name)
+ local val = rawget(_base_0, name)
+ if val == nil then
+ local parent = rawget(cls, "__parent")
+ if parent then
+ return parent[name]
+ end
+ else
+ return val
+ end
+ end,
+ __call = function(cls, ...)
+ local _self_0 = setmetatable({}, _base_0)
+ cls.__init(_self_0, ...)
+ return _self_0
+ end
+ })
+ _base_0.__class = _class_0
+ if _parent_0.__inherited then
+ _parent_0.__inherited(_parent_0, _class_0)
+ end
+ Nomsu = _class_0
+end
return {
+ Code = Code,
+ Nomsu = Nomsu,
Lua = Lua,
- Location = Location
+ Source = Source
}
diff --git a/lua_obj.moon b/lua_obj.moon
index ab5b5a3..6ee1970 100644
--- a/lua_obj.moon
+++ b/lua_obj.moon
@@ -1,25 +1,46 @@
{:insert, :remove, :concat} = table
immutable = require 'immutable'
-local Lua, Location
+local Lua, Source
export LINE_STARTS
-Location = immutable {"filename","start","stop"}, {
- name:"Location"
+Source = immutable {"filename","start","stop"}, {
+ name:"Source"
__new: (filename, start, stop)=>
- --assert(type(filename) == 'string' and type(start) == 'number' and type(stop) == 'number')
- return filename, start, stop or start
- __tostring: => "Location(\"#{@filename}\", #{@start}, #{@stop})"
+ if stop then assert(start <= stop, "Invalid range: #{start}, #{stop}")
+ return filename, start, stop
+ __tostring: =>
+ if @stop
+ "Source(\"#{@filename}\", #{@start}, #{@stop})"
+ else
+ "Source(\"#{@filename}\", #{@start})"
__lt: (other)=>
assert(@filename == other.filename, "Cannot compare sources from different files")
return if @start == other.start
- @stop < other.stop
+ (@stop or @start) < (other.stop or other.start)
else @start < other.start
__le: (other)=>
assert(@filename == other.filename, "Cannot compare sources from different files")
return if @start == other.start
- @stop <= other.stop
+ (@stop or @start) <= (other.stop or other.start)
else @start <= other.start
- get_text: => FILE_CACHE[@filename]\sub(@start,@stop)
+ __add: (offset)=>
+ if type(self) == 'number'
+ offset, self = self, offset
+ else assert(type(offset) == 'number', "Cannot add Source and #{type(offset)}")
+ return Source(@filename, @start+offset, @stop)
+ sub: (start, stop)=>
+ if not @stop
+ assert(not stop, "cannot subscript non-range with range")
+ assert(start > 0, "cannot subscript non-range with negative index")
+ return Source(@filename, @start + (start or 0))
+ else
+ start or= 1
+ if start < 0 then start = @stop + start + 1
+ stop or= -1
+ if stop < 0 then stop = @stop + stop + 1
+ return Source(@filename, @start + start - 1, @start + stop - 1)
+ get_text: =>
+ FILE_CACHE[@filename]\sub(@start,@stop)
get_line_number: =>
-- TODO: do a binary search if this is actually slow, which I doubt
src = FILE_CACHE[@filename]
@@ -39,12 +60,56 @@ Location = immutable {"filename","start","stop"}, {
else "#{@filename}:#{start_line}-#{stop_line}"
}
-class Lua
+class Code
new: (@source, ...)=>
if type(@source) == 'string'
filename,start,stop = @source\match("^(.-)[(%d+):(%d+)]$")
- @source = Location(filename, tonumber(start), tonumber(stop))
+ @source = Source(filename, tonumber(start), tonumber(stop))
@bits = {...}
+
+ clone: =>
+ cls = @__class
+ copy = cls(@source, unpack(@bits))
+ copy.is_value = @is_value
+ for k,v in pairs @free_vars
+ copy.free_vars[k] = v
+ return copy
+
+ __tostring: =>
+ buff = {}
+ for i,b in ipairs @bits
+ buff[#buff+1] = tostring(b)
+ ret = concat(buff, "")
+ return ret
+
+ __len: =>
+ len = 0
+ for b in *@bits
+ len += #b
+ return len
+
+ sub: (start,stop)=>
+ str = tostring(self)\sub(start,stop)
+ cls = @__class
+ return cls(@source\sub(start-@source.start+1,stop-@source.stop+1), str)
+
+ append: (...)=>
+ n = select("#",...)
+ bits = @bits
+ for i=1,n
+ bits[#bits+1] = select(i, ...)
+
+ prepend: (...)=>
+ n = select("#",...)
+ bits = @bits
+ for i=#bits+n,n+1,-1
+ bits[i] = bits[i-n]
+ for i=1,n
+ bits[i] = select(i, ...)
+
+class Lua extends Code
+ new: (...)=>
+ super ...
@free_vars = {}
@is_value = false
@@ -53,13 +118,6 @@ class Lua
lua.is_value = true
return lua
- clone: =>
- copy = Lua(@source, {unpack(@bits)})
- copy.is_value = @is_value
- for k,v in pairs @free_vars
- copy.free_vars[k] = v
- return copy
-
add_free_vars: (...)=>
seen = {[v]:true for v in *@free_vars}
for i=1,select("#",...)
@@ -90,8 +148,6 @@ class Lua
buff = {}
for i,b in ipairs @bits
buff[#buff+1] = tostring(b)
- if i < #@bits and type(b) != 'string' and not b.is_value
- buff[#buff+1] = "\n"
ret = concat(buff, "")
return ret
@@ -100,29 +156,32 @@ class Lua
for b in *@bits
len += #b
return len
-
- __add: (other)=>
- Lua(nil, self, other)
-
- __concat: (other)=>
- Lua(nil, self, other)
append: (...)=>
n = select("#",...)
bits = @bits
for i=1,n
- bits[#bits+1] = select(i, ...)
+ bit = select(i, ...)
+ bits[#bits+1] = bit
+ if type(bit) != 'string' and not bit.is_value and #@bits > 0
+ bits[#bits+1] = "\n"
prepend: (...)=>
n = select("#",...)
bits = @bits
- for i=#bits+n,n+1,-1
- bits[i] = bits[i-n]
+ insert_index = 1
+ -- TODO: optimize?
for i=1,n
- bits[i] = select(i, ...)
+ bit = select(i, ...)
+ insert bits, insert_index, bit
+ insert_index += 1
+ if type(bit) != 'string' and not bit.is_value and insert_index < #@bits + 1
+ insert bits, insert_index, "\n"
+ insert_index += 1
- make_offset_table: (lua_chunkname)=>
+ make_offset_table: =>
-- Return a mapping from output (lua) character number to input (nomsu) character number
+ lua_chunkname = tostring(@source)..".lua"
lua_str = tostring(self)
metadata = {
nomsu_filename:@source.filename
@@ -138,7 +197,7 @@ class Lua
for b in *lua.bits
walk b
lua_stop = lua_offset
- nomsu_src, lua_src = lua.source, Location(lua_chunkname, lua_start, lua_stop)
+ nomsu_src, lua_src = lua.source, Source(lua_chunkname, lua_start, lua_stop)
metadata.lua_to_nomsu[lua_src] = nomsu_src
metadata.nomsu_to_lua[nomsu_src] = lua_src
walk self
@@ -151,4 +210,18 @@ class Lua
else
error "Cannot parenthesize lua statements"
-return {:Lua, :Location}
+class Nomsu extends Code
+ __tostring: =>
+ buff = {}
+ for i,b in ipairs @bits
+ buff[#buff+1] = tostring(b)
+ ret = concat(buff, "")
+ return ret
+
+ __len: =>
+ len = 0
+ for b in *@bits
+ len += #b
+ return len
+
+return {:Code, :Nomsu, :Lua, :Source}
diff --git a/nomsu.lua b/nomsu.lua
index fad9856..9a55d6a 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -30,10 +30,10 @@ do
insert, remove, concat = _obj_0.insert, _obj_0.remove, _obj_0.concat
end
local debug_getinfo = debug.getinfo
-local Lua, Location
+local Nomsu, Lua, Source
do
local _obj_0 = require("lua_obj")
- Lua, Location = _obj_0.Lua, _obj_0.Location
+ Nomsu, Lua, Source = _obj_0.Nomsu, _obj_0.Lua, _obj_0.Source
end
FILE_CACHE = setmetatable({ }, {
__index = function(self, filename)
@@ -41,10 +41,16 @@ FILE_CACHE = setmetatable({ }, {
if not (file) then
return nil
end
- local source = file:read("a"):sub(1, -2)
+ local code = file:read("a"):sub(1, -2)
file:close()
- self[filename] = source
- return source
+ local source = Source(filename, 1, #code)
+ if filename:match("%.nom$") then
+ code = Nomsu(source, code)
+ elseif filename:match("%.lua$") then
+ code = Lua(source, code)
+ end
+ self[filename] = code
+ return code
end
})
local line_counter = re.compile([[ lines <- {| line (%nl line)* |}
@@ -55,7 +61,7 @@ local line_counter = re.compile([[ lines <- {| line (%nl line)* |}
LINE_STARTS = setmetatable({ }, {
__mode = "k",
__index = function(self, k)
- local line_starts = line_counter:match(k)
+ local line_starts = line_counter:match(tostring(k))
self[k] = line_starts
return line_starts
end
@@ -149,17 +155,17 @@ do
end
end)
_with_0.error = function(src, pos, err_msg)
- if lpeg.userdata.source_code:sub(pos, pos):match("[\r\n]") then
- pos = pos + #lpeg.userdata.source_code:match("[ \t\n\r]*", pos)
+ if src:sub(pos, pos):match("[\r\n]") then
+ pos = pos + #src:match("[ \t\n\r]*", pos)
end
local line_no = 1
- local text_loc = Location(lpeg.userdata.filename, pos)
+ local text_loc = lpeg.userdata.source_code.source:sub(pos, pos)
line_no = text_loc:get_line_number()
local prev_line = src:sub(LINE_STARTS[src][line_no - 1] or 1, LINE_STARTS[src][line_no] - 1)
local err_line = src:sub(LINE_STARTS[src][line_no], (LINE_STARTS[src][line_no + 1] or 0) - 1)
local next_line = src:sub(LINE_STARTS[src][line_no + 1] or -1, (LINE_STARTS[src][line_no + 2] or 0) - 1)
local pointer = ("-"):rep(pos - LINE_STARTS[src][line_no]) .. "^"
- err_msg = (err_msg or "Parse error") .. " in " .. tostring(lpeg.userdata.filename) .. " on line " .. tostring(line_no) .. ":\n"
+ err_msg = (err_msg or "Parse error") .. " in " .. tostring(lpeg.userdata.source_code.source.filename) .. " on line " .. tostring(line_no) .. ":\n"
err_msg = err_msg .. "\n" .. tostring(prev_line) .. "\n" .. tostring(err_line) .. "\n" .. tostring(pointer) .. "\n" .. tostring(next_line) .. "\n"
return error(err_msg)
end
@@ -172,8 +178,8 @@ setmetatable(NOMSU_DEFS, {
if type(value) == 'table' then
error("Not a tuple: " .. tostring(repr(value)))
end
- local loc = Location(lpeg.userdata.filename, start, stop)
- local node = Types[key](value, loc)
+ local source = lpeg.userdata.source_code.source:sub(start, stop)
+ local node = Types[key](value, source)
return node
end
self[key] = make_node
@@ -197,7 +203,7 @@ end
local NomsuCompiler
do
local _class_0
- local _chunk_counter, stub_defs, stub_pattern, var_pattern
+ local stub_defs, stub_pattern, var_pattern
local _base_0 = {
define_action = function(self, signature, source, fn)
if type(fn) ~= 'function' then
@@ -310,34 +316,35 @@ do
end
return code:gsub("\n", "\n" .. (" "):rep(levels))
end,
- parse = function(self, nomsu_code, filename)
- assert(type(filename) == "string", "Bad filename type: " .. tostring(type(filename)))
+ parse = function(self, nomsu_code)
local userdata = {
source_code = nomsu_code,
- filename = filename,
indent_stack = {
""
}
}
local old_userdata
old_userdata, lpeg.userdata = lpeg.userdata, userdata
- local tree = NOMSU_PATTERN:match(nomsu_code)
+ local tree = NOMSU_PATTERN:match(tostring(nomsu_code))
lpeg.userdata = old_userdata
assert(tree, "In file " .. tostring(colored.blue(filename)) .. " failed to parse:\n" .. tostring(colored.onyellow(colored.black(nomsu_code))))
return tree
end,
- run = function(self, nomsu_code, filename)
+ run = function(self, nomsu_code, source)
+ if type(source) == 'string' then
+ source = Source(source, 1, #nomsu_code)
+ end
if nomsu_code == "" then
- return nil, ""
+ return nil
end
- local tree = self:parse(nomsu_code, filename)
+ local tree = self:parse(nomsu_code, source)
assert(tree, "Failed to parse: " .. tostring(nomsu_code))
assert(tree.type == "File", "Attempt to run non-file: " .. tostring(tree.type))
local lua = self:tree_to_lua(tree)
lua:convert_to_statements()
lua:declare_locals()
- lua:prepend("-- File: " .. tostring(filename) .. "\n")
- return self:run_lua(lua, filename .. ".lua")
+ lua:prepend("-- File: " .. tostring(source) .. "\n")
+ return self:run_lua(lua)
end,
run_file = function(self, filename)
local file_attributes = assert(lfs.attributes(filename), "File not found: " .. tostring(filename))
@@ -396,25 +403,17 @@ do
end
return loaded[filename]
end,
- run_lua = function(self, lua, filename)
- if filename == nil then
- filename = nil
- end
- if filename == nil then
- if type(lua) == 'string' then
- _chunk_counter = _chunk_counter + 1
- filename = "<lua chunk #" .. tostring(_chunk_counter) .. ">"
- else
- filename = lua.source.filename .. ".lua"
- end
- FILE_CACHE[filename] = tostring(lua)
+ run_lua = function(self, lua)
+ assert(type(lua) ~= 'string', "Attempt to run lua string instead of Lua (object)")
+ local lua_string, metadata = lua:make_offset_table()
+ LUA_METADATA[metadata.lua_filename] = metadata
+ if rawget(FILE_CACHE, lua.source.filename) == nil then
+ FILE_CACHE[lua.source.filename] = lua_string
end
- if type(lua) ~= 'string' then
- local metadata
- lua, metadata = lua:make_offset_table(filename)
- LUA_METADATA[lua] = metadata
+ if rawget(FILE_CACHE, lua.source) == nil then
+ FILE_CACHE[lua.source] = lua_string
end
- local run_lua_fn, err = load(lua, filename, "t", self.environment)
+ local run_lua_fn, err = load(lua_string, filename, "t", self.environment)
if not run_lua_fn then
local n = 1
local fn
@@ -422,7 +421,7 @@ do
n = n + 1
return ("\n%-3d|"):format(n)
end
- local line_numbered_lua = "1 |" .. lua:gsub("\n", fn)
+ 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
return run_lua_fn()
@@ -1204,7 +1203,8 @@ do
end
self.environment.Tuple = Tuple
self.environment.Lua = Lua
- self.environment.Location = Location
+ self.environment.Nomsu = Nomsu
+ self.environment.Source = Source
self.environment.ACTIONS = setmetatable({ }, {
__index = function(self, key)
return error("Attempt to run undefined action: " .. tostring(key), 0)
@@ -1226,7 +1226,6 @@ do
})
_base_0.__class = _class_0
local self = _class_0
- _chunk_counter = 0
self.unescape_string = function(self, str)
return Cs(((P("\\\\") / "\\") + (P("\\\"") / '"') + NOMSU_DEFS.escaped_char + P(1)) ^ 0):match(str)
end
diff --git a/nomsu.moon b/nomsu.moon
index 3b80aba..d9c3252 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -25,7 +25,7 @@ colors = setmetatable({}, {__index:->""})
colored = setmetatable({}, {__index:(_,color)-> ((msg)-> colors[color]..tostring(msg or '')..colors.reset)})
{:insert, :remove, :concat} = table
debug_getinfo = debug.getinfo
-{:Lua, :Location} = require "lua_obj"
+{:Nomsu, :Lua, :Source} = require "lua_obj"
-- TODO:
-- consider non-linear codegen, rather than doing thunks for things like comprehensions
@@ -45,10 +45,15 @@ FILE_CACHE = setmetatable {}, {
__index: (filename)=>
file = io.open(filename)
return nil unless file
- source = file\read("a")\sub(1,-2) -- Lua appends trailing newline for no apparent reason.
+ code = file\read("a")\sub(1,-2) -- Lua appends trailing newline for no apparent reason.
file\close!
- self[filename] = source
- return source
+ source = Source(filename, 1, #code)
+ if filename\match("%.nom$")
+ code = Nomsu(source, code)
+ elseif filename\match("%.lua$")
+ code = Lua(source, code)
+ self[filename] = code
+ return code
}
line_counter = re.compile([[
@@ -60,7 +65,7 @@ export LINE_STARTS
LINE_STARTS = setmetatable {}, {
__mode:"k"
__index: (k)=>
- line_starts = line_counter\match(k)
+ line_starts = line_counter\match(tostring(k))
self[k] = line_starts
return line_starts
}
@@ -142,24 +147,24 @@ NOMSU_DEFS = with {}
return start + #nodent
.error = (src,pos,err_msg)->
- if lpeg.userdata.source_code\sub(pos,pos)\match("[\r\n]")
- pos += #lpeg.userdata.source_code\match("[ \t\n\r]*", pos)
+ if src\sub(pos,pos)\match("[\r\n]")
+ pos += #src\match("[ \t\n\r]*", pos)
line_no = 1
- text_loc = Location(lpeg.userdata.filename, pos)
+ text_loc = lpeg.userdata.source_code.source\sub(pos,pos)
line_no = text_loc\get_line_number!
prev_line = src\sub(LINE_STARTS[src][line_no-1] or 1, LINE_STARTS[src][line_no]-1)
err_line = src\sub(LINE_STARTS[src][line_no], (LINE_STARTS[src][line_no+1] or 0)-1)
next_line = src\sub(LINE_STARTS[src][line_no+1] or -1, (LINE_STARTS[src][line_no+2] or 0)-1)
pointer = ("-")\rep(pos-LINE_STARTS[src][line_no]) .. "^"
- err_msg = (err_msg or "Parse error").." in #{lpeg.userdata.filename} on line #{line_no}:\n"
+ err_msg = (err_msg or "Parse error").." in #{lpeg.userdata.source_code.source.filename} on line #{line_no}:\n"
err_msg ..="\n#{prev_line}\n#{err_line}\n#{pointer}\n#{next_line}\n"
error(err_msg)
setmetatable(NOMSU_DEFS, {__index:(key)=>
make_node = (start, value, stop)->
if type(value) == 'table' then error("Not a tuple: #{repr value}")-- = Tuple(value)
- loc = Location(lpeg.userdata.filename, start, stop)
- node = Types[key](value, loc)
+ source = lpeg.userdata.source_code.source\sub(start,stop)
+ node = Types[key](value, source)
return node
self[key] = make_node
return make_node
@@ -212,7 +217,8 @@ class NomsuCompiler
for k,v in pairs(Types) do @environment[k] = v
@environment.Tuple = Tuple
@environment.Lua = Lua
- @environment.Location = Location
+ @environment.Nomsu = Nomsu
+ @environment.Source = Source
@environment.ACTIONS = setmetatable({}, {__index:(key)=>
error("Attempt to run undefined action: #{key}", 0)
})
@@ -279,30 +285,30 @@ class NomsuCompiler
indent: (code, levels=1)=>
return code\gsub("\n","\n"..(" ")\rep(levels))
- parse: (nomsu_code, filename)=>
- assert type(filename) == "string", "Bad filename type: #{type filename}"
-
+ parse: (nomsu_code)=>
userdata = {
- source_code:nomsu_code, :filename, indent_stack: {""}
+ source_code:nomsu_code, indent_stack: {""}
}
old_userdata, lpeg.userdata = lpeg.userdata, userdata
- tree = NOMSU_PATTERN\match(nomsu_code)
+ tree = NOMSU_PATTERN\match(tostring(nomsu_code))
lpeg.userdata = old_userdata
assert tree, "In file #{colored.blue filename} failed to parse:\n#{colored.onyellow colored.black nomsu_code}"
return tree
- run: (nomsu_code, filename)=>
- if nomsu_code == "" then return nil, ""
- tree = @parse(nomsu_code, filename)
+ run: (nomsu_code, source)=>
+ if type(source) == 'string'
+ source = Source(source,1,#nomsu_code)
+ if nomsu_code == "" then return nil
+ tree = @parse(nomsu_code, source)
assert tree, "Failed to parse: #{nomsu_code}"
assert tree.type == "File", "Attempt to run non-file: #{tree.type}"
lua = @tree_to_lua(tree)
lua\convert_to_statements!
lua\declare_locals!
- lua\prepend "-- File: #{filename}\n"
- return @run_lua(lua, filename..".lua")
+ lua\prepend "-- File: #{source}\n"
+ return @run_lua(lua)
run_file: (filename)=>
file_attributes = assert(lfs.attributes(filename), "File not found: #{filename}")
@@ -342,26 +348,22 @@ class NomsuCompiler
loaded[filename] = @run_file(filename) or true
return loaded[filename]
- _chunk_counter = 0
- run_lua: (lua, filename=nil)=>
- if filename == nil
- filename = if type(lua) == 'string'
- _chunk_counter += 1
- "<lua chunk ##{_chunk_counter}>"
- else
- lua.source.filename..".lua"
- FILE_CACHE[filename] = tostring(lua)
- if type(lua) != 'string'
- lua, metadata = lua\make_offset_table(filename)
- LUA_METADATA[lua] = metadata
+ run_lua: (lua)=>
+ assert(type(lua) != 'string', "Attempt to run lua string instead of Lua (object)")
+ lua_string, metadata = lua\make_offset_table!
+ LUA_METADATA[metadata.lua_filename] = metadata
+ if rawget(FILE_CACHE, lua.source.filename) == nil
+ FILE_CACHE[lua.source.filename] = lua_string
+ if rawget(FILE_CACHE, lua.source) == nil
+ FILE_CACHE[lua.source] = lua_string
- run_lua_fn, err = load(lua, filename, "t", @environment)
+ run_lua_fn, err = load(lua_string, filename, "t", @environment)
if not run_lua_fn
n = 1
fn = ->
n = n + 1
("\n%-3d|")\format(n)
- line_numbered_lua = "1 |"..lua\gsub("\n", fn)
+ 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)
return run_lua_fn!
diff --git a/nomsu_tree.moon b/nomsu_tree.moon
index 9b00d85..d327e2e 100644
--- a/nomsu_tree.moon
+++ b/nomsu_tree.moon
@@ -50,7 +50,7 @@ Tree "File",
Tree "Nomsu",
as_lua: (nomsu)=>
- Lua.Value(@source, "nomsu:parse(",repr(@source\get_text!),", ",repr(@source.filename),")")
+ Lua.Value(@source, "nomsu:parse(Nomsu(",repr(@source),", ",repr(@source\get_text!),"))")
Tree "Block",
as_lua: (nomsu)=>