diff --git a/lib/core/src/DynArray.ri b/lib/core/src/DynArray.ri index 0c24c3f5d..5049673ef 100644 --- a/lib/core/src/DynArray.ri +++ b/lib/core/src/DynArray.ri @@ -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] @@ -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 { @@ -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] @@ -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); } @@ -212,9 +211,7 @@ struct DynArray { func __drop__(self) { unsafe { - if !self.is_ref { - mem_dealloc(self.ptr); - } + mem_dealloc(self.ptr); } } } diff --git a/lib/core/src/array.c.ri b/lib/core/src/array.c.ri index 45fd09b36..1bc2ed653 100644 --- a/lib/core/src/array.c.ri +++ b/lib/core/src/array.c.ri @@ -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; @@ -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); } diff --git a/rivetc/src/__init__.py b/rivetc/src/__init__.py index ef5efea28..9a9350d19 100644 --- a/rivetc/src/__init__.py +++ b/rivetc/src/__init__.py @@ -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): diff --git a/rivetc/src/checker.py b/rivetc/src/checker.py index 4775d8db5..37c506829 100644 --- a/rivetc/src/checker.py +++ b/rivetc/src/checker.py @@ -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: @@ -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 diff --git a/rivetc/src/codegen/__init__.py b/rivetc/src/codegen/__init__.py index dc9ee82de..e7c87b016 100644 --- a/rivetc/src/codegen/__init__.py +++ b/rivetc/src/codegen/__init__.py @@ -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 ) @@ -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]) @@ -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): diff --git a/rivetc/src/codegen/cg_utils.py b/rivetc/src/codegen/cg_utils.py index 42f7f72bf..b269a1ccb 100644 --- a/rivetc/src/codegen/cg_utils.py +++ b/rivetc/src/codegen/cg_utils.py @@ -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" diff --git a/rivetc/src/codegen/ir.py b/rivetc/src/codegen/ir.py index eafac43cb..7285cb01a 100644 --- a/rivetc/src/codegen/ir.py +++ b/rivetc/src/codegen/ir.py @@ -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") @@ -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__() \ No newline at end of file + return self.__repr__() diff --git a/rivetc/src/parser.py b/rivetc/src/parser.py index 466624dd0..2ed377872 100644 --- a/rivetc/src/parser.py +++ b/rivetc/src/parser.py @@ -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) diff --git a/rivetc/src/resolver.py b/rivetc/src/resolver.py index 0901f1e4a..8dd0ba288 100644 --- a/rivetc/src/resolver.py +++ b/rivetc/src/resolver.py @@ -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: diff --git a/rivetc/src/sym.py b/rivetc/src/sym.py index e729cd570..830dc4aa0 100644 --- a/rivetc/src/sym.py +++ b/rivetc/src/sym.py @@ -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()}" @@ -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])) @@ -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() @@ -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: @@ -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 diff --git a/rivetc/src/type.py b/rivetc/src/type.py index a311e0915..37542327b 100644 --- a/rivetc/src/type.py +++ b/rivetc/src/type.py @@ -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() @@ -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: @@ -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