aboutsummaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-07-21 01:55:56 +0200
committerEugen Wissner <belka@caraus.de>2026-07-21 01:55:56 +0200
commit44d6e8a27294e5ca7300ab11900011b73d9336d4 (patch)
treed21addb0dec93fa8fa376bbd11076b17f3412173 /boot
parent6b131c925dee7a5f97516edd581e051e08bb52d8 (diff)
downloadelna-44d6e8a27294e5ca7300ab11900011b73d9336d4.tar.gz
Implement slices
Diffstat (limited to 'boot')
-rw-r--r--boot/ast.cc96
-rw-r--r--boot/evaluator.cc12
-rw-r--r--boot/lexer.ll3
-rw-r--r--boot/name_analysis.cc40
-rw-r--r--boot/parser.yy7
-rw-r--r--boot/symbol.cc21
-rw-r--r--boot/type_check.cc5
7 files changed, 183 insertions, 1 deletions
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<enumeration_type>() != 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<slice_type>() != nullptr)
+ {
+ return target.pointer_size + target.word_size;
+ }
else if (is_primitive_type(resolved, "Pointer")
|| resolved.get<pointer_type>() != 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<slice_type>())
+ {
+ if (field_name == "length")
+ {
+ return lookup_primitive_type("Word");
+ }
+ else if (field_name == "ptr")
+ {
+ return type(std::make_shared<pointer_type>(slice->base));
+ }
+ }
else if (auto primitive = resolved_type.get<primitive_type>(); primitive != nullptr && primitive->identifier == "String")
{
if (field_name == "length")
@@ -209,6 +220,12 @@ namespace elna::boot
this->current_type = type(std::make_shared<array_type>(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<slice_type>(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<array_type>(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<pointer_type>())
+ {
+ expression->type_decoration = type(std::make_shared<slice_type>(pointer->base));
+ }
+ else if (auto array = resolved_base.get<array_type>())
+ {
+ expression->type_decoration = type(std::make_shared<slice_type>(array->base));
+ }
+ else if (auto slice = resolved_base.get<slice_type>())
+ {
+ expression->type_decoration = type(slice);
+ }
+ }
+
void name_analysis_visitor::visit(procedure_type_expression *expression)
{
std::shared_ptr<procedure_type> 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<slice_type>())
+ {
+ 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_type> slice)
+ : payload(slice)
+ {
+ }
+
type::type(std::shared_ptr<procedure_type> procedure)
: payload(procedure)
{
@@ -86,6 +91,7 @@ namespace elna::boot
template std::shared_ptr<record_type> type::get<record_type>() const;
template std::shared_ptr<pointer_type> type::get<pointer_type>() const;
template std::shared_ptr<array_type> type::get<array_type>() const;
+ template std::shared_ptr<slice_type> type::get<slice_type>() const;
template std::shared_ptr<constant_type> type::get<constant_type>() const;
template std::shared_ptr<procedure_type> type::get<procedure_type>() const;
template std::shared_ptr<enumeration_type> type::get<enumeration_type>() 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<slice_type>())
+ {
+ auto right_slice = resolved_that.get<slice_type>();
+
+ return right_slice != nullptr && left_slice->base == right_slice->base;
+ }
if (auto left_procedure = resolved_this.get<procedure_type>())
{
auto right_procedure = resolved_that.get<procedure_type>();
@@ -176,6 +188,10 @@ namespace elna::boot
{
return "[" + std::to_string(payload->size) + "]" + payload->base.to_string();
}
+ else if constexpr (std::is_same_v<T, std::shared_ptr<slice_type>>)
+ {
+ return "[]" + payload->base.to_string();
+ }
else if constexpr (std::is_same_v<T, std::shared_ptr<record_type>>)
{
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);