Skip to content

Commit

Permalink
Introduce concepts system!
Browse files Browse the repository at this point in the history
  • Loading branch information
edubart committed Feb 11, 2020
1 parent 6852faf commit 4f0cc44
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 71 deletions.
31 changes: 4 additions & 27 deletions lib/myarraytable.nelua
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
--TODO: lazy functions to make it generic
--TODO: record metamethods

## strict = true
## unitname = 'nelua'
Expand Down Expand Up @@ -42,7 +41,7 @@
end
end

function ArrayTableT:_grow() <noinline>
function ArrayTableT:_grow()
local cap: usize
if self.impl.data.size ~= 0 then
cap = self.impl.data.size * 2
Expand All @@ -52,7 +51,7 @@
self.impl.data = allocator.spanrealloc(self.impl.data, cap)
end

function ArrayTableT:reserve(n: usize <autocast>) <noinline>
function ArrayTableT:reserve(n: usize <autocast>)
self:init()
local cap = n + 1
if self.impl.data.size < cap then
Expand Down Expand Up @@ -97,7 +96,7 @@
return self.impl.data[i]
end

function ArrayTableT:at(i: usize <autocast>): T* <inline>
function ArrayTableT:__atindex(i: usize <autocast>): T* <inline>
self:init()
if unlikely(i > self.impl.size) then
check(i == self.impl.size + 1, 'arraytable.at: index out of range')
Expand All @@ -110,29 +109,7 @@
return &self.impl.data[i]
end

function ArrayTableT:set(i: usize <autocast>, v: T) <inline>
self:init()
if unlikely(i > self.impl.size) then
check(i == self.impl.size + 1, 'arraytable.at: index out of range')
self.impl.size = self.impl.size + 1
end
if unlikely(self.impl.size + 1 > self.impl.data.size) then
self:_grow()
end
self.impl.data[i] = v
end

function ArrayTableT:get(i: usize <autocast>): T <inline>
if unlikely(i == 0 and (not self.impl or self.impl.data.size == 0)) then
local v: T
return v
else
check(self.impl and i <= self.impl.size, 'arraytable.get: index out of range')
return self.impl.data[i]
end
end

function ArrayTableT:len(): isize <inline>
function ArrayTableT:__len(): isize <inline>
if unlikely(not self.impl) then
return 0
end
Expand Down
44 changes: 26 additions & 18 deletions nelua/analyzer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,12 @@ local function visitor_Table_literal(context, node)
local childnodes = node[1]
context:traverse_nodes(childnodes)
attr.type = primtypes.table
attr.node = node
end

function visitors.Table(context, node)
local desiredtype = node.desiredtype
if not desiredtype or desiredtype:is_table() then
if not desiredtype or (desiredtype:is_table() or desiredtype.lazyable) then
visitor_Table_literal(context, node)
elseif desiredtype:is_arraytable() then
visitor_ArrayTable_literal(context, node, desiredtype)
Expand All @@ -200,6 +201,7 @@ function visitors.Table(context, node)
elseif desiredtype:is_record() then
visitor_Record_literal(context, node, desiredtype)
else
-- concept will be traversed again later
node:raisef("type '%s' cannot be initialized using a table literal", desiredtype:prettyname())
end
end
Expand Down Expand Up @@ -744,7 +746,7 @@ local function visitor_Call(context, node, argnodes, calleetype, calleesym, call
funcargtype = funcarg.type
end
if argnode then
argnode.desiredtype = funcargtype
argnode.desiredtype = argnode.desiredtype or funcargtype
context:traverse_node(argnode)
argtype = argnode.attr.type
if argtype then
Expand All @@ -754,29 +756,36 @@ local function visitor_Call(context, node, argnodes, calleetype, calleesym, call
arg = argtype
end

if calleetype:is_lazyfunction() then
if funcargtype.lazyable then
lazyargs[i] = arg
else
lazyargs[i] = funcargtype
end
end

if argtype and argtype:is_nil() and not funcargtype:is_nilable() then
node:raisef("in call of function '%s': expected an argument at index %d but got nothing",
calleetype:prettyname(), i)
end
if arg then
if funcargtype then
local ok, err = funcargtype:is_convertible_from(arg, traits.is_attr(funcarg) and funcarg.autocast)
if not ok then
node:raisef("in call of function '%s' at argument %d: %s",
calleetype:prettyname(), i, err)
end
local explicit = traits.is_attr(funcarg) and funcarg.autocast
local wantedtype, err = funcargtype:is_convertible_from(arg, explicit)
if not wantedtype then
node:raisef("in call of function '%s' at argument %d: %s",
calleetype:prettyname(), i, err)
end

if funcargtype ~= wantedtype and argnode then
-- new type suggested, need to traverse again
argnode.desiredtype = wantedtype
context:traverse_node(argnode)
end
funcargtype = wantedtype
else
knownallargs = false
end

if calleetype:is_lazyfunction() then
if funcargtype.lazyable then
lazyargs[i] = arg
else
lazyargs[i] = funcargtype
end
end

if calleeobjnode and argtype and pseudoargtypes[i]:is_auto() then
pseudoargtypes[i] = argtype
end
Expand Down Expand Up @@ -1310,7 +1319,7 @@ function visitors.VarDecl(context, node)
local symbol = context:traverse_node(varnode)
assert(symbol)
local vartype = varnode.attr.type
if vartype and vartype:is_varanys() then
if vartype and vartype.nolvalue then
varnode:raisef("variable declaration cannot be of the type '%s'", vartype:prettyname())
end
assert(symbol.type == vartype)
Expand Down Expand Up @@ -1483,7 +1492,6 @@ local function resolve_function_argtypes(symbol, varnode, argnodes, scope, check
argattrs[i] = argattr
end


if varnode.tag == 'ColonIndex' and symbol and symbol.metafunc then
-- inject 'self' type as first argument
local selfsym = symbol.selfsym
Expand Down
9 changes: 8 additions & 1 deletion nelua/preprocessor.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
local traits = require 'nelua.utils.traits'
local tabler = require 'nelua.utils.tabler'
local compat = require 'pl.compat'
local types = require 'nelua.types'
local typedefs = require 'nelua.typedefs'
local VisitorContext = require 'nelua.analyzercontext'
local PPContext = require 'nelua.ppcontext'
Expand Down Expand Up @@ -129,14 +130,15 @@ function preprocessor.preprocess(context, ast)
except.raise(msg, 2)
end

local primtypes = require 'nelua.typedefs'.primtypes
local primtypes = typedefs.primtypes
local ppenv = {
context = context,
ppcontext = ppcontext,
ppregistry = ppcontext.registry,
ast = ast,
aster = aster,
config = config,
types = types,
primtypes = primtypes
}
tabler.update(ppenv, {
Expand Down Expand Up @@ -192,6 +194,11 @@ function preprocessor.preprocess(context, ast)
end
return status
end,
concept = function(f)
local type = types.ConceptType(f)
type.node = context:get_current_node()
return type
end
})
setmetatable(ppenv, { __index = function(_, key)
local v = rawget(ppcontext.context.env, key)
Expand Down
Loading

0 comments on commit 4f0cc44

Please sign in to comment.