#include #include "include/utils.h" #include "include/errors.h" #include "include/analysis.h" bool bool_castable(AnalysisResult type) { (void)type; return true; } void check_comparable(AnalysisResult res1, AnalysisResult res2, CodePosition pos) { if (holds_alternative(res1) || holds_alternative(res2)) { throw TypeError(ErrorType::TypesNotComparable, pos); } Type type1 = get(res1); Type type2 = get(res2); switch (type1) { case Type::Int: case Type::Double: { switch (type2) { case Type::Int: case Type::Double: { return; } default: throw TypeError(ErrorType::TypesNotComparable, pos); } } default: throw TypeError(ErrorType::TypesNotComparable, pos); } } Type get_cast(AnalysisResult type1, AnalysisResult type2, CodePosition pos) { (void)type1; (void)type2; (void)pos; return Type::Int; } bool is_arithmetic_type(Type type) { switch (type) { case Type::Int: case Type::Double: return true; default: return false; } } Type try_string_to_type(string type_name, CodePosition pos) { try { Type type = string_to_type(type_name); return type; } catch (...) { throw TypeError(ErrorType::UnknownType, pos, type_name); } } AnalysisResult analyze(Node &ast, Memory &memory) { if (holds_alternative(ast)) { Token token = get(ast); switch (token.type) { case TokenType::Litteral: { if (holds_alternative(token.data)) { return Type::Int; } else if (holds_alternative(token.data)) { return Type::Double; } throw exception(); break; } case TokenType::Identifier: { string identifier = get(token.data); if (!memory.contains(identifier)) throw RuntimeError(ErrorType::UnknownIdentifier, token.pos, identifier); return memory.get(identifier).type; throw exception(); break; } case TokenType::Break: case TokenType::Continue: return {}; default: throw exception(); } } else { InnerNode node = get(ast); switch (node.type) { case NodeType::Prog: analyze(node.children[0], memory); analyze(node.children[1], memory); return {}; break; case NodeType::Epsilon: return {}; break; case NodeType::If: case NodeType::IfElse: { if (!bool_castable(analyze(node.children[0], memory))) { throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[0]), "bool"); } analyze(node.children[1], memory); if (node.type == NodeType::IfElse) analyze(node.children[2], memory); return {}; } break; case NodeType::While: { if (!bool_castable(analyze(node.children[0], memory))) { throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[0]), "bool"); } analyze(node.children[1], memory); return {}; } break; case NodeType::For: { memory.add_scope(ScopeType::For); analyze(node.children[0], memory); if (!bool_castable(analyze(node.children[1], memory))) { throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[1]), "bool"); } analyze(node.children[2], memory); analyze(node.children[3], memory); memory.remove_scope(); return {}; } break; case NodeType::Bloc: { memory.add_scope(ScopeType::Block); analyze(node.children[0], memory); memory.remove_scope(); return {}; } break; case NodeType::Lor: case NodeType::Land: { if (!bool_castable(analyze(node.children[0], memory))) { throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[0]), "bool"); } if (!bool_castable(analyze(node.children[1], memory))) { throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[1]), "bool"); } return Type::Int; } break; case NodeType::Neg: { if (!bool_castable(analyze(node.children[0], memory))) { throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[0]), "bool"); } return Type::Int; } break; case NodeType::Lt: case NodeType::Gt: case NodeType::Leq: case NodeType::Geq: { AnalysisResult res1 = analyze(node.children[0], memory); AnalysisResult res2 = analyze(node.children[1], memory); check_comparable(res1, res2, node.pos); return Type::Int; } break; case NodeType::Eq: case NodeType::Neq: case NodeType::Plus: case NodeType::Minus: case NodeType::Mult: case NodeType::Div: { AnalysisResult res1 = analyze(node.children[0], memory); AnalysisResult res2 = analyze(node.children[1], memory); return get_cast(res1, res2, node.pos); } break; case NodeType::Mod: { AnalysisResult e1 = analyze(node.children[0], memory); AnalysisResult e2 = analyze(node.children[1], memory); if (holds_alternative(e1) || get(e1) != Type::Int) { throw TypeError(ErrorType::ExpectedIntegralType, get_node_pos(node.children[0])); } if (holds_alternative(e2) || get(e2) != Type::Int) { throw TypeError(ErrorType::ExpectedIntegralType, get_node_pos(node.children[1])); } return Type::Int; } break; case NodeType::UnaryPlus: case NodeType::UnaryMinus: { AnalysisResult res = analyze(node.children[0], memory); if (holds_alternative(res) || !is_arithmetic_type(get(res))) { throw TypeError(ErrorType::ExpectedArithmeticType, get_node_pos(node.children[0])); } return get(res); } break; case NodeType::Declaration: { Token type_token = get(node.children[0]); string type_string = get(type_token.data); Token token = get(node.children[1]); string identifier = get(token.data); if (memory.contains_top(identifier)) throw RuntimeError(ErrorType::AlreadyDeclaredIdentifier, token.pos, identifier); Type type = try_string_to_type(type_string, type_token.pos); memory.declare(identifier, type); return {}; } break; case NodeType::AssignedDeclaration: { Token type_token = get(node.children[0]); string type_string = get(type_token.data); Token token = get(node.children[1]); string identifier = get(token.data); if (memory.contains_top(identifier)) throw RuntimeError(ErrorType::AlreadyDeclaredIdentifier, token.pos, identifier); Type type = try_string_to_type(type_string, type_token.pos); memory.declare(identifier, type); get_cast(type, analyze(node.children[2], memory), get_node_pos(node)); return type; } break; case NodeType::Assignment: { Token identifierTok = get(node.children[0]); string identifier = get(identifierTok.data); if (!memory.contains(identifier)) throw RuntimeError(ErrorType::UnknownIdentifier, identifierTok.pos, identifier); Type type = memory.get(identifier).type; AnalysisResult res = analyze(node.children[1], memory); get_cast(type, res, get_node_pos(node.children[1])); return type; } break; case NodeType::LIncr: case NodeType::RIncr: case NodeType::LDecr: case NodeType::RDecr: { Token identifierTok = get(node.children[0]); string identifier = get(identifierTok.data); if (!memory.contains(identifier)) throw RuntimeError(ErrorType::UnknownIdentifier, identifierTok.pos, identifier); return memory.get(identifier).type; } case NodeType::Comma: { analyze(node.children[0], memory); return analyze(node.children[1], memory); } } } throw exception(); }