From ec2e007c83aaa5f74c97017ef165eafd6a25d44d Mon Sep 17 00:00:00 2001 From: StunxFS Date: Mon, 25 Dec 2023 18:03:21 -0400 Subject: [PATCH] self-host: support slice types --- lib/rivet/src/ast/Sym.ri | 36 +++++++++++++++++++++++++++++++-- lib/rivet/src/ast/Type.ri | 23 +++++++++++++++++++-- lib/rivet/src/ast/TypeInfo.ri | 29 ++++++++++++++++---------- lib/rivet/src/checker/exprs.ri | 12 +++++------ lib/rivet/src/checker/mod.ri | 2 +- lib/rivet/src/checker/stmts.ri | 2 +- lib/rivet/src/checker/types.ri | 10 +++++++-- lib/rivet/src/parser/types.ri | 11 +++++++--- lib/rivet/src/resolver/types.ri | 10 +++++++-- 9 files changed, 105 insertions(+), 30 deletions(-) diff --git a/lib/rivet/src/ast/Sym.ri b/lib/rivet/src/ast/Sym.ri index 083ef6d90..9c3956d89 100644 --- a/lib/rivet/src/ast/Sym.ri +++ b/lib/rivet/src/ast/Sym.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 std/traits; @@ -150,6 +150,38 @@ pub struct SymRef < Sym { #[boxed] pub struct Module < Sym { + pub func add_or_get_slice(mut self, elem_type: Type, is_mut: bool) -> TypeSym { + unique_name := if is_mut { "[:]mut " } else { "[:]" }.concat(elem_type.to_qualstring()); + if type_sym := self.scope.find(unique_name) { + return @as(TypeSym, type_sym); + } + mut type_sym := TypeSym( + is_public: true, + name: unique_name, + info: .DynArray(elem_type, is_mut), + fields: +[ + Field( + name: "len", is_public: true, + type: .Basic(self.scope.find_type_symbol_by_index_or_panic(11)) + ) + ] + ); + type_sym.scope.add(Func( + name: "to_dynamic_array", + is_public: true, + is_method: true, + self_is_ptr: true, + self_type: .Basic(type_sym), + ret_type: .Basic(self.add_or_get_dyn_array(elem_type, is_mut)), + has_body: true + )) catch {}; + if slice_sym := self.scope.find("core")?.scope.find("Slice") { + type_sym.scope.add(slice_sym.scope.find("is_empty")?) catch {}; + } + self.scope.add(type_sym) catch {}; + return type_sym; + } + pub func add_or_get_array(mut self, elem_typ: Type, size: uint, is_mut: bool) -> TypeSym { unique_name := if is_mut { "[{}]mut {}" diff --git a/lib/rivet/src/ast/Type.ri b/lib/rivet/src/ast/Type.ri index 3375e422a..9705d60d4 100644 --- a/lib/rivet/src/ast/Type.ri +++ b/lib/rivet/src/ast/Type.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 std/traits; @@ -51,6 +51,12 @@ pub enum Type < traits.Stringable { mut sym: TypeSym; pos: token.Pos; }, + Slice { + mut inner: Type; + is_mut: bool; + mut sym: TypeSym; + pos: token.Pos; + }, DynArray { mut inner: Type; is_mut: bool; @@ -124,6 +130,9 @@ pub enum Type < traits.Stringable { } .Tuple(unaliased_types, tuple_data.sym) }, + .Slice(mut slice_data) -> .Slice( + slice_data.inner.unalias() ?? slice_data.inner, slice_data.is_mut + ), .DynArray(mut dyn_array_data) -> .DynArray( dyn_array_data.inner.unalias() ?? dyn_array_data.inner, dyn_array_data.is_mut ), @@ -167,6 +176,7 @@ pub enum Type < traits.Stringable { .Option(option) -> option.inner.symbol(), .Tuple(tuple_data) -> tuple_data.sym, .Variadic(variadic_data) -> variadic_data.sym, + .Slice(slice_data) -> slice_data.sym, .DynArray(dyn_array_data) -> dyn_array_data.sym, .Array(array_data) -> array_data.sym, .Pointer(pointer_data) -> pointer_data.inner.symbol(), @@ -238,6 +248,7 @@ pub enum Type < traits.Stringable { .Result(res_t) -> res_t.pos, .Tuple(tuple_t) -> tuple_t.pos, .Variadic(variadic_t) -> variadic_t.pos, + .Slice(slice_t) -> slice_t.pos, .DynArray(dyn_array_t) -> dyn_array_t.pos, .Array(arr_t) -> arr_t.pos, .Pointer(ptr_t) -> ptr_t.pos, @@ -264,6 +275,8 @@ pub enum Type < traits.Stringable { .Tuple(tuple_lhs) if rhs is .Tuple(tuple_rhs) -> tuple_lhs == tuple_rhs, .Variadic(variadic_lhs) if rhs is .Variadic(variadic_rhs) -> variadic_lhs.inner == variadic_rhs.inner, + .Slice(slice_lhs) if rhs is .Slice(slice_rhs) -> + slice_lhs.inner == slice_rhs.inner && slice_lhs.is_mut == slice_rhs.is_mut, .DynArray(dyn_array_lhs) if rhs is .DynArray(dyn_array_rhs) -> dyn_array_lhs.inner == dyn_array_rhs.inner && dyn_array_lhs.is_mut == dyn_array_rhs.is_mut, .Array(array_lhs) if rhs is .Array(array_rhs) -> @@ -346,6 +359,11 @@ pub enum Type < traits.Stringable { sb.to_string() }, .Variadic(variadic_data) -> "...".concat(variadic_data.inner.to_string_(qualstr)), + .Slice(slice_data) -> if slice_data.is_mut { + "[:]mut" + } else { + "[:]" + }.concat(slice_data.inner.to_string_(qualstr)), .DynArray(dyn_array_data) -> if dyn_array_data.is_mut { "[]mut" } else { @@ -561,6 +579,7 @@ extend Env { } else { self.type_size(enum_info.underlying_type) }, + .Slice -> (self.pointer_size * 3, self.pointer_size), .DynArray -> self.type_symbol_size(self.dyn_array_sym, is_raw), .Array(array_info) -> { (elem_size, elem_align) := self.type_size(array_info.elem_type); diff --git a/lib/rivet/src/ast/TypeInfo.ri b/lib/rivet/src/ast/TypeInfo.ri index fec2b616f..ccd265311 100644 --- a/lib/rivet/src/ast/TypeInfo.ri +++ b/lib/rivet/src/ast/TypeInfo.ri @@ -1,9 +1,17 @@ -// 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 std/traits; +pub struct EnumVariant { + pub name: string; + pub value: int; + pub has_type: bool; + pub mut type: Type; + pub has_fields: bool; +} + pub enum TypeInfo < traits.Stringable { Invalid, Placeholder, @@ -34,6 +42,11 @@ pub enum TypeInfo < traits.Stringable { is_mut: bool; has_contains_method: bool; }, + Slice { + elem_type: Type; + is_mut: bool; + has_contains_method: bool; + }, DynArray { elem_type: Type; is_mut: bool; @@ -141,8 +154,9 @@ pub enum TypeInfo < traits.Stringable { } #[inline] - pub func is_mut_arr_or_dyn_array(self) -> bool { + pub func is_mut_array(self) -> bool { return match self { + .Slice(slice) -> slice.is_mut, .Array(arr) -> arr.is_mut, .DynArray(vec) -> vec.is_mut, else -> false @@ -179,6 +193,7 @@ pub enum TypeInfo < traits.Stringable { .String -> "string", .Func -> "func", .Alias -> "alias", + .Slice -> "slice", .Array -> "array", .DynArray -> "dynamic array", .Tuple -> "tuple", @@ -192,11 +207,3 @@ pub enum TypeInfo < traits.Stringable { }; } } - -pub struct EnumVariant { - pub name: string; - pub value: int; - pub has_type: bool; - pub mut type: Type; - pub has_fields: bool; -} diff --git a/lib/rivet/src/checker/exprs.ri b/lib/rivet/src/checker/exprs.ri index 63dd2f11d..0179276e8 100644 --- a/lib/rivet/src/checker/exprs.ri +++ b/lib/rivet/src/checker/exprs.ri @@ -347,7 +347,7 @@ extend Checker { if value_sym.info is .Array(array_info) { size = array_info.size; } - is_mut = value_sym.info.is_mut_arr_or_dyn_array(); + is_mut = value_sym.info.is_mut_array(); } else if !self.expected_type.is_void() { has_expected_type = true; value_type = self.expected_type; @@ -512,16 +512,16 @@ extend Checker { ); } index.type = match left_sym.info { - .Array, .DynArray -> { + .Array, .DynArray, .Slice -> { elem_type := left_sym.info.elem_type()?; if index.index is .Range { - is_mut := left_sym.info.is_mut_arr_or_dyn_array(); - if left_sym.info is .DynArray { + is_mut := left_sym.info.is_mut_array(); + if left_sym.info is .Slice { index.left_type } else { - .DynArray( + .Slice( elem_type, is_mut, - self.env.universe.add_or_get_dyn_array(elem_type, is_mut) + self.env.universe.add_or_get_slice(elem_type, is_mut) ) } } else { diff --git a/lib/rivet/src/checker/mod.ri b/lib/rivet/src/checker/mod.ri index dea9b2ba1..77b8df986 100644 --- a/lib/rivet/src/checker/mod.ri +++ b/lib/rivet/src/checker/mod.ri @@ -320,7 +320,7 @@ pub struct Checker { } self.check_expr_is_mut(index.left); expr_sym := index.left_type.symbol()?; - if !expr_sym.info.is_mut_arr_or_dyn_array() { + if !expr_sym.info.is_mut_array() { report.error( "cannot modify elements of an immutable {}".fmt(expr_sym.info), index.pos diff --git a/lib/rivet/src/checker/stmts.ri b/lib/rivet/src/checker/stmts.ri index 71c561be7..f4d421670 100644 --- a/lib/rivet/src/checker/stmts.ri +++ b/lib/rivet/src/checker/stmts.ri @@ -57,7 +57,7 @@ extend Checker { if for_stmt.values.len == 1 { value0 := for_stmt.values[0]; if value0.is_mut { - if !iterable_sym.info.is_mut_arr_or_dyn_array() { + if !iterable_sym.info.is_mut_array() { report.error( "cannot modify immutable {}".fmt(iterable_sym.info), for_stmt.iterable.position() diff --git a/lib/rivet/src/checker/types.ri b/lib/rivet/src/checker/types.ri index 8c13e5104..5e831130e 100644 --- a/lib/rivet/src/checker/types.ri +++ b/lib/rivet/src/checker/types.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 ../ast; @@ -155,6 +155,12 @@ extend Checker { return true; } }, + .Slice(slice_lhs) if got_sym.info is .Slice(slice_rhs) -> { + if slice_lhs.is_mut && !slice_rhs.is_mut { + return false; + } + return slice_lhs.elem_type == slice_rhs.elem_type; + }, .Array(array_info) if got_sym.info is .Array(array_info2) -> { if array_info.is_mut && !array_info2.is_mut { return false; diff --git a/lib/rivet/src/parser/types.ri b/lib/rivet/src/parser/types.ri index d248536f2..6b4619358 100644 --- a/lib/rivet/src/parser/types.ri +++ b/lib/rivet/src/parser/types.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 ../ast; @@ -55,13 +55,18 @@ extend Parser { self.accept(.Lbracket) -> { // arrays or dynamic arrays if self.tok.kind != .Rbracket { - // indexable pointers if self.accept(.Amp) { + // indexable pointers self.expect(.Rbracket); is_mut := self.accept(.KwMut); .Pointer( self.parse_type(), is_mut, true, pos: pos + self.prev_tok.pos ) + } else if self.accept(.Colon) { + // slice + self.expect(.Rbracket); + is_mut := self.accept(.KwMut); + .Slice(self.parse_type(), is_mut, pos: pos + self.prev_tok.pos) } else { // array size := self.parse_expr(); diff --git a/lib/rivet/src/resolver/types.ri b/lib/rivet/src/resolver/types.ri index ecefe002c..86120fc79 100644 --- a/lib/rivet/src/resolver/types.ri +++ b/lib/rivet/src/resolver/types.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 ../ast; @@ -21,6 +21,12 @@ extend Resolver { } else { false }, + .Slice(mut slice) -> if self.resolve_type(slice.inner) { + slice.sym = self.env.universe.add_or_get_slice(slice.inner, slice.is_mut); + true + } else { + false + }, .DynArray(mut dyn_arr) -> if self.resolve_type(dyn_arr.inner) { dyn_arr.sym = self.env.universe.add_or_get_dyn_array(dyn_arr.inner, dyn_arr.is_mut); true