diff options
Diffstat (limited to 'boot')
| -rw-r--r-- | boot/evaluator.cc | 4 | ||||
| -rw-r--r-- | boot/name_analysis.cc | 8 | ||||
| -rw-r--r-- | boot/parser.yy | 4 | ||||
| -rw-r--r-- | boot/symbol.cc | 27 | ||||
| -rw-r--r-- | boot/type_check.cc | 64 |
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); + } + } + } } |
