aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-07-21 21:27:03 +0200
committerEugen Wissner <belka@caraus.de>2026-07-21 21:27:03 +0200
commit5cc2947143f2a6ebd4ef1ae4d25ab956b87de808 (patch)
tree0d4489b298da3be04ed4bce117f616468146a0f8
parent44d6e8a27294e5ca7300ab11900011b73d9336d4 (diff)
downloadelna-5cc2947143f2a6ebd4ef1ae4d25ab956b87de808.tar.gz
Redefine strings as slice of constant charactersHEADcpp
-rw-r--r--boot/ast.cc38
-rw-r--r--boot/evaluator.cc42
-rw-r--r--boot/name_analysis.cc135
-rw-r--r--boot/symbol.cc2
-rw-r--r--boot/type_check.cc254
-rw-r--r--gcc/gcc/elna-builtins.cc20
-rw-r--r--gcc/gcc/elna-diagnostic.cc4
-rw-r--r--gcc/gcc/elna-generic.cc388
-rw-r--r--gcc/gcc/elna-tree.cc36
-rw-r--r--include/elna/boot/ast.h20
-rw-r--r--include/elna/boot/name_analysis.h53
-rw-r--r--include/elna/boot/type_check.h65
-rw-r--r--include/elna/gcc/elna-generic.h8
-rw-r--r--include/elna/gcc/elna-tree.h18
-rw-r--r--include/elna/gcc/elna1.h7
-rw-r--r--rakelib/gcc.rake7
-rw-r--r--source/common.elna4
-rw-r--r--source/cstdio.elna14
-rw-r--r--source/cstring.elna14
-rw-r--r--source/lexer.elna10
-rw-r--r--source/main.elna18
-rw-r--r--testsuite/runnable/record_extension.elna2
-rw-r--r--testsuite/runnable/return_aggregate.elna4
-rw-r--r--testsuite/runnable/slice_array.elna11
-rw-r--r--testsuite/runnable/slice_pointer.elna11
-rw-r--r--testsuite/runnable/slice_slice.elna13
26 files changed, 649 insertions, 549 deletions
diff --git a/boot/ast.cc b/boot/ast.cc
index 3727aba..ec5b27d 100644
--- a/boot/ast.cc
+++ b/boot/ast.cc
@@ -438,8 +438,8 @@ namespace elna::boot
void walking_visitor::visit(slicing_expression *expression)
{
expression->base().accept(this);
- expression->offset().accept(this);
- expression->length().accept(this);
+ expression->start().accept(this);
+ expression->end().accept(this);
}
void walking_visitor::visit(traits_expression *trait)
@@ -1070,8 +1070,8 @@ 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)
+ expression *base, expression *start, expression *end)
+ : node(position), m_base(base), m_start(start), m_end(end)
{
}
@@ -1088,8 +1088,8 @@ namespace elna::boot
slicing_expression::~slicing_expression()
{
delete m_base;
- delete m_offset;
- delete m_length;
+ delete m_start;
+ delete m_end;
}
expression& slicing_expression::base()
@@ -1097,14 +1097,14 @@ namespace elna::boot
return *this->m_base;
}
- expression& slicing_expression::offset()
+ expression& slicing_expression::start()
{
- return *this->m_offset;
+ return *this->m_start;
}
- expression& slicing_expression::length()
+ expression& slicing_expression::end()
{
- return *this->m_length;
+ return *this->m_end;
}
named_expression::named_expression(const source_position position, const std::string& name)
@@ -1242,6 +1242,11 @@ namespace elna::boot
return m_operator;
}
+ void binary_expression::operation(binary_operator operation)
+ {
+ this->m_operator = operation;
+ }
+
binary_expression::~binary_expression()
{
delete m_lhs;
@@ -1274,6 +1279,11 @@ namespace elna::boot
return this->m_operator;
}
+ void unary_expression::operation(unary_operator operation)
+ {
+ this->m_operator = operation;
+ }
+
unary_expression::~unary_expression()
{
delete m_operand;
@@ -1540,10 +1550,16 @@ namespace elna::boot
case greater_equal:
return ">=";
case conjunction:
- return "and";
+ case logical_conjunction:
+ case bitwise_conjunction:
+ return "&";
case disjunction:
+ case logical_disjunction:
+ case bitwise_disjunction:
return "or";
case exclusive_disjunction:
+ case logical_exclusive_disjunction:
+ case bitwise_exclusive_disjunction:
return "xor";
case shift_left:
return "<<";
diff --git a/boot/evaluator.cc b/boot/evaluator.cc
index 990f358..77a56ad 100644
--- a/boot/evaluator.cc
+++ b/boot/evaluator.cc
@@ -169,7 +169,7 @@ namespace elna::boot
return std::nullopt;
}, operand.value());
}
- if (subject.operation() == unary_operator::negation)
+ if (subject.operation() == unary_operator::logical_negation)
{
return std::visit([](auto value) -> std::optional<constant_value> {
using T = std::decay_t<decltype(value)>;
@@ -178,7 +178,15 @@ namespace elna::boot
{
return constant_value{ !value };
}
- else if constexpr (std::is_integral_v<T>)
+ return std::nullopt;
+ }, operand.value());
+ }
+ if (subject.operation() == unary_operator::bitwise_negation)
+ {
+ return std::visit([](auto value) -> std::optional<constant_value> {
+ using T = std::decay_t<decltype(value)>;
+
+ if constexpr (std::is_integral_v<T>)
{
return constant_value{ ~value };
}
@@ -299,23 +307,44 @@ namespace elna::boot
}
return std::nullopt;
case disjunction:
- if constexpr (std::is_integral_v<T>)
+ case bitwise_disjunction:
+ if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>)
{
return constant_value{ lhs | rhs };
}
return std::nullopt;
case conjunction:
- if constexpr (std::is_integral_v<T>)
+ case bitwise_conjunction:
+ if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>)
{
return constant_value{ lhs & rhs };
}
return std::nullopt;
case exclusive_disjunction:
- if constexpr (std::is_integral_v<T>)
+ case bitwise_exclusive_disjunction:
+ if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>)
{
return constant_value{ lhs ^ rhs };
}
return std::nullopt;
+ case logical_conjunction:
+ if constexpr (std::is_same_v<T, bool>)
+ {
+ return constant_value{ lhs && rhs };
+ }
+ return std::nullopt;
+ case logical_disjunction:
+ if constexpr (std::is_same_v<T, bool>)
+ {
+ return constant_value{ lhs || rhs };
+ }
+ return std::nullopt;
+ case logical_exclusive_disjunction:
+ if constexpr (std::is_same_v<T, bool>)
+ {
+ return constant_value{ lhs != rhs };
+ }
+ return std::nullopt;
case shift_left:
if constexpr (std::is_integral_v<T> && !std::is_same_v<T, bool>)
{
@@ -420,8 +449,7 @@ namespace elna::boot
{
return target.bool_size;
}
- else if (is_primitive_type(resolved, "String")
- || resolved.get<slice_type>() != nullptr)
+ else if (resolved.get<slice_type>() != nullptr)
{
return target.pointer_size + target.word_size;
}
diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc
index a2cacb2..907f318 100644
--- a/boot/name_analysis.cc
+++ b/boot/name_analysis.cc
@@ -17,7 +17,6 @@ along with GCC; see the file COPYING3. If not see
#include "elna/boot/name_analysis.h"
-#include <algorithm>
#include <utility>
namespace elna::boot
@@ -81,6 +80,84 @@ namespace elna::boot
return "Duplicate 'const' qualifier is not allowed";
}
+ field_not_found_error::field_not_found_error(const identifier& field_name,
+ type composite_type)
+ : error(field_name.position()), field_name(field_name.name()), composite_type(std::move(composite_type))
+ {
+ }
+
+ std::string field_not_found_error::what() const
+ {
+ type const resolved = resolve_underlying_type(composite_type);
+ bool const is_enum = resolved.get<enumeration_type>() != nullptr;
+ bool const is_record = resolved.get<record_type>() != nullptr;
+
+ if (is_enum || is_record)
+ {
+ std::string message = is_enum ? "Enumeration" : "Record";
+
+ if (auto alias = composite_type.get<alias_type>())
+ {
+ message += " '" + alias->name + "'";
+ }
+ message += " does not have a ";
+ message += is_enum ? "member" : "field";
+ message += " named '" + field_name + "'";
+ return message;
+ }
+ return "Type '" + composite_type.to_string()
+ + "' does not have a field named '" + field_name + "'";
+ }
+
+ duplicate_member_error::duplicate_member_error(const boot::identifier& member_name,
+ type aggregate, std::optional<source_position> original,
+ std::optional<std::string> base_name)
+ : error(member_name.position()), member_name(member_name.name()), aggregate(std::move(aggregate)),
+ original(original), base_name(std::move(base_name))
+ {
+ }
+
+ std::string duplicate_member_error::what() const
+ {
+ type const resolved = resolve_underlying_type(aggregate);
+ bool const is_enum = resolved.get<enumeration_type>() != nullptr;
+ std::string const kind = is_enum ? "member" : "field";
+ std::string message = is_enum ? "Enumeration" : "Record";
+
+ if (auto alias = aggregate.get<alias_type>())
+ {
+ message += " '" + alias->name + "'";
+ }
+ message += " already has a " + kind + " named '" + member_name + "'";
+
+ if (base_name.has_value())
+ {
+ message += " (defined in base type '" + *base_name + "')";
+ }
+ return message;
+ }
+
+ std::optional<std::pair<std::string, source_position>> duplicate_member_error::note() const
+ {
+ if (original.has_value() && original->start().available())
+ {
+ return std::make_pair("previously declared here", *original);
+ }
+ return std::nullopt;
+ }
+
+ unsupported_trait_type_error::unsupported_trait_type_error(const identifier& trait,
+ type actual)
+ : error(trait.position()), actual(std::move(actual)), trait_name(trait.name())
+ {
+ }
+
+ std::string unsupported_trait_type_error::what() const
+ {
+ return "Type '" + actual.to_string()
+ + "' does not support trait '#" + trait_name + "'";
+ }
+
// Members of a constant aggregate are constant themselves.
static type qualify_member_type(const type& element, const type& aggregate)
{
@@ -133,6 +210,20 @@ namespace elna::boot
return result_type;
}
+ std::optional<type> name_analysis_visitor::lookup_pointer_like_field(
+ const std::string& field_name, const type& element_type)
+ {
+ if (field_name == "length")
+ {
+ return lookup_primitive_type("Word");
+ }
+ if (field_name == "ptr")
+ {
+ return type(std::make_shared<pointer_type>(element_type));
+ }
+ return std::nullopt;
+ }
+
type name_analysis_visitor::lookup_primitive_type(const std::string& name)
{
return this->bag.lookup(name)->is_type()->symbol;
@@ -156,26 +247,18 @@ namespace elna::boot
return lookup_field(record->base, field_name);
}
}
- else if (auto slice = resolved_type.get<slice_type>())
+ else if (auto array = resolved_type.get<array_type>())
{
- if (field_name == "length")
- {
- return lookup_primitive_type("Word");
- }
- else if (field_name == "ptr")
+ if (auto field = lookup_pointer_like_field(field_name, array->base))
{
- return type(std::make_shared<pointer_type>(slice->base));
+ return field.value();
}
}
- else if (auto primitive = resolved_type.get<primitive_type>(); primitive != nullptr && primitive->identifier == "String")
+ else if (auto slice = resolved_type.get<slice_type>())
{
- if (field_name == "length")
+ if (auto field = lookup_pointer_like_field(field_name, slice->base))
{
- return lookup_primitive_type("Word");
- }
- else if (field_name == "ptr")
- {
- return type(std::make_shared<pointer_type>(lookup_primitive_type("Char")));
+ return field.value();
}
}
return type();
@@ -303,17 +386,6 @@ namespace elna::boot
}
else
{
- type actual;
-
- if (auto var = base_symbol->is_variable())
- {
- actual = var->symbol;
- }
- else if (auto proc = base_symbol->is_procedure())
- {
- actual = type(std::make_shared<procedure_type>(proc->symbol));
- }
- add_error<base_type_error>(actual, expression->position());
this->current_type = type();
return;
}
@@ -513,10 +585,6 @@ for (const auto& member : expression->members)
{
call->type_decoration = procedure->return_type.proper_type;
}
- else if (call->callable().is_named() != nullptr)
- {
- call->type_decoration = this->current_type;
- }
for (expression *const argument : call->arguments)
{
argument->accept(this);
@@ -653,10 +721,6 @@ for (const auto& member : expression->members)
{
expression->type_decoration = slice->base;
}
- else if (resolved_base == lookup_primitive_type("String"))
- {
- expression->type_decoration = lookup_primitive_type("Char");
- }
// Elements of a constant array are constant themselves since a static
// array is a holistic type.
if (!expression->type_decoration.empty())
@@ -765,7 +829,8 @@ for (const auto& member : expression->members)
void name_analysis_visitor::visit(literal<std::string> *literal)
{
- literal->type_decoration = lookup_primitive_type("String");
+ literal->type_decoration = type(std::make_shared<slice_type>(
+ type(std::make_shared<constant_type>(lookup_primitive_type("Char")))));
}
declaration_visitor::declaration_visitor()
diff --git a/boot/symbol.cc b/boot/symbol.cc
index 738e4e1..da948fd 100644
--- a/boot/symbol.cc
+++ b/boot/symbol.cc
@@ -329,8 +329,6 @@ namespace elna::boot
result->enter("Char", std::make_shared<type_info>(type(std::make_shared<primitive_type>("Char"))));
result->enter("Pointer", std::make_shared<type_info>(type(std::make_shared<primitive_type>("Pointer"))));
result->enter("Float", std::make_shared<type_info>(type(std::make_shared<primitive_type>("Float"))));
- result->enter("String", std::make_shared<type_info>(type(std::make_shared<primitive_type>("String"))));
-
type const boolean = type(std::make_shared<primitive_type>("Bool"));
result->enter("Bool", std::make_shared<type_info>(boolean));
diff --git a/boot/type_check.cc b/boot/type_check.cc
index 5d0c7a6..7989925 100644
--- a/boot/type_check.cc
+++ b/boot/type_check.cc
@@ -56,72 +56,6 @@ namespace elna::boot
+ "', because it is constant or contains constant members";
}
- field_not_found_error::field_not_found_error(const identifier& field_name,
- type composite_type)
- : error(field_name.position()), field_name(field_name.name()), composite_type(std::move(composite_type))
- {
- }
-
- std::string field_not_found_error::what() const
- {
- type const resolved = resolve_underlying_type(composite_type);
- bool const is_enum = resolved.get<enumeration_type>() != nullptr;
- bool const is_record = resolved.get<record_type>() != nullptr;
-
- if (is_enum || is_record)
- {
- std::string message = is_enum ? "Enumeration" : "Record";
-
- if (auto alias = composite_type.get<alias_type>())
- {
- message += " '" + alias->name + "'";
- }
- message += " does not have a ";
- message += is_enum ? "member" : "field";
- message += " named '" + field_name + "'";
- return message;
- }
- return "Type '" + composite_type.to_string()
- + "' does not have a field named '" + field_name + "'";
- }
-
- duplicate_member_error::duplicate_member_error(const boot::identifier& member_name,
- type aggregate, std::optional<source_position> original,
- std::optional<std::string> base_name)
- : error(member_name.position()), member_name(member_name.name()), aggregate(std::move(aggregate)),
- original(original), base_name(std::move(base_name))
- {
- }
-
- std::string duplicate_member_error::what() const
- {
- type const resolved = resolve_underlying_type(aggregate);
- bool const is_enum = resolved.get<enumeration_type>() != nullptr;
- std::string const kind = is_enum ? "member" : "field";
- std::string message = is_enum ? "Enumeration" : "Record";
-
- if (auto alias = aggregate.get<alias_type>())
- {
- message += " '" + alias->name + "'";
- }
- message += " already has a " + kind + " named '" + member_name + "'";
-
- if (base_name.has_value())
- {
- message += " (defined in base type '" + *base_name + "')";
- }
- return message;
- }
-
- std::optional<std::pair<std::string, source_position>> duplicate_member_error::note() const
- {
- if (original.has_value() && original->start().available())
- {
- return std::make_pair("previously declared here", *original);
- }
- return std::nullopt;
- }
-
cyclic_declaration_error::cyclic_declaration_error(const std::vector<std::string>& cycle,
const source_position position)
: error(position), cycle(cycle)
@@ -189,18 +123,6 @@ namespace elna::boot
}
}
- unsupported_trait_type_error::unsupported_trait_type_error(const identifier& trait,
- type actual)
- : error(trait.position()), actual(std::move(actual)), trait_name(trait.name())
- {
- }
-
- std::string unsupported_trait_type_error::what() const
- {
- return "Type '" + actual.to_string()
- + "' does not support trait '#" + trait_name + "'";
- }
-
unary_operation_error::unary_operation_error(const source_position position,
type actual, unary_operator operation)
: error(position), actual(std::move(actual)), op(operation)
@@ -215,6 +137,8 @@ namespace elna::boot
case reference:
return '@';
case negation:
+ case bitwise_negation:
+ case logical_negation:
return '~';
case minus:
return '-';
@@ -368,10 +292,36 @@ namespace elna::boot
return verdict::pass;
}
+ assign_check::verdict assign_check::check_slice_conversion() const
+ {
+ auto assignee_slice = ctx.resolved_assignee.get<slice_type>();
+ auto assignment_slice = ctx.resolved_assignment.get<slice_type>();
+
+ if (assignee_slice == nullptr || assignment_slice == nullptr)
+ {
+ return verdict::pass;
+ }
+ auto assignee_element_const = resolve_aliases(assignee_slice->base).get<constant_type>();
+ auto assignment_element_const = resolve_aliases(assignment_slice->base).get<constant_type>();
+
+ // Const can be added to the element type, but not removed.
+ if (assignee_element_const != nullptr
+ && assignee_element_const->unqualified == assignment_slice->base)
+ {
+ return verdict::accept;
+ }
+ if (assignment_element_const != nullptr && assignee_element_const == nullptr)
+ {
+ return verdict::reject;
+ }
+ return verdict::pass;
+ }
+
bool assign_check::run()
{
for (auto handler : {&assign_check::guard_const_laundering,
&assign_check::check_exact_match,
+ &assign_check::check_slice_conversion,
&assign_check::check_pointer_hatch,
&assign_check::check_pointer_conversion})
{
@@ -534,10 +484,18 @@ namespace elna::boot
{
if (expression->base.has_value())
{
- type const base_type = resolve_underlying_type(this->bag.lookup(expression->base.value().name())->is_type()->symbol);
- if (base_type.get<record_type>() == nullptr)
+ auto const base_symbol = this->bag.lookup(expression->base.value().name());
+ if (base_symbol == nullptr || base_symbol->is_type() == nullptr)
{
- add_error<base_type_error>(base_type, expression->position());
+ add_error<base_type_error>(type(), expression->position());
+ }
+ else
+ {
+ type const base_type = resolve_underlying_type(base_symbol->is_type()->symbol);
+ if (base_type.get<record_type>() == nullptr)
+ {
+ add_error<base_type_error>(base_type, expression->position());
+ }
}
}
walking_visitor::visit(expression);
@@ -571,6 +529,12 @@ namespace elna::boot
call->arguments.size(), call->position());
}
}
+ else if (!call->callable().type_decoration.empty())
+ {
+ add_error<type_mismatch_error>(call->position(),
+ type(std::make_shared<procedure_type>()),
+ call->callable().type_decoration);
+ }
}
void type_analysis_visitor::visit(record_constructor_expression *expression)
@@ -660,12 +624,136 @@ namespace elna::boot
}
else if (operation == unary_operator::negation)
{
- if (!is_primitive_type(resolved, "Bool")
- && !is_integral_type(resolved))
+ if (is_primitive_type(resolved, "Bool"))
+ {
+ expression->operation(unary_operator::logical_negation);
+ }
+ else if (is_integral_type(resolved))
+ {
+ expression->operation(unary_operator::bitwise_negation);
+ }
+ else
{
add_error<unary_operation_error>(expression->position(),
expression->operand().type_decoration, operation);
}
}
+ else if (operation == unary_operator::reference)
+ {
+ auto *designator = expression->operand().is_designator();
+ if (designator == nullptr || designator->is_slicing() != nullptr)
+ {
+ add_error<unary_operation_error>(expression->position(),
+ expression->operand().type_decoration, operation);
+ }
+ }
+ }
+
+ binary_operation_error::binary_operation_error(const source_position position,
+ type left, type right, binary_operator operation)
+ : error(position), left(std::move(left)), right(std::move(right)), op(operation)
+ {
+ }
+
+ std::string binary_operation_error::what() const
+ {
+ return "Invalid operands of type '" + left.to_string()
+ + "' and '" + right.to_string()
+ + "' for operator " + print_binary_operator(op);
+ }
+
+ void type_analysis_visitor::visit(binary_expression *expression)
+ {
+ walking_visitor::visit(expression);
+
+ auto operation = expression->operation();
+ type const lhs_resolved = resolve_underlying_type(expression->lhs().type_decoration);
+ type const rhs_resolved = resolve_underlying_type(expression->rhs().type_decoration);
+ bool valid = false;
+
+ switch (operation)
+ {
+ using enum binary_operator;
+ case sum:
+ valid = (is_any_pointer_type(lhs_resolved) && is_integral_type(rhs_resolved))
+ || (is_integral_type(lhs_resolved) && is_any_pointer_type(rhs_resolved))
+ || (is_numeric_type(lhs_resolved) && lhs_resolved == rhs_resolved);
+ break;
+ case subtraction:
+ valid = (is_any_pointer_type(lhs_resolved) && is_integral_type(rhs_resolved))
+ || (is_any_pointer_type(lhs_resolved) && is_any_pointer_type(rhs_resolved))
+ || (is_numeric_type(lhs_resolved) && lhs_resolved == rhs_resolved);
+ break;
+ case division:
+ case remainder:
+ case multiplication:
+ valid = is_numeric_type(lhs_resolved) && lhs_resolved == rhs_resolved;
+ break;
+ case less:
+ case greater:
+ case less_equal:
+ case greater_equal:
+ valid = (is_numeric_type(lhs_resolved) && lhs_resolved == rhs_resolved)
+ || (is_any_pointer_type(lhs_resolved) && is_any_pointer_type(rhs_resolved));
+ break;
+ case conjunction:
+ case disjunction:
+ case exclusive_disjunction:
+ if (is_primitive_type(lhs_resolved, "Bool") && lhs_resolved == rhs_resolved)
+ {
+ switch (operation)
+ {
+ case conjunction:
+ expression->operation(logical_conjunction);
+ break;
+ case disjunction:
+ expression->operation(logical_disjunction);
+ break;
+ case exclusive_disjunction:
+ expression->operation(logical_exclusive_disjunction);
+ break;
+ default:
+ break;
+ }
+ valid = true;
+ }
+ else if (is_integral_type(lhs_resolved) && lhs_resolved == rhs_resolved)
+ {
+ switch (operation)
+ {
+ case conjunction:
+ expression->operation(bitwise_conjunction);
+ break;
+ case disjunction:
+ expression->operation(bitwise_disjunction);
+ break;
+ case exclusive_disjunction:
+ expression->operation(bitwise_exclusive_disjunction);
+ break;
+ default:
+ break;
+ }
+ valid = true;
+ }
+ break;
+ case equals:
+ case not_equals:
+ valid = lhs_resolved == rhs_resolved
+ || (is_primitive_type(lhs_resolved, "Pointer") && is_any_pointer_type(rhs_resolved))
+ || (is_any_pointer_type(lhs_resolved) && is_primitive_type(rhs_resolved, "Pointer"))
+ || (lhs_resolved.get<slice_type>() && rhs_resolved.get<slice_type>())
+ || (lhs_resolved.get<record_type>() && rhs_resolved.get<record_type>());
+ break;
+ case shift_left:
+ case shift_right:
+ valid = is_integral_type(lhs_resolved)
+ && is_primitive_type(rhs_resolved, "Word");
+ break;
+ }
+ if (!valid)
+ {
+ add_error<binary_operation_error>(expression->position(),
+ expression->lhs().type_decoration, expression->rhs().type_decoration, operation);
+ }
}
}
diff --git a/gcc/gcc/elna-builtins.cc b/gcc/gcc/elna-builtins.cc
index 141b34f..77ffb1c 100644
--- a/gcc/gcc/elna-builtins.cc
+++ b/gcc/gcc/elna-builtins.cc
@@ -38,17 +38,6 @@ namespace elna::gcc
elna_bool_false_node = boolean_false_node;
elna_pointer_nil_node = null_pointer_node;
-
- elna_string_type_node = make_node(RECORD_TYPE);
- tree string_ptr_type = build_pointer_type(elna_char_type_node);
-
- elna_string_length_field_node = build_field(UNKNOWN_LOCATION,
- elna_string_type_node, "length", build_qualified_type(elna_word_type_node, TYPE_QUAL_CONST));
- elna_string_ptr_field_node = build_field(UNKNOWN_LOCATION,
- elna_string_type_node, "ptr", build_qualified_type(string_ptr_type, TYPE_QUAL_CONST));
-
- TYPE_FIELDS(elna_string_type_node) = chainon(elna_string_ptr_field_node, elna_string_length_field_node);
- layout_type(elna_string_type_node);
}
static
@@ -73,10 +62,6 @@ namespace elna::gcc
declare_builtin_type(builtin_table, "Pointer", elna_pointer_type_node);
declare_builtin_type(builtin_table, "Float", elna_float_type_node);
- tree string_declaration = declare_builtin_type(builtin_table, "String", elna_string_type_node);
- TYPE_NAME(elna_string_type_node) = DECL_NAME(string_declaration);
- TYPE_STUB_DECL(elna_string_type_node) = string_declaration;
-
return builtin_table;
}
@@ -165,7 +150,7 @@ namespace elna::gcc
TYPE_FIELDS(slice_record) = chainon(ptr_field, length_field);
layout_type(slice_record);
- return slice_record;
+ return type_hash_canon(type_hash_canon_hash(slice_record), slice_record);
}
else if (auto reference = type.get<boot::procedure_type>())
{
@@ -175,7 +160,8 @@ namespace elna::gcc
}
else if (auto reference = type.get<boot::constant_type>())
{
- return get_inner_alias(reference->unqualified, symbols);
+ tree unqualified = get_inner_alias(reference->unqualified, symbols);
+ return build_qualified_type(unqualified, TYPE_QUAL_CONST);
}
else if (auto reference = type.get<boot::alias_type>())
{
diff --git a/gcc/gcc/elna-diagnostic.cc b/gcc/gcc/elna-diagnostic.cc
index 3769ee4..630db0c 100644
--- a/gcc/gcc/elna-diagnostic.cc
+++ b/gcc/gcc/elna-diagnostic.cc
@@ -108,10 +108,6 @@ namespace elna::gcc
{
return "Char";
}
- else if (unqualified_type == elna_string_type_node)
- {
- return "String";
- }
else if (is_void_type(unqualified_type)) // For procedures without a return type.
{
return "()";
diff --git a/gcc/gcc/elna-generic.cc b/gcc/gcc/elna-generic.cc
index ea209df..c2c59aa 100644
--- a/gcc/gcc/elna-generic.cc
+++ b/gcc/gcc/elna-generic.cc
@@ -126,18 +126,7 @@ namespace elna::gcc
? this->current_expression
: TREE_TYPE(this->current_expression);
- if (TREE_CODE(expression_type) == RECORD_TYPE
- && TYPE_NAME(expression_type) == get_identifier("String"))
- {
- vec<constructor_elt, va_gc> *elms = nullptr;
-
- call->arguments.at(0)->accept(this);
- CONSTRUCTOR_APPEND_ELT(elms, elna_string_ptr_field_node, this->current_expression);
- call->arguments.at(1)->accept(this);
- CONSTRUCTOR_APPEND_ELT(elms, elna_string_length_field_node, this->current_expression);
- this->current_expression = build_constructor(elna_string_type_node, elms);
- }
- else if (TREE_CODE(expression_type) == FUNCTION_TYPE)
+ if (TREE_CODE(expression_type) == FUNCTION_TYPE)
{
this->current_expression = build1(ADDR_EXPR,
build_pointer_type(expression_type), this->current_expression);
@@ -230,28 +219,31 @@ namespace elna::gcc
tree base = this->current_expression;
tree base_type = TREE_TYPE(base);
- expression->offset().accept(this);
- tree offset = fold_convert(elna_word_type_node, this->current_expression);
- offset = build2(MINUS_EXPR, elna_word_type_node, offset, size_one_node);
+ expression->start().accept(this);
+ tree start_index = fold_convert(elna_word_type_node, this->current_expression);
+ tree zero_based_offset = build2(MINUS_EXPR, elna_word_type_node,
+ start_index, size_one_node);
tree slice_ptr;
if (TREE_CODE(base_type) == ARRAY_TYPE)
{
+ // Elna arrays are 1-indexed in TYPE_DOMAIN. Pass the raw
+ // (1-based) start index — GCC handles the 1→0 conversion
+ // via the domain lower bound. No -1 adjustment needed here.
slice_ptr = build4_loc(location, ARRAY_REF, TREE_TYPE(base_type),
- base, offset, size_one_node, NULL_TREE);
+ base, start_index, size_one_node, NULL_TREE);
slice_ptr = build1(ADDR_EXPR, build_pointer_type(TREE_TYPE(base_type)), slice_ptr);
}
else
{
tree ptr = build3_loc(location, COMPONENT_REF, TREE_TYPE(ptr_field),
base, ptr_field, NULL_TREE);
- slice_ptr = do_pointer_arithmetic(boot::binary_operator::sum, ptr, offset, location);
+ slice_ptr = do_pointer_arithmetic(boot::binary_operator::sum,
+ ptr, zero_based_offset, location);
}
- expression->length().accept(this);
+ expression->end().accept(this);
tree end_index = fold_convert(elna_word_type_node, this->current_expression);
- expression->offset().accept(this);
- tree start_index = fold_convert(elna_word_type_node, this->current_expression);
tree slice_length = build2(MINUS_EXPR, elna_word_type_node,
end_index, start_index);
slice_length = build2(PLUS_EXPR, elna_word_type_node, slice_length, size_one_node);
@@ -288,10 +280,7 @@ namespace elna::gcc
DECL_CONTEXT(resdecl) = fndecl;
DECL_RESULT(fndecl) = resdecl;
- push_struct_function(fndecl, false);
- DECL_STRUCT_FUNCTION(fndecl)->language = ggc_cleared_alloc<language_function>();
-
- enter_scope();
+ begin_function(fndecl);
tree parameter_type = TYPE_ARG_TYPES(declaration_type);
for (const char *argument_name : std::array<const char *, 2>{ "count", "parameters" })
@@ -311,18 +300,9 @@ namespace elna::gcc
tree return_stmt = build1(RETURN_EXPR, void_type_node, set_result);
append_statement(return_stmt);
this->current_expression = NULL_TREE;
- tree mapping = leave_scope();
-
- BLOCK_SUPERCONTEXT(BIND_EXPR_BLOCK(mapping)) = fndecl;
- DECL_INITIAL(fndecl) = BIND_EXPR_BLOCK(mapping);
- DECL_SAVED_TREE(fndecl) = mapping;
DECL_EXTERNAL(fndecl) = 0;
- DECL_PRESERVE_P(fndecl) = 1;
-
- pop_cfun();
- gimplify_function_tree(fndecl);
- cgraph_node::finalize_function(fndecl, true);
+ finish_function(fndecl);
}
}
@@ -334,10 +314,7 @@ namespace elna::gcc
{
return;
}
- push_struct_function(fndecl, false);
- DECL_STRUCT_FUNCTION(fndecl)->language = ggc_cleared_alloc<language_function>();
-
- enter_scope();
+ begin_function(fndecl);
this->bag.enter(this->bag.lookup(declaration->identifier.name())->is_procedure()->scope);
tree argument_chain = DECL_ARGUMENTS(fndecl);
@@ -369,18 +346,8 @@ namespace elna::gcc
this->current_expression = NULL_TREE;
}
- tree mapping = leave_scope();
this->bag.leave();
-
- BLOCK_SUPERCONTEXT(BIND_EXPR_BLOCK(mapping)) = fndecl;
- DECL_INITIAL(fndecl) = BIND_EXPR_BLOCK(mapping);
- DECL_SAVED_TREE(fndecl) = mapping;
-
- DECL_PRESERVE_P(fndecl) = 1;
-
- pop_cfun();
- gimplify_function_tree(fndecl);
- cgraph_node::finalize_function(fndecl, true);
+ finish_function(fndecl);
}
void generic_visitor::enter_scope()
@@ -416,14 +383,72 @@ namespace elna::gcc
return bind_expr;
}
+ void generic_visitor::begin_function(tree fndecl)
+ {
+ push_struct_function(fndecl, false);
+ DECL_STRUCT_FUNCTION(fndecl)->language = ggc_cleared_alloc<language_function>();
+ enter_scope();
+ }
+
+ void generic_visitor::finish_function(tree fndecl)
+ {
+ tree mapping = leave_scope();
+
+ BLOCK_SUPERCONTEXT(BIND_EXPR_BLOCK(mapping)) = fndecl;
+ DECL_INITIAL(fndecl) = BIND_EXPR_BLOCK(mapping);
+ DECL_SAVED_TREE(fndecl) = mapping;
+
+ DECL_PRESERVE_P(fndecl) = 1;
+
+ pop_cfun();
+ gimplify_function_tree(fndecl);
+ cgraph_node::finalize_function(fndecl, true);
+ }
+
+ static tree constant_to_tree(const boot::constant_value& constant_value)
+ {
+ if (std::holds_alternative<std::int32_t>(constant_value))
+ {
+ return build_int_cst(elna_int_type_node, std::get<std::int32_t>(constant_value));
+ }
+ else if (std::holds_alternative<std::uint32_t>(constant_value))
+ {
+ return build_int_cstu(elna_word_type_node, std::get<std::uint32_t>(constant_value));
+ }
+
+ else if (std::holds_alternative<double>(constant_value))
+ {
+ auto real_value = std::get<double>(constant_value);
+ REAL_VALUE_TYPE real;
+ HOST_WIDE_INT target_bits[(sizeof(double) + sizeof(HOST_WIDE_INT) - 1)
+ / sizeof(HOST_WIDE_INT)];
+ std::memcpy(target_bits, &real_value, sizeof(real_value));
+ real_from_target(&real, target_bits, REAL_MODE_FORMAT(TYPE_MODE(elna_float_type_node)));
+ return build_real(elna_float_type_node, real);
+ }
+ else if (std::holds_alternative<bool>(constant_value))
+ {
+ return std::get<bool>(constant_value) ? boolean_true_node : boolean_false_node;
+ }
+ else if (std::holds_alternative<unsigned char>(constant_value))
+ {
+ return build_int_cstu(elna_char_type_node, std::get<unsigned char>(constant_value));
+ }
+ else if (std::holds_alternative<std::nullptr_t>(constant_value))
+ {
+ return elna_pointer_nil_node;
+ }
+ return NULL_TREE;
+ }
+
void generic_visitor::visit(boot::literal<std::int32_t> *literal)
{
- this->current_expression = build_int_cst(elna_int_type_node, literal->value);
+ this->current_expression = constant_to_tree(boot::constant_value{ literal->value });
}
void generic_visitor::visit(boot::literal<std::uint32_t> *literal)
{
- this->current_expression = build_int_cstu(elna_word_type_node, literal->value);
+ this->current_expression = constant_to_tree(boot::constant_value{ literal->value });
}
void generic_visitor::visit(boot::literal<double> *literal)
@@ -443,97 +468,43 @@ namespace elna::gcc
void generic_visitor::visit(boot::literal<bool> *boolean)
{
- this->current_expression = boolean->value ? boolean_true_node : boolean_false_node;
+ this->current_expression = constant_to_tree(boot::constant_value{ boolean->value });
}
void generic_visitor::visit(boot::literal<unsigned char> *character)
{
- this->current_expression = build_int_cstu(elna_char_type_node, character->value);
+ this->current_expression = constant_to_tree(boot::constant_value{ character->value });
}
void generic_visitor::visit(boot::literal<std::nullptr_t> *)
{
- this->current_expression = elna_pointer_nil_node;
+ this->current_expression = constant_to_tree(boot::constant_value{ std::nullptr_t{} });
}
void generic_visitor::visit(boot::literal<std::string> *string)
{
tree index_constant = build_int_cstu(elna_word_type_node, string->value.size());
- tree string_type = build_array_type(elna_char_type_node, build_index_type(index_constant));
+ tree char_array_type = build_array_type(elna_char_type_node, build_index_type(index_constant));
tree string_literal = build_string(string->value.size(), string->value.c_str());
- TREE_TYPE(string_literal) = string_type;
+ TREE_TYPE(string_literal) = char_array_type;
TREE_CONSTANT(string_literal) = 1;
TREE_READONLY(string_literal) = 1;
TREE_STATIC(string_literal) = 1;
- string_type = TREE_TYPE(elna_string_ptr_field_node);
+ tree slice_type = get_inner_alias(string->type_decoration, this->symbols);
+ tree ptr_field = TYPE_FIELDS(slice_type);
+
+ tree ptr_type = TREE_TYPE(ptr_field);
string_literal = build4(ARRAY_REF, elna_char_type_node,
string_literal, integer_zero_node, NULL_TREE, NULL_TREE);
- string_literal = build1(ADDR_EXPR, string_type, string_literal);
+ string_literal = build1(ADDR_EXPR, ptr_type, string_literal);
vec<constructor_elt, va_gc> *elms = nullptr;
- CONSTRUCTOR_APPEND_ELT(elms, elna_string_ptr_field_node, string_literal);
- CONSTRUCTOR_APPEND_ELT(elms, elna_string_length_field_node, index_constant);
-
- this->current_expression = build_constructor(elna_string_type_node, elms);
- }
-
- tree generic_visitor::build_arithmetic_operation(boot::binary_expression *expression,
- tree_code operator_code, tree left, tree right)
- {
- return build_binary_operation(is_numeric_type(TREE_TYPE(left)),
- expression, operator_code, left, right, TREE_TYPE(left));
- }
-
- tree generic_visitor::build_comparison_operation(boot::binary_expression *expression,
- tree_code operator_code, tree left, tree right)
- {
- return build_binary_operation(is_numeric_type(TREE_TYPE(left)) || POINTER_TYPE_P(TREE_TYPE(left)),
- expression, operator_code, left, right, elna_bool_type_node);
- }
+ CONSTRUCTOR_APPEND_ELT(elms, ptr_field, string_literal);
+ CONSTRUCTOR_APPEND_ELT(elms, TREE_CHAIN(ptr_field), index_constant);
- tree generic_visitor::build_bit_logic_operation(boot::binary_expression *expression, tree left, tree right)
- {
- location_t expression_location = get_location(&expression->position());
- tree left_type = TREE_TYPE(left);
- tree right_type = TREE_TYPE(right);
- tree_code logical_code, bit_code;
-
- if (expression->operation() == boot::binary_operator::conjunction)
- {
- bit_code = BIT_AND_EXPR;
- logical_code = TRUTH_ANDIF_EXPR;
- }
- else if (expression->operation() == boot::binary_operator::disjunction)
- {
- bit_code = BIT_IOR_EXPR;
- logical_code = TRUTH_ORIF_EXPR;
- }
- else if (expression->operation() == boot::binary_operator::exclusive_disjunction)
- {
- bit_code = BIT_XOR_EXPR;
- logical_code = TRUTH_XOR_EXPR;
- }
- else
- {
- gcc_unreachable();
- }
- if (left_type == elna_bool_type_node)
- {
- return build2_loc(expression_location, logical_code, elna_bool_type_node, left, right);
- }
- else if (is_integral_type(left_type))
- {
- return build2_loc(expression_location, bit_code, left_type, left, right);
- }
- else
- {
- error_at(expression_location, "Invalid operands of type '%s' and '%s' for operator %s",
- print_type(left_type).c_str(), print_type(right_type).c_str(),
- boot::print_binary_operator(expression->operation()));
- return error_mark_node;
- }
+ this->current_expression = build_constructor(slice_type, elms);
}
tree generic_visitor::build_equality_operation(boot::binary_expression *expression, tree left, tree right)
@@ -555,26 +526,7 @@ namespace elna::gcc
{
gcc_unreachable();
}
- if (TREE_TYPE(left) == elna_string_type_node)
- {
- tree lhs_length = build3(COMPONENT_REF, TREE_TYPE(elna_string_length_field_node),
- left, elna_string_length_field_node, NULL_TREE);
- tree lhs_ptr = build3(COMPONENT_REF, TREE_TYPE(elna_string_ptr_field_node),
- left, elna_string_ptr_field_node, NULL_TREE);
-
- tree rhs_length = build3(COMPONENT_REF, TREE_TYPE(elna_string_length_field_node),
- right, elna_string_length_field_node, NULL_TREE);
- tree rhs_ptr = build3(COMPONENT_REF, TREE_TYPE(elna_string_ptr_field_node),
- right, elna_string_ptr_field_node, NULL_TREE);
-
- tree length_equality = build2(equality_code, elna_bool_type_node, lhs_length, rhs_length);
- tree memcmp_call = call_built_in(UNKNOWN_LOCATION, "__builtin_memcmp", integer_type_node,
- lhs_ptr, rhs_ptr, lhs_length);
- tree equals_zero = build2(equality_code, elna_bool_type_node, memcmp_call, integer_zero_node);
-
- return build2(combination_code, elna_bool_type_node, length_equality, equals_zero);
- }
- else if (expression->lhs().type_decoration.get<boot::slice_type>() != nullptr)
+ if (expression->lhs().type_decoration.get<boot::slice_type>() != nullptr)
{
tree lhs_ptr_field = TYPE_FIELDS(TREE_TYPE(left));
tree lhs_length_field = TREE_CHAIN(lhs_ptr_field);
@@ -600,7 +552,8 @@ namespace elna::gcc
return build2(combination_code, elna_bool_type_node, length_equality, equals_zero);
}
- else if (TREE_CODE(TREE_TYPE(left)) == RECORD_TYPE)
+ else if (expression->lhs().type_decoration.get<boot::record_type>() != nullptr
+ || expression->lhs().type_decoration.get<boot::array_type>() != nullptr)
{
tree size = fold_convert(elna_word_type_node,
size_in_bytes(TREE_TYPE(left)));
@@ -636,84 +589,90 @@ namespace elna::gcc
{
this->current_expression = do_pointer_arithmetic(expression->operation(),
left, right, expression_location);
- if (this->current_expression == error_mark_node)
- {
- error_at(expression_location,
- "invalid operation %s on a pointer and an integral type",
- boot::print_binary_operator(expression->operation()));
- }
- else if (TREE_TYPE(this->current_expression) == ssizetype)
+ if (TREE_TYPE(this->current_expression) == ssizetype)
{
this->current_expression = fold_convert(elna_int_type_node, this->current_expression);
}
return;
}
- if (left_type != right_type
- && !are_compatible_pointers(left_type, right)
- && !are_compatible_pointers(right_type, left)
- && !(is_integral_type(left_type) && right_type == elna_word_type_node))
- {
- error_at(expression_location,
- "invalid operands of type '%s' and '%s' for operator %s",
- print_type(left_type).c_str(), print_type(right_type).c_str(),
- boot::print_binary_operator(expression->operation()));
- this->current_expression = error_mark_node;
- return;
- }
switch (expression->operation())
{
using enum boot::binary_operator;
case sum:
- this->current_expression = build_arithmetic_operation(expression, PLUS_EXPR, left, right);
+ this->current_expression = fold_build2_loc(expression_location,
+ PLUS_EXPR, left_type, left, right);
break;
case subtraction:
- this->current_expression = build_arithmetic_operation(expression, MINUS_EXPR, left, right);
+ this->current_expression = fold_build2_loc(expression_location,
+ MINUS_EXPR, left_type, left, right);
break;
case division:
- this->current_expression = build_arithmetic_operation(expression, TRUNC_DIV_EXPR, left, right);
+ this->current_expression = fold_build2_loc(expression_location,
+ TRUNC_DIV_EXPR, left_type, left, right);
break;
case remainder:
- this->current_expression = build_arithmetic_operation(expression, TRUNC_MOD_EXPR, left, right);
+ this->current_expression = fold_build2_loc(expression_location,
+ TRUNC_MOD_EXPR, left_type, left, right);
break;
case multiplication:
- this->current_expression = build_arithmetic_operation(expression, MULT_EXPR, left, right);
+ this->current_expression = fold_build2_loc(expression_location,
+ MULT_EXPR, left_type, left, right);
break;
case less:
- this->current_expression = build_comparison_operation(expression, LT_EXPR, left, right);
+ this->current_expression = fold_build2_loc(expression_location,
+ LT_EXPR, elna_bool_type_node, left, right);
break;
case greater:
- this->current_expression = build_comparison_operation(expression, GT_EXPR, left, right);
+ this->current_expression = fold_build2_loc(expression_location,
+ GT_EXPR, elna_bool_type_node, left, right);
break;
case less_equal:
- this->current_expression = build_comparison_operation(expression, LE_EXPR, left, right);
+ this->current_expression = fold_build2_loc(expression_location,
+ LE_EXPR, elna_bool_type_node, left, right);
break;
case greater_equal:
- this->current_expression = build_comparison_operation(expression, GE_EXPR, left, right);
+ this->current_expression = fold_build2_loc(expression_location,
+ GE_EXPR, elna_bool_type_node, left, right);
break;
case conjunction:
- this->current_expression = build_bit_logic_operation(expression, left, right);
- break;
case disjunction:
- this->current_expression = build_bit_logic_operation(expression, left, right);
- break;
case exclusive_disjunction:
- this->current_expression = build_bit_logic_operation(expression, left, right);
+ gcc_unreachable();
+ case logical_conjunction:
+ this->current_expression = build2_loc(expression_location,
+ TRUTH_ANDIF_EXPR, elna_bool_type_node, left, right);
break;
- case equals:
- this->current_expression = build_equality_operation(expression, left, right);
+ case logical_disjunction:
+ this->current_expression = build2_loc(expression_location,
+ TRUTH_ORIF_EXPR, elna_bool_type_node, left, right);
break;
+ case logical_exclusive_disjunction:
+ this->current_expression = build2_loc(expression_location,
+ TRUTH_XOR_EXPR, elna_bool_type_node, left, right);
+ break;
+ case bitwise_conjunction:
+ this->current_expression = build2_loc(expression_location,
+ BIT_AND_EXPR, left_type, left, right);
+ break;
+ case bitwise_disjunction:
+ this->current_expression = build2_loc(expression_location,
+ BIT_IOR_EXPR, left_type, left, right);
+ break;
+ case bitwise_exclusive_disjunction:
+ this->current_expression = build2_loc(expression_location,
+ BIT_XOR_EXPR, left_type, left, right);
+ break;
+ case equals:
case not_equals:
this->current_expression = build_equality_operation(expression, left, right);
break;
case shift_left:
- this->current_expression = build_binary_operation(
- is_numeric_type(left_type) && right_type == elna_word_type_node,
- expression, LSHIFT_EXPR, left, right, left_type);
+ this->current_expression = fold_build2_loc(expression_location,
+ LSHIFT_EXPR, left_type, left, right);
break;
case shift_right:
- this->current_expression = build_binary_operation(
- is_numeric_type(left_type) && right_type == elna_word_type_node,
- expression, RSHIFT_EXPR, left, right, left_type);
+ this->current_expression = fold_build2_loc(expression_location,
+ RSHIFT_EXPR, left_type, left, right);
break;
}
}
@@ -734,22 +693,14 @@ namespace elna::gcc
build_pointer_type(TREE_TYPE(this->current_expression)));
TREE_NO_TRAMPOLINE(this->current_expression) = 1;
break;
- case negation:
- {
- tree operand_type = TREE_TYPE(this->current_expression);
-
- if (operand_type == elna_bool_type_node)
- {
- this->current_expression = build1_loc(location, TRUTH_NOT_EXPR,
- boolean_type_node, this->current_expression);
- }
- else
- {
- this->current_expression = build1_loc(location, BIT_NOT_EXPR,
- operand_type, this->current_expression);
- }
+ case bitwise_negation:
+ this->current_expression = build1_loc(location, BIT_NOT_EXPR,
+ TREE_TYPE(this->current_expression), this->current_expression);
+ break;
+ case logical_negation:
+ this->current_expression = build1_loc(location, TRUTH_NOT_EXPR,
+ boolean_type_node, this->current_expression);
break;
- }
case minus:
{
tree operand_type = TREE_TYPE(this->current_expression);
@@ -761,45 +712,11 @@ namespace elna::gcc
case plus:
// Identity: operand already in current_expression.
break;
+ default:
+ gcc_unreachable();
}
}
- static tree constant_to_tree(const boot::constant_value& constant_value)
- {
- if (std::holds_alternative<std::int32_t>(constant_value))
- {
- return build_int_cst(elna_int_type_node, std::get<std::int32_t>(constant_value));
- }
- else if (std::holds_alternative<std::uint32_t>(constant_value))
- {
- return build_int_cst(elna_word_type_node, std::get<std::uint32_t>(constant_value));
- }
-
- else if (std::holds_alternative<double>(constant_value))
- {
- auto real_value = std::get<double>(constant_value);
- REAL_VALUE_TYPE real;
- HOST_WIDE_INT target_bits[(sizeof(double) + sizeof(HOST_WIDE_INT) - 1)
- / sizeof(HOST_WIDE_INT)];
- std::memcpy(target_bits, &real_value, sizeof(real_value));
- real_from_target(&real, target_bits, REAL_MODE_FORMAT(TYPE_MODE(elna_float_type_node)));
- return build_real(elna_float_type_node, real);
- }
- else if (std::holds_alternative<bool>(constant_value))
- {
- return std::get<bool>(constant_value) ? boolean_true_node : boolean_false_node;
- }
- else if (std::holds_alternative<unsigned char>(constant_value))
- {
- return build_int_cst(elna_char_type_node, std::get<unsigned char>(constant_value));
- }
- else if (std::holds_alternative<std::nullptr_t>(constant_value))
- {
- return elna_pointer_nil_node;
- }
- return NULL_TREE;
- }
-
void generic_visitor::visit(boot::variable_declaration *declaration)
{
for (const auto& variable_identifier : declaration->identifiers)
@@ -865,7 +782,7 @@ namespace elna::gcc
DECL_CONTEXT(declaration_tree) = current_function_decl;
f_names = chainon(f_names, declaration_tree);
- auto declaration_statement = build1_loc(declaration_location, DECL_EXPR,
+ auto *declaration_statement = build1_loc(declaration_location, DECL_EXPR,
void_type_node, declaration_tree);
append_statement(declaration_statement);
}
@@ -909,12 +826,9 @@ namespace elna::gcc
this->current_expression = build4_loc(location,
ARRAY_REF, element_type, designator, offset, size_one_node, NULL_TREE);
}
- else if (TREE_TYPE(designator) == elna_string_type_node
- || expression->base().type_decoration.get<boot::slice_type>() != nullptr)
+ else if (expression->base().type_decoration.get<boot::slice_type>() != nullptr)
{
- tree ptr_field = (TREE_TYPE(designator) == elna_string_type_node)
- ? elna_string_ptr_field_node
- : TYPE_FIELDS(TREE_TYPE(designator));
+ tree ptr_field = TYPE_FIELDS(TREE_TYPE(designator));
offset = build2(MINUS_EXPR, elna_word_type_node, offset, size_one_node);
tree slice_ptr = build3_loc(location, COMPONENT_REF, TREE_TYPE(ptr_field),
designator, ptr_field, NULL_TREE);
diff --git a/gcc/gcc/elna-tree.cc b/gcc/gcc/elna-tree.cc
index 0227433..ab7363f 100644
--- a/gcc/gcc/elna-tree.cc
+++ b/gcc/gcc/elna-tree.cc
@@ -53,15 +53,6 @@ namespace elna::gcc
return INTEGRAL_TYPE_P(type) || POINTER_TYPE_P(type) || TREE_CODE(type) == REAL_TYPE;
}
- bool are_compatible_pointers(tree lhs_type, tree rhs)
- {
- gcc_assert(TYPE_P(lhs_type));
- tree rhs_type = TREE_TYPE(rhs);
-
- return (POINTER_TYPE_P(lhs_type) && rhs == elna_pointer_nil_node)
- || (POINTER_TYPE_P(lhs_type) && lhs_type == rhs_type);
- }
-
tree prepare_rvalue(tree rvalue)
{
if (DECL_P(rvalue) && TREE_CODE(TREE_TYPE(rvalue)) == FUNCTION_TYPE)
@@ -74,12 +65,6 @@ namespace elna::gcc
}
}
- bool is_assignable_from(tree assignee, tree assignment)
- {
- return get_qualified_type(TREE_TYPE(assignment), TYPE_UNQUALIFIED) == assignee
- || are_compatible_pointers(assignee, assignment);
- }
-
void append_statement(tree statement_tree)
{
if (!vec_safe_is_empty(f_binding_level->defers))
@@ -187,27 +172,6 @@ namespace elna::gcc
gcc_unreachable();
}
- tree build_binary_operation(bool condition, boot::binary_expression *expression,
- tree_code operator_code, tree left, tree right, tree target_type)
- {
- location_t expression_location = get_location(&expression->position());
- tree left_type = get_qualified_type(TREE_TYPE(left), TYPE_UNQUALIFIED);
- tree right_type = get_qualified_type(TREE_TYPE(right), TYPE_UNQUALIFIED);
-
- if (condition)
- {
- return fold_build2_loc(expression_location, operator_code, target_type, left, right);
- }
- else
- {
- error_at(expression_location,
- "invalid operands of type '%s' and '%s' for operator %s",
- print_type(left_type).c_str(), print_type(right_type).c_str(),
- boot::print_binary_operator(expression->operation()));
- return error_mark_node;
- }
- }
-
tree find_field_by_name(location_t expression_location, tree type, const std::string& field_name)
{
if (type == error_mark_node)
diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h
index 9cc1419..6080155 100644
--- a/include/elna/boot/ast.h
+++ b/include/elna/boot/ast.h
@@ -43,6 +43,12 @@ namespace elna::boot
disjunction,
conjunction,
exclusive_disjunction,
+ logical_conjunction,
+ logical_disjunction,
+ logical_exclusive_disjunction,
+ bitwise_conjunction,
+ bitwise_disjunction,
+ bitwise_exclusive_disjunction,
shift_left,
shift_right
};
@@ -51,6 +57,8 @@ namespace elna::boot
{
reference,
negation,
+ bitwise_negation,
+ logical_negation,
minus,
plus
};
@@ -638,18 +646,18 @@ namespace elna::boot
class slicing_expression : public designator_expression
{
expression *m_base;
- expression *m_offset;
- expression *m_length;
+ expression *m_start;
+ expression *m_end;
public:
slicing_expression(const source_position position,
- expression *base, expression *offset, expression *length);
+ expression *base, expression *start, expression *end);
void accept(parser_visitor *visitor) override;
slicing_expression *is_slicing() override;
expression& base();
- expression& offset();
- expression& length();
+ expression& start();
+ expression& end();
~slicing_expression() override;
};
@@ -882,6 +890,7 @@ namespace elna::boot
expression& lhs();
expression& rhs();
binary_operator operation() const;
+ void operation(binary_operator operation);
~binary_expression() override;
};
@@ -900,6 +909,7 @@ namespace elna::boot
expression& operand();
unary_operator operation() const;
+ void operation(unary_operator operation);
~unary_expression() override;
};
diff --git a/include/elna/boot/name_analysis.h b/include/elna/boot/name_analysis.h
index bb66c7a..5afe102 100644
--- a/include/elna/boot/name_analysis.h
+++ b/include/elna/boot/name_analysis.h
@@ -20,11 +20,11 @@ along with GCC; see the file COPYING3. If not see
#include <string>
#include <memory>
#include <map>
+#include <optional>
#include "elna/boot/ast.h"
#include "elna/boot/result.h"
#include "elna/boot/symbol.h"
-#include "elna/boot/type_check.h"
namespace elna::boot
{
@@ -93,6 +93,55 @@ namespace elna::boot
};
/**
+ * Access to a field that does not exist in the given type.
+ */
+ class field_not_found_error : public error
+ {
+ std::string field_name;
+ type composite_type;
+
+ public:
+ field_not_found_error(const identifier& field_name,
+ type composite_type);
+
+ std::string what() const override;
+ };
+
+ /**
+ * Field with the same name is already declared in this type.
+ */
+ class duplicate_member_error : public error
+ {
+ std::string member_name;
+ type aggregate;
+ std::optional<source_position> original;
+ std::optional<std::string> base_name;
+
+ public:
+ duplicate_member_error(const boot::identifier& member_name,
+ type aggregate, std::optional<source_position> original = std::nullopt,
+ std::optional<std::string> base_name = std::nullopt);
+
+ std::string what() const override;
+
+ std::optional<std::pair<std::string, source_position>> note() const override;
+ };
+
+ /**
+ * Trait is not applicable to the given type.
+ */
+ class unsupported_trait_type_error : public error
+ {
+ type actual;
+ std::string trait_name;
+
+ public:
+ unsupported_trait_type_error(const identifier& trait, type actual);
+
+ std::string what() const override;
+ };
+
+ /**
* Origin of a field in a composite type.
*/
struct field_origin
@@ -120,6 +169,8 @@ namespace elna::boot
type lookup_primitive_type(const std::string& name);
type lookup_field(const type& composite_type, const std::string& field_name);
+ std::optional<type> lookup_pointer_like_field(const std::string& field_name,
+ const type& element_type);
public:
name_analysis_visitor(symbol_bag bag);
diff --git a/include/elna/boot/type_check.h b/include/elna/boot/type_check.h
index 32da10c..1680077 100644
--- a/include/elna/boot/type_check.h
+++ b/include/elna/boot/type_check.h
@@ -59,38 +59,6 @@ namespace elna::boot
/**
* Attempted to access a field that does not exist on the given type.
*/
- class field_not_found_error : public error
- {
- std::string field_name;
- type composite_type;
-
- public:
- field_not_found_error(const identifier& field_name,
- type composite_type);
-
- std::string what() const override;
- };
-
- /**
- * Field with the same name is already declared in this type.
- */
- class duplicate_member_error : public error
- {
- std::string member_name;
- type aggregate;
- std::optional<source_position> original;
- std::optional<std::string> base_name;
-
- public:
- duplicate_member_error(const boot::identifier& member_name,
- type aggregate, std::optional<source_position> original = std::nullopt,
- std::optional<std::string> base_name = std::nullopt);
-
- std::string what() const override;
-
- std::optional<std::pair<std::string, source_position>> note() const override;
- };
-
/**
* Cyclic type declaration.
*/
@@ -133,8 +101,8 @@ namespace elna::boot
};
/**
- * Argument count in a procedure or record call doesn't match
- * the expected number of parameters or fields.
+ * Argument count in a procedure call or array constructor doesn't match
+ * the expected number of parameters or elements.
*/
class argument_count_error : public error
{
@@ -152,17 +120,6 @@ namespace elna::boot
* Type passed to a trait like #min or #max does not support
* the trait.
*/
- class unsupported_trait_type_error : public error
- {
- type actual;
- std::string trait_name;
-
- public:
- unsupported_trait_type_error(const identifier& trait, type actual);
-
- std::string what() const override;
- };
-
/**
* A module-level variable initializer must be a constant expression.
*/
@@ -192,6 +149,22 @@ namespace elna::boot
};
/**
+ * A binary operator is applied to unsupported types.
+ */
+ class binary_operation_error : public error
+ {
+ type left;
+ type right;
+ binary_operator op;
+
+ public:
+ binary_operation_error(const source_position position,
+ type left, type right, binary_operator operation);
+
+ std::string what() const override;
+ };
+
+ /**
* Chain of responsibility for type compatibility checks.
*
* Populate \c ctx with pre-resolved types, then call \c run().
@@ -220,6 +193,7 @@ namespace elna::boot
verdict check_exact_match() const;
verdict check_pointer_hatch() const;
verdict check_pointer_conversion() const;
+ verdict check_slice_conversion() const;
bool run();
};
@@ -261,5 +235,6 @@ namespace elna::boot
void visit(array_constructor_expression *expression) override;
void visit(slicing_expression *expression) override;
void visit(unary_expression *expression) override;
+ void visit(binary_expression *expression) override;
};
}
diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h
index 1d98675..04b91fb 100644
--- a/include/elna/gcc/elna-generic.h
+++ b/include/elna/gcc/elna-generic.h
@@ -45,14 +45,12 @@ namespace elna::gcc
void enter_scope();
tree leave_scope();
+ void begin_function(tree fndecl);
+ void finish_function(tree fndecl);
+
tree make_if_branch(boot::conditional_statements& branch, tree next,
tree goto_append = NULL_TREE);
- tree build_arithmetic_operation(boot::binary_expression *expression,
- tree_code operator_code, tree left, tree right);
- tree build_comparison_operation(boot::binary_expression *expression,
- tree_code operator_code, tree left, tree right);
- tree build_bit_logic_operation(boot::binary_expression *expression, tree left, tree right);
tree build_equality_operation(boot::binary_expression *expression, tree left, tree right);
void build_procedure_call(location_t call_location,
tree procedure_address, const std::vector<boot::expression *>& arguments);
diff --git a/include/elna/gcc/elna-tree.h b/include/elna/gcc/elna-tree.h
index 556d52b..d826f25 100644
--- a/include/elna/gcc/elna-tree.h
+++ b/include/elna/gcc/elna-tree.h
@@ -47,13 +47,6 @@ namespace elna::gcc
bool is_castable_type(tree type);
/**
- * \param lhs Left hand value.
- * \param rhs Right hand value.
- * \return Whether rhs can be assigned to lhs.
- */
- bool are_compatible_pointers(tree lhs_type, tree rhs);
-
- /**
* Prepares a value to be bound to a variable or parameter.
*
* If rvalue is a procedure declaration, builds a procedure pointer.
@@ -63,23 +56,12 @@ namespace elna::gcc
*/
tree prepare_rvalue(tree rvalue);
- /**
- * \param assignee Assignee.
- * \param assignee Assignment.
- * \return Whether an expression assignment can be assigned to a variable of type assignee.
- */
- bool is_assignable_from(tree assignee, tree assignment);
-
void append_statement(tree statement_tree);
void defer(tree statement_tree);
tree chain_defer();
tree do_pointer_arithmetic(boot::binary_operator binary_operator,
tree left, tree right, location_t expression_location);
- tree build_binary_operation(bool condition, boot::binary_expression *expression,
- tree_code operator_code, tree left, tree right, tree target_type);
- tree build_arithmetic_operation(boot::binary_expression *expression,
- tree_code operator_code, tree left, tree right);
tree build_field(location_t location, tree record_type, const std::string name, tree type);
tree find_field_by_name(location_t expression_location, tree type, const std::string& field_name);
tree build_static_array_type(tree type, const std::uint64_t size);
diff --git a/include/elna/gcc/elna1.h b/include/elna/gcc/elna1.h
index 3f48af5..b05cdf2 100644
--- a/include/elna/gcc/elna1.h
+++ b/include/elna/gcc/elna1.h
@@ -25,12 +25,9 @@ enum elna_tree_index
ELNA_TI_BOOL_TYPE,
ELNA_TI_POINTER_TYPE,
ELNA_TI_FLOAT_TYPE,
- ELNA_TI_STRING_TYPE,
ELNA_TI_BOOL_TRUE,
ELNA_TI_BOOL_FALSE,
ELNA_TI_POINTER_NIL,
- ELNA_TI_STRING_PTR_FIELD,
- ELNA_TI_STRING_LENGTH_FIELD,
ELNA_TI_MAX
};
@@ -44,13 +41,9 @@ extern std::vector<std::string> elna_include_dirs;
#define elna_bool_type_node elna_global_trees[ELNA_TI_BOOL_TYPE]
#define elna_pointer_type_node elna_global_trees[ELNA_TI_POINTER_TYPE]
#define elna_float_type_node elna_global_trees[ELNA_TI_FLOAT_TYPE]
-#define elna_string_type_node elna_global_trees[ELNA_TI_STRING_TYPE]
#define elna_bool_true_node elna_global_trees[ELNA_TI_BOOL_TRUE]
#define elna_bool_false_node elna_global_trees[ELNA_TI_BOOL_FALSE]
#define elna_pointer_nil_node elna_global_trees[ELNA_TI_POINTER_NIL]
-#define elna_string_ptr_field_node elna_global_trees[ELNA_TI_STRING_PTR_FIELD]
-#define elna_string_length_field_node elna_global_trees[ELNA_TI_STRING_LENGTH_FIELD]
-
/* Language-dependent contents of a type. */
struct GTY (()) lang_type
{
diff --git a/rakelib/gcc.rake b/rakelib/gcc.rake
index ce02bb6..abdeb6d 100644
--- a/rakelib/gcc.rake
+++ b/rakelib/gcc.rake
@@ -147,7 +147,11 @@ namespace :gcc do
desc 'Run tests'
task :check do
+ log_file = Pathname.new(HOST_GCC) + 'gcc/testsuite/elna/elna.log'
+
sh 'make', 'check-elna', chdir: File.join(HOST_GCC, 'gcc')
+
+ fail "\nSee #{log_file}." if log_file.file? and log_file.read =~ /^(FAIL|XPASS|UNRESOLVED|ERROR):/
end
desc 'Run clang-tidy'
@@ -165,6 +169,9 @@ namespace :gcc do
task :doc do
sh 'make', 'html', chdir: File.join(HOST_GCC, 'gcc')
end
+
+ desc 'Run GCC linters and tests'
+ task test: %w[gcc:tidy gcc:check]
end
desc 'Build the bootstrap compiler'
diff --git a/source/common.elna b/source/common.elna
index b6f85f1..1bdfa1f 100644
--- a/source/common.elna
+++ b/source/common.elna
@@ -17,7 +17,7 @@ type
proc write*(fd: Int; buf: Pointer; Word: Int): Int
extern
-proc write_s*(value: String)
+proc write_s*(value: []const Char)
begin
(* fwrite(cast(value.ptr: Pointer), value.length, 1u, stdout) *)
write(1, cast(value.ptr: Pointer), cast(value.length: Int))
@@ -78,7 +78,7 @@ begin
return nil
(* Returns true or false depending whether two strings are equal. *)
-proc string_compare*(lhs_pointer: ^Char; lhs_length: Word; rhs_pointer: String): Bool
+proc string_compare*(lhs_pointer: ^Char; lhs_length: Word; rhs_pointer: []const Char): Bool
var
result: Bool
begin
diff --git a/source/cstdio.elna b/source/cstdio.elna
index 15c467e..f44a972 100644
--- a/source/cstdio.elna
+++ b/source/cstdio.elna
@@ -10,7 +10,7 @@ var
stdout*: ^FILE := extern
stderr*: ^FILE := extern
-proc fopen*(pathname: ^Char; mode: ^Char): ^FILE
+proc fopen*(pathname, mode: ^const Char): ^FILE
extern
proc fclose*(stream: ^FILE): Int
@@ -31,28 +31,28 @@ extern
proc fread*(ptr: Pointer; size: Word; nmemb: Word; stream: ^FILE): Word
extern
-proc fwrite*(ptr: Pointer; size: Word; nitems: Word; stream: ^FILE): Word
+proc fwrite*(ptr: const Pointer; size: Word; nitems: Word; stream: ^FILE): Word
extern
proc fputc*(c: Int; stream: ^FILE): Word
extern
-proc perror*(s: ^Char)
+proc perror*(s: ^const Char)
extern
-proc puts*(s: ^Char): Int
+proc puts*(s: ^const Char): Int
extern
proc putchar*(c: Int): Int
extern
-proc sprintf*(str: Pointer; format: ^Char; number: Word): Int
+proc sprintf*(str: Pointer; format: ^const Char; number: Word): Int
extern
-proc fprintf*(stream: Pointer; format: ^Char; number: Word): Int
+proc fprintf*(stream: Pointer; format: ^const Char; number: Word): Int
extern
-proc fdopen*(fildes: Int; mode: ^Char): Pointer
+proc fdopen*(fildes: Int; mode: ^const Char): Pointer
extern
end.
diff --git a/source/cstring.elna b/source/cstring.elna
index e21056a..0b4bd90 100644
--- a/source/cstring.elna
+++ b/source/cstring.elna
@@ -5,25 +5,25 @@
proc memset*(ptr: Pointer; c: Int; n: Word): ^Char
extern
-proc memcpy*(dst, src: Pointer; n: Word)
+proc memcpy*(dst: Pointer; src: const Pointer; n: Word)
extern
-proc memcmp*(s1, s2: Pointer; n: Word): Int
+proc memcmp*(s1, s2: const Pointer; n: Word): Int
extern
-proc strcmp*(s1: ^Char; s2: ^Char): Int
+proc strcmp*(s1: ^const Char; s2: ^const Char): Int
extern
-proc strncmp*(s1: ^Char; s2: ^Char; n: Word): Int
+proc strncmp*(s1: ^const Char; s2: ^const Char; n: Word): Int
extern
-proc strncpy*(dst: ^Char; src: ^Char; dsize: Word): ^Char
+proc strncpy*(dst: ^Char; src: ^const Char; dsize: Word): ^Char
extern
-proc strcpy*(dst: ^Char; src: ^Char): ^Char
+proc strcpy*(dst: ^Char; src: ^const Char): ^Char
extern
-proc strlen*(ptr: ^Char): Word
+proc strlen*(ptr: ^const Char): Word
extern
end.
diff --git a/source/lexer.elna b/source/lexer.elna
index 9e1db21..fa79917 100644
--- a/source/lexer.elna
+++ b/source/lexer.elna
@@ -28,7 +28,7 @@ type
)
ElnaLexerToken* = record
kind: ElnaLexerKind;
- start: String; (* DEPRECATED *)
+ start: []const Char; (* DEPRECATED *)
position: ElnaPosition
end
ElnaLexerBooleanToken* = record(ElnaLexerToken)
@@ -38,7 +38,7 @@ type
value: Char
end
ElnaLexerStringToken* = record(ElnaLexerToken)
- value: String
+ value: []const Char
end
ElnaLexerIntegerToken* = record(ElnaLexerToken)
value: Int
@@ -540,7 +540,7 @@ begin
result_length := cast(position_end - position_start: Word);
result := elna_lexer_token_create(ElnaLexerKind.identifier, position);
- result^.start := String(position_start, result_length);
+ result^.start := position_start[1 to result_length];
if position_start^ = '#' then
result^.kind := ElnaLexerKind.trait
@@ -601,7 +601,7 @@ begin
elsif delimiter = '"' then
result := elna_lexer_token_create(ElnaLexerKind.string, position)
end;
- result^.start := String(start_position, cast(end_position - start_position: Word))
+ result^.start := start_position[1 to cast(end_position - start_position: Word)]
return result
proc elna_lexer_classify_integer(start_position, end_position: ^Char; position: ^ElnaPosition): ^ElnaLexerToken
@@ -609,7 +609,7 @@ var
result: ^ElnaLexerToken
begin
result := elna_lexer_token_create(ElnaLexerKind.integer, position);
- result^.start := String(start_position, cast(end_position - start_position: Word))
+ result^.start := start_position[1 to cast(end_position - start_position: Word)]
return result
proc elna_lexer_classify_finalize(start_position: ^Char; position: ^ElnaPosition): ^ElnaLexerToken
diff --git a/source/main.elna b/source/main.elna
index 4a23898..c127ba4 100644
--- a/source/main.elna
+++ b/source/main.elna
@@ -40,19 +40,13 @@ var
proc reallocarray(ptr: Pointer; n: Word; size: Word): Pointer
return realloc(ptr, n * size)
-proc substring(string: String; start: Word; count: Word): String
-return String(string.ptr + start, count)
-
-proc open_substring(string: String; start: Word): String
-return substring(string, start, string.length - start)
-
-proc string_dup(origin: String): String
+proc string_dup(origin: []const Char): []const Char
var
copy: ^Char
begin
copy := malloc(origin.length);
strncpy(copy, origin.ptr, origin.length)
-return String(copy, origin.length)
+return copy[1 to origin.length]
proc string_buffer_new(): StringBuffer
var
@@ -78,11 +72,11 @@ begin
buffer^.size := buffer^.size - count
return
-proc string_buffer_clear(buffer: ^StringBuffer): String
+proc string_buffer_clear(buffer: ^StringBuffer): []const Char
var
- result: String
+ result: []const Char
begin
- result := String(cast(buffer^.data: ^Char), buffer^.size);
+ result := cast(buffer^.data: ^Char)[1 to buffer^.size];
buffer^.size := 0u
return result
@@ -300,7 +294,7 @@ begin
return
(* Categorize an identifier. *)
-proc lexer_categorize(token_content: String): ^ElnaLexerToken
+proc lexer_categorize(token_content: []const Char): ^ElnaLexerToken
var
current_token: ^ElnaLexerToken
begin
diff --git a/testsuite/runnable/record_extension.elna b/testsuite/runnable/record_extension.elna
index 1aae5b3..47ac908 100644
--- a/testsuite/runnable/record_extension.elna
+++ b/testsuite/runnable/record_extension.elna
@@ -3,7 +3,7 @@ type
kind: Word
end
ElnaLexerStringToken = record(ElnaLexerToken)
- value: String
+ value: []const Char
end
var
diff --git a/testsuite/runnable/return_aggregate.elna b/testsuite/runnable/return_aggregate.elna
index e162498..90c1677 100644
--- a/testsuite/runnable/return_aggregate.elna
+++ b/testsuite/runnable/return_aggregate.elna
@@ -5,8 +5,8 @@ type
end
proc f(): R
-return R{a: 1, b: 2}
+return R{ a: 1, b: 2 }
begin
- assert(f() = R{a: 1, b: 2})
+ assert(f() = R{ a: 1, b: 2 })
end.
diff --git a/testsuite/runnable/slice_array.elna b/testsuite/runnable/slice_array.elna
new file mode 100644
index 0000000..af0a270
--- /dev/null
+++ b/testsuite/runnable/slice_array.elna
@@ -0,0 +1,11 @@
+var
+ array: [3]Int := [3]Int{ 2, 4, 6 }
+ slice: []Int
+
+begin
+ slice := array[1 to 3];
+
+ assert(slice.length = 3u);
+ assert(slice[1] = 2);
+ assert(slice[3] = 6)
+end.
diff --git a/testsuite/runnable/slice_pointer.elna b/testsuite/runnable/slice_pointer.elna
new file mode 100644
index 0000000..d053f51
--- /dev/null
+++ b/testsuite/runnable/slice_pointer.elna
@@ -0,0 +1,11 @@
+var
+ array: [3]Int := [3]Int{ 2, 4, 6 }
+ slice: []Int
+
+begin
+ slice := array.ptr[1 to 3];
+
+ assert(slice.length = 3u);
+ assert(slice[1] = 2);
+ assert(slice[3] = 6)
+end.
diff --git a/testsuite/runnable/slice_slice.elna b/testsuite/runnable/slice_slice.elna
new file mode 100644
index 0000000..d6f309f
--- /dev/null
+++ b/testsuite/runnable/slice_slice.elna
@@ -0,0 +1,13 @@
+var
+ array: [5]Int := [5]Int{ 2, 4, 6, 8, 10 }
+ slice1, slice2: []Int
+
+begin
+ slice1 := array.ptr[1 to array.length];
+ slice2 := slice1[2 to 4];
+
+ assert(slice2.length = 3u);
+ assert(slice2[1] = 4);
+ assert(slice2[2] = 6);
+ assert(slice2[3] = 8)
+end.