From 83183122f180ce0fdbf3b5c1c8ff828d762348a8 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Mon, 4 Jun 2018 20:41:20 -0700 Subject: [PATCH] Optimizations and cleanup. Build script now fails on first error and uses the precompiled versions it has just compiled. --- code_obj.lua | 48 ------------------------- code_obj.moon | 34 ------------------ compile_lib.sh | 6 ++-- core/collections.nom | 2 -- core/metaprogramming.nom | 1 - core/operators.nom | 1 - nomsu.lua | 75 +++++++++++++++++++++------------------- nomsu.moon | 61 ++++++++++++++++---------------- 8 files changed, 72 insertions(+), 156 deletions(-) diff --git a/code_obj.lua b/code_obj.lua index dcdd95a..fa36234 100644 --- a/code_obj.lua +++ b/code_obj.lua @@ -11,16 +11,6 @@ Source = immutable({ "stop" }, { name = "Source", - __new = function(self, filename, start, stop) - assert(type(filename) == 'string') - if not start then - start, stop = 1, #FILE_CACHE[filename] - end - if stop and start > stop + 1 then - error("Invalid range: " .. tostring(start) .. ", " .. tostring(stop)) - end - return filename, start, stop - end, from_string = function(self, str) local filename, start, stop = str:match("^@(.-)%[(%d+):(%d+)%]$") if not (filename) then @@ -60,44 +50,6 @@ Source = immutable({ end end return Source(self.filename, self.start + offset, self.stop) - end, - sub = function(self, start, stop) - start = start or 1 - assert(start > 0 and (stop == nil or stop > 0), "Negative subscripts not supported") - if not self.stop then - assert(not stop, "cannot subscript non-range with range") - return Source(self.filename, self.start + start - 1) - else - stop = stop or self.stop - 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, - get_line_number = function(self) - local src = FILE_CACHE[self.filename] - local line_starts = LINE_STARTS[src] - local start_line = 1 - while (line_starts[start_line + 1] or math.huge) <= self.start do - start_line = start_line + 1 - end - local stop_line = start_line - while (line_starts[stop_line + 1] or math.huge) <= self.stop do - stop_line = stop_line + 1 - end - return start_line, stop_line - end, - get_line = function(self) - return tostring(self.filename) .. ":" .. tostring(self:get_line_number()) - end, - get_line_range = function(self) - local start_line, stop_line = self:get_line_number() - if stop_line == start_line then - return tostring(self.filename) .. ":" .. tostring(start_line) - else - return tostring(self.filename) .. ":" .. tostring(start_line) .. "-" .. tostring(stop_line) - end end }) local Code diff --git a/code_obj.moon b/code_obj.moon index 8dfc0a1..5fe6c98 100644 --- a/code_obj.moon +++ b/code_obj.moon @@ -5,12 +5,6 @@ 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}") - return filename, start, stop from_string: (str)=> filename,start,stop = str\match("^@(.-)%[(%d+):(%d+)%]$") unless filename @@ -36,34 +30,6 @@ Source = immutable {"filename","start","stop"}, { offset, self = self, offset else if type(offset) != 'number' then error("Cannot add Source and #{type(offset)}") return Source(@filename, @start+offset, @stop) - sub: (start, stop)=> - start or= 1 - assert(start > 0 and (stop == nil or stop > 0), "Negative subscripts not supported") - if not @stop - assert(not stop, "cannot subscript non-range with range") - return Source(@filename, @start + start - 1) - else - stop or= @stop - 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] - line_starts = LINE_STARTS[src] - start_line = 1 - while (line_starts[start_line+1] or math.huge) <= @start - start_line += 1 - stop_line = start_line - while (line_starts[stop_line+1] or math.huge) <= @stop - stop_line += 1 - return start_line, stop_line - get_line: => "#{@filename}:#{@get_line_number!}" - get_line_range: => - start_line, stop_line = @get_line_number! - return if stop_line == start_line - "#{@filename}:#{start_line}" - else "#{@filename}:#{start_line}-#{stop_line}" } class Code diff --git a/compile_lib.sh b/compile_lib.sh index 9bf0487..fa932b3 100755 --- a/compile_lib.sh +++ b/compile_lib.sh @@ -1,14 +1,16 @@ #!/bin/sh # This file is a script that converts the .nom files in lib/ into slightly more optimized # precompiled versions that are only lua> ".." and =lua ".." bits which are faster to load. +set -e moonc *.moon +rm -f core/*.lua lib/*.lua for file in core/*.nom; do printf "Compiling $file ..." - ./nomsu.moon -o "core/$(basename $file .nom).lua" $file + lua ./nomsu.lua -O -o "core/$(basename $file .nom).lua" $file echo "done." done for file in lib/*.nom; do printf "Compiling $file ..." - ./nomsu.moon -o "lib/$(basename $file .nom).lua" $file + lua ./nomsu.lua -O -o "lib/$(basename $file .nom).lua" $file echo "done." done diff --git a/core/collections.nom b/core/collections.nom index 8e7576d..0bf5cef 100644 --- a/core/collections.nom +++ b/core/collections.nom @@ -172,5 +172,3 @@ immediately (% in %seen) <- (yes) return %unique - -# TODO: maybe make a generator/coroutine? diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom index 66af1e6..c54a72f 100644 --- a/core/metaprogramming.nom +++ b/core/metaprogramming.nom @@ -211,7 +211,6 @@ immediately error(\(repr %assumption), 0); end - # TODO: factor this out and replace with "unless %condition: barf %message" compile [assume %condition or barf %message] to Lua ".." if not \(%condition as lua expr) then diff --git a/core/operators.nom b/core/operators.nom index 5222a69..dd57cea 100644 --- a/core/operators.nom +++ b/core/operators.nom @@ -22,7 +22,6 @@ 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))" - # TODO: optimize case of [%x,%y] = [1,2] compile [%a is %b, %a = %b, %a == %b] to lua> ".." local safe = {Text=true, Number=true} diff --git a/nomsu.lua b/nomsu.lua index 8121a18..54a6cd8 100644 --- a/nomsu.lua +++ b/nomsu.lua @@ -132,6 +132,20 @@ LINE_STARTS = setmetatable({ }, { return line_starts end }) +local pos_to_line +pos_to_line = function(str, pos) + local line_starts = LINE_STARTS[str] + 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 do local STRING_METATABLE = getmetatable("") STRING_METATABLE.__add = function(self, other) @@ -204,13 +218,13 @@ do return #src + 1 end local err_pos = start_pos - local text_loc = userdata.source:sub(err_pos, err_pos) - local line_no = text_loc:get_line_number() - src = FILE_CACHE[text_loc.filename] - local prev_line = line_no == 1 and "" or src:sub(LINE_STARTS[src][line_no - 1] or 1, LINE_STARTS[src][line_no] - 2) - local err_line = src:sub(LINE_STARTS[src][line_no], (LINE_STARTS[src][line_no + 1] or 0) - 2) - local next_line = src:sub(LINE_STARTS[src][line_no + 1] or -1, (LINE_STARTS[src][line_no + 2] or 0) - 2) - local i = err_pos - LINE_STARTS[src][line_no] + 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 @@ -230,7 +244,11 @@ setmetatable(NOMSU_DEFS, { __index = function(self, key) local make_node make_node = function(start, value, stop, userdata) - local source = userdata.source:sub(start, stop - 1) + local source + do + local _with_0 = userdata.source + source = Source(_with_0.filename, _with_0.start + start - 1, _with_0.start + stop - 1) + end local tree if Types[key].is_multi then tree = Types[key](source, unpack(value)) @@ -391,13 +409,13 @@ do insert(_running_files, filename) if filename:match("%.lua$") then local file = assert(FILE_CACHE[filename], "Could not find file: " .. tostring(filename)) - ret = self:run_lua(Lua(Source(filename), file)) + ret = self:run_lua(Lua(Source(filename, 1, #file), file)) elseif filename:match("%.nom$") or filename:match("^/dev/fd/[012]$") then if not self.skip_precompiled then local lua_filename = filename:gsub("%.nom$", ".lua") local file = FILE_CACHE[lua_filename] if file then - ret = self:run_lua(Lua(Source(filename), file)) + ret = self:run_lua(Lua(Source(filename, 1, #file), file)) remove(_running_files) _continue_0 = true break @@ -441,24 +459,9 @@ do local map = { } local offset = 1 local source = lua.source - local nomsu_raw = FILE_CACHE[source.filename]:sub(source.start, source.stop) - local nomsu_line_to_pos = LINE_STARTS[nomsu_raw] - local lua_line_to_pos = 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 nomsu_str = tostring(FILE_CACHE[source.filename]:sub(source.start, source.stop)) local lua_line = 1 - local nomsu_line = pos_to_line(nomsu_line_to_pos, lua.source.start) + local nomsu_line = pos_to_line(nomsu_str, lua.source.start) local fn fn = function(s) if type(s) == 'string' then @@ -469,7 +472,7 @@ do else local old_line = nomsu_line if s.source then - nomsu_line = pos_to_line(nomsu_line_to_pos, s.source.start) + nomsu_line = pos_to_line(nomsu_str, s.source.start) end local _list_0 = s.bits for _index_0 = 1, #_list_0 do @@ -1598,18 +1601,12 @@ OPTIONS } args.interactive = true end - local output_file - if args.output_file == "-" then - output_file = io.stdout - elseif args.output_file then - output_file = io.open(args.output_file, 'w') - end local print_file if args.print_file == "-" then print_file = io.stdout elseif args.print_file then print_file = io.open(args.print_file, 'w') - elseif output_file == io.stdout then + elseif args.output_file == '-' then print_file = nil else print_file = io.stdout @@ -1631,8 +1628,14 @@ OPTIONS end end local compile_fn - if output_file then + if args.output_file then compile_fn = function(code) + local output_file + if args.output_file == "-" then + output_file = io.stdout + elseif args.output_file then + output_file = io.open(args.output_file, 'w') + end output_file:write("local IMMEDIATE = true;\n" .. tostring(code)) return output_file:flush() end diff --git a/nomsu.moon b/nomsu.moon index c2e2ca9..15028cc 100755 --- a/nomsu.moon +++ b/nomsu.moon @@ -111,6 +111,16 @@ LINE_STARTS = setmetatable {}, { self[k] = line_starts return line_starts } +pos_to_line = (str, pos)-> + line_starts = LINE_STARTS[str] + -- 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 -- Use + operator for string coercive concatenation (note: "asdf" + 3 == "asdf3") -- Use [] for accessing string characters, or s[{3,4}] for s:sub(3,4) @@ -173,13 +183,13 @@ NOMSU_DEFS = with {} err_pos = start_pos --if src\sub(err_pos,err_pos)\match("[\r\n]") -- err_pos += #src\match("[ \t\n\r]*", err_pos) - text_loc = userdata.source\sub(err_pos,err_pos) - line_no = text_loc\get_line_number! - src = FILE_CACHE[text_loc.filename] - prev_line = line_no == 1 and "" or src\sub(LINE_STARTS[src][line_no-1] or 1, LINE_STARTS[src][line_no]-2) - err_line = src\sub(LINE_STARTS[src][line_no], (LINE_STARTS[src][line_no+1] or 0)-2) - next_line = src\sub(LINE_STARTS[src][line_no+1] or -1, (LINE_STARTS[src][line_no+2] or 0)-2) - i = err_pos-LINE_STARTS[src][line_no] + 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) @@ -192,7 +202,9 @@ NOMSU_DEFS = with {} setmetatable(NOMSU_DEFS, {__index:(key)=> make_node = (start, value, stop, userdata)-> - source = userdata.source\sub(start, stop-1) + local source + with userdata.source + source = Source(.filename, .start + start-1, .start + stop-1) tree = if Types[key].is_multi Types[key](source, unpack(value)) else Types[key](source, value) @@ -366,13 +378,13 @@ class NomsuCompiler insert _running_files, filename if filename\match("%.lua$") file = assert(FILE_CACHE[filename], "Could not find file: #{filename}") - ret = @run_lua(Lua(Source(filename), file)) + ret = @run_lua(Lua(Source(filename, 1, #file), file)) elseif filename\match("%.nom$") or filename\match("^/dev/fd/[012]$") if not @skip_precompiled -- Look for precompiled version lua_filename = filename\gsub("%.nom$", ".lua") file = FILE_CACHE[lua_filename] if file - ret = @run_lua(Lua(Source(filename), file)) + ret = @run_lua(Lua(Source(filename, 1, #file), file)) remove _running_files continue file = file or FILE_CACHE[filename] @@ -403,23 +415,9 @@ class NomsuCompiler map = {} offset = 1 source = lua.source - nomsu_raw = FILE_CACHE[source.filename]\sub(source.start, source.stop) - - nomsu_line_to_pos = LINE_STARTS[nomsu_raw] - lua_line_to_pos = 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 - + nomsu_str = tostring(FILE_CACHE[source.filename]\sub(source.start, source.stop)) lua_line = 1 - nomsu_line = pos_to_line(nomsu_line_to_pos, lua.source.start) + nomsu_line = pos_to_line(nomsu_str, lua.source.start) fn = (s)-> if type(s) == 'string' for nl in s\gmatch("\n") @@ -428,7 +426,7 @@ class NomsuCompiler else old_line = nomsu_line if s.source - nomsu_line = pos_to_line(nomsu_line_to_pos, s.source.start) + nomsu_line = pos_to_line(nomsu_str, s.source.start) for b in *s.bits do fn(b) fn(lua) map[lua_line] or= nomsu_line @@ -1113,12 +1111,9 @@ OPTIONS args.inputs = {"core"} args.interactive = true - output_file = if args.output_file == "-" then io.stdout - elseif args.output_file then io.open(args.output_file, 'w') - print_file = if args.print_file == "-" then io.stdout elseif args.print_file then io.open(args.print_file, 'w') - elseif output_file == io.stdout then nil + elseif args.output_file == '-' then nil else io.stdout nomsu.skip_precompiled = not args.optimized @@ -1134,8 +1129,10 @@ OPTIONS print_file\write('\n') print_file\flush! - compile_fn = if output_file + compile_fn = if args.output_file (code)-> + output_file = if args.output_file == "-" then io.stdout + elseif args.output_file then io.open(args.output_file, 'w') output_file\write("local IMMEDIATE = true;\n"..tostring(code)) output_file\flush! else nil