aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bitbucket@bruce-hill.com>2018-06-23 00:57:31 -0700
committerBruce Hill <bitbucket@bruce-hill.com>2018-06-23 00:57:39 -0700
commitdbf3de3d8efc0d150e1f439c4fc15fc09fea7d27 (patch)
tree01720f6812163ffe485e5358a222ab41ee2fedf4
parent11800f6fc2af204f62bb9add339259f520e70ea1 (diff)
Added versioning system.
-rw-r--r--Makefile45
-rw-r--r--README.md14
-rw-r--r--core/collections.nom11
-rw-r--r--core/metaprogramming.nom39
-rw-r--r--nomsu.lua43
-rwxr-xr-xnomsu.moon35
-rw-r--r--nomsu.peg1
-rw-r--r--nomsu_compiler.lua54
-rw-r--r--nomsu_compiler.moon40
-rw-r--r--parser.lua16
-rw-r--r--parser.moon12
11 files changed, 240 insertions, 70 deletions
diff --git a/Makefile b/Makefile
index 181efc0..a09d83e 100644
--- a/Makefile
+++ b/Makefile
@@ -20,46 +20,61 @@ CORE_LUA_FILES= $(patsubst %.nom,%.lua,$(CORE_NOM_FILES))
LIB_NOM_FILES= $(wildcard lib/*.nom)
LIB_LUA_FILES= $(patsubst %.nom,%.lua,$(LIB_NOM_FILES))
PEG_FILE= nomsu.peg
-
-NOMSU_HEADER=\#!$(LUA_BIN)\npackage.path = [[$(NOMSU_LIB_DIR)/?.lua;]]..package.path\npackage.nomsupath = [[$(NOMSU_LIB_DIR)]]
+GET_VERSION= $(LUA_BIN) nomsu.lua --version
all: build optimize
.PHONY: test
test: build optimize
- ./nomsu tests
+ ./nomsu_latest tests
%.lua: %.moon
@moonc $<
%.lua: %.nom
- @./nomsu -c $<
+ @./nomsu_latest -c $<
.PHONY: check_header
-check_header:
- @if [ "`head -n 3 nomsu 2>/dev/null`" != "`echo '$(NOMSU_HEADER)'`" ]; then rm -f nomsu core/*.lua lib/*.lua; fi
-
-nomsu: nomsu.lua
- @echo '$(NOMSU_HEADER)' | cat - nomsu.lua > nomsu
- @chmod +x nomsu
+check_header: version
+ @if [ -f nomsu_latest ]; then \
+ NOMSU_HEADER="#!$(LUA_BIN)\\npackage.path = [[$(NOMSU_LIB_DIR)/$$(cat version)/?.lua;]]..package.path\\npackage.nomsupath = [[$(NOMSU_LIB_DIR)/$$(cat version)]]"; \
+ if [ "`head -n 3 nomsu_latest 2>/dev/null`" != "`echo $$NOMSU_HEADER`" ]; then \
+ rm -f nomsu_latest; \
+ fi; \
+ fi;
+
+version: $(PEG_FILE) nomsu.lua $(CORE_NOM_FILES) $(LIB_NOM_FILES)
+ @$(LUA_BIN) nomsu.lua --version > version
+
+nomsu_latest: nomsu.lua
+ @rm -f nomsu_latest
+ @NOMSU_HEADER="#!$(LUA_BIN)\\npackage.path = [[$(NOMSU_LIB_DIR)/$$(cat version)/?.lua;]]..package.path\\npackage.nomsupath = [[$(NOMSU_LIB_DIR)/$$(cat version)]]"; \
+ echo $$NOMSU_HEADER | cat - nomsu.lua > nomsu_latest
+ @chmod +x nomsu_latest
+ @mv -f nomsu_latest nomsu`./nomsu_latest --version`
+ @ln -s nomsu`$(LUA_BIN) nomsu.lua --version` nomsu_latest
@echo "Built nomsu binary"
-build: $(LUA_FILES) check_header nomsu
+build: $(LUA_FILES) version check_header nomsu_latest
.PHONY: optimize
optimize: build $(CORE_LUA_FILES) $(LIB_LUA_FILES)
.PHONY: clean
clean:
- rm -rf nomsu core/*.lua lib/*.lua
+ @echo "Deleting..."
+ @rm -rvf nomsu`./nomsu_latest --version 2>/dev/null` nomsu_latest core/*.lua lib/*.lua
.PHONY: install
install: all
- mkdir -p $(NOMSU_BIN_DIR) && cp nomsu $(NOMSU_BIN_DIR)
- mkdir -p $(NOMSU_LIB_DIR) && cp -r $(LUA_FILES) $(PEG_FILE) core lib $(NOMSU_LIB_DIR)
+ mkdir -pv $(NOMSU_BIN_DIR) && cp -v nomsu nomsu`./nomsu_latest --version` $(NOMSU_BIN_DIR)
+ mkdir -pv $(NOMSU_LIB_DIR)/`./nomsu_latest --version` && cp -rv $(LUA_FILES) $(PEG_FILE) core lib $(NOMSU_LIB_DIR)/`./nomsu_latest --version`
.PHONY: uninstall
uninstall: all
- rm -rf $(NOMSU_LIB_DIR) $(NOMSU_BIN_DIR)/nomsu
+ @echo "Deleting..."
+ @rm -rvf $(NOMSU_LIB_DIR)/`$(GET_VERSION)` $(NOMSU_BIN_DIR)/nomsu`$(GET_VERSION)`
+ @if [ "`ls $(NOMSU_BIN_DIR)/nomsu*`" == "nomsu" ]; then rm -v $(NOMSU_BIN_DIR)/nomsu; fi
+ @if [ "`ls $(NOMSU_LIB_DIR) 2>/dev/null`" == "" ]; then rm -rvf $(NOMSU_LIB_DIR); fi
# eof
diff --git a/README.md b/README.md
index a100c1e..546e8ce 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,8 @@ If you enjoy Nomsu so much that you'd like to tinker with it or have it in your
All `.moon` files have been precompiled into corresponding `.lua` files, so you don't need to have [Moonscript](http://moonscript.org/) installed to run the Nomsu compiler.
-* `nomsu.moon` - The Nomsu command line runner. This handles launching the compiler and running the REPL.
+* `nomsu` - A shell script that selects between different installed versions of Nomsu (using the `-V` flag). You can use this script to, for example, run `nomsu -V 1.2 your_script.nom` to run with the latest version of Nomsu that matches `1.2.?.?`. All flags and arguments are passed along to whichever Nomsu compiler is chosen.
+* `nomsu.moon` - The source code for the Nomsu command line runner. This handles launching the compiler and running the REPL.
* `nomsu.peg` - The [Parsing Expression Grammar](https://en.wikipedia.org/wiki/Parsing_expression_grammar) used to define Nomsu's syntax. The format of this file is a slightly modified version of the format accepted by LPEG's `re` module.
* `nomsu_compiler.moon` - **The actual Nomsu compiler**. This file can be imported and used without going through the regular command line interface (e.g. for applications that want to embed the compiler).
* `parser.moon` - The Nomsu parser. This file can also be imported and used directly for applications that only need to *parse* Nomsu, not compile it.
@@ -41,6 +42,17 @@ All `.moon` files have been precompiled into corresponding `.lua` files, so you
* `LICENSE` - The software license (MIT).
* `README.md` - This file.
+## Versioning
+
+Nomsu uses the following versioning scheme: `[syntax version].[core library API version].[compiler internal API version].[lib/ API version]`. Which means:
+
+* Any code that parses on `Nomsu X.a.b.c.d` will also parse on Nomsu `X.p.w.r.s`
+* Any code that compiles on Nomsu `X.Y.a.b.c` will also compile on Nomsu `X.Y.p.q.r` and run without any differences, as long as it only depends on the behavior of the core library functions (i.e. stuff defined in `core/*.nom`), and doesn't mess with the compiler internals at all.
+* Any code that compiles on Nomsu `X.Y.Z.a.b` will also compile on Nomsu `X.Y.Z.p.q` and run without any differences, even if it messes with the compiler internals, as long as it doesn't use anything from `lib/*.nom`.
+* Any code that compiles on Nomsu `X.Y.Z.W` will also compile on any other Nomsu `X.Y.Z.W` and run without any differences, even if it uses stuff from `lib/*.nom`.
+
+When Nomsu is istalled via `make install`, all of Nomsu's lua files and `core/*.nom` and `lib/*.nom` files are stored in `$PREFIX/lib/nomsu/$NOMSU_VERSION` and the Nomsu executable is installed to `$PREFIX/bin/nomsu$NOMSU_VERSION`, along with the file `nomsu` (the version-selection script), which goes to `$PREFIX/bin/nomsu`. When `make uninstall` is run, all those files are deleted (except for `nomsu`, if there are other versions installed).
+
## Extra
There is a vim plugin for the language available in the [Vim Nomsu repository](https://bitbucket.org/squidarms/vim-nomsu/src). It is usually kept relatively up-to-date with Nomsu, but occasionally lags behind.
diff --git a/core/collections.nom b/core/collections.nom
index abd4a3a..0f53679 100644
--- a/core/collections.nom
+++ b/core/collections.nom
@@ -150,13 +150,14 @@ action [%items sorted, sorted %items]
%copy <- (% for % in %items)
sort %copy
return %copy
-action [..]
+parse [..]
%items sorted by %item = %key
%items sorted by %item -> %key
-..
- %copy <- (% for % in %items)
- sort %copy by %item = %key
- return %copy
+..as
+ result of
+ %copy <- (% for % in %items)
+ sort %copy by %item = %key
+ return %copy
action [unique %items]
%unique <- []
diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom
index 068513a..4e3e99a 100644
--- a/core/metaprogramming.nom
+++ b/core/metaprogramming.nom
@@ -2,6 +2,8 @@
This File contains actions for making actions and compile-time actions and some helper
functions to make that easier.
+lua> "NOMSU_CORE_VERSION = 1"
+
lua> ".."
nomsu.COMPILE_ACTIONS["% -> %"] = function(nomsu, tree, \%args, \%body)
local lua = LuaCode.Value(tree.source, "function(")
@@ -52,6 +54,13 @@ lua> ".."
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+compile [call %fn with %args] to
+ lua> ".."
+ local lua = LuaCode.Value(tree.source, nomsu:compile(\%fn), "(")
+ lua:concat_append(table.map(\%args, function(a) return nomsu:compile(a) end), ", ")
+ lua:append(")")
+ return lua
+
compile [using %defs compile %body] to
lua> ".."
local lua = LuaCode(tree.source)
@@ -124,8 +133,9 @@ compile [parse %actions as %body] to
local \%new_body = LuaCode(\%body.source,
"__MANGLE_INDEX = (__MANGLE_INDEX or 0) + 1",
"\nlocal tree = ", make_tree(\%body),
- "\nreturn nomsu:compile(tree)")
- return \(compile as: compile %actions to %new_body)
+ "\nlocal lua = nomsu:compile(tree); return lua")
+ local ret = \(compile as: compile %actions to %new_body)
+ return ret
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -171,6 +181,15 @@ compile [%tree with %t -> %replacement] to
\(%replacement as lua return)
end)
+compile [%tree with vars %v] to
+ Lua value ".."
+ \(%tree as lua expr):map(function(t)
+ local replacements = \(%v as lua expr)
+ if t.type == "Var" then
+ return replacements[t[1]]
+ end
+ end)
+
compile [declare locals in %code] to
Lua value "\(%code as lua expr):declare_locals()"
@@ -190,7 +209,7 @@ compile [quote %s] to
('"'..\(%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 ".."
@@ -201,11 +220,7 @@ compile [run %nomsu_code] to
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)
+ return nomsu:run(\%tree)
compile [compile %block, compiled %block, %block compiled] to
Lua value "nomsu:compile(\(%block as lua))"
@@ -219,4 +234,12 @@ compile [return %return_value] to: Lua "do return \(%return_value as lua expr);
compile [yes] to: Lua value "true"
compile [no] to: Lua value "false"
compile [nothing, nil, null] to: Lua value "nil"
+compile [Nomsu syntax version] to: Lua value "NOMSU_SYNTAX_VERSION"
+compile [Nomsu compiler version] to: Lua value "NOMSU_COMPILER_VERSION"
+compile [core version] to: Lua value "NOMSU_CORE_VERSION"
+compile [lib version] to: Lua value "NOMSU_LIB_VERSION"
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+action [Nomsu version]
+ use "lib/version.nom"
+ return "\(Nomsu syntax version).\(Nomsu compiler version).\(core version).\(lib version)"
diff --git a/nomsu.lua b/nomsu.lua
index 7239d44..44ad759 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -1,7 +1,7 @@
local EXIT_SUCCESS, EXIT_FAILURE = 0, 1
local usage = [=[Nomsu Compiler
-Usage: (lua nomsu.lua | moon nomsu.moon) [-i] [-O] [-v] [-c] [-f] [-s] [--help] [-p print_file] file1 file2... [-- nomsu args...]
+Usage: (lua nomsu.lua | moon nomsu.moon) [-V version] [-i] [-O] [-v] [-c] [-f] [-s] [--help] [--version] [-p print_file] file1 file2... [-- nomsu args...]
OPTIONS
-i Run the compiler in interactive mode (REPL)
@@ -11,6 +11,8 @@ OPTIONS
-f Auto-format the given Nomsu file and print the result.
-s Check the program for syntax errors.
-h/--help Print this message.
+ --version Print the version number and exit.
+ -V specify which Nomsu version is desired
-p <file> Print to the specified file instead of stdout.
<input> Input file can be "-" to use stdin.
]=]
@@ -29,6 +31,8 @@ do
local _obj_0 = require("code_obj")
NomsuCode, LuaCode, Source = _obj_0.NomsuCode, _obj_0.LuaCode, _obj_0.Source
end
+local repr
+repr = require("utils").repr
local STDIN, STDOUT, STDERR = "/dev/fd/0", "/dev/fd/1", "/dev/fd/2"
if not arg or debug.getinfo(2).func == require then
return NomsuCompiler
@@ -43,20 +47,26 @@ local parser = re.compile([[ args <- {| (flag ";")* {:inputs: {| ({file} ";")
/ {:compile: ("-c" -> true) :}
/ {:verbose: ("-v" -> true) :}
/ {:help: (("-h" / "--help") -> true) :}
+ / {:version: ("--version" -> true) :}
+ / {:requested_version: "-V" ((";")? {([0-9.])+})? :}
file <- "-" / [^;]+
]], {
["true"] = function()
return true
end
})
-local args = table.concat(arg, ";") .. ";"
-args = parser:match(args)
+local arg_string = table.concat(arg, ";") .. ";"
+local args = parser:match(arg_string)
if not args or args.help then
print(usage)
os.exit(EXIT_FAILURE)
end
local nomsu = NomsuCompiler
nomsu.arg = args.nomsu_args
+if args.version then
+ nomsu:run('use "core"\nsay (Nomsu version)')
+ os.exit(EXIT_SUCCESS)
+end
FILE_CACHE = setmetatable({ }, {
__index = function(self, filename)
local file = io.open(filename)
@@ -194,7 +204,15 @@ run = function()
to_run[f] = true
end
end
- nomsu.skip_precompiled = to_run
+ nomsu.can_optimize = function(f)
+ if not (args.optimized) then
+ return false
+ end
+ if to_run[f] then
+ return false
+ end
+ return true
+ end
if args.compile or args.verbose then
nomsu.on_compile = function(code, from_file)
if not (to_run[from_file]) then
@@ -253,11 +271,25 @@ run = function()
os.exit(EXIT_SUCCESS)
end
if args.interactive then
+ nomsu:run('say "\\n\\(bright)\\(underscore)Welcome to the Nomsu v\\(Nomsu version) interactive console!\\(reset color)\\n press \'enter\' twice to run a command\\n"')
+ local ready_to_quit = false
+ nomsu.A_quit = function()
+ ready_to_quit = true
+ return print("Goodbye!")
+ end
+ nomsu.A_exit = nomsu.A_quit
+ nomsu.A_help = function()
+ print("This is the Nomsu v" .. tostring(nomsu.A_Nomsu_version()) .. " interactive console.")
+ print("You can type in Nomsu code here and hit 'enter' twice to run it.")
+ return print("To exit, type 'exit' or 'quit' and hit enter twice")
+ end
for repl_line = 1, math.huge do
io.write(colored.bright(colored.yellow(">> ")))
local buff = { }
while true do
+ io.write(colors.bright)
local line = io.read("*L")
+ io.write(colors.reset)
if line == "\n" or not line then
if #buff > 0 then
io.write("\027[1A\027[2K")
@@ -285,6 +317,9 @@ run = function()
elseif not ok then
Errhand.print_error(ret)
end
+ if ready_to_quit then
+ break
+ end
end
end
end
diff --git a/nomsu.moon b/nomsu.moon
index 780e8bc..14f8992 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -4,7 +4,7 @@ EXIT_SUCCESS, EXIT_FAILURE = 0, 1
usage = [=[
Nomsu Compiler
-Usage: (lua nomsu.lua | moon nomsu.moon) [-i] [-O] [-v] [-c] [-f] [-s] [--help] [-p print_file] file1 file2... [-- nomsu args...]
+Usage: (lua nomsu.lua | moon nomsu.moon) [-V version] [-i] [-O] [-v] [-c] [-f] [-s] [--help] [--version] [-p print_file] file1 file2... [-- nomsu args...]
OPTIONS
-i Run the compiler in interactive mode (REPL)
@@ -14,6 +14,8 @@ OPTIONS
-f Auto-format the given Nomsu file and print the result.
-s Check the program for syntax errors.
-h/--help Print this message.
+ --version Print the version number and exit.
+ -V specify which Nomsu version is desired
-p <file> Print to the specified file instead of stdout.
<input> Input file can be "-" to use stdin.
]=]
@@ -28,6 +30,7 @@ if not ok
Errhand = require "error_handling"
NomsuCompiler = require "nomsu_compiler"
{:NomsuCode, :LuaCode, :Source} = require "code_obj"
+{:repr} = require "utils"
STDIN, STDOUT, STDERR = "/dev/fd/0", "/dev/fd/1", "/dev/fd/2"
-- If this file was reached via require(), then just return the Nomsu compiler
@@ -45,10 +48,12 @@ parser = re.compile([[
/ {:compile: ("-c" -> true) :}
/ {:verbose: ("-v" -> true) :}
/ {:help: (("-h" / "--help") -> true) :}
+ / {:version: ("--version" -> true) :}
+ / {:requested_version: "-V" ((";")? {([0-9.])+})? :}
file <- "-" / [^;]+
]], {true: -> true})
-args = table.concat(arg, ";")..";"
-args = parser\match(args)
+arg_string = table.concat(arg, ";")..";"
+args = parser\match(arg_string)
if not args or args.help
print usage
os.exit(EXIT_FAILURE)
@@ -56,6 +61,10 @@ if not args or args.help
nomsu = NomsuCompiler
nomsu.arg = args.nomsu_args
+if args.version
+ nomsu\run 'use "core"\nsay (Nomsu version)'
+ os.exit(EXIT_SUCCESS)
+
export FILE_CACHE
-- FILE_CACHE is a map from filename (string) -> string of file contents
FILE_CACHE = setmetatable {}, {
@@ -154,7 +163,10 @@ run = ->
input_files[#input_files+1] = f
to_run[f] = true
- nomsu.skip_precompiled = to_run
+ nomsu.can_optimize = (f)->
+ return false unless args.optimized
+ return false if to_run[f]
+ return true
if args.compile or args.verbose
nomsu.on_compile = (code, from_file)->
@@ -206,11 +218,24 @@ run = ->
if args.interactive
-- REPL
+ nomsu\run 'say "\\n\\(bright)\\(underscore)Welcome to the Nomsu v\\(Nomsu version) interactive console!\\(reset color)\\n press \'enter\' twice to run a command\\n"'
+ ready_to_quit = false
+ nomsu.A_quit = ->
+ export ready_to_quit
+ ready_to_quit = true
+ print("Goodbye!")
+ nomsu.A_exit = nomsu.A_quit
+ nomsu.A_help = ->
+ print("This is the Nomsu v#{nomsu.A_Nomsu_version()} interactive console.")
+ print("You can type in Nomsu code here and hit 'enter' twice to run it.")
+ print("To exit, type 'exit' or 'quit' and hit enter twice")
for repl_line=1,math.huge
io.write(colored.bright colored.yellow ">> ")
buff = {}
while true
+ io.write(colors.bright)
line = io.read("*L")
+ io.write(colors.reset)
if line == "\n" or not line
if #buff > 0
io.write("\027[1A\027[2K")
@@ -231,6 +256,8 @@ run = ->
print "= "..repr(ret)
elseif not ok
Errhand.print_error ret
+ if ready_to_quit
+ break
has_ldt, ldt = pcall(require,'ldt')
if has_ldt
diff --git a/nomsu.peg b/nomsu.peg
index a137675..15d0444 100644
--- a/nomsu.peg
+++ b/nomsu.peg
@@ -1,3 +1,4 @@
+-- Nomsu version 1
file:
(ignored_line %nl)*
(file_chunks / block / action / expression)?
diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua
index 0e3a27c..c94685a 100644
--- a/nomsu_compiler.lua
+++ b/nomsu_compiler.lua
@@ -29,7 +29,7 @@ do
NomsuCode, LuaCode, Source = _obj_0.NomsuCode, _obj_0.LuaCode, _obj_0.Source
end
local AST = require("nomsu_tree")
-local parse = require("parser")
+local Parser = require("parser")
SOURCE_MAP = { }
string.as_lua_id = function(str)
local argnum = 0
@@ -169,6 +169,28 @@ local _list_mt = {
end
return _accum_0
end)(), ", ") .. "]"
+ end,
+ __lt = function(self, other)
+ assert(type(self) == 'table' and type(other) == 'table', "Incompatible types for comparison")
+ for i = 1, math.max(#self, #other) do
+ if self[i] < other[i] then
+ return true
+ elseif self[i] > other[i] then
+ return false
+ end
+ end
+ return false
+ end,
+ __le = function(self, other)
+ assert(type(self) == 'table' and type(other) == 'table', "Incompatible types for comparison")
+ for i = 1, math.max(#self, #other) do
+ if self[i] < other[i] then
+ return true
+ elseif self[i] > other[i] then
+ return false
+ end
+ end
+ return true
end
}
local list
@@ -207,10 +229,15 @@ local NomsuCompiler = setmetatable({ }, {
end
})
do
+ NomsuCompiler.NOMSU_COMPILER_VERSION = 1
+ NomsuCompiler.NOMSU_SYNTAX_VERSION = Parser.version
NomsuCompiler._ENV = NomsuCompiler
NomsuCompiler.nomsu = NomsuCompiler
NomsuCompiler.parse = function(self, ...)
- return parse(...)
+ return Parser.parse(...)
+ end
+ NomsuCompiler.can_optimize = function()
+ return false
end
local to_add = {
repr = repr,
@@ -218,6 +245,7 @@ do
utils = utils,
lpeg = lpeg,
re = re,
+ all_files = all_files,
next = next,
unpack = unpack,
setmetatable = setmetatable,
@@ -393,11 +421,15 @@ do
if source == nil then
source = nil
end
+ source = source or (to_run.source or Source(to_run, 1, #to_run))
+ if not rawget(FILE_CACHE, source.filename) then
+ FILE_CACHE[source.filename] = to_run
+ end
local tree
if AST.is_syntax_tree(to_run) then
- tree = tree
+ tree = to_run
else
- tree = self:parse(to_run, source or to_run.source)
+ tree = self:parse(to_run, source)
end
if tree == nil then
return nil
@@ -407,22 +439,22 @@ do
local all_lua = { }
for _index_0 = 1, #tree do
local chunk = tree[_index_0]
- local lua = self:compile(chunk):as_statements()
+ local lua = self:compile(chunk):as_statements("return ")
lua:declare_locals()
- lua:prepend("-- File: " .. tostring(chunk.source or "") .. "\n")
+ lua:prepend("-- File: " .. tostring(source.filename:gsub("\n.*", "...")) .. "\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)
+ self.on_compile(concat(all_lua, "\n"), source.filename)
end
return ret
else
- local lua = self:compile(tree, compile_actions):as_statements()
+ local lua = self:compile(tree, compile_actions):as_statements("return ")
lua:declare_locals()
- lua:prepend("-- File: " .. tostring(source or to_run.source or "") .. "\n")
+ lua:prepend("-- File: " .. tostring(source.filename:gsub("\n.*", "...")) .. "\n")
if self.on_compile then
- self.on_compile(lua, (source or to_run.source).filename)
+ self.on_compile(lua, source.filename)
end
return self:run_lua(lua)
end
@@ -465,7 +497,7 @@ do
ret = self:run_lua(file, Source(filename, 1, #file))
elseif match(filename, "%.nom$") or match(filename, "^/dev/fd/[012]$") then
local ran_lua
- if not self.skip_precompiled or not self.skip_precompiled[filename] then
+ if self.can_optimize(filename) then
local lua_filename = gsub(filename, "%.nom$", ".lua")
do
local file = FILE_CACHE[lua_filename]
diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon
index d214380..56ef86e 100644
--- a/nomsu_compiler.moon
+++ b/nomsu_compiler.moon
@@ -22,7 +22,7 @@ unpack or= table.unpack
{:match, :sub, :rep, :gsub, :format, :byte, :match, :find} = string
{:NomsuCode, :LuaCode, :Source} = require "code_obj"
AST = require "nomsu_tree"
-parse = require("parser")
+Parser = require("parser")
-- Mapping from source string (e.g. "@core/metaprogramming.nom[1:100]") to a mapping
-- from lua line number to nomsu line number
export SOURCE_MAP
@@ -134,6 +134,19 @@ _list_mt =
-- Could consider adding a __newindex to enforce list-ness, but would hurt performance
__tostring: =>
"["..concat([repr(b) for b in *@], ", ").."]"
+ __lt: (other)=>
+ assert type(@) == 'table' and type(other) == 'table', "Incompatible types for comparison"
+ for i=1,math.max(#@, #other)
+ if @[i] < other[i] then return true
+ elseif @[i] > other[i] then return false
+ return false
+ __le: (other)=>
+ assert type(@) == 'table' and type(other) == 'table', "Incompatible types for comparison"
+ for i=1,math.max(#@, #other)
+ if @[i] < other[i] then return true
+ elseif @[i] > other[i] then return false
+ return true
+
list = (t)-> setmetatable(t, _list_mt)
_dict_mt =
@@ -145,13 +158,16 @@ 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
+ .NOMSU_COMPILER_VERSION = 1
+ .NOMSU_SYNTAX_VERSION = Parser.version
._ENV = NomsuCompiler
.nomsu = NomsuCompiler
- .parse = (...)=> parse(...)
+ .parse = (...)=> Parser.parse(...)
+ .can_optimize = -> false
-- Discretionary/convenience stuff
to_add = {
- repr:repr, stringify:stringify, utils:utils, lpeg:lpeg, re:re,
+ repr:repr, stringify:stringify, utils:utils, lpeg:lpeg, re:re, all_files:all_files,
-- Lua stuff:
:next, :unpack, :setmetatable, :coroutine, :rawequal, :getmetatable, :pcall,
:error, :package, :os, :require, :tonumber, :tostring, :string, :xpcall, :module,
@@ -272,7 +288,9 @@ with NomsuCompiler
}
.run = (to_run, source=nil)=>
- tree = if AST.is_syntax_tree(to_run) then tree else @parse(to_run, source or to_run.source)
+ source or= to_run.source or Source(to_run, 1, #to_run)
+ if not rawget(FILE_CACHE,source.filename) then FILE_CACHE[source.filename] = to_run
+ tree = if AST.is_syntax_tree(to_run) then to_run else @parse(to_run, source)
if tree == nil -- Happens if pattern matches, but there are no captures, e.g. an empty string
return nil
if tree.type == "FileChunks"
@@ -282,20 +300,20 @@ with NomsuCompiler
ret = nil
all_lua = {}
for chunk in *tree
- lua = @compile(chunk)\as_statements!
+ lua = @compile(chunk)\as_statements("return ")
lua\declare_locals!
- lua\prepend "-- File: #{chunk.source or ""}\n"
+ lua\prepend "-- File: #{source.filename\gsub("\n.*", "...")}\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)
+ self.on_compile(concat(all_lua, "\n"), source.filename)
return ret
else
- lua = @compile(tree, compile_actions)\as_statements!
+ lua = @compile(tree, compile_actions)\as_statements("return ")
lua\declare_locals!
- lua\prepend "-- File: #{source or to_run.source or ""}\n"
+ lua\prepend "-- File: #{source.filename\gsub("\n.*", "...")}\n"
if @on_compile
- self.on_compile(lua, (source or to_run.source).filename)
+ self.on_compile(lua, source.filename)
return @run_lua(lua)
_running_files = {} -- For detecting circular imports
@@ -319,7 +337,7 @@ with NomsuCompiler
file = assert(FILE_CACHE[filename], "Could not find file: #{filename}")
ret = @run_lua file, Source(filename, 1, #file)
elseif match(filename, "%.nom$") or match(filename, "^/dev/fd/[012]$")
- ran_lua = if not @skip_precompiled or not @skip_precompiled[filename] -- Look for precompiled version
+ ran_lua = if @.can_optimize(filename) -- Look for precompiled version
lua_filename = gsub(filename, "%.nom$", ".lua")
if file = FILE_CACHE[lua_filename]
ret = @run_lua file, Source(lua_filename, 1, #file)
diff --git a/parser.lua b/parser.lua
index 7b734c3..c04e95c 100644
--- a/parser.lua
+++ b/parser.lua
@@ -72,7 +72,6 @@ do
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)
@@ -116,9 +115,11 @@ setmetatable(NOMSU_DEFS, {
return make_node
end
})
+local Parser = { }
local NOMSU_PATTERN
do
- local peg_tidier = re.compile([[ file <- {~ %nl* (def/comment) (%nl+ (def/comment))* %nl* ~}
+ local peg_tidier = re.compile([[ file <- %nl* version? %nl* {~ (def/comment) (%nl+ (def/comment))* %nl* ~}
+ version <- "--" (!"version" [^%nl])* "version" ([ ])* (([0-9])+ -> set_version) ([^%nl])*
def <- anon_def / captured_def
anon_def <- ({ident} (" "*) ":"
{((%nl " "+ [^%nl]*)+) / ([^%nl]*)}) -> "%1 <- %2"
@@ -126,15 +127,18 @@ do
{((%nl " "+ [^%nl]*)+) / ([^%nl]*)}) -> "%1 <- (({} %3 {} %%userdata) -> %2)"
ident <- [a-zA-Z_][a-zA-Z0-9_]*
comment <- "--" [^%nl]*
- ]])
+ ]], {
+ set_version = function(v)
+ Parser.version = tonumber(v)
+ end
+ })
local peg_file = io.open("nomsu.peg") or (package.nomsupath and io.open(package.nomsupath .. "/nomsu.peg"))
assert(peg_file, "could not find nomsu.peg file")
local nomsu_peg = peg_tidier:match(peg_file:read('*a'))
peg_file:close()
NOMSU_PATTERN = re.compile(nomsu_peg, NOMSU_DEFS)
end
-local parse
-parse = function(nomsu_code, source)
+Parser.parse = function(nomsu_code, source)
if source == nil then
source = nil
end
@@ -169,4 +173,4 @@ parse = function(nomsu_code, source)
end
return tree
end
-return parse
+return Parser
diff --git a/parser.moon b/parser.moon
index 1d62364..a61b3c1 100644
--- a/parser.moon
+++ b/parser.moon
@@ -56,7 +56,7 @@ NOMSU_DEFS = with {}
return #src+1
err_pos = start_pos
line_no = pos_to_line(src, err_pos)
- src = FILE_CACHE[userdata.source.filename]
+ --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)
@@ -85,11 +85,13 @@ setmetatable(NOMSU_DEFS, {__index:(key)=>
return make_node
})
+Parser = {}
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* ~}
+ file <- %nl* version? %nl* {~ (def/comment) (%nl+ (def/comment))* %nl* ~}
+ version <- "--" (!"version" [^%nl])* "version" ([ ])* (([0-9])+ -> set_version) ([^%nl])*
def <- anon_def / captured_def
anon_def <- ({ident} (" "*) ":"
{((%nl " "+ [^%nl]*)+) / ([^%nl]*)}) -> "%1 <- %2"
@@ -97,14 +99,14 @@ NOMSU_PATTERN = do
{((%nl " "+ [^%nl]*)+) / ([^%nl]*)}) -> "%1 <- (({} %3 {} %%userdata) -> %2)"
ident <- [a-zA-Z_][a-zA-Z0-9_]*
comment <- "--" [^%nl]*
- ]]
+ ]], {set_version: (v) -> Parser.version = tonumber(v)}
peg_file = io.open("nomsu.peg") or (package.nomsupath and io.open(package.nomsupath.."/nomsu.peg"))
assert(peg_file, "could not find nomsu.peg file")
nomsu_peg = peg_tidier\match(peg_file\read('*a'))
peg_file\close!
re.compile(nomsu_peg, NOMSU_DEFS)
-parse = (nomsu_code, source=nil)->
+Parser.parse = (nomsu_code, source=nil)->
nomsu_code = tostring(nomsu_code)
userdata = {
indent: "", errors: {}, :source
@@ -123,4 +125,4 @@ parse = (nomsu_code, source=nil)->
return tree
-return parse
+return Parser