Skip to content

Commit

Permalink
bootstrap: add slice type
Browse files Browse the repository at this point in the history
  • Loading branch information
StunxFS committed Dec 25, 2023
1 parent 1edc63a commit b37ba53
Show file tree
Hide file tree
Showing 11 changed files with 118 additions and 35 deletions.
23 changes: 10 additions & 13 deletions lib/core/src/DynArray.ri
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (C) 2023-present Jose Mendoza - All rights reserved. Use of this
// source code is governed by an MIT license that can be found in the LICENSE
// Copyright (C) 2023-present Jose Mendoza - All rights reserved. Use of this
// source code is governed by an MIT license that can be found in the LICENSE
// file.

#[boxed]
Expand All @@ -8,7 +8,6 @@ struct DynArray {
elem_size: uint;
mut len: uint;
mut cap: uint;
is_ref: bool;

#[unsafe; inline]
func new(elem_size: uint, cap: uint) -> Self {
Expand Down Expand Up @@ -43,7 +42,7 @@ struct DynArray {

#[unsafe; inline]
func from_array_no_alloc(arr: rawptr, elem_size: uint, len: uint) -> Self {
return Self(arr, elem_size, len, len, is_ref: true);
return Self(arr, elem_size, len, len);
}

#[unsafe; inline]
Expand Down Expand Up @@ -178,24 +177,24 @@ struct DynArray {
self.cap = cap;
}

func slice(self, start: uint, end: uint) -> Self {
func slice(self, start: uint, end: uint) -> Slice {
if start > end || end > self.len {
runtime_error(
"slice index out of range (range: {}..{}, len: {})", start, end, self.len
"slice index [{}:{}] out of range (len: {})", start, end, self.len
);
}
len := end - start;
if len == self.len {
return self;
return Slice(self.ptr, self.elem_size, self.len);
}
return Self(
return Slice(
unsafe { @ptr_add(@as([&]mut uint8, self.ptr), start * self.elem_size) },
self.elem_size, len, len, true
self.elem_size, len
);
}

#[inline]
func slice_from(self, start: uint) -> Self {
func slice_from(self, start: uint) -> Slice {
return self.slice(start, self.len);
}

Expand All @@ -212,9 +211,7 @@ struct DynArray {

func __drop__(self) {
unsafe {
if !self.is_ref {
mem_dealloc(self.ptr);
}
mem_dealloc(self.ptr);
}
}
}
12 changes: 6 additions & 6 deletions lib/core/src/array.c.ri
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (C) 2023-present Jose Mendoza - All rights reserved. Use of this
// source code is governed by an MIT license that can be found in the LICENSE
// Copyright (C) 2023-present Jose Mendoza - All rights reserved. Use of this
// source code is governed by an MIT license that can be found in the LICENSE
// file.

import c/libc;
Expand Down Expand Up @@ -29,19 +29,19 @@ func array_ne(arr: rawptr, other_arr: rawptr, len: uint) -> bool {
return !array_eq(arr, other_arr, len);
}

func array_slice(arr: rawptr, elem_size: uint, size: uint, start: uint, end: uint) -> DynArray {
func array_slice(arr: rawptr, elem_size: uint, size: uint, start: uint, end: uint) -> Slice {
if start > end || end > size {
runtime_error("slice index out of range (range: {}..{}, len: {})", start, end, size);
runtime_error("slice index [{}:{}] out of range (len: {})", start, end, size);
}
len := end - start;
return unsafe {
DynArray.from_array_no_alloc(
Slice(
if len == size { arr } else { @ptr_add(arr, start * elem_size) }, elem_size, len
)
};
}

#[inline]
func array_slice_from(arr: rawptr, elem_size: uint, size: uint, start: uint) -> DynArray {
func array_slice_from(arr: rawptr, elem_size: uint, size: uint, start: uint) -> Slice {
return array_slice(arr, elem_size, size, start, size);
}
2 changes: 2 additions & 0 deletions rivetc/src/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,8 @@ def type_symbol_size(self, sy):
elif sy.kind == sym.TypeKind.Array:
elem_size, elem_align = self.type_size(sy.info.elem_typ)
size, align = int(sy.info.size.lit) * elem_size, elem_align
elif sy.kind == sym.TypeKind.Slice:
size, align = self.pointer_size * 3, self.pointer_size
elif sy.is_boxed():
size, align = self.pointer_size, self.pointer_size
elif sy.kind in (sym.TypeKind.Struct, sym.TypeKind.Tuple):
Expand Down
14 changes: 8 additions & 6 deletions rivetc/src/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -872,19 +872,17 @@ def check_expr(self, expr):
f"expected unsigned integer value, found `{idx_t}`",
expr.index.pos
)
if left_sym.kind in (TypeKind.Array, TypeKind.DynArray):
if left_sym.kind in (TypeKind.Array, TypeKind.DynArray, TypeKind.Slice):
if isinstance(expr.index, ast.RangeExpr):
if left_sym.kind == TypeKind.DynArray:
if left_sym.kind == TypeKind.Slice:
expr.typ = expr.left_typ
else:
expr.typ = type.DynArray(
expr.typ = type.Slice(
left_sym.info.elem_typ, left_sym.info.is_mut
)
expr.typ.sym = self.comp.universe.add_or_get_dyn_array(
expr.typ.sym = self.comp.universe.add_or_get_slice(
left_sym.info.elem_typ, left_sym.info.is_mut
)
elif left_sym.kind == TypeKind.DynArray:
expr.typ = left_sym.info.elem_typ
else:
expr.typ = left_sym.info.elem_typ
else:
Expand Down Expand Up @@ -1867,6 +1865,10 @@ def check_compatible_types(self, got, expected):
if exp_sym.info.is_mut and not got_sym.info.is_mut:
return False
return exp_sym.info.elem_typ == got_sym.info.elem_typ
elif exp_sym.kind == TypeKind.Slice and got_sym.kind == TypeKind.Slice:
if exp_sym.info.is_mut and not got_sym.info.is_mut:
return False
return exp_sym.info.elem_typ == got_sym.info.elem_typ
elif exp_sym.kind == TypeKind.Tuple and got_sym.kind == TypeKind.Tuple:
if len(exp_sym.info.types) != len(got_sym.info.types):
return False
Expand Down
14 changes: 10 additions & 4 deletions rivetc/src/codegen/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1687,13 +1687,16 @@ def gen_expr(self, expr, custom_tmp = None):
ir.InstKind.Call,
[ir.Name("_R4core6string2atM"), left, idx], expr_typ_ir
)
elif s.kind == TypeKind.DynArray:
elif s.kind in (TypeKind.DynArray, TypeKind.Slice):
method_name = "_R4core5Slice3getM" if s.kind == TypeKind.Slice else "_R4core8DynArray3getM"
expr_typ_ir2 = expr_typ_ir.ptr()
if s.kind == TypeKind.Slice and not isinstance(left.typ, type.Ptr):
left = ir.Inst(ir.InstKind.GetPtr, [left], left.typ.ptr())
value = ir.Inst(
ir.InstKind.Cast, [
ir.Inst(
ir.InstKind.Call,
[ir.Name("_R4core8DynArray3getM"), left, idx]
[ir.Name(method_name), left, idx]
), expr_typ_ir2
], expr_typ_ir2
)
Expand Down Expand Up @@ -2442,14 +2445,15 @@ def gen_left_assign(self, expr, right, assign_op):
left_ir_typ = self.ir_type(expr.left_typ)
left_sym = expr.left_typ.symbol()
sym_is_boxed = left_sym.is_boxed()
if left_sym.kind == TypeKind.DynArray and assign_op == Kind.Assign:
if left_sym.kind in (TypeKind.DynArray, TypeKind.Slice) and assign_op == Kind.Assign:
rec = self.gen_expr_with_cast(expr.left_typ, expr.left)
if not isinstance(left_ir_typ, ir.Pointer):
rec = ir.Inst(ir.InstKind.GetPtr, [rec])
expr_right = self.gen_expr_with_cast(right.typ, right)
val_sym = right.typ.symbol()
method_name = "_R4core5Slice3setM" if left_sym.kind == TypeKind.Slice else "_R4core8DynArray3setM"
self.cur_func.add_call(
"_R4core8DynArray3setM", [
method_name, [
rec,
self.gen_expr(expr.index),
ir.Inst(ir.InstKind.GetPtr, [expr_right])
Expand Down Expand Up @@ -2977,6 +2981,8 @@ def ir_type(self, typ, gen_self_arg = False):
arg_t = ir.Pointer(arg_t)
args.append(arg_t)
return ir.Function(args, self.ir_type(typ.ret_typ))
elif isinstance(typ, type.Slice):
return ir.SLICE_T
elif isinstance(typ, type.Array):
return ir.Array(self.ir_type(typ.typ), typ.size)
elif isinstance(typ, type.DynArray):
Expand Down
3 changes: 3 additions & 0 deletions rivetc/src/codegen/cg_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ def mangle_symbol(s):
name = f"{len(name)}{name}"
res.insert(0, name)
s.mangled_name = name
elif s.kind == TypeKind.Slice:
res.insert(0, "4core5Slice")
s.mangled_name = "_R4core5Slice"
elif s.kind == TypeKind.DynArray:
res.insert(0, "4core8DynArray")
s.mangled_name = "_R4core8DynArray"
Expand Down
3 changes: 2 additions & 1 deletion rivetc/src/codegen/ir.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def __eq__(self, other):
Float64_T = Type("float64")
INT_T = Type("ri_int")
UINT_T = Type("ri_uint")
SLICE_T = Type("_R4core5Slice")
DYN_ARRAY_T = Type("_R4core8DynArray")
STRING_T = Type("_R4core6string")
TEST_T = Type("_R4core4Test")
Expand Down Expand Up @@ -616,4 +617,4 @@ def __repr__(self):
return f"{self.kind} {', '.join([str(arg) for arg in self.args])}"

def __str__(self):
return self.__repr__()
return self.__repr__()
7 changes: 6 additions & 1 deletion rivetc/src/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -1444,11 +1444,16 @@ def parse_type(self):
elif self.accept(Kind.Lbracket):
# arrays or dynamic arrays
if self.tok.kind != Kind.Rbracket:
# indexable pointers
if self.accept(Kind.Amp):
# indexable pointers
self.expect(Kind.Rbracket)
is_mut = self.accept(Kind.KwMut)
return type.Ptr(self.parse_type(), is_mut, True)
elif self.accept(Kind.Colon):
# slices
self.expect(Kind.Rbracket)
is_mut = self.accept(Kind.KwMut)
return type.Slice(self.parse_type(), is_mut)
# array
size = self.parse_expr()
self.expect(Kind.Rbracket)
Expand Down
8 changes: 8 additions & 0 deletions rivetc/src/resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,14 @@ def resolve_type(self, typ):
)
)
return True
elif isinstance(typ, type.Slice):
if self.resolve_type(typ.typ):
typ.resolve(
self.comp.universe.add_or_get_slice(
typ.typ, typ.is_mut
)
)
return True
elif isinstance(typ, type.Tuple):
res = False
for t in typ.types:
Expand Down
39 changes: 37 additions & 2 deletions rivetc/src/sym.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,32 @@ def is_core_mod(self):
return self.ref.is_core_mod()

class Mod(Sym):
def add_or_get_slice(self, elem_typ, is_mut = False):
if is_mut:
unique_name = f"[:]mut {elem_typ.qualstr()}"
else:
unique_name = f"[:]{elem_typ.qualstr()}"
if sym := self.find(unique_name):
return sym
from .type import Type as type_Type
slice_sym = Type(
True, unique_name, TypeKind.Slice, info = SliceInfo(elem_typ, is_mut),
fields = [
Field("len", False, True, type_Type(self[14]))
]
)
slice_sym.add(
Func(
ABI.Rivet, True, False, False, True, False, "to_dynamic_array", [],
type_Type(slice_sym), False, True, NO_POS, False, False,
type_Type(slice_sym)
)
)
if core_slice_sym := self.find("core").find("Slice"):
if is_empty_m := core_slice_sym.find("is_empty"):
slice_sym.add(is_empty_m)
return self.add_and_return(slice_sym)

def add_or_get_array(self, elem_typ, size, is_mut = False):
if is_mut:
unique_name = f"[{size}]mut {elem_typ.qualstr()}"
Expand All @@ -257,7 +283,7 @@ def add_or_get_dyn_array(self, elem_typ, is_mut = False):
return sym
from .type import Type as type_Type
dyn_array_sym = Type(
True, unique_name, TypeKind.DynArray, info = info(elem_typ, is_mut),
True, unique_name, TypeKind.DynArray, info = DynArrayInfo(elem_typ, is_mut),
fields = [
Field("len", False, True, type_Type(self[14])),
Field("cap", False, True, type_Type(self[14]))
Expand Down Expand Up @@ -357,6 +383,7 @@ class TypeKind(Enum):
Float64 = auto_enum()
String = auto_enum()
Alias = auto_enum()
Slice = auto_enum()
Array = auto_enum()
DynArray = auto_enum()
Tuple = auto_enum()
Expand Down Expand Up @@ -417,6 +444,8 @@ def __repr__(self):
return "string"
elif self == TypeKind.Alias:
return "alias"
elif self == TypeKind.Slice:
return "slice"
elif self == TypeKind.Array:
return "array"
elif self == TypeKind.DynArray:
Expand Down Expand Up @@ -450,7 +479,13 @@ def __init__(self, elem_typ, size, is_mut):
self.is_mut = is_mut
self.has_contains_method = False

class info:
class DynArrayInfo:
def __init__(self, elem_typ, is_mut):
self.elem_typ = elem_typ
self.is_mut = is_mut
self.has_contains_method = False

class SliceInfo:
def __init__(self, elem_typ, is_mut):
self.elem_typ = elem_typ
self.is_mut = is_mut
Expand Down
28 changes: 26 additions & 2 deletions rivetc/src/type.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def store(self, val):

class TBase:
def symbol(self):
if isinstance(self, (DynArray, Array, Tuple, Variadic)):
if isinstance(self, (DynArray, Array, Tuple, Variadic, Slice)):
return self.sym
elif isinstance(self, Func):
return self.info()
Expand All @@ -33,7 +33,7 @@ def unalias(self):
elif isinstance(self, Tuple):
for t in self.types:
t.unalias()
elif isinstance(self, (Array, DynArray, Ptr, Variadic)):
elif isinstance(self, (Array, DynArray, Ptr, Variadic, Slice)):
self.typ.unalias()
elif isinstance(self, Type):
if self.is_resolved() and self.sym.kind == TypeKind.Alias:
Expand Down Expand Up @@ -152,6 +152,30 @@ def __str__(self):
return f"[]mut {self.typ}"
return f"[]{self.typ}"

class Slice(TBase):
def __init__(self, typ, is_mut):
self.typ = typ
self.is_mut = is_mut
self.sym = None

def resolve(self, sym):
self.sym = sym

def qualstr(self):
if self.is_mut:
return f"[:]mut {self.typ.qualstr()}"
return f"[:]{self.typ.qualstr()}"

def __eq__(self, other):
if not isinstance(other, DynArray):
return False
return self.typ == other.typ and self.is_mut == other.is_mut

def __str__(self):
if self.is_mut:
return f"[:]mut {self.typ}"
return f"[:]{self.typ}"

class Variadic(TBase):
def __init__(self, typ):
self.typ = typ
Expand Down

0 comments on commit b37ba53

Please sign in to comment.