Skip to content

Commit

Permalink
Implement search in require
Browse files Browse the repository at this point in the history
  • Loading branch information
edubart committed Jun 30, 2019
1 parent a2ff88e commit 608ad47
Show file tree
Hide file tree
Showing 32 changed files with 126 additions and 40 deletions.
2 changes: 1 addition & 1 deletion .luacheckrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ exclude_files={'playground', 'nelua_cache'}
unused_secondaries=false
globals = {
io = {"stdout", "stderr" }
}
}
7 changes: 3 additions & 4 deletions examples/brainfuck.nelua
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
local function getchar(): int32 !cimport end
local function putchar(c: int32): int32 !cimport end
require 'C.stdio'

local data: int32[1024]
local ptr: int32 = 0
Expand All @@ -22,9 +21,9 @@ for i=1,#source do
elseif c == "-" then
]##] data[ptr] = data[ptr] - 1 [##[
elseif c == "." then
]##] putchar(data[ptr]) [##[
]##] C.putchar(data[ptr]) [##[
elseif c == "," then
]##] data[ptr] = getchar() [##[
]##] data[ptr] = C.getchar() [##[
elseif c == "[" then
--generate labels to represent the beginning and ending of the loop
local target = { before = 'b' .. i, after = 'a' .. i }
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion nelua.lua
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#!/usr/bin/env lua
require 'nelua.runner'.run(arg)
require 'nelua.runner'.run(arg)
31 changes: 17 additions & 14 deletions nelua/cbuiltins.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ local builtins = {}
local operators = {}
builtins.operators = operators

function operators.len(_, emitter, argnode)
function operators.len(node, emitter, argnode)
local type = argnode.attr.type
if type:is_arraytable() then
emitter:add(type, '_length(&', argnode, ')')
Expand All @@ -15,7 +15,7 @@ function operators.len(_, emitter, argnode)
elseif type:is_type() then
emitter:add(argnode.attr.holdedtype.size)
else --luacov:disable
error('not implemented')
node:errorf('not implemented')
end --luacov:enable
end

Expand All @@ -29,7 +29,7 @@ function operators.div(node, emitter, lnode, rnode, lname, rname)
emitter:add(lname, ' / ', rname)
end
else --luacov:disable
error('not implemented')
node:errorf('not implemented')
end --luacov:enable
end

Expand All @@ -44,7 +44,7 @@ function operators.idiv(node, emitter, lnode, rnode, lname, rname)
emitter:add(lname, ' / ', rname)
end
else --luacov:disable
error('not implemented')
node:errorf('not implemented')
end --luacov:enable
end

Expand All @@ -59,7 +59,7 @@ function operators.mod(node, emitter, lnode, rnode, lname, rname)
emitter:add(lname, ' % ', rname)
end
else --luacov:disable
error('not implemented')
node:errorf('not implemented')
end --luacov:enable
end

Expand All @@ -70,7 +70,7 @@ function operators.pow(node, emitter, lnode, rnode, lname, rname)
emitter:add(powname, '(', lname, ', ', rname, ')')
emitter.context.has_math = true
else --luacov:disable
error('not implemented')
node:errorf('not implemented')
end --luacov:enable
end

Expand All @@ -79,7 +79,7 @@ function operators.eq(_, emitter, lnode, rnode, lname, rname)
if ltype:is_string() and rtype:is_string() then
emitter:add('nelua_string_eq(', lname, ', ', rname, ')')
else
emitter:add(lname, ' ', '==', ' ', rname)
emitter:add(lname, ' ', cdefs.compare_ops.eq, ' ', rname)
end
end

Expand All @@ -88,7 +88,7 @@ function operators.ne(_, emitter, lnode, rnode, lname, rname)
if ltype:is_string() and rtype:is_string() then
emitter:add('nelua_string_ne(', lname, ', ', rname, ')')
else
emitter:add(lname, ' ', '!=', ' ', rname)
emitter:add(lname, ' ', cdefs.compare_ops.ne, ' ', rname)
end
end

Expand Down Expand Up @@ -209,13 +209,16 @@ end

function functions.require(context, node, emitter)
local scope = context:push_scope('block')
local ast = node.attr.loadedast
assert(ast)
scope.staticstorage = true
local hasstatnodes = #node.attr.loadedast[1] > 0
if hasstatnodes then
emitter:add_indent_ln('{')
end
emitter:add(node.attr.loadedast)
if hasstatnodes then
local bracepos = emitter:get_pos()
emitter:add_indent_ln('{')
local lastpos = emitter:get_pos()
emitter:add(ast)
if emitter:get_pos() == lastpos then
emitter:remove_until_pos(bracepos)
else
emitter:add_indent_ln('}')
end
context:pop_scope()
Expand Down
2 changes: 1 addition & 1 deletion nelua/ccontext.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function CContext:declname(node)
end
local declname = attr.codename
if not attr.nodecl then
if not attr.cimport then
if not attr.cimport and not attr.metavar then
if self.scope:is_static_storage() and traits.is_astnode(node) then
local modname = attr.modname or node.modname
if modname ~= '' then
Expand Down
16 changes: 15 additions & 1 deletion nelua/configer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ local defconfig = {
cc = 'gcc',
lua = 'lua',
lua_version = '5.3',
cache_dir = 'nelua_cache',
cpu_bits = 64
}

Expand Down Expand Up @@ -39,7 +40,8 @@ local function create_parser(argv)
argparser:option('--lua', "Lua interpreter to use when runnning", defconfig.lua)
argparser:option('--lua-version', "Target lua version for lua generator", defconfig.lua_version)
argparser:option('--lua-options', "Lua options to use when running")
argparser:option('--cache-dir', "Compilation cache directory", "nelua_cache")
argparser:option('--cache-dir', "Compilation cache directory", defconfig.cache_dir)
argparser:option('--path', "Nelua modules search path", defconfig.path)
argparser:argument("input", "Input source file"):action(function(options, _, v)
-- hacky way to stop handling options
local index = tabler.ifind(argv, v) + 1
Expand All @@ -57,11 +59,21 @@ local function get_runtime_path(arg0)
return fs.join(fs.getdatapath(arg0), 'runtime')
end

local function get_path(arg0)
local libdir = fs.join(fs.getdatapath(arg0), 'lib')
return
fs.join(libdir,'?.nelua')..';'..
fs.join(libdir,'?','init.nelua')..';'..
fs.join('.','?.nelua')..';'..
fs.join('.','?','init.nelua')
end

function configer.parse(args)
local argparser = create_parser(tabler.copy(args))
local ok, options = argparser:pparse(args)
except.assertraise(ok, options)
config.runtime_path = get_runtime_path(args[0])
config.path = get_path(args[0])
metamagic.setmetaindex(options, defconfig)
metamagic.setmetaindex(config, options, true)
return config
Expand All @@ -73,6 +85,8 @@ end

local function init_default_configs()
defconfig.runtime_path = get_runtime_path()
defconfig.path = os.getenv('NELUA_PATH') or get_path()
defconfig.cache_dir = os.getenv('NELUA_CACHE_DIR') or defconfig.cache_dir
defconfig.lua = os.getenv('LUA') or defconfig.lua
defconfig.cc = os.getenv('CC') or defconfig.cc
defconfig.cflags = os.getenv('CFLAGS')
Expand Down
14 changes: 13 additions & 1 deletion nelua/emitter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,21 @@ function Emitter:add_ln(what, ...)
self:add('\n')
end

function Emitter:get_pos()
return #self.codes
end

function Emitter:remove_until_pos(pos)
while #self.codes > pos do
table.remove(self.codes)
end
end

function Emitter:add_one(what)
if traits.is_string(what) then
table.insert(self.codes, what)
if #what > 0 then
table.insert(self.codes, what)
end
elseif traits.is_number(what) or traits.is_bignumber(what) then
table.insert(self.codes, tostring(what))
elseif traits.is_astnode(what) then
Expand Down
27 changes: 19 additions & 8 deletions nelua/typechecker.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ local types = require 'nelua.types'
local bn = require 'nelua.utils.bn'
local preprocessor = require 'nelua.preprocessor'
local fs = require 'nelua.utils.fs'
local config = require 'nelua.configer'.get()
local typechecker = {}

local primtypes = typedefs.primtypes
Expand Down Expand Up @@ -591,11 +592,13 @@ local function visitor_FieldIndex(context, node)
symbol = Symbol(symname, node)
symbol.attr.const = true
symbol.attr.metafunc = true
symbol.attr.metavar = true
symbol.attr.metarecordtype = typedefs.get_pointer_type(objnode, objtype)
objtype:set_metafield(name, symbol)
elseif context.inglobaldecl == parentnode then
-- declaration of record global variable
symbol = Symbol(symname, node)
symbol.attr.metavar = true
objtype:set_metafield(name, symbol)

-- add symbol to scope to enable type deduction
Expand Down Expand Up @@ -864,18 +867,22 @@ local function builtin_call_require(context, node)
argnode.attr.type and argnode.attr.type:is_string() and
argnode.attr.compconst) then
-- not a compile time require
return
end
local filename = argnode.attr.value
if not stringer.endswith(filename, '.nelua') then
-- not a nelua file
node:assertraisef(context.state.backend ~= 'c', 'runtime require is not supported in C backend yet')
return
end

local modulename = argnode.attr.value
node.attr.modulename = modulename

-- load it and parse
local input, err = fs.tryreadfile(filename)
node:assertraisef(input, "failed to require nelua file: %s", err)
local ast = context.parser:parse(input, filename)
local filepath = fs.findmodulefile(modulename, config.path)
if not filepath then
-- maybe it would succeed at runtime
node:assertraisef(context.state.backend ~= 'c', "compile time module '%s' not found", node.attr.modulename)
return
end
local input = fs.readfile(filepath)
local ast = context.parser:parse(input, filepath)

-- analyze it
typechecker.analyze(ast, context.parser, context)
Expand Down Expand Up @@ -1575,6 +1582,10 @@ function typechecker.analyze(ast, parser, parentcontext)
context.parser = parser
context.astbuilder = parser.astbuilder

if not context.state.backend then
context.state.backend = config.generator
end

-- phase 1 traverse: infer and check types
context.phase = phases.type_inference
context:repeat_scope_until_resolution('function', function(scope)
Expand Down
2 changes: 1 addition & 1 deletion nelua/types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ function PointerType:_init(node, subtype)
self.subtype = subtype
Type._init(self, 'pointer', cpusize, node)
if not subtype:is_void() then
self.codename = subtype.codename .. '_pointer'
self.codename = subtype.codename .. '_ptr'
end
self.unary_operators['deref'] = subtype
end
Expand Down
12 changes: 12 additions & 0 deletions nelua/utils/fs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ local pldir = require 'pl.dir'
local plfile = require 'pl.file'
local plpath = require 'pl.path'
local except = require 'nelua.utils.except'
local stringer = require 'nelua.utils.stringer'

local fs = {}

Expand Down Expand Up @@ -51,4 +52,15 @@ function fs.getdatapath(arg0)
return path
end

function fs.findmodulefile(name, path)
name = name:gsub('%.', plpath.sep)
local paths = stringer.split(path, ';')
for _,trypath in ipairs(paths) do
trypath = trypath:gsub('%?', name)
if plpath.isfile(trypath) then
return trypath
end
end
end

return fs
20 changes: 18 additions & 2 deletions rockspecs/nelua-dev-1.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ dependencies = {
'lbc >= 20180729',

-- dev dependencies only
'busted >= 2.0rc13',
'busted == 2.0rc13',
'luacheck >= 0.23.0',
'luacov >= 0.13.0',
'cluacov >= 0.1.1',
'dumper >= 0.1.0',
'dumper >= 0.1.1',
}

build = {
Expand Down Expand Up @@ -100,6 +100,22 @@ build = {
['runtime/c/nelua_arrtab.h'] = 'runtime/c/nelua_arrtab.h',
['runtime/c/nelua_record.c'] = 'runtime/c/nelua_record.c',
['runtime/c/nelua_record.h'] = 'runtime/c/nelua_record.h',
['lib/io.nelua'] = 'lib/io.nelua',
['lib/math.nelua'] = 'lib/math.nelua',
['lib/myarraytable.nelua'] = 'lib/myarraytable.nelua',
['lib/mystring.nelua'] = 'lib/mystring.nelua',
['lib/mytable.nelua'] = 'lib/mytable.nelua',
['lib/os.nelua'] = 'lib/os.nelua',
['lib/utf8.nelua'] = 'lib/utf8.nelua',
['lib/C/ctype.nelua'] = 'lib/C/ctype.nelua',
['lib/C/errno.nelua'] = 'lib/C/errno.nelua',
['lib/C/locale.nelua'] = 'lib/C/locale.nelua',
['lib/C/math.nelua'] = 'lib/C/math.nelua',
['lib/C/signal.nelua'] = 'lib/C/signal.nelua',
['lib/C/stdio.nelua'] = 'lib/C/stdio.nelua',
['lib/C/stdlib.nelua'] = 'lib/C/stdlib.nelua',
['lib/C/string.nelua'] = 'lib/C/string.nelua',
['lib/C/time.nelua'] = 'lib/C/time.nelua',
}
}
}
File renamed without changes.
2 changes: 1 addition & 1 deletion spec/03-typechecker_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -889,7 +889,7 @@ it("builtins", function()
end)

it("require builtin", function()
assert.analyze_ast("require 'examples/helloworld.nelua'")
assert.analyze_ast("require 'examples.helloworld'")
assert.analyze_ast("require 'somelualib'")
assert.analyze_ast("local a = 'dynamiclib'; require(a)")
end)
Expand Down
21 changes: 18 additions & 3 deletions spec/05-cgenerator_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,12 @@ it("record methods", function()
end)

it("record globals", function()
assert.generate_c([[
## state.nohashcodenames = true
local Math = @record{}
global Math.PI: compconst = 3.14
compconst Math.E = 2.7
]], "double mymod_Math_PI = 3.14")
assert.run_c([[
local Math = @record{}
global Math.PI = 3.14
Expand Down Expand Up @@ -906,7 +912,7 @@ it("type codenames", function()
return r:foo()
]], {
"typedef struct myrecord {\n int64_t x;\n} myrecord;",
"static int64_t myrecord_foo(myrecord_pointer self);"
"static int64_t myrecord_foo(myrecord_ptr self);"
})
end)

Expand Down Expand Up @@ -1087,12 +1093,21 @@ end)

it("require builtin", function()
assert.generate_c([[
require 'examples/helloworld.nelua'
require 'examples.helloworld'
]], "hello world")

assert.run_c([[
require 'examples/helloworld.nelua'
require 'examples.helloworld'
]], "hello world")

assert.run_error_c([[
local a = 'mylib'
require(a)
]], "runtime require is not supported in C")

assert.run_error_c([[
require 'invalid_file'
]], "compile time module 'invalid_file' not found")
end)

end)

0 comments on commit 608ad47

Please sign in to comment.