#include #include "include/utils.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("Incomparable values", 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("Incomparable values", pos); } } default: throw TypeError("Incomparable values", 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; } } 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; break; case TokenType::Identifier: { string identifier = get(token.data); if (!memory.contains(identifier)) throw RuntimeError("Unknown identifier \""+identifier+"\"", token.pos); return memory.get(identifier).type; } throw; break; default: throw; } } 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("Can't find an explicit cast to bool", get_node_pos(node.children[0])); } 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("Can't find a cast to bool", get_node_pos(node.children[0])); } 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("Can't find an explicit cast to bool", get_node_pos(node.children[1])); } 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("Can't find an explicit cast to bool", get_node_pos(node.children[0])); } if (!bool_castable(analyze(node.children[1], memory))) { throw TypeError("Can't find an explicit cast to bool", get_node_pos(node.children[1])); } return Type::Int; } break; case NodeType::Neg: { if (!bool_castable(analyze(node.children[0], memory))) { throw TypeError("Can't find an explicit cast to bool", get_node_pos(node.children[0])); } 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("Expression must have integral type", get_node_pos(node.children[0])); } if (holds_alternative(e2) || get(e2) != Type::Int) { throw TypeError("Expression must have integral type", 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("Expressions must have arithmetic type", get_node_pos(node.children[1])); } } break; case NodeType::Declaration: { Token token = get(node.children[0]); string identifier = get(token.data); if (memory.contains(identifier)) throw TypeError("Already defined identifier \""+identifier+"\"", token.pos); Type type = string_to_type(get(token.data), token.pos); memory.declare(identifier, type); return {}; } break; case NodeType::AssignedDeclaration: { Token token = get(node.children[0]); string identifier = get(token.data); if (memory.contains(identifier)) throw TypeError("Already defined identifier \""+identifier+"\"", token.pos); Type type = string_to_type(get(token.data), token.pos); memory.declare(identifier, type); cout << "declared" << endl; 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 TypeError("Unknown identifier \""+identifier+"\"", identifierTok.pos); 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("Unknown identifier \""+identifier+"\"", identifierTok.pos); return memory.get(identifier).type; } } } throw; }