aboutsummaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
Diffstat (limited to 'boot')
-rw-r--r--boot/evaluator.cc4
-rw-r--r--boot/name_analysis.cc8
-rw-r--r--boot/parser.yy4
-rw-r--r--boot/symbol.cc27
-rw-r--r--boot/type_check.cc64
5 files changed, 100 insertions, 7 deletions
diff --git a/boot/evaluator.cc b/boot/evaluator.cc
index f782dd6..1acadd3 100644
--- a/boot/evaluator.cc
+++ b/boot/evaluator.cc
@@ -185,6 +185,10 @@ namespace elna::boot
return std::nullopt;
}, operand.value());
}
+ if (subject.operation() == unary_operator::plus)
+ {
+ return operand;
+ }
return std::nullopt;
}
diff --git a/boot/name_analysis.cc b/boot/name_analysis.cc
index 5255878..b13c043 100644
--- a/boot/name_analysis.cc
+++ b/boot/name_analysis.cc
@@ -538,14 +538,8 @@ namespace elna::boot
{
type resolved = resolve_underlying_type(trait->type_decoration);
bool is_enum = resolved.get<enumeration_type>() != nullptr;
- bool is_integral = false;
- if (auto prim = resolved.get<primitive_type>())
- {
- is_integral = prim->identifier == "Int" || prim->identifier == "Word"
- || prim->identifier == "Bool" || prim->identifier == "Char";
- }
- if (!is_enum && !is_integral)
+ if (!is_enum && !is_discrete_type(resolved))
{
add_error<unsupported_trait_type_error>(trait->name,
trait->type_decoration);
diff --git a/boot/parser.yy b/boot/parser.yy
index 1dd42a8..aad5769 100644
--- a/boot/parser.yy
+++ b/boot/parser.yy
@@ -351,6 +351,10 @@ unary_expression:
{
$$ = new boot::unary_expression(boot::make_position(@$), $2, boot::unary_operator::minus);
}
+ | "+" operand
+ {
+ $$ = new boot::unary_expression(boot::make_position(@$), $2, boot::unary_operator::plus);
+ }
expressions:
expression "," expressions
{
diff --git a/boot/symbol.cc b/boot/symbol.cc
index 6ad89b7..7b45612 100644
--- a/boot/symbol.cc
+++ b/boot/symbol.cc
@@ -420,6 +420,33 @@ namespace elna::boot
return false;
}
+ bool is_numeric_type(const type& checked)
+ {
+ type resolved = resolve_underlying_type(checked);
+
+ return is_primitive_type(resolved, "Int")
+ || is_primitive_type(resolved, "Word")
+ || is_primitive_type(resolved, "Float");
+ }
+
+ bool is_integral_type(const type& checked)
+ {
+ type resolved = resolve_underlying_type(checked);
+
+ return is_primitive_type(resolved, "Int")
+ || is_primitive_type(resolved, "Word");
+ }
+
+ bool is_discrete_type(const type& checked)
+ {
+ type resolved = resolve_underlying_type(checked);
+
+ return is_primitive_type(resolved, "Int")
+ || is_primitive_type(resolved, "Word")
+ || is_primitive_type(resolved, "Bool")
+ || is_primitive_type(resolved, "Char");
+ }
+
bool is_any_pointer_type(const type& checked)
{
return checked.get<pointer_type>() != nullptr
diff --git a/boot/type_check.cc b/boot/type_check.cc
index b310e34..d9f3071 100644
--- a/boot/type_check.cc
+++ b/boot/type_check.cc
@@ -200,6 +200,35 @@ namespace elna::boot
+ "' does not support trait '#" + trait_name + "'";
}
+ unary_operation_error::unary_operation_error(const source_position position,
+ type actual, unary_operator op)
+ : error(position), actual(actual), op(op)
+ {
+ }
+
+ char unary_operation_error::unary_operator_symbol(unary_operator op)
+ {
+ switch (op)
+ {
+ case unary_operator::reference:
+ return '@';
+ case unary_operator::negation:
+ return '~';
+ case unary_operator::minus:
+ return '-';
+ case unary_operator::plus:
+ return '+';
+ }
+ __builtin_unreachable();
+ }
+
+ std::string unary_operation_error::what() const
+ {
+ return "Type '" + actual.to_string()
+ + "' cannot be used with unary '"
+ + unary_operator_symbol(op) + "'";
+ }
+
/*
* Whether the type itself is constant or has a constant member at any
* nesting level, so that values of this type cannot be reassigned as a
@@ -597,4 +626,39 @@ namespace elna::boot
}
}
}
+
+ void type_analysis_visitor::visit(unary_expression *expression)
+ {
+ walking_visitor::visit(expression);
+
+ auto op = expression->operation();
+ type resolved = resolve_underlying_type(expression->operand().type_decoration);
+
+ if (op == unary_operator::plus)
+ {
+ if (!is_numeric_type(resolved))
+ {
+ add_error<unary_operation_error>(expression->position(),
+ expression->operand().type_decoration, op);
+ }
+ }
+ else if (op == unary_operator::minus)
+ {
+ if (!is_primitive_type(resolved, "Int")
+ && !is_primitive_type(resolved, "Float"))
+ {
+ add_error<unary_operation_error>(expression->position(),
+ expression->operand().type_decoration, op);
+ }
+ }
+ else if (op == unary_operator::negation)
+ {
+ if (!is_primitive_type(resolved, "Bool")
+ && !is_integral_type(resolved))
+ {
+ add_error<unary_operation_error>(expression->position(),
+ expression->operand().type_decoration, op);
+ }
+ }
+ }
}