Initial working version.

This commit is contained in:
Bruce Hill 2018-09-15 20:20:40 -07:00
parent f8cfdd0f22
commit 2282085e13
8 changed files with 117 additions and 96 deletions

View File

@ -205,14 +205,8 @@ compile [parse %actions as %body] to (..)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
action [%tree as lua expr]:
lua> "\
..\%tree_lua = nomsu:compile(\%tree)
if not \%tree_lua.is_value then
nomsu:compile_error(\%tree.source, "Could not convert %s to a Lua expression",
nomsu:tree_to_nomsu(\%tree))
end
return \%tree_lua"
# TODO: add check for .is_value
compile [%tree as lua expr] to (Lua value "nomsu:compile(\(=lua "nomsu:compile(\%tree)"))")
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -343,18 +337,17 @@ compile [parse %text from %filename] to (..)
test:
assume ((run "return (2 + 99)") == 101)
external %passed = (no)
run \:
\(external \%passed = \(yes))
run "external %passed = (yes)"
assume %passed
compile [run %nomsu_code] to (..)
Lua value "\
..nomsu:run(\(%nomsu_code as lua expr), \(..)
..nomsu:run(NomsuCode(\(..)
=lua "repr(tostring(\(%nomsu_code.source)))"
..)"
.., \(%nomsu_code as lua expr)))"
test:
assume ((\(\(5) + \(5)) as value) == 10) or barf "%tree as value failed."
action [run tree %tree, %tree as value] (lua> "return nomsu:run(\%tree)")
compile [run tree %tree, %tree as value] to (Lua value "nomsu:run(\(%tree as lua expr))")
compile [compile %block, compiled %block, %block compiled] to (..)
Lua value "nomsu:compile(\(%block as lua))"

View File

@ -187,7 +187,7 @@ run = function()
if not (args.no_core) then
for _, filename in Files.walk('core') do
if filename:match("%.nom$") then
nomsu:run_file(filename)
nomsu:import(nomsu:run_file(filename))
end
end
end

View File

@ -126,7 +126,7 @@ run = ->
unless args.no_core
for _,filename in Files.walk('core')
if filename\match "%.nom$"
nomsu\run_file filename
nomsu\import(nomsu\run_file(filename))
get_file_and_source = (filename)->
local file, source

View File

@ -141,21 +141,9 @@ for version = 1, 999 do
end
end
local MAX_LINE = 80
local NomsuCompiler = setmetatable({
name = "Nomsu"
}, {
__index = function(self, k)
do
local _self = rawget(self, "self")
if _self then
return _self[k]
else
return nil
end
end
end,
local NomsuCompiler = setmetatable({ }, {
__tostring = function(self)
return self.name
return "Nomsu"
end
})
local _anon_chunk = 0
@ -163,6 +151,7 @@ do
NomsuCompiler.NOMSU_COMPILER_VERSION = 8
NomsuCompiler.NOMSU_SYNTAX_VERSION = max_parser_version
NomsuCompiler.nomsu = NomsuCompiler
NomsuCompiler.global = Dict({ })
NomsuCompiler.parse = function(self, nomsu_code, source, version)
if source == nil then
source = nil
@ -316,6 +305,26 @@ do
NomsuCompiler.LOADED = { }
NomsuCompiler.TESTS = { }
NomsuCompiler.AST = AST
NomsuCompiler.fork = function(self)
local f = setmetatable({ }, {
__index = self
})
f.COMPILE_ACTIONS = setmetatable({ }, {
__index = self.COMPILE_ACTIONS
})
f.nomsu = f
return f
end
local math_expression = re.compile([[ ([+-] " ")* [0-9]+ (" " [*/^+-] (" " [+-])* " " [0-9]+)+ !. ]])
NomsuCompiler.get_compile_action = function(self, stub)
local ret = self.COMPILE_ACTIONS[stub]
if not (ret == nil) then
return ret
end
if math_expression:match(stub) then
return self.COMPILE_ACTIONS["# compile math expr #"]
end
end
NomsuCompiler.compile_error = function(self, source, err_format_string, ...)
err_format_string = err_format_string:gsub("%%[^s]", "%%%1")
local file = Files.read(source.filename)
@ -330,7 +339,6 @@ do
local err_msg = err_format_string:format(src, ...)
return error(tostring(source.filename) .. ":" .. tostring(line_no) .. ": " .. err_msg, 0)
end
local math_expression = re.compile([[ ([+-] " ")* [0-9]+ (" " [*/^+-] (" " [+-])* " " [0-9]+)+ !. ]])
local add_lua_bits
add_lua_bits = function(self, val_or_stmt, code)
local cls = val_or_stmt == "value" and LuaCode.Value or LuaCode
@ -389,7 +397,7 @@ do
end
return operate_on_text(code)
end
NomsuCompiler.COMPILE_ACTIONS = setmetatable({
NomsuCompiler.COMPILE_ACTIONS = {
["# compile math expr #"] = function(self, tree, ...)
local lua = LuaCode.Value(tree.source)
for i, tok in ipairs(tree) do
@ -419,23 +427,23 @@ do
end,
["lua > 1"] = function(self, tree, code)
if code.type ~= "Text" then
return LuaCode(tree.source, "nomsu:run_lua(", self:compile(code), ");")
return LuaCode(tree.source, "nomsu:run_lua(", self:compile(code), ", nomsu);")
end
return add_lua_bits(self, "statements", code)
end,
["= lua 1"] = function(self, tree, code)
if code.type ~= "Text" then
return LuaCode.Value(tree.source, "nomsu:run_lua(", self:compile(code), ":as_statements('return '))")
return LuaCode.Value(tree.source, "nomsu:run_lua(", self:compile(code), ":as_statements('return '), nomsu)")
end
return add_lua_bits(self, "value", code)
end,
["use 1"] = function(self, tree, path)
if path.type == 'Text' and #path == 1 and type(path[1]) == 'string' then
for _, f in Files.walk(path[1]) do
self:run_file(f)
self:import(self:run_file(f))
end
end
return LuaCode(tree.source, "for i,f in Files.walk(", self:compile(path), ") do nomsu:run_file(f) end")
return LuaCode(tree.source, "for i,f in Files.walk(", self:compile(path), ") do nomsu:import(nomsu:run_file(f)) end")
end,
["tests"] = function(self, tree)
return LuaCode.Value(tree.source, "TESTS")
@ -459,21 +467,19 @@ do
["Lua version"] = function(self, tree, code)
return LuaCode.Value(tree.source, repr(_VERSION))
end
}, {
__index = function(self, stub)
if math_expression:match(stub) then
return self["# compile math expr #"]
}
NomsuCompiler.import = function(self, mod)
for k, v in pairs(mod) do
if not (k == "COMPILE_ACTIONS" or k == "nomsu" or k == "_ENV") then
self[k] = v
end
end
})
NomsuCompiler.run = function(self, to_run, source, version)
if source == nil then
source = nil
for k, v in pairs(mod.COMPILE_ACTIONS) do
self.COMPILE_ACTIONS[k] = v
end
if version == nil then
version = nil
end
source = source or (to_run.source or Source(to_run, 1, #to_run))
NomsuCompiler.run = function(self, to_run)
local source = to_run.source or Source(to_run, 1, #to_run)
if type(source) == 'string' then
source = Source:from_string(source)
end
@ -484,7 +490,7 @@ do
if AST.is_syntax_tree(to_run) then
tree = to_run
else
tree = self:parse(to_run, source, version)
tree = self:parse(to_run, source)
end
if tree == nil then
return nil
@ -528,10 +534,11 @@ do
end
end
insert(_running_files, filename)
local ret = nil
local mod = self:fork()
mod.from_file = filename
if match(filename, "%.lua$") then
local file = assert(Files.read(filename), "Could not find file: " .. tostring(filename))
ret = self:run_lua(file, Source(filename, 1, #file))
local ret = mod:run_lua(LuaCode(Source(filename, 1, #file), file))
elseif match(filename, "%.nom$") or match(filename, "^/dev/fd/[012]$") then
local ran_lua
if self.can_optimize(filename) then
@ -539,7 +546,10 @@ do
do
local file = Files.read(lua_filename)
if file then
ret = self:run_lua(file, Source(lua_filename, 1, #file))
local ret = mod:run_lua(LuaCode(Source(lua_filename, 1, #file), file))
if type(ret) == 'table' then
mod = ret
end
ran_lua = true
end
end
@ -549,20 +559,19 @@ do
if not file then
error("Tried to run file that does not exist: " .. tostring(filename))
end
ret = self:run(file, Source(filename, 1, #file))
local ret = mod:run(NomsuCode(Source(filename, 1, #file), file))
if type(ret) == 'table' then
mod = ret
end
end
else
error("Invalid filetype for " .. tostring(filename), 0)
end
self.LOADED[filename] = ret or true
self.LOADED[filename] = mod
remove(_running_files)
self.LOADED[filename] = ret or true
return ret
end
NomsuCompiler.run_lua = function(self, lua, source)
if source == nil then
source = nil
return mod
end
NomsuCompiler.run_lua = function(self, lua)
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
@ -577,7 +586,7 @@ do
end)(), "\n")
error("Failed to compile generated code:\n" .. tostring(colored.bright(colored.blue(colored.onblack(line_numbered_lua)))) .. "\n\n" .. tostring(err), 0)
end
source = source or lua.source
local source = lua.source or Source(lua_string, 1, #lua_string)
local source_key = tostring(source)
if not (SOURCE_MAP[source_key]) then
local map = { }
@ -632,7 +641,7 @@ do
if "Action" == _exp_0 then
local stub = tree.stub
do
local compile_action = self.COMPILE_ACTIONS[stub]
local compile_action = self:get_compile_action(stub)
if compile_action then
local args
do

View File

@ -84,14 +84,13 @@ for version=1,999
else break
MAX_LINE = 80 -- For beautification purposes, try not to make lines much longer than this value
NomsuCompiler = setmetatable {name:"Nomsu"},
__index: (k)=> if _self = rawget(@, "self") then _self[k] else nil
__tostring: => @name
NomsuCompiler = setmetatable {}, __tostring: => "Nomsu"
_anon_chunk = 0
with NomsuCompiler
.NOMSU_COMPILER_VERSION = 8
.NOMSU_SYNTAX_VERSION = max_parser_version
.nomsu = NomsuCompiler
.global = Dict{}
.parse = (nomsu_code, source=nil, version=nil)=>
source or= nomsu_code.source
nomsu_code = tostring(nomsu_code)
@ -152,6 +151,24 @@ with NomsuCompiler
.TESTS = {}
.AST = AST
.fork = =>
f = setmetatable({}, {__index:@})
f.COMPILE_ACTIONS = setmetatable({}, {__index:@COMPILE_ACTIONS})
f.nomsu = f
return f
-- 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 [[ ([+-] " ")* [0-9]+ (" " [*/^+-] (" " [+-])* " " [0-9]+)+ !. ]]
.get_compile_action = (stub)=>
ret = @COMPILE_ACTIONS[stub]
return ret unless ret == nil
if math_expression\match(stub)
return @COMPILE_ACTIONS["# compile math expr #"]
-- TODO: use pretty_error instead of this
.compile_error = (source, err_format_string, ...)=>
err_format_string = err_format_string\gsub("%%[^s]", "%%%1")
file = Files.read(source.filename)
@ -166,11 +183,6 @@ with NomsuCompiler
err_msg = err_format_string\format(src, ...)
error("#{source.filename}:#{line_no}: "..err_msg, 0)
-- 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 [[ ([+-] " ")* [0-9]+ (" " [*/^+-] (" " [+-])* " " [0-9]+)+ !. ]]
add_lua_bits = (val_or_stmt, code)=>
cls = val_or_stmt == "value" and LuaCode.Value or LuaCode
operate_on_text = (text)->
@ -214,7 +226,7 @@ with NomsuCompiler
return lua
return operate_on_text code
.COMPILE_ACTIONS = setmetatable {
.COMPILE_ACTIONS = {
["# compile math expr #"]: (tree, ...)=>
lua = LuaCode.Value(tree.source)
for i,tok in ipairs tree
@ -239,19 +251,20 @@ with NomsuCompiler
["lua > 1"]: (tree, code)=>
if code.type != "Text"
return LuaCode tree.source, "nomsu:run_lua(", @compile(code), ");"
return LuaCode tree.source, "nomsu:run_lua(", @compile(code), ", nomsu);"
return add_lua_bits(@, "statements", code)
["= lua 1"]: (tree, code)=>
if code.type != "Text"
return LuaCode.Value tree.source, "nomsu:run_lua(", @compile(code), ":as_statements('return '))"
return LuaCode.Value tree.source, "nomsu:run_lua(", @compile(code), ":as_statements('return '), nomsu)"
return add_lua_bits(@, "value", code)
["use 1"]: (tree, path)=>
if path.type == 'Text' and #path == 1 and type(path[1]) == 'string'
for _,f in Files.walk(path[1])
@run_file(f)
return LuaCode(tree.source, "for i,f in Files.walk(", @compile(path), ") do nomsu:run_file(f) end")
@import(@run_file(f))
return LuaCode(tree.source, "for i,f in Files.walk(", @compile(path), ") do nomsu:import(nomsu:run_file(f)) end")
["tests"]: (tree)=> LuaCode.Value(tree.source, "TESTS")
["test 1"]: (tree, body)=>
@ -263,17 +276,19 @@ with NomsuCompiler
["Lua version"]: (tree, code)=>
return LuaCode.Value(tree.source, repr(_VERSION))
}, {
__index: (stub)=>
if math_expression\match(stub)
return @["# compile math expr #"]
}
.run = (to_run, source=nil, version=nil)=>
source or= to_run.source or Source(to_run, 1, #to_run)
.import = (mod)=>
for k,v in pairs(mod)
@[k] = v unless k == "COMPILE_ACTIONS" or k == "nomsu" or k == "_ENV"
for k,v in pairs(mod.COMPILE_ACTIONS)
@COMPILE_ACTIONS[k] = v
.run = (to_run)=>
source = to_run.source or Source(to_run, 1, #to_run)
if type(source) == 'string' then source = Source\from_string(source)
if not Files.read(source.filename) then Files.spoof(source.filename, to_run)
tree = if AST.is_syntax_tree(to_run) then to_run else @parse(to_run, source, version)
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"
@ -305,30 +320,33 @@ with NomsuCompiler
error("Circular import, this loops forever: #{concat loop, " -> "}...")
insert _running_files, filename
ret = nil
mod = @fork!
mod.from_file = filename
if match(filename, "%.lua$")
file = assert(Files.read(filename), "Could not find file: #{filename}")
ret = @run_lua file, Source(filename, 1, #file)
ret = mod\run_lua(LuaCode(Source(filename, 1, #file), file))
elseif match(filename, "%.nom$") or match(filename, "^/dev/fd/[012]$")
ran_lua = if @.can_optimize(filename) -- Look for precompiled version
lua_filename = gsub(filename, "%.nom$", ".lua")
if file = Files.read(lua_filename)
ret = @run_lua file, Source(lua_filename, 1, #file)
ret = mod\run_lua(LuaCode(Source(lua_filename, 1, #file), file))
if type(ret) == 'table'
mod = ret
true
unless ran_lua
file = Files.read(filename)
if not file
error("Tried to run file that does not exist: #{filename}")
ret = @run file, Source(filename,1,#file)
ret = mod\run(NomsuCode(Source(filename,1,#file), file))
if type(ret) == 'table'
mod = ret
else
error("Invalid filetype for #{filename}", 0)
@LOADED[filename] = ret or true
@LOADED[filename] = mod
remove _running_files
return mod
@LOADED[filename] = ret or true
return ret
.run_lua = (lua, source=nil)=>
.run_lua = (lua)=>
lua_string = tostring(lua)
run_lua_fn, err = load(lua_string, nil and tostring(source or lua.source), "t", self)
if not run_lua_fn
@ -336,7 +354,7 @@ with NomsuCompiler
[format("%3d|%s",i,line) for i, line in ipairs Files.get_lines(lua_string)],
"\n")
error("Failed to compile generated code:\n#{colored.bright colored.blue colored.onblack line_numbered_lua}\n\n#{err}", 0)
source or= lua.source
source = lua.source or Source(lua_string, 1, #lua_string)
source_key = tostring(source)
unless SOURCE_MAP[source_key]
map = {}
@ -372,7 +390,7 @@ with NomsuCompiler
switch tree.type
when "Action"
stub = tree.stub
if compile_action = @COMPILE_ACTIONS[stub]
if compile_action = @get_compile_action(stub)
args = [arg for arg in *tree when type(arg) != "string"]
-- Force Lua to avoid tail call optimization for debugging purposes
-- TODO: use tail call?

View File

@ -42,10 +42,10 @@ for _index_0 = 1, #types do
return getmetatable(x) == self
end
cls.__tostring = function(self)
return tostring(self.type) .. tostring(repr(self))
return tostring(self.type) .. tostring(repr(self, (function() end)))
end
cls.__repr = function(self)
return tostring(self.type) .. tostring(repr(self))
return tostring(self.type) .. tostring(repr(self, (function() end)))
end
cls.source_code_for_tree = setmetatable({ }, {
__index = function(self, t)

View File

@ -19,8 +19,8 @@ for name in *types
.__name = name
.type = name
.is_instance = (x)=> getmetatable(x) == @
.__tostring = => "#{@type}#{repr @}"
.__repr = => "#{@type}#{repr @}"
.__tostring = => "#{@type}#{repr @, (->)}"
.__repr = => "#{@type}#{repr @, (->)}"
.source_code_for_tree = setmetatable({}, {__index:(t)=>
s = t.source
Files = require 'files'

View File

@ -17,6 +17,7 @@ for %path in (command line args):
if (%filename::matches "%.nom$"): use %filename
for %path in (command line args): use %path
%tests = ((=lua "Source:from_string(\%s)") = %t for %s = %t in (tests))
for %path in (command line args):
for file %filename in %path: