From cc218d08342b95cad32ba4fa9fd18cf5c90c5241 Mon Sep 17 00:00:00 2001 From: augustin64 Date: Fri, 12 Jan 2024 15:40:03 +0100 Subject: [PATCH] Add casting.cpp --- src/analysis.cpp | 103 +++++++++++---------------------------- src/casting.cpp | 101 ++++++++++++++++++++++++++++++++++++++ src/include/analysis.hpp | 8 ++- src/include/casting.hpp | 37 ++++++++++++++ src/include/memory.hpp | 4 +- src/include/tokenize.hpp | 4 +- src/include/types.hpp | 6 +-- src/include/utils.hpp | 2 +- src/interpreter.cpp | 41 ++-------------- src/memory.cpp | 2 +- src/utils.cpp | 10 ++-- test/analysis.cpp | 71 +++++++++++++++++++++++++++ 12 files changed, 259 insertions(+), 130 deletions(-) create mode 100644 src/casting.cpp create mode 100644 src/include/casting.hpp create mode 100644 test/analysis.cpp diff --git a/src/analysis.cpp b/src/analysis.cpp index c861e10..83342d9 100644 --- a/src/analysis.cpp +++ b/src/analysis.cpp @@ -1,53 +1,8 @@ #include -#include "include/utils.hpp" #include "include/errors.hpp" #include "include/analysis.hpp" +#include "include/casting.hpp" -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.type) { - case TypeType::Int: - case TypeType::Double: { - switch (type2.type) { - case TypeType::Int: - case TypeType::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_type_to_type(TypeType::Int); -} - -bool is_arithmetic_type(Type type) { - switch (type.type) { - case TypeType::Int: - case TypeType::Double: - return true; - default: - return false; - } -} Type try_string_to_type(string type_name, CodePosition pos) { try { @@ -58,7 +13,7 @@ Type try_string_to_type(string type_name, CodePosition pos) { } } -AnalysisResult analyze(Node &ast, Memory &memory) { +Type analyze(Node &ast, Memory &memory) { if (holds_alternative(ast)) { Token token = get(ast); switch (token.type) { @@ -100,7 +55,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) { break; case NodeType::If: case NodeType::IfElse: { - if (!bool_castable(analyze(node.children[0], memory))) { + if (!is_arithmetic_type(analyze(node.children[0], memory))) { throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[0]), "bool"); } @@ -111,7 +66,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) { return {}; } break; case NodeType::While: { - if (!bool_castable(analyze(node.children[0], memory))) { + if (!is_arithmetic_type(analyze(node.children[0], memory))) { throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[0]), "bool"); } analyze(node.children[1], memory); @@ -123,7 +78,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) { analyze(node.children[0], memory); - if (!bool_castable(analyze(node.children[1], memory))) { + if (!is_arithmetic_type(analyze(node.children[1], memory))) { throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[1]), "bool"); } @@ -142,17 +97,17 @@ AnalysisResult analyze(Node &ast, Memory &memory) { } break; case NodeType::Lor: case NodeType::Land: { - if (!bool_castable(analyze(node.children[0], memory))) { + if (!is_arithmetic_type(analyze(node.children[0], memory))) { throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[0]), "bool"); } - if (!bool_castable(analyze(node.children[1], memory))) { + if (!is_arithmetic_type(analyze(node.children[1], memory))) { throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[1]), "bool"); } return type_type_to_type(TypeType::Int); } break; case NodeType::Neg: { - if (!bool_castable(analyze(node.children[0], memory))) { + if (!is_arithmetic_type(analyze(node.children[0], memory))) { throw TypeError(ErrorType::TypeNotCastable, get_node_pos(node.children[0]), "bool"); } @@ -161,33 +116,33 @@ AnalysisResult analyze(Node &ast, Memory &memory) { 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); + case NodeType::Geq: + case NodeType::Eq: + case NodeType::Neq: { + Type res1 = analyze(node.children[0], memory); + Type res2 = analyze(node.children[1], memory); check_comparable(res1, res2, node.pos); return type_type_to_type(TypeType::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); + Type res1 = analyze(node.children[0], memory); + Type res2 = analyze(node.children[1], memory); - return get_cast(res1, res2, node.pos); + return get_operation_cast(res1, res2, node.pos); } break; case NodeType::Mod: { - AnalysisResult e1 = analyze(node.children[0], memory); - AnalysisResult e2 = analyze(node.children[1], memory); + Type e1 = analyze(node.children[0], memory); + Type e2 = analyze(node.children[1], memory); - if (holds_alternative(e1) || get(e1).type != TypeType::Int) { + if (e1.type != TypeType::Int) { throw TypeError(ErrorType::ExpectedIntegralType, get_node_pos(node.children[0])); } - if (holds_alternative(e2) || get(e2).type != TypeType::Int) { + if (e2.type != TypeType::Int) { throw TypeError(ErrorType::ExpectedIntegralType, get_node_pos(node.children[1])); } @@ -195,13 +150,13 @@ AnalysisResult analyze(Node &ast, Memory &memory) { } break; case NodeType::UnaryPlus: case NodeType::UnaryMinus: { - AnalysisResult res = analyze(node.children[0], memory); + Type res = analyze(node.children[0], memory); - if (holds_alternative(res) || !is_arithmetic_type(get(res))) { + if (!is_arithmetic_type(res)) { throw TypeError(ErrorType::ExpectedArithmeticType, get_node_pos(node.children[0])); } - return get(res); + return res; } break; case NodeType::Declaration: { Token type_token = get(node.children[0]); @@ -237,7 +192,7 @@ AnalysisResult analyze(Node &ast, Memory &memory) { memory.declare(identifier, type); - get_cast(type, analyze(node.children[2], memory), get_node_pos(node)); + check_cast(type, analyze(node.children[2], memory), get_node_pos(node)); return type; } break; @@ -248,9 +203,9 @@ AnalysisResult analyze(Node &ast, Memory &memory) { throw TypeError(ErrorType::UnknownIdentifier, identifier_token.pos, identifier); Type type = memory.get(identifier).type; - AnalysisResult res = analyze(node.children[1], memory); + Type res = analyze(node.children[1], memory); - get_cast(type, res, get_node_pos(node.children[1])); + check_cast(type, res, get_node_pos(node.children[1])); return type; } break; @@ -408,10 +363,10 @@ AnalysisResult analyze(Node &ast, Memory &memory) { if (node.children.size() == 0) throw TypeError(ErrorType::IncompatibleReturnValue, node.pos, {}); - AnalysisResult res = analyze(node.children[0], memory); - AnalysisResult expected_type = return_type; + Type res = analyze(node.children[0], memory); + Type expected_type = return_type; - get_cast(res, expected_type, node.pos); + check_cast(res, expected_type, node.pos); return {}; } diff --git a/src/casting.cpp b/src/casting.cpp new file mode 100644 index 0000000..c2e9556 --- /dev/null +++ b/src/casting.cpp @@ -0,0 +1,101 @@ +#include "include/casting.hpp" +#include "include/errors.hpp" + + +bool check_valid_cast_int(Type type) { + switch (type.type) { + case TypeType::Int: + case TypeType::Double: + return true; + default: + return false; + } +} + +bool check_valid_cast_double(Type type) { + switch (type.type) { + case TypeType::Int: + case TypeType::Double: + return true; + default: + return false; + } +} + + +bool check_valid_cast(Type dest, Type type) { + switch (dest.type) { + case TypeType::Void: return true; + case TypeType::Function: return false; + case TypeType::Int: return check_valid_cast_int(type); + case TypeType::Double: return check_valid_cast_double(type); + default: + return false; + } +} + +void check_cast(Type dest, Type type, CodePosition pos) { + if (!check_valid_cast(dest, type)) + throw TypeError(ErrorType::TypeNotCastable, pos, type_type_to_string(type.type)); +} + +Type get_operation_cast(Type type1, Type type2, CodePosition pos) { + + if (!is_arithmetic_type(type1) || !is_arithmetic_type(type2)) + throw TypeError(ErrorType::ExpectedArithmeticType, pos, {}); + + if (type1.type == TypeType::Double || type2.type == TypeType::Double) + return type_type_to_type(TypeType::Double); + + return type_type_to_type(TypeType::Int); +} + +bool is_arithmetic_type(Type type) { + switch (type.type) { + case TypeType::Int: + case TypeType::Double: + return true; + default: + return false; + } +} + +void check_comparable(Type type1, Type type2, CodePosition pos) { + if (!is_arithmetic_type(type1) || !is_arithmetic_type(type2)) + throw TypeError(ErrorType::TypesNotComparable, pos); +} + +bool bool_cast(EvalResult value) { + if (holds_alternative(value)) { + return get(value) != 0; + } + else if (holds_alternative(value)) { + return get(value) != 0; + } + else { + throw exception(); + } +} + +int int_cast(EvalResult value) { + if (holds_alternative(value)) { + return get(value); + } else if (holds_alternative(value)) { + return int(get(value)); + } + else { + throw exception(); + } +} + +double double_cast(EvalResult value) { + if (holds_alternative(value)) { + return double(get(value)); + } + else if (holds_alternative(value)) { + return get(value); + } + else { + throw exception(); + } +} diff --git a/src/include/analysis.hpp b/src/include/analysis.hpp index 0fa24e9..4f88a5a 100644 --- a/src/include/analysis.hpp +++ b/src/include/analysis.hpp @@ -1,12 +1,10 @@ -#ifndef ANALYSIS_H -#define ANALYSIS_H +#ifndef DEF_ANALYSIS_H +#define DEF_ANALYSIS_H #include "types.hpp" #include "memory.hpp" using namespace std; -using AnalysisResult = variant; - -AnalysisResult analyze(Node &ast, Memory &memory); +Type analyze(Node &ast, Memory &memory); #endif \ No newline at end of file diff --git a/src/include/casting.hpp b/src/include/casting.hpp new file mode 100644 index 0000000..29db4c1 --- /dev/null +++ b/src/include/casting.hpp @@ -0,0 +1,37 @@ +#ifndef DEF_CASTING_H +#define DEF_CASTING_H + +#include "utils.hpp" +#include "types.hpp" + +/** + * Check if two types are comparable +*/ +void check_comparable(Type type1, Type type2, CodePosition pos); + +/** + * Check if cast possible de type vers dest + * Else throw error +*/ +void check_cast(Type dest, Type type, CodePosition pos); + +/** + * cast type de retour d'une opération entre type1 et type2 + * Par exemple: (Int) / (Float) -> (Float) + * If impossible, throw error +*/ +Type get_operation_cast(Type dest, Type type, CodePosition pos); + +/** + * Check if type is arithmetic + * double, int, ... +*/ +bool is_arithmetic_type(Type type); + +bool bool_cast(EvalResult value); + +int int_cast(EvalResult value); + +double double_cast(EvalResult value); + +#endif \ No newline at end of file diff --git a/src/include/memory.hpp b/src/include/memory.hpp index 304f3d5..9a8c4b8 100644 --- a/src/include/memory.hpp +++ b/src/include/memory.hpp @@ -1,5 +1,5 @@ -#ifndef MEMORY_H -#define MEMORY_H +#ifndef DEF_MEMORY_H +#define DEF_MEMORY_H #include #include diff --git a/src/include/tokenize.hpp b/src/include/tokenize.hpp index f8a8b8a..4f4b8b7 100644 --- a/src/include/tokenize.hpp +++ b/src/include/tokenize.hpp @@ -1,5 +1,5 @@ -#ifndef TOKENIZE_H -#define TOKENIZE_H +#ifndef DEF_TOKENIZE_H +#define DEF_TOKENIZE_H #include #include diff --git a/src/include/types.hpp b/src/include/types.hpp index 33c15c0..2c59225 100644 --- a/src/include/types.hpp +++ b/src/include/types.hpp @@ -1,5 +1,5 @@ -#ifndef TYPES_H -#define TYPES_H +#ifndef DEF_TYPES_H +#define DEF_TYPES_H #include #include @@ -25,7 +25,7 @@ using FunctionPrototype = vector; using TypeData = variant; struct Type { - TypeType type; + TypeType type=TypeType::Void; TypeData data { }; }; diff --git a/src/include/utils.hpp b/src/include/utils.hpp index e2bd64b..1b83b8e 100644 --- a/src/include/utils.hpp +++ b/src/include/utils.hpp @@ -32,7 +32,7 @@ vector split_string(const string& input, char delimiter); /** * Returns a human-readable name for a TypeType object */ -string _debug_get_type_type_name(TypeType type); +string type_type_to_string(TypeType type); /** * Check if two types are equal diff --git a/src/interpreter.cpp b/src/interpreter.cpp index 9fdc247..575af6d 100644 --- a/src/interpreter.cpp +++ b/src/interpreter.cpp @@ -1,46 +1,13 @@ #include #include #include -#include "include/parser.hpp" -#include "include/interpreter.hpp" -#include "include/memory.hpp" #include "include/utils.hpp" +#include "include/memory.hpp" +#include "include/parser.hpp" +#include "include/casting.hpp" +#include "include/interpreter.hpp" using namespace std; -bool bool_cast(EvalResult value) { - if (holds_alternative(value)) { - return get(value) != 0; - } - else if (holds_alternative(value)) { - return get(value) != 0; - } - else { - throw exception(); - } -} - -int int_cast(EvalResult value) { - if (holds_alternative(value)) { - return get(value); - } else if (holds_alternative(value)) { - return int(get(value)); - } - else { - throw exception(); - } -} - -double double_cast(EvalResult value) { - if (holds_alternative(value)) { - return double(get(value)); - } - else if (holds_alternative(value)) { - return get(value); - } - else { - throw exception(); - } -} EvalResult cast_from_type(Type type, EvalResult val) { switch (type.type) { diff --git a/src/memory.cpp b/src/memory.cpp index 9bb7ffd..754130e 100644 --- a/src/memory.cpp +++ b/src/memory.cpp @@ -187,7 +187,7 @@ void _debug_print_scope(Scope scope) { cout << setw (14) << it.first << " "; } cout << "|"; - cout << setw (9) << _debug_get_type_type_name(it.second.type.type) << " |"; + cout << setw (9) << type_type_to_string(it.second.type.type) << " |"; _debug_print_memory_var(it.second); cout << endl; diff --git a/src/utils.cpp b/src/utils.cpp index ab99e75..4c01641 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -68,12 +68,12 @@ vector split_string(const string& input, char delimiter) { return tokens; } -string _debug_get_type_type_name(TypeType type) { +string type_type_to_string(TypeType type) { switch (type) { - case TypeType::Int: return "INT"; - case TypeType::Double: return "DOUBLE"; - case TypeType::Void: return "VOID"; - case TypeType::Function: return "FUNCTION"; + case TypeType::Int: return "int"; + case TypeType::Double: return "double"; + case TypeType::Void: return "void"; + case TypeType::Function: return "function"; default: return "Unknown"; } } diff --git a/test/analysis.cpp b/test/analysis.cpp new file mode 100644 index 0000000..2d72bbb --- /dev/null +++ b/test/analysis.cpp @@ -0,0 +1,71 @@ +#include "include/test.hpp" + +#include "../src/include/execute.hpp" +#include "../src/include/utils.hpp" + +int execute(string s) { + Memory memory; + return get(execute(split_string(s, '\n'), memory)); +} + +int main() { + _TEST_PRESENTATION("Analyse statique"); + + _TEST_ASSERT( + _TEST_IS_EXCEPTION(execute("unknown x;"), ErrorType::UnknownType), + "Type inconnu", + true + ); + + _TEST_ASSERT( + _TEST_IS_EXCEPTION(execute(R"( + void f() {} + int x = f(); + )"), ErrorType::TypeNotCastable), + "Cast depuis void", + true + ); + + _TEST_ASSERT( + _TEST_IS_EXCEPTION(execute(R"( + void f() {} + 5.0 / f(); + )"), ErrorType::ExpectedArithmeticType), + "Division par void", + true + ); + + _TEST_ASSERT( + _TEST_IS_EXCEPTION(execute("5 % (5.0 / 2.0);"), ErrorType::ExpectedIntegralType), + "Modulo flottant", + true + ); + + _TEST_ASSERT( + _TEST_IS_EXCEPTION(execute("void x;"), ErrorType::IncompleteType), + "Variable de type void", + true + ); + + _TEST_ASSERT( + _TEST_IS_EXCEPTION(execute(R"( + int x; + int x; + )"), ErrorType::AlreadyDeclaredIdentifier), + "Redéclaration", + true + ); + + _TEST_ASSERT( + _TEST_IS_EXCEPTION(execute(R"( + int x; + void x() {} + )"), ErrorType::IncompatibleRedefinition), + "Redéfinition", + true + ); + + + + return 0; +} \ No newline at end of file