Skip to content

Commit

Permalink
Implement span type
Browse files Browse the repository at this point in the history
  • Loading branch information
edubart committed Jul 22, 2019
1 parent 7f4ed67 commit 60f3f2f
Show file tree
Hide file tree
Showing 15 changed files with 150 additions and 75 deletions.
36 changes: 15 additions & 21 deletions lib/memory.nelua
Original file line number Diff line number Diff line change
Expand Up @@ -16,44 +16,38 @@ local function free(ptr: pointer): void !cimport 'free' end

global memory = @record{}

local span = @record {
data: byte[0]*,
size: usize
}
global memory.span = span

function memory.alloc(size: usize): span
function memory.allocnoinit(size: usize): span<byte>
assert(size > 0)
local data = @byte[0]*(malloc(size))
local data = @byte*(malloc(size))
assert(data)
return span { data, size }
return @span<byte> { data, size }
end

function memory.alloc0(size: usize): span
function memory.alloc(size: usize): span<byte>
assert(size > 0)
local data = @byte[0]*(calloc(1, size))
local data = @byte*(calloc(1, size))
assert(data)
return span { data, size }
return @span<byte> { data, size }
end

function memory.realloc(s: span*, size: usize)
function memory.reallocnoinit(s: span<byte>*, size: usize)
assert(size > 0)
s.data = @byte[0]*(realloc(s.data, size))
s.data = @byte*(realloc(s.data, size))
assert(s.data)
s.size = size
end

function memory.realloc0(s: span*, size: usize)
function memory.realloc(s: span<byte>*, size: usize)
assert(size > 0)
s.data = @byte[0]*(realloc(s.data, size))
s.data = @byte*(realloc(s.data, size))
assert(s.data)
if size > s.size then
memset(&s.data[s.size], 0, size - s.size)
memset(&s[s.size], 0, size - s.size)
end
s.size = size
end

function memory.dealloc(s: span*)
function memory.dealloc(s: span<byte>*)
if s.size == 0 then
return
end
Expand All @@ -62,16 +56,16 @@ function memory.dealloc(s: span*)
s.size = 0
end

function memory.copy(dest: span, src: span)
function memory.copy(dest: span<byte>, src: span<byte>)
assert(dest.size >= src.size)
memcpy(dest.data, src.data, src.size)
end

function memory.move(dest: span, src: span)
function memory.move(dest: span<byte>, src: span<byte>)
assert(dest.size >= src.size)
memcpy(dest.data, src.data, src.size)
end

function memory.set(dest: span, x: byte)
function memory.set(dest: span<byte>, x: byte)
memset(dest.data, x, dest.size)
end
25 changes: 6 additions & 19 deletions lib/myarraytable.nelua
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,22 @@

!!strict


!!cinclude '<stdlib.h>'
!!cinclude '<string.h>'
require 'memory'

local function calloc(nmemb: csize, size: csize): pointer !cimport 'calloc' end
local function realloc(ptr: pointer, size: usize): pointer !cimport end
local function memset(s: pointer, c: int32, n: usize): pointer !cimport end
local function memcpy(dest: pointer, src: pointer, n: csize): pointer !cimport end

local T = @number
local T = @byte
local myarraytableobj !codename 'myarraytable' = @record{
len: usize,
cap: usize,
data: T[0]*
data: span<T>
}
local myarraytable = @myarraytableobj*

function myarraytable.create(): myarraytable
return @myarraytable(calloc(@csize(#myarraytableobj), 1))
return @myarraytable(memory.alloc(@usize(#myarraytableobj)))
end

function myarraytable:reserve(cap: usize)
local data = @T[0]*(realloc(self.data, (cap + 1_usize) * @usize(#T)))
memory.realloc(self.data, (cap + 1_usize) * @usize(#T))
if unlikely(not data) then
error 'myarraytable_reserve: not enough memory'
end
Expand All @@ -47,7 +40,7 @@ function myarraytable:resize_zero(n: usize)
local addn = n - self.len
if addn > 0 then
self:reserve(n)
memset(&self.data[self.len+1], 0, addn);
memory.memset(span{&self.data[self.len+1], addn}, 0)
self.len = n
end
end
Expand All @@ -63,12 +56,6 @@ function myarraytable:resize(n: usize, v: T)
end
end

function myarraytable:init(a: T[0]*, n: usize)
self:reserve(n)
memcpy(&self.data[1], &a[0], n * @usize(#T))
self.len = n
end

function myarraytable:push(v: T)
self.len = self.len + 1
if unlikely(self.len > self.cap) then
Expand Down
3 changes: 3 additions & 0 deletions nelua/astdefs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ astbuilder:register('ArrayType', {
astbuilder:register('PointerType', {
ntypes.Node:is_optional(), -- subtype typexpr
})
astbuilder:register('SpanType', {
ntypes.Node, -- subtype typexpr
})
astbuilder:register('MultipleType', {
stypes.array_of(ntypes.Node), -- typexprs
})
Expand Down
2 changes: 1 addition & 1 deletion nelua/cgenerator.lua
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ function visitors.ArrayIndex(context, node, emitter)
end
if objtype:is_arraytable() then
emitter:add(', ', index, ')')
elseif objtype:is_array() then
elseif objtype:is_array() or objtype:is_span() then
emitter:add('.data[', index, ']')
else
emitter:add('[', index, ']')
Expand Down
5 changes: 5 additions & 0 deletions nelua/syntaxdefs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,7 @@ local function get_parser(std)
enum_type /
arraytable_type /
array_type /
span_type /
pointer_type /
primtype /
ppexpr
Expand Down Expand Up @@ -514,6 +515,10 @@ local function get_parser(std)
{} 'arraytable' -> 'ArrayTableType'
eLANGLE etypexpr eRANGLE
) -> to_astnode
span_type <- (
{} 'span' -> 'SpanType'
eLANGLE etypexpr eRANGLE
) -> to_astnode
array_type <- (
{} 'array' -> 'ArrayType'
eLANGLE etypexpr eCOMMA typexpr_param_expr eRANGLE
Expand Down
15 changes: 14 additions & 1 deletion nelua/typechecker.lua
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,19 @@ function visitors.ArrayTableType(context, node)
attr.compconst = true
end

function visitors.SpanType(context, node)
local attr = node.attr
if attr.type then return end
local subtypenode = node:args()
context:traverse(subtypenode)
local subtype = subtypenode.attr.holdedtype
subtypenode:assertraisef(not subtype:is_void(), 'spans cannot be of "void" type')
local type = types.SpanType(node, subtype)
attr.type = primtypes.type
attr.holdedtype = type
attr.compconst = true
end

function visitors.ArrayType(context, node)
local attr = node.attr
if attr.type then return end
Expand Down Expand Up @@ -651,7 +664,7 @@ function visitors.ArrayIndex(context, node)
objtype = objtype.subtype
end

if objtype:is_arraytable() or objtype:is_array() then
if objtype:is_arraytable() or objtype:is_array() or objtype:is_span() then
local indextype = indexnode.attr.type
if indextype then
indexnode:assertraisef(indextype:is_integral(),
Expand Down
4 changes: 2 additions & 2 deletions nelua/typedefs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ local clongsize = math.max(cpusize, 4)

-- primitive types
local primtypes = {
isize = Type('isize', cpusize),
isize = Type.isize,
int8 = Type('int8', 1),
int16 = Type('int16', 2),
int32 = Type('int32', 4),
int64 = Type('int64', 8),
usize = Type('usize', cpusize),
usize = Type.usize,
uint8 = Type('uint8', 1),
uint16 = Type('uint16', 2),
uint32 = Type('uint32', 4),
Expand Down
41 changes: 38 additions & 3 deletions nelua/types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ function Type:is_cstring()
end

function Type:is_record()
return self.name == 'record'
return self.name == 'record' or self.name == 'span'
end

function Type:is_boolean()
Expand Down Expand Up @@ -223,6 +223,10 @@ function Type:is_pointer()
return self.name == 'pointer'
end

function Type:is_span()
return self.name == 'span'
end

function Type:is_generic_pointer()
return self.name == 'pointer' and self.subtype:is_void()
end
Expand Down Expand Up @@ -250,15 +254,17 @@ end
-- types used internally
Type.type = Type('type', 0)
Type.void = Type('void', 0)
Type.usize = Type('usize', cpusize)
Type.isize = Type('isize', cpusize)
Type.any = Type('any')

local function gencodename(self)
local hash = stringer.hash(self.key, 16)
return string.format('%s_%s', self.name, hash)
end

local function typeclass()
local type = class(Type)
local function typeclass(base)
local type = class(base or Type)
type.unary_operators = {}
type.binary_operators = {}
metamagic.setmetaindex(type.unary_operators, Type.unary_operators)
Expand Down Expand Up @@ -593,6 +599,33 @@ function PointerType:__tostring()
end
end

--------------------------------------------------------------------------------
local SpanType = typeclass(RecordType)

function SpanType:_init(node, subtype)
local fields = {
{name = 'data', type = PointerType(node, subtype)},
{name = 'size', type = Type.usize}
}
local size = compute_record_size(fields)
self.fields = fields
Type._init(self, 'span', size, node)
self.key = 'span_' .. subtype.codename
self.codename = gencodename(self)
self.metatype = MetaType()
self.subtype = subtype
end

function SpanType:is_equal(type)
return type.name == self.name and
getmetatable(type) == getmetatable(self) and
type.subtype == self.subtype
end

function SpanType:__tostring()
return sstream(self.name, '<', self.subtype, '>'):tostring()
end

local types = {
Type = Type,
ArrayTableType = ArrayTableType,
Expand All @@ -602,5 +635,7 @@ local types = {
MultipleType = MultipleType,
RecordType = RecordType,
PointerType = PointerType,
SpanType = SpanType,
}

return types
5 changes: 3 additions & 2 deletions nelua/utils/console.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ local colors = require 'term.colors'

local console = {}

do -- check if colored output is supported
do --luacov:disable
-- check if colored output is supported
local isatty = io.type(io.stdout) == 'file' and term.isatty and term.isatty(io.stdout)
if not isatty then
colors = tabler.copy(colors)
for k,_ in pairs(colors) do
colors[k] = ''
end
end
end
end --luacov:enable

console.colors = colors

Expand Down
35 changes: 16 additions & 19 deletions nelua/utils/memoize.lua
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@
local tabler = require 'nelua.utils.tabler'

local cache = {}
local function memoize(f)
local cache = {}

local function cacheget(f, params)
local cachef = cache[f]
if cachef then
for cparams,cres in pairs(cachef) do
if tabler.deepcompare(cparams, params) then
return tabler.unpack(cres, 1, cres.n)
return function(...)
local params = tabler.pack(...)
local cachef = cache[f]
if cachef then
for cparams,cres in pairs(cachef) do
if tabler.deepcompare(cparams, params) then
return tabler.unpack(cres, 1, cres.n)
end
end
else
cachef = {}
cache[f] = cachef
end
else
cachef = {}
cache[f] = cachef
end
local res = table.pack(f(tabler.unpack(params, 1, params.n)))
cachef[params] = res
return tabler.unpack(res, 1, res.n)
end

local function memoize(f)
return function(...)
return cacheget(f, table.pack(...))
local res = table.pack(f(tabler.unpack(params, 1, params.n)))
cachef[params] = res
return tabler.unpack(res, 1, res.n)
end
end

Expand Down
7 changes: 7 additions & 0 deletions spec/02-syntaxdefs_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1403,6 +1403,13 @@ describe("type expression", function()
{ n.IdDecl{'p', nil, n.PointerType{n.PointerType{n.Type{'integer'}}}}}
}}})
end)
it("span type", function()
assert.parse_ast(nelua_parser, "local p: span<integer>",
n.Block{{
n.VarDecl{'local', nil,
{ n.IdDecl{'p', nil, n.SpanType{n.Type{'integer'}}}}
}}})
end)
it("complex types", function()
assert.parse_ast(nelua_parser, "local p: integer*[10]*[10]",
n.Block{{
Expand Down

0 comments on commit 60f3f2f

Please sign in to comment.