aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bitbucket@bruce-hill.com>2018-05-29 16:14:53 -0700
committerBruce Hill <bitbucket@bruce-hill.com>2018-05-29 16:15:10 -0700
commit3573dfe9950d7037dfc3c48c6486d432100e6866 (patch)
treebf320c63545eb6ad51609585271568b05e14fe99
parente17822d1e548f96952efb95c64c69704fdfeaf76 (diff)
Almost-working reimplementation of source code mapping.
-rw-r--r--code_obj.lua3
-rw-r--r--code_obj.moon3
-rw-r--r--core/text.nom6
-rw-r--r--nomsu.lua109
-rwxr-xr-xnomsu.moon77
5 files changed, 187 insertions, 11 deletions
diff --git a/code_obj.lua b/code_obj.lua
index 990f3bc..2aba03d 100644
--- a/code_obj.lua
+++ b/code_obj.lua
@@ -12,6 +12,7 @@ Source = immutable({
}, {
name = "Source",
__new = function(self, filename, start, stop)
+ assert(type(filename) == 'string')
if not start then
start, stop = 1, #FILE_CACHE[filename]
end
@@ -159,7 +160,7 @@ do
if type(self.source) == 'string' then
self.source = Source:from_string(self.source)
end
- return assert(self.source)
+ return assert(self.source and Source:is_instance(self.source))
end,
__base = _base_0,
__name = "Code"
diff --git a/code_obj.moon b/code_obj.moon
index e821b7e..17ec816 100644
--- a/code_obj.moon
+++ b/code_obj.moon
@@ -6,6 +6,7 @@ export LINE_STARTS
Source = immutable {"filename","start","stop"}, {
name:"Source"
__new: (filename, start, stop)=>
+ assert(type(filename) == 'string')
if not start
start, stop = 1, #FILE_CACHE[filename]
if stop and start > stop+1 then error("Invalid range: #{start}, #{stop}")
@@ -71,7 +72,7 @@ class Code
@append(...)
if type(@source) == 'string'
@source = Source\from_string(@source)
- assert(@source)
+ assert(@source and Source\is_instance(@source))
append: (...)=>
n = select("#",...)
diff --git a/core/text.nom b/core/text.nom
index 95451ee..8b75ca4 100644
--- a/core/text.nom
+++ b/core/text.nom
@@ -27,7 +27,7 @@ lua> ".."
};
for name, e in pairs(escapes) do
local lua = "'"..e.."'";
- nomsu:define_compile_action(name, function(tree) return Lua.Value(tree.value, lua); end);
+ nomsu:define_compile_action(name, function(tree) return Lua.Value(tree.source, lua); end);
end
local colors = {
["reset color"]="\\\\27[0m", bright="\\\\27[1m", dim="\\\\27[2m", underscore="\\\\27[4m",
@@ -42,9 +42,9 @@ lua> ".."
for name, c in pairs(colors) do
local color = "'"..c.."'";
local reset = "'"..colors["reset color"].."'";
- nomsu:define_compile_action(name, function(tree) return Lua.Value(tree.value, color); end);
+ nomsu:define_compile_action(name, function(tree) return Lua.Value(tree.source, color); end);
nomsu:define_compile_action(name.." %", function(\%)
- return Lua.Value(tree.value, color, "..", \(% as lua), "..", reset);
+ return Lua.Value(tree.source, color, "..", \(% as lua), "..", reset);
end);
end
end
diff --git a/nomsu.lua b/nomsu.lua
index 10c907f..ddad7dd 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -233,7 +233,7 @@ setmetatable(NOMSU_DEFS, {
__index = function(self, key)
local make_node
make_node = function(start, value, stop, userdata)
- local source = userdata.source:sub(start, stop)
+ local source = userdata.source:sub(start, stop - 1)
local tree
if Types[key].is_multi then
tree = Types[key](Tuple(unpack(value)), source)
@@ -313,6 +313,24 @@ do
define_compile_action = function(self, signature, fn)
return self:define_action(signature, fn, true)
end,
+ lua_line_to_nomsu = function(self, source, line_no)
+ local pos = 0
+ local line = 0
+ local filename = source:match('"([^[]*)')
+ for line in FILE_CACHE[filename]:gmatch("[^\n]*\n") do
+ line = line + 1
+ pos = pos + #line
+ if line == line_no then
+ break
+ end
+ end
+ for i, entry in ipairs(self.source_map[source]) do
+ if entry[1] > pos then
+ return self.source_map[source][i - 1][2]
+ end
+ end
+ return self.source_map[source][#self.source_map[source]][2]
+ end,
parse = function(self, nomsu_code)
if type(nomsu_code) == 'string' then
_nomsu_chunk_counter = _nomsu_chunk_counter + 1
@@ -419,7 +437,7 @@ do
if not file then
error("File does not exist: " .. tostring(filename), 0)
end
- ret = self:run(Nomsu(Source(filename), file), compile_fn)
+ ret = self:run(Nomsu(Source(filename, 1, #file), file), compile_fn)
else
error("Invalid filetype for " .. tostring(filename), 0)
end
@@ -437,7 +455,7 @@ do
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, filename, "t", self.environment)
+ 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
@@ -448,6 +466,69 @@ do
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
+ if not (self.source_map[tostring(lua.source)]) then
+ local map = { }
+ local offset = 1
+ local source = lua.source
+ local nomsu_raw = FILE_CACHE[source.filename]:sub(source.start, source.stop)
+ local get_line_starts
+ get_line_starts = function(s)
+ local starts = { }
+ local pos = 1
+ for line in s:gmatch("[^\n]*\n") do
+ insert(starts, pos)
+ pos = pos + #line
+ end
+ insert(starts, pos)
+ return starts
+ end
+ local nomsu_line_to_pos = get_line_starts(nomsu_raw)
+ local lua_line_to_pos = get_line_starts(tostring(lua))
+ local pos_to_line
+ pos_to_line = function(line_starts, pos)
+ local lo, hi = 1, #line_starts
+ while lo <= hi do
+ local mid = math.floor((lo + hi) / 2)
+ if line_starts[mid] > pos then
+ hi = mid - 1
+ else
+ lo = mid + 1
+ end
+ end
+ return hi
+ end
+ local lua_line = 1
+ local nomsu_line = pos_to_line(nomsu_line_to_pos, lua.source.start)
+ local fn
+ fn = function(s)
+ if type(s) == 'string' then
+ map[lua_line] = map[lua_line] or {
+ nomsu_line
+ }
+ for nl in s:gmatch("\n") do
+ lua_line = lua_line + 1
+ map[lua_line] = map[lua_line] or {
+ nomsu_line
+ }
+ end
+ else
+ local old_line = nomsu_line
+ if s.source then
+ nomsu_line = pos_to_line(nomsu_line_to_pos, s.source.start)
+ if nomsu_line ~= old_line then
+ insert(map[lua_line], nomsu_line)
+ end
+ end
+ local _list_0 = s.bits
+ for _index_0 = 1, #_list_0 do
+ local b = _list_0[_index_0]
+ fn(b)
+ end
+ end
+ end
+ fn(lua)
+ self.source_map[tostring(lua.source)] = map
+ end
return run_lua_fn()
end,
tree_to_lua = function(self, tree)
@@ -1185,6 +1266,7 @@ do
self.file_metadata = setmetatable({ }, {
__mode = "k"
})
+ self.source_map = { }
self.environment = {
nomsu = self,
repr = repr,
@@ -1407,6 +1489,27 @@ OPTIONS
break
end
end
+ do
+ local map = nomsu.source_map[info.source]
+ if map then
+ if info.currentline then
+ info.currentline = (map[info.currentline] or {
+ info.currentline
+ })[1]
+ end
+ if info.linedefined then
+ info.linedefined = (map[info.linedefined] or {
+ info.linedefined
+ })[1]
+ end
+ if info.lastlinedefined then
+ info.lastlinedefined = (map[info.lastlinedefined] or {
+ info.lastlinedefined
+ })[1]
+ end
+ info.short_src = info.source:match('"([^[]*)')
+ end
+ end
local _ = [=[ if metadata = nomsu.action_metadata[info.func]
info.name = metadata.aliases[1]
filename = if type(metadata.source) == 'string'
diff --git a/nomsu.moon b/nomsu.moon
index 883b702..36911bd 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -202,7 +202,7 @@ NOMSU_DEFS = with {}
setmetatable(NOMSU_DEFS, {__index:(key)=>
make_node = (start, value, stop, userdata)->
- source = userdata.source\sub(start, stop)
+ source = userdata.source\sub(start, stop-1)
tree = if Types[key].is_multi
Types[key](Tuple(unpack(value)), source)
else Types[key](value, source)
@@ -242,6 +242,7 @@ class NomsuCompiler
return id
})
@file_metadata = setmetatable({}, {__mode:"k"})
+ @source_map = {}
@environment = {
-- Discretionary/convenience stuff
@@ -324,6 +325,20 @@ class NomsuCompiler
define_compile_action: (signature, fn)=>
return @define_action(signature, fn, true)
+ lua_line_to_nomsu: (source, line_no)=>
+ pos = 0
+ line = 0
+ filename = source\match('"([^[]*)')
+ for line in FILE_CACHE[filename]\gmatch("[^\n]*\n")
+ line += 1
+ pos += #line
+ if line == line_no
+ break
+ for i, entry in ipairs @source_map[source]
+ if entry[1] > pos
+ return @source_map[source][i-1][2]
+ return @source_map[source][#@source_map[source]][2]
+
_nomsu_chunk_counter = 0
parse: (nomsu_code)=>
if type(nomsu_code) == 'string'
@@ -393,7 +408,7 @@ class NomsuCompiler
file = file or FILE_CACHE[filename]
if not file
error("File does not exist: #{filename}", 0)
- ret = @run(Nomsu(Source(filename), file), compile_fn)
+ ret = @run(Nomsu(Source(filename,1,#file), file), compile_fn)
else
error("Invalid filetype for #{filename}", 0)
loaded[filename] = ret or true
@@ -405,7 +420,7 @@ class NomsuCompiler
run_lua: (lua)=>
assert(type(lua) != 'string', "Attempt to run lua string instead of Lua (object)")
lua_string = tostring(lua)
- run_lua_fn, err = load(lua_string, filename, "t", @environment)
+ run_lua_fn, err = load(lua_string, tostring(lua.source), "t", @environment)
if not run_lua_fn
n = 1
fn = ->
@@ -413,6 +428,53 @@ 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)
+ unless @source_map[tostring(lua.source)]
+ map = {}
+ offset = 1
+ source = lua.source
+ nomsu_raw = FILE_CACHE[source.filename]\sub(source.start, source.stop)
+
+ get_line_starts = (s)->
+ starts = {}
+ pos = 1
+ for line in s\gmatch("[^\n]*\n")
+ insert starts, pos
+ pos += #line
+ insert starts, pos
+ return starts
+
+ nomsu_line_to_pos = get_line_starts(nomsu_raw)
+ lua_line_to_pos = get_line_starts(tostring(lua))
+
+ pos_to_line = (line_starts, pos)->
+ -- Binary search for line number of position
+ lo, hi = 1, #line_starts
+ while lo <= hi
+ mid = math.floor((lo+hi)/2)
+ if line_starts[mid] > pos
+ hi = mid-1
+ else lo = mid+1
+ return hi
+
+ lua_line = 1
+ nomsu_line = pos_to_line(nomsu_line_to_pos, lua.source.start)
+ fn = (s)->
+ if type(s) == 'string'
+ map[lua_line] or= {nomsu_line}
+ for nl in s\gmatch("\n")
+ lua_line += 1
+ map[lua_line] or= {nomsu_line}
+ else
+ old_line = nomsu_line
+ if s.source
+ nomsu_line = pos_to_line(nomsu_line_to_pos, s.source.start)
+ if nomsu_line != old_line
+ insert map[lua_line], nomsu_line
+ for b in *s.bits do fn(b)
+ fn(lua)
+ -- Mapping from lua line number to nomsu line numbers
+ @source_map[tostring(lua.source)] = map
+
return run_lua_fn!
MAX_LINE = 80 -- For beautification purposes, try not to make lines much longer than this value
@@ -993,6 +1055,15 @@ OPTIONS
if v == info.func
info.name = k
break
+
+ if map = nomsu.source_map[info.source]
+ if info.currentline
+ info.currentline = (map[info.currentline] or {info.currentline})[1]
+ if info.linedefined
+ info.linedefined = (map[info.linedefined] or {info.linedefined})[1]
+ if info.lastlinedefined
+ info.lastlinedefined = (map[info.lastlinedefined] or {info.lastlinedefined})[1]
+ info.short_src = info.source\match('"([^[]*)')
[=[
if metadata = nomsu.action_metadata[info.func]
info.name = metadata.aliases[1]