2023-12-08 15:59:45 +01:00
|
|
|
#include <iostream>
|
|
|
|
#include "include/utils.h"
|
2023-12-15 14:57:07 +01:00
|
|
|
#include "include/errors.h"
|
2023-12-08 15:59:45 +01:00
|
|
|
#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<monostate>(res1) || holds_alternative<monostate>(res2)) {
|
2023-12-15 14:11:44 +01:00
|
|
|
throw TypeError(ErrorType::TypesNotComparable, pos);
|
2023-12-08 15:59:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Type type1 = get<Type>(res1);
|
|
|
|
Type type2 = get<Type>(res2);
|
|
|
|
|
|
|
|
|
2023-12-26 15:50:33 +01:00
|
|
|
switch (type1.type) {
|
|
|
|
case TypeType::Int:
|
|
|
|
case TypeType::Double: {
|
|
|
|
switch (type2.type) {
|
|
|
|
case TypeType::Int:
|
|
|
|
case TypeType::Double: {
|
2023-12-08 15:59:45 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
default:
|
2023-12-15 14:11:44 +01:00
|
|
|
throw TypeError(ErrorType::TypesNotComparable, pos);
|
2023-12-08 15:59:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
2023-12-15 14:11:44 +01:00
|
|
|
throw TypeError(ErrorType::TypesNotComparable, pos);
|
2023-12-08 15:59:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Type get_cast(AnalysisResult type1, AnalysisResult type2, CodePosition pos) {
|
|
|
|
(void)type1; (void)type2; (void)pos;
|
2023-12-26 15:50:33 +01:00
|
|
|
return type_type_to_type(TypeType::Int);
|
2023-12-08 15:59:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool is_arithmetic_type(Type type) {
|
2023-12-26 15:50:33 +01:00
|
|
|
switch (type.type) {
|
|
|
|
case TypeType::Int:
|
|
|
|
case TypeType::Double:
|
2023-12-08 15:59:45 +01:00
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-09 11:41:14 +01:00
|
|
|
Type try_string_to_type(string type_name, CodePosition pos) {
|
|
|
|
try {
|
|
|
|
Type type = string_to_type(type_name);
|
|
|
|
return type;
|
|
|
|
} catch (...) {
|
2023-12-15 14:11:44 +01:00
|
|
|
throw TypeError(ErrorType::UnknownType, pos, type_name);
|
2023-12-09 11:41:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-08 15:59:45 +01:00
|
|
|
AnalysisResult analyze(Node &ast, Memory &memory) {
|
|
|
|
if (holds_alternative<Token>(ast)) {
|
|
|
|
Token token = get<Token>(ast);
|
|
|
|
switch (token.type) {
|
|
|
|
case TokenType::Litteral: {
|
|
|
|
if (holds_alternative<int>(token.data)) {
|
2023-12-26 15:50:33 +01:00
|
|
|
return type_type_to_type(TypeType::Int);
|
2023-12-08 15:59:45 +01:00
|
|
|
} else if (holds_alternative<double>(token.data)) {
|
2023-12-26 15:50:33 +01:00
|
|
|
return type_type_to_type(TypeType::Double);
|
2023-12-08 15:59:45 +01:00
|
|
|
}
|
2023-12-15 10:37:44 +01:00
|
|
|
throw exception();
|
|
|
|
break;
|
2023-12-08 15:59:45 +01:00
|
|
|
}
|
|
|
|
case TokenType::Identifier: {
|
|
|
|
string identifier = get<string>(token.data);
|
|
|
|
|
|
|
|
if (!memory.contains(identifier))
|
2023-12-15 14:11:44 +01:00
|
|
|
throw RuntimeError(ErrorType::UnknownIdentifier, token.pos, identifier);
|
2023-12-08 15:59:45 +01:00
|
|
|
|
|
|
|
return memory.get(identifier).type;
|
2023-12-15 10:37:44 +01:00
|
|
|
throw exception();
|
|
|
|
break;
|
2023-12-08 15:59:45 +01:00
|
|
|
}
|
2023-12-15 10:37:44 +01:00
|
|
|
case TokenType::Break:
|
|
|
|
case TokenType::Continue:
|
|
|
|
return {};
|
2023-12-08 15:59:45 +01:00
|
|
|
default:
|
2023-12-09 11:41:14 +01:00
|
|
|
throw exception();
|
2023-12-08 15:59:45 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
InnerNode node = get<InnerNode>(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))) {
|
2023-12-15 14:11:44 +01:00
|
|
|
throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[0]), "bool");
|
2023-12-08 15:59:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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))) {
|
2023-12-15 14:11:44 +01:00
|
|
|
throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[0]), "bool");
|
2023-12-08 15:59:45 +01:00
|
|
|
}
|
|
|
|
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))) {
|
2023-12-15 14:11:44 +01:00
|
|
|
throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[1]), "bool");
|
2023-12-08 15:59:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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))) {
|
2023-12-15 14:11:44 +01:00
|
|
|
throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[0]), "bool");
|
2023-12-08 15:59:45 +01:00
|
|
|
}
|
|
|
|
if (!bool_castable(analyze(node.children[1], memory))) {
|
2023-12-15 14:11:44 +01:00
|
|
|
throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[1]), "bool");
|
2023-12-08 15:59:45 +01:00
|
|
|
}
|
|
|
|
|
2023-12-26 15:50:33 +01:00
|
|
|
return type_type_to_type(TypeType::Int);
|
2023-12-08 15:59:45 +01:00
|
|
|
} break;
|
|
|
|
case NodeType::Neg: {
|
|
|
|
if (!bool_castable(analyze(node.children[0], memory))) {
|
2023-12-15 14:11:44 +01:00
|
|
|
throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[0]), "bool");
|
2023-12-08 15:59:45 +01:00
|
|
|
}
|
|
|
|
|
2023-12-26 15:50:33 +01:00
|
|
|
return type_type_to_type(TypeType::Int);
|
2023-12-08 15:59:45 +01:00
|
|
|
} 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);
|
|
|
|
|
2023-12-26 15:50:33 +01:00
|
|
|
return type_type_to_type(TypeType::Int);
|
2023-12-08 15:59:45 +01:00
|
|
|
} 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);
|
|
|
|
|
2023-12-26 15:50:33 +01:00
|
|
|
if (holds_alternative<monostate>(e1) || get<Type>(e1).type != TypeType::Int) {
|
2023-12-15 14:11:44 +01:00
|
|
|
throw TypeError(ErrorType::ExpectedIntegralType, get_node_pos(node.children[0]));
|
2023-12-08 15:59:45 +01:00
|
|
|
}
|
2023-12-26 15:50:33 +01:00
|
|
|
if (holds_alternative<monostate>(e2) || get<Type>(e2).type != TypeType::Int) {
|
2023-12-15 14:11:44 +01:00
|
|
|
throw TypeError(ErrorType::ExpectedIntegralType, get_node_pos(node.children[1]));
|
2023-12-08 15:59:45 +01:00
|
|
|
}
|
|
|
|
|
2023-12-26 15:50:33 +01:00
|
|
|
return type_type_to_type(TypeType::Int);
|
2023-12-08 15:59:45 +01:00
|
|
|
} break;
|
|
|
|
case NodeType::UnaryPlus:
|
|
|
|
case NodeType::UnaryMinus: {
|
|
|
|
AnalysisResult res = analyze(node.children[0], memory);
|
|
|
|
|
|
|
|
if (holds_alternative<monostate>(res) || !is_arithmetic_type(get<Type>(res))) {
|
2023-12-15 14:11:44 +01:00
|
|
|
throw TypeError(ErrorType::ExpectedArithmeticType, get_node_pos(node.children[0]));
|
2023-12-08 15:59:45 +01:00
|
|
|
}
|
2023-12-13 14:42:29 +01:00
|
|
|
|
|
|
|
return get<Type>(res);
|
2023-12-08 15:59:45 +01:00
|
|
|
} break;
|
|
|
|
case NodeType::Declaration: {
|
2023-12-09 12:04:43 +01:00
|
|
|
Token type_token = get<Token>(node.children[0]);
|
|
|
|
string type_string = get<string>(type_token.data);
|
|
|
|
|
|
|
|
Token token = get<Token>(node.children[1]);
|
2023-12-08 15:59:45 +01:00
|
|
|
string identifier = get<string>(token.data);
|
2023-12-09 12:04:43 +01:00
|
|
|
|
2023-12-15 10:38:36 +01:00
|
|
|
if (memory.contains_top(identifier))
|
2023-12-15 15:36:09 +01:00
|
|
|
throw RuntimeError(ErrorType::AlreadyDeclaredIdentifier, token.pos, identifier);
|
2023-12-08 15:59:45 +01:00
|
|
|
|
2023-12-09 12:04:43 +01:00
|
|
|
Type type = try_string_to_type(type_string, type_token.pos);
|
2023-12-08 15:59:45 +01:00
|
|
|
memory.declare(identifier, type);
|
|
|
|
|
|
|
|
return {};
|
|
|
|
} break;
|
|
|
|
case NodeType::AssignedDeclaration: {
|
2023-12-09 12:04:43 +01:00
|
|
|
Token type_token = get<Token>(node.children[0]);
|
|
|
|
string type_string = get<string>(type_token.data);
|
|
|
|
|
|
|
|
Token token = get<Token>(node.children[1]);
|
2023-12-08 15:59:45 +01:00
|
|
|
string identifier = get<string>(token.data);
|
2023-12-09 12:04:43 +01:00
|
|
|
|
2023-12-15 10:38:36 +01:00
|
|
|
if (memory.contains_top(identifier))
|
2023-12-15 15:36:09 +01:00
|
|
|
throw RuntimeError(ErrorType::AlreadyDeclaredIdentifier, token.pos, identifier);
|
2023-12-08 15:59:45 +01:00
|
|
|
|
2023-12-09 12:04:43 +01:00
|
|
|
Type type = try_string_to_type(type_string, type_token.pos);
|
2023-12-08 15:59:45 +01:00
|
|
|
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<Token>(node.children[0]);
|
|
|
|
string identifier = get<string>(identifierTok.data);
|
|
|
|
if (!memory.contains(identifier))
|
2023-12-15 14:11:44 +01:00
|
|
|
throw RuntimeError(ErrorType::UnknownIdentifier, identifierTok.pos, identifier);
|
2023-12-08 15:59:45 +01:00
|
|
|
|
|
|
|
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<Token>(node.children[0]);
|
|
|
|
string identifier = get<string>(identifierTok.data);
|
|
|
|
|
|
|
|
if (!memory.contains(identifier))
|
2023-12-15 14:11:44 +01:00
|
|
|
throw RuntimeError(ErrorType::UnknownIdentifier, identifierTok.pos, identifier);
|
2023-12-08 15:59:45 +01:00
|
|
|
|
|
|
|
return memory.get(identifier).type;
|
|
|
|
}
|
2023-12-15 10:52:53 +01:00
|
|
|
case NodeType::Comma: {
|
|
|
|
analyze(node.children[0], memory);
|
|
|
|
return analyze(node.children[1], memory);
|
|
|
|
}
|
2023-12-27 18:43:56 +01:00
|
|
|
default:
|
|
|
|
return {};
|
2023-12-08 15:59:45 +01:00
|
|
|
}
|
|
|
|
}
|
2023-12-09 11:41:14 +01:00
|
|
|
throw exception();
|
2023-12-08 15:59:45 +01:00
|
|
|
}
|