From 44d6e8a27294e5ca7300ab11900011b73d9336d4 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Tue, 21 Jul 2026 01:55:56 +0200 Subject: Implement slices --- boot/ast.cc | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++ boot/evaluator.cc | 12 ++++++- boot/lexer.ll | 3 ++ boot/name_analysis.cc | 40 +++++++++++++++++++++ boot/parser.yy | 7 ++++ boot/symbol.cc | 21 +++++++++++ boot/type_check.cc | 5 +++ 7 files changed, 183 insertions(+), 1 deletion(-) (limited to 'boot') diff --git a/boot/ast.cc b/boot/ast.cc index 9b3fbe4..3727aba 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -26,6 +26,11 @@ namespace elna::boot __builtin_unreachable(); } + void empty_visitor::visit(slice_type_expression *) + { + __builtin_unreachable(); + } + void empty_visitor::visit(pointer_type_expression *) { __builtin_unreachable(); @@ -126,6 +131,11 @@ namespace elna::boot __builtin_unreachable(); } + void empty_visitor::visit(slicing_expression *) + { + __builtin_unreachable(); + } + void empty_visitor::visit(traits_expression *) { __builtin_unreachable(); @@ -363,6 +373,11 @@ namespace elna::boot expression->base().accept(this); } + void walking_visitor::visit(slice_type_expression *expression) + { + expression->base().accept(this); + } + void walking_visitor::visit(pointer_type_expression *expression) { expression->base().accept(this); @@ -420,6 +435,13 @@ namespace elna::boot } } + void walking_visitor::visit(slicing_expression *expression) + { + expression->base().accept(this); + expression->offset().accept(this); + expression->length().accept(this); + } + void walking_visitor::visit(traits_expression *trait) { if (!trait->arguments.empty()) @@ -549,6 +571,11 @@ namespace elna::boot return nullptr; } + slice_type_expression *type_expression::is_slice() + { + return nullptr; + } + array_type_expression *type_expression::is_array() { return nullptr; @@ -605,6 +632,32 @@ namespace elna::boot return *m_base; } + slice_type_expression::slice_type_expression(const source_position position, + type_expression *base) + : node(position), m_base(base) + { + } + + slice_type_expression::~slice_type_expression() + { + delete m_base; + } + + void slice_type_expression::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + slice_type_expression *slice_type_expression::is_slice() + { + return this; + } + + type_expression& slice_type_expression::base() + { + return *m_base; + } + pointer_type_expression::pointer_type_expression(const source_position position, type_expression *base) : node(position), m_base(base) @@ -1016,6 +1069,44 @@ namespace elna::boot } } + slicing_expression::slicing_expression(const source_position position, + expression *base, expression *offset, expression *length) + : node(position), m_base(base), m_offset(offset), m_length(length) + { + } + + void slicing_expression::accept(parser_visitor *visitor) + { + visitor->visit(this); + } + + slicing_expression *slicing_expression::is_slicing() + { + return this; + } + + slicing_expression::~slicing_expression() + { + delete m_base; + delete m_offset; + delete m_length; + } + + expression& slicing_expression::base() + { + return *this->m_base; + } + + expression& slicing_expression::offset() + { + return *this->m_offset; + } + + expression& slicing_expression::length() + { + return *this->m_length; + } + named_expression::named_expression(const source_position position, const std::string& name) : node(position), name(name) { @@ -1339,6 +1430,11 @@ namespace elna::boot return nullptr; } + slicing_expression *designator_expression::is_slicing() + { + return nullptr; + } + designator_expression& assign_statement::lvalue() { return *m_lvalue; diff --git a/boot/evaluator.cc b/boot/evaluator.cc index 7eb612b..990f358 100644 --- a/boot/evaluator.cc +++ b/boot/evaluator.cc @@ -399,7 +399,8 @@ namespace elna::boot { type const resolved = resolve_underlying_type(subject); - if (is_primitive_type(resolved, "Int")) + if (is_primitive_type(resolved, "Int") + || resolved.get() != nullptr) { return target.int_size; } @@ -415,6 +416,15 @@ namespace elna::boot { return target.float_size; } + else if (is_primitive_type(resolved, "Bool")) + { + return target.bool_size; + } + else if (is_primitive_type(resolved, "String") + || resolved.get() != nullptr) + { + return target.pointer_size + target.word_size; + } else if (is_primitive_type(resolved, "Pointer") || resolved.get() != nullptr) { diff --git a/boot/lexer.ll b/boot/lexer.ll index e84af85..9fe0398 100644 --- a/boot/lexer.ll +++ b/boot/lexer.ll @@ -152,6 +152,9 @@ case { of { return yy::parser::make_OF(this->location); } +to { + return yy::parser::make_TO(this->location); +} {ID1}{ID2}* { return yy::parser::make_IDENTIFIER(yytext, this->location); } diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc index 54a2d1a..a2cacb2 100644 --- a/boot/name_analysis.cc +++ b/boot/name_analysis.cc @@ -156,6 +156,17 @@ namespace elna::boot return lookup_field(record->base, field_name); } } + else if (auto slice = resolved_type.get()) + { + if (field_name == "length") + { + return lookup_primitive_type("Word"); + } + else if (field_name == "ptr") + { + return type(std::make_shared(slice->base)); + } + } else if (auto primitive = resolved_type.get(); primitive != nullptr && primitive->identifier == "String") { if (field_name == "length") @@ -209,6 +220,12 @@ namespace elna::boot this->current_type = type(std::make_shared(this->current_type, expression->size)); } + void name_analysis_visitor::visit(slice_type_expression *expression) + { + walking_visitor::visit(expression); + this->current_type = type(std::make_shared(this->current_type)); + } + /** * Collects field names from a record type recursively, base first. */ @@ -358,6 +375,25 @@ namespace elna::boot expression->type_decoration = type(std::make_shared(element_type, expression->size)); } + void name_analysis_visitor::visit(slicing_expression *expression) + { + walking_visitor::visit(expression); + auto resolved_base = resolve_underlying_type(expression->base().type_decoration); + + if (auto pointer = resolved_base.get()) + { + expression->type_decoration = type(std::make_shared(pointer->base)); + } + else if (auto array = resolved_base.get()) + { + expression->type_decoration = type(std::make_shared(array->base)); + } + else if (auto slice = resolved_base.get()) + { + expression->type_decoration = type(slice); + } + } + void name_analysis_visitor::visit(procedure_type_expression *expression) { std::shared_ptr const result_type = @@ -613,6 +649,10 @@ for (const auto& member : expression->members) { expression->type_decoration = array->base; } + else if (auto slice = resolved_base.get()) + { + expression->type_decoration = slice->base; + } else if (resolved_base == lookup_primitive_type("String")) { expression->type_decoration = lookup_primitive_type("Char"); diff --git a/boot/parser.yy b/boot/parser.yy index aad5769..bc2ddb5 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -112,6 +112,7 @@ along with GCC; see the file COPYING3. If not see DEFER "defer" CASE "case" OF "of" + TO "to" PIPE "|" %token OR "or" AND "&" XOR "xor" EQUALS "=" NOT_EQUAL "<>" LESS_THAN "<" GREATER_THAN ">" LESS_EQUAL "<=" GREATER_EQUAL ">=" @@ -372,6 +373,8 @@ type_expressions: designator_expression: simple_expression "[" expression "]" { $$ = new boot::array_access_expression(boot::make_position(@$), $1, $3); } + | simple_expression "[" expression "to" expression "]" + { $$ = new boot::slicing_expression(boot::make_position(@$), $1, $3, $5); } | simple_expression "." identifier { $$ = new boot::field_access_expression(boot::make_position(@$), $1, std::move(*$3)); } | simple_expression "^" @@ -446,6 +449,10 @@ type_expression: { $$ = new boot::array_type_expression(boot::make_position(@$), $4, $2); } + | "[" "]" type_expression + { + $$ = new boot::slice_type_expression(boot::make_position(@$), $3); + } | "const" type_expression { $$ = new boot::constant_type_expression(boot::make_position(@$), $2); diff --git a/boot/symbol.cc b/boot/symbol.cc index d7a1cae..738e4e1 100644 --- a/boot/symbol.cc +++ b/boot/symbol.cc @@ -51,6 +51,11 @@ namespace elna::boot { } + type::type(std::shared_ptr slice) + : payload(slice) + { + } + type::type(std::shared_ptr procedure) : payload(procedure) { @@ -86,6 +91,7 @@ namespace elna::boot template std::shared_ptr type::get() const; template std::shared_ptr type::get() const; template std::shared_ptr type::get() const; + template std::shared_ptr type::get() const; template std::shared_ptr type::get() const; template std::shared_ptr type::get() const; template std::shared_ptr type::get() const; @@ -133,6 +139,12 @@ namespace elna::boot return right_array != nullptr && left_array->size == right_array->size && left_array->base == right_array->base; } + if (auto left_slice = resolved_this.get()) + { + auto right_slice = resolved_that.get(); + + return right_slice != nullptr && left_slice->base == right_slice->base; + } if (auto left_procedure = resolved_this.get()) { auto right_procedure = resolved_that.get(); @@ -176,6 +188,10 @@ namespace elna::boot { return "[" + std::to_string(payload->size) + "]" + payload->base.to_string(); } + else if constexpr (std::is_same_v>) + { + return "[]" + payload->base.to_string(); + } else if constexpr (std::is_same_v>) { return payload->base.empty() @@ -226,6 +242,11 @@ namespace elna::boot { } + slice_type::slice_type(type base) + : base(std::move(base)) + { + } + primitive_type::primitive_type(const std::string& identifier) : identifier(identifier) { diff --git a/boot/type_check.cc b/boot/type_check.cc index c5fb062..5d0c7a6 100644 --- a/boot/type_check.cc +++ b/boot/type_check.cc @@ -629,6 +629,11 @@ namespace elna::boot } } + void type_analysis_visitor::visit(slicing_expression *expression) + { + walking_visitor::visit(expression); + } + void type_analysis_visitor::visit(unary_expression *expression) { walking_visitor::visit(expression); -- cgit v1.2.3