#include "cfg/opt.h" #include #include #include #include #include #include #include #include #include static GHashTable* declaredComposites = NULL; // pointer to composites with // names static GHashTable* declaredBoxes = NULL; // pointer to type static GHashTable* functionParameter = NULL; static GHashTable* definedFunctions = NULL; static GHashTable* declaredFunctions = NULL; static GArray* Scope = NULL; // list of hashtables. last Hashtable is current depth of program. // hashtable key: ident, value: Variable* to var int createTypeCastFromExpression(Expression* expression, Type* resultType, Expression** result); bool compareTypes(Type* leftType, Type* rightType); char* type_to_string(Type* type); const Type ShortShortUnsingedIntType = { .kind = TypeKindComposite, .impl = {.composite = {.sign = Unsigned, .scale = 0.25, .primitive = Int}}, .nodePtr = NULL, }; const Type StringLiteralType = { .kind = TypeKindReference, .impl = { .reference = (ReferenceType) &ShortShortUnsingedIntType, }, .nodePtr = NULL, }; /** * @brief Convert a string into a sign typ * @return 0 on success, 1 otherwise */ int sign_from_string(const char* string, Sign* sign) { assert(string != NULL); assert(sign != NULL); if (strcmp(string, "unsigned") == 0) { *sign = Unsigned; return SEMANTIC_OK; } if (strcmp(string, "signed") == 0) { *sign = Signed; return SEMANTIC_OK; } return SEMANTIC_ERROR; } /** * @brief Convert a string into a primitive type * @return 0 on success, 1 otherwise */ int primitive_from_string(const char* string, PrimitiveType* primitive) { assert(string != NULL); assert(primitive != NULL); DEBUG("find primitive in string"); if (strcmp(string, "int") == 0) { *primitive = Int; return SEMANTIC_OK; } if (strcmp(string, "float") == 0) { *primitive = Float; return SEMANTIC_OK; } return SEMANTIC_ERROR; } int scale_factor_from(const char* string, double* factor) { assert(string != NULL); assert(factor != NULL); if (strcmp(string, "half") == 0 || strcmp(string, "short") == 0) { *factor = 0.5; return SEMANTIC_OK; } if (strcmp(string, "double") == 0 || strcmp(string, "long") == 0) { *factor = 2.0; return SEMANTIC_OK; } return SEMANTIC_ERROR; } int check_scale_factor(AST_NODE_PTR node, Scale scale) { assert(node != NULL); if (8 < scale) { print_diagnostic(&node->location, Error, "Composite scale overflow"); return SEMANTIC_ERROR; } if (0.25 > scale) { print_diagnostic(&node->location, Error, "Composite scale underflow"); return SEMANTIC_ERROR; } return SEMANTIC_OK; } int merge_scale_list(AST_NODE_PTR scale_list, Scale* scale) { assert(scale_list != NULL); assert(scale != NULL); for (size_t i = 0; i < scale_list->children->len; i++) { double scale_in_list = 1.0; int scale_invalid = scale_factor_from(AST_get_node(scale_list, i)->value, &scale_in_list); if (scale_invalid == SEMANTIC_ERROR) { return SEMANTIC_ERROR; } *scale *= scale_in_list; } return SEMANTIC_OK; } /** * @brief Get an already declared type from its name */ int get_type_decl(const char* name, Type** type) { assert(name != NULL); assert(type != NULL); if (g_hash_table_contains(declaredComposites, name) == TRUE) { *type = (Type*) g_hash_table_lookup(declaredComposites, name); return SEMANTIC_OK; } return SEMANTIC_ERROR; } int set_impl_composite_type(AST_NODE_PTR ast_type, CompositeType* composite) { assert(ast_type != NULL); assert(composite != NULL); DEBUG("Type is a Composite"); int status = SEMANTIC_OK; int scaleNodeOffset = 0; composite->sign = Signed; // check if we have a sign if (AST_Sign == AST_get_node(ast_type, 0)->kind) { status = sign_from_string(AST_get_node(ast_type, 0)->value, &composite->sign); if (status == SEMANTIC_ERROR) { ERROR("invalid sign: %s", AST_get_node(ast_type, 0)->value); return SEMANTIC_ERROR; } scaleNodeOffset++; } composite->scale = 1.0; // check if we have a list of scale factors if (AST_get_node(ast_type, scaleNodeOffset)->kind == AST_List) { status = merge_scale_list(AST_get_node(ast_type, scaleNodeOffset), &composite->scale); if (status == SEMANTIC_ERROR) { return SEMANTIC_ERROR; } } AST_NODE_PTR typeKind = AST_get_last_node(ast_type); status = primitive_from_string(typeKind->value, &composite->primitive); // type kind is not primitve, must be a predefined composite if (status == SEMANTIC_ERROR) { // not a primitive try to resolve the type by name (must be a composite) Type* nested_type = NULL; status = get_type_decl(typeKind->value, &nested_type); if (status == SEMANTIC_ERROR) { print_diagnostic(&typeKind->location, Error, "Unknown composite type in declaration"); return SEMANTIC_ERROR; } if (nested_type->kind == TypeKindComposite) { // valid composite type composite->primitive = nested_type->impl.composite.primitive; // no sign was set, use sign of type if (scaleNodeOffset == 0) { composite->sign = nested_type->impl.composite.sign; } composite->scale = composite->scale * nested_type->impl.composite.scale; if (composite->scale > 8 || composite->scale < 0.25) { print_diagnostic(&typeKind->location, Error, "Invalid type scale of composite type: %lf", composite->scale); return SEMANTIC_ERROR; } } else { print_diagnostic(&typeKind->location, Error, "Type must be either composite or primitive"); return SEMANTIC_ERROR; } } return check_scale_factor(ast_type, composite->scale); } int set_get_type_impl(AST_NODE_PTR currentNode, Type** type); int set_impl_reference_type(AST_NODE_PTR currentNode, Type** type) { DEBUG("implementing reference type"); ReferenceType reference; int status = set_get_type_impl(AST_get_node(currentNode, 0), &reference); *type = mem_alloc(MemoryNamespaceSet, sizeof(Type)); (*type)->kind = TypeKindReference; (*type)->impl.reference = reference; return status; } /** * @brief Converts the given AST node to a gemstone type implementation. * @param currentNode AST node of type kind type * @param type pointer output for the type * @return the gemstone type implementation */ int set_get_type_impl(AST_NODE_PTR currentNode, Type** type) { assert(currentNode != NULL); assert(currentNode->kind == AST_Type || currentNode->kind == AST_Reference); assert(currentNode->children->len > 0); DEBUG("start Type"); int status; if (currentNode->kind == AST_Reference) { return set_impl_reference_type(currentNode, type); } const char* typekind = AST_get_node(currentNode, currentNode->children->len - 1)->value; // find type in composites if (g_hash_table_contains(declaredComposites, typekind) == TRUE) { *type = g_hash_table_lookup(declaredComposites, typekind); return SEMANTIC_OK; } if (g_hash_table_contains(declaredBoxes, typekind) == TRUE) { *type = g_hash_table_lookup(declaredBoxes, typekind); if (currentNode->children->len > 1) { print_diagnostic(¤tNode->location, Error, "Box type cannot modified"); return SEMANTIC_ERROR; } return SEMANTIC_OK; } // type is not yet declared, make a new one Type* new_type = mem_alloc(MemoryNamespaceSet, sizeof(Type)); new_type->nodePtr = currentNode; // only one child means either composite or primitive // try to implement primitive first // if not successfull continue building a composite if (currentNode->children->len == 1) { // type is a primitive new_type->kind = TypeKindPrimitive; status = primitive_from_string(typekind, &new_type->impl.primitive); // if err continue at composite construction if (status == SEMANTIC_OK) { *type = new_type; return SEMANTIC_OK; } print_diagnostic(&AST_get_last_node(currentNode)->location, Error, "Expected either primitive or composite type: `%s`", AST_get_last_node(currentNode)->value); return SEMANTIC_ERROR; } new_type->kind = TypeKindComposite; new_type->impl.composite.nodePtr = currentNode; status = set_impl_composite_type(currentNode, &new_type->impl.composite); *type = new_type; return status; } StorageQualifier Qualifier_from_string(const char* str) { assert(str != NULL); if (strcmp(str, "local") == 0) { return Local; } if (strcmp(str, "static") == 0) { return Static; } if (strcmp(str, "global") == 0) { return Global; } PANIC("Provided string is not a storagequalifier: %s", str); } int addVarToScope(Variable* variable); int createRef(AST_NODE_PTR currentNode, Type** reftype) { assert(currentNode != NULL); assert(currentNode->children->len == 1); Type* type = mem_alloc(MemoryNamespaceSet, sizeof(Type)); Type* referenceType = mem_alloc(MemoryNamespaceSet, sizeof(Type)); referenceType->kind = TypeKindReference; referenceType->nodePtr = currentNode; AST_NODE_PTR ast_type = AST_get_node(currentNode, 0); int signal = set_get_type_impl(ast_type, &type); if (signal) { return SEMANTIC_ERROR; } referenceType->impl.reference = type; *reftype = referenceType; return SEMANTIC_OK; } int createDecl(AST_NODE_PTR currentNode, GArray** variables) { DEBUG("create declaration"); AST_NODE_PTR ident_list = AST_get_last_node(currentNode); *variables = mem_new_g_array(MemoryNamespaceSet, sizeof(Variable*)); VariableDeclaration decl; decl.nodePtr = currentNode; decl.qualifier = Static; int status = SEMANTIC_OK; DEBUG("Child Count: %i", currentNode->children->len); for (size_t i = 0; i < currentNode->children->len; i++) { switch (AST_get_node(currentNode, i)->kind) { case AST_Storage: DEBUG("fill Qualifier"); decl.qualifier = Qualifier_from_string(AST_get_node(currentNode, i)->value); break; case AST_Type: DEBUG("fill Type"); status = set_get_type_impl(AST_get_node(currentNode, i), &decl.type); break; case AST_IdentList: break; case AST_Reference: status = createRef(AST_get_node(currentNode, i), &decl.type); break; default: PANIC("invalid node type: %ld", AST_get_node(currentNode, i)->kind); break; } } for (size_t i = 0; i < ident_list->children->len; i++) { Variable* variable = mem_alloc(MemoryNamespaceSet, sizeof(Variable)); variable->kind = VariableKindDeclaration; variable->nodePtr = currentNode; variable->name = AST_get_node(ident_list, i)->value; variable->impl.declaration = decl; g_array_append_val(*variables, variable); int signal = addVarToScope(variable); if (signal) { return SEMANTIC_ERROR; } } return status; } Expression* createExpression(AST_NODE_PTR currentNode); int createDef(AST_NODE_PTR currentNode, GArray** variables) { assert(variables != NULL); assert(currentNode != NULL); assert(currentNode->kind == AST_Def); DEBUG("create definition"); AST_NODE_PTR declaration = AST_get_node(currentNode, 0); AST_NODE_PTR expression = AST_get_node(currentNode, 1); AST_NODE_PTR ident_list = AST_get_last_node(declaration); *variables = mem_new_g_array(MemoryNamespaceSet, sizeof(Variable*)); VariableDeclaration decl; VariableDefiniton def; def.nodePtr = currentNode; decl.qualifier = Static; decl.nodePtr = AST_get_node(currentNode, 0); int status = SEMANTIC_OK; DEBUG("Child Count: %i", declaration->children->len); for (size_t i = 0; i < declaration->children->len; i++) { AST_NODE_PTR child = AST_get_node(declaration, i); switch (child->kind) { case AST_Storage: DEBUG("fill Qualifier"); decl.qualifier = Qualifier_from_string(child->value); break; case AST_Reference: case AST_Type: DEBUG("fill Type"); status = set_get_type_impl(child, &decl.type); if (status == SEMANTIC_ERROR) { return SEMANTIC_ERROR; } break; case AST_IdentList: break; default: PANIC("invalid node type: %ld", child->kind); break; } } def.declaration = decl; Expression* name = createExpression(expression); if (name == NULL) { status = SEMANTIC_OK; } if (!compareTypes(def.declaration.type, name->result)) { char* expected_type = type_to_string(def.declaration.type); char* gotten_type = type_to_string(name->result); print_diagnostic(&name->nodePtr->location, Warning, "expected `%s` got `%s`", expected_type, gotten_type); def.initializer = mem_alloc(MemoryNamespaceSet, sizeof(Expression)); if (createTypeCastFromExpression(name, def.declaration.type, &def.initializer) == SEMANTIC_ERROR) { return SEMANTIC_ERROR; } } else { def.initializer = name; } for (size_t i = 0; i < ident_list->children->len; i++) { Variable* variable = mem_alloc(MemoryNamespaceSet, sizeof(Variable)); variable->kind = VariableKindDefinition; variable->nodePtr = currentNode; variable->name = AST_get_node(ident_list, i)->value; variable->impl.definiton = def; g_array_append_val(*variables, variable); if (addVarToScope(variable) == SEMANTIC_ERROR) { return SEMANTIC_ERROR; } } return status; } char* type_to_string(Type* type) { char* string = NULL; switch (type->kind) { case TypeKindPrimitive: if (type->impl.primitive == Int) { string = mem_strdup(MemoryNamespaceSet, "int"); } else if (type->impl.primitive == Float) { string = mem_strdup(MemoryNamespaceSet, "float"); } else if (type->impl.primitive == Char) { string = mem_strdup(MemoryNamespaceSet, "codepoint"); } break; case TypeKindComposite: { if (type->impl.composite.primitive == Int) { string = mem_strdup(MemoryNamespaceSet, "int"); } else { string = mem_strdup(MemoryNamespaceSet, "float"); } if (type->impl.composite.scale < 1.0) { for (int i = 0; i < (int) (type->impl.composite.scale * 4); i++) { char* concat = g_strconcat("half ", string, NULL); string = mem_strdup(MemoryNamespaceSet, concat); g_free(concat); } } else if (type->impl.composite.scale > 1.0) { for (int i = 0; i < (int) type->impl.composite.scale; i++) { char* concat = g_strconcat("long ", string, NULL); string = mem_strdup(MemoryNamespaceSet, concat); g_free(concat); } } if (type->impl.composite.sign == Unsigned) { char* concat = g_strconcat("unsigned ", string, NULL); string = mem_strdup(MemoryNamespaceSet, concat); g_free(concat); } break; } case TypeKindReference: { char* type_string = type_to_string(type->impl.reference); char* concat = g_strconcat("ref ", type_string, NULL); mem_free(type_string); string = mem_strdup(MemoryNamespaceSet, concat); g_free(concat); break; } case TypeKindBox: string = mem_strdup(MemoryNamespaceSet, "box"); break; } return string; } int getParameter(const char* name, Parameter** parameter) { // loop through all variable scope and find a variable if (functionParameter != NULL) { if (g_hash_table_contains(functionParameter, name)) { *parameter = g_hash_table_lookup(functionParameter, name); return SEMANTIC_OK; } } return SEMANTIC_ERROR; } int getVariableFromScope(const char* name, Variable** variable) { assert(name != NULL); assert(variable != NULL); assert(Scope != NULL); DEBUG("getting var from scope"); int found = 0; for (size_t i = 0; i < Scope->len; i++) { GHashTable* variable_table = g_array_index(Scope, GHashTable*, i); if (g_hash_table_contains(variable_table, name)) { if (found == 0) { *variable = g_hash_table_lookup(variable_table, name); } found += 1; } } if (found == 1) { DEBUG("Var: %s", (*variable)->name); DEBUG("Var Typekind: %d", (*variable)->kind); DEBUG("Found var"); return SEMANTIC_OK; } else if (found > 1) { print_diagnostic(&(*variable)->nodePtr->location, Warning, "Parameter shadows variable of same name: %s", name); return SEMANTIC_OK; } DEBUG("nothing found"); return SEMANTIC_ERROR; } int addVarToScope(Variable* variable) { Variable* tmp = NULL; if (getVariableFromScope(variable->name, &tmp) == SEMANTIC_OK) { print_diagnostic(&variable->nodePtr->location, Error, "Variable already exist: ", variable->name); return SEMANTIC_ERROR; } GHashTable* currentScope = g_array_index(Scope, GHashTable*, Scope->len - 1); g_hash_table_insert(currentScope, (gpointer) variable->name, variable); return SEMANTIC_OK; } int fillTablesWithVars(GHashTable* variableTable, const GArray* variables) { DEBUG("filling vars in scope and table"); for (size_t i = 0; i < variables->len; i++) { Variable* var = g_array_index(variables, Variable*, i); // this variable is discarded, only need status code if (g_hash_table_contains(variableTable, (gpointer) var->name)) { print_diagnostic(&var->nodePtr->location, Error, "Variable already exists"); return SEMANTIC_ERROR; } g_hash_table_insert(variableTable, (gpointer) var->name, var); } return SEMANTIC_OK; } [[nodiscard("type must be freed")]] TypeValue createTypeValue(AST_NODE_PTR currentNode) { DEBUG("create TypeValue"); TypeValue value; Type* type = mem_alloc(MemoryNamespaceSet, sizeof(Type)); value.type = type; type->kind = TypeKindPrimitive; type->nodePtr = currentNode; switch (currentNode->kind) { case AST_Int: type->impl.primitive = Int; break; case AST_Float: type->impl.primitive = Float; break; case AST_Char: // validate we have a single UTF-8 codepoint if (g_utf8_strlen(currentNode->value, 4) != 1) { print_diagnostic(¤tNode->location, Error, "Character must be UTF-8 codepoint"); } type->impl.primitive = Char; break; default: PANIC("Node is not an expression but from kind: %i", currentNode->kind); break; } value.nodePtr = currentNode; value.value = currentNode->value; return value; } #define CLONE(x) mem_clone(MemoryNamespaceSet, (void*) &(x), sizeof(x)) TypeValue createString(AST_NODE_PTR currentNode) { DEBUG("create String"); TypeValue value; Type* type = CLONE(StringLiteralType); value.type = type; value.nodePtr = currentNode; value.value = currentNode->value; return value; } Type* createTypeFromOperands(Type* LeftOperandType, Type* RightOperandType, AST_NODE_PTR currentNode) { DEBUG("create type from operands"); Type* result = mem_alloc(MemoryNamespaceSet, sizeof(Type)); result->nodePtr = currentNode; DEBUG("LeftOperandType->kind: %i", LeftOperandType->kind); DEBUG("RightOperandType->kind: %i", RightOperandType->kind); if (LeftOperandType->kind == TypeKindComposite && RightOperandType->kind == TypeKindComposite) { result->kind = TypeKindComposite; CompositeType resultImpl; resultImpl.nodePtr = currentNode; resultImpl.sign = MAX(LeftOperandType->impl.composite.sign, RightOperandType->impl.composite.sign); resultImpl.scale = MAX(LeftOperandType->impl.composite.scale, RightOperandType->impl.composite.scale); resultImpl.primitive = MAX(LeftOperandType->impl.composite.primitive, RightOperandType->impl.composite.primitive); result->impl.composite = resultImpl; } else if (LeftOperandType->kind == TypeKindPrimitive && RightOperandType->kind == TypeKindPrimitive) { DEBUG("both operands are primitive"); result->kind = TypeKindPrimitive; result->impl.primitive = MAX(LeftOperandType->impl.primitive, RightOperandType->impl.primitive); } else if (LeftOperandType->kind == TypeKindPrimitive && RightOperandType->kind == TypeKindComposite) { result->kind = TypeKindComposite; result->impl.composite.sign = Signed; result->impl.composite.scale = MAX(1.0, RightOperandType->impl.composite.scale); result->impl.composite.primitive = MAX(Int, RightOperandType->impl.composite.primitive); result->impl.composite.nodePtr = currentNode; } else if (LeftOperandType->kind == TypeKindComposite && RightOperandType->kind == TypeKindPrimitive) { result->kind = TypeKindComposite; result->impl.composite.sign = Signed; result->impl.composite.scale = MAX(1.0, LeftOperandType->impl.composite.scale); result->impl.composite.primitive = MAX(Int, LeftOperandType->impl.composite.primitive); result->impl.composite.nodePtr = currentNode; } else { mem_free(result); print_diagnostic(¤tNode->location, Error, "Incompatible types in expression"); return NULL; } DEBUG("Succsessfully created type"); return result; } int createTypeCastFromExpression(Expression* expression, Type* resultType, Expression** result) { Expression* expr = mem_alloc(MemoryNamespaceSet, sizeof(Expression)); expr->result = resultType; expr->nodePtr = expression->nodePtr; expr->kind = ExpressionKindTypeCast; TypeCast typeCast; typeCast.nodePtr = expression->nodePtr; typeCast.targetType = resultType; typeCast.operand = expression; expr->impl.typecast = typeCast; if (expression->result->kind != TypeKindComposite && expression->result->kind != TypeKindPrimitive) { print_diagnostic(&expression->nodePtr->location, Error, "Expected either primitive or composite type"); return SEMANTIC_ERROR; } *result = expr; return SEMANTIC_OK; } int createArithOperation(Expression* ParentExpression, AST_NODE_PTR currentNode, size_t expectedChildCount) { DEBUG("create arithmetic operation"); ParentExpression->impl.operation.kind = Arithmetic; ParentExpression->impl.operation.nodePtr = currentNode; ParentExpression->impl.operation.operands = mem_new_g_array(MemoryNamespaceSet, sizeof(Expression*)); assert(expectedChildCount == currentNode->children->len); for (size_t i = 0; i < currentNode->children->len; i++) { Expression* expression = createExpression(AST_get_node(currentNode, i)); if (NULL == expression) { return SEMANTIC_ERROR; } g_array_append_val(ParentExpression->impl.operation.operands, expression); } DEBUG("created all Expressions"); switch (currentNode->kind) { case AST_Add: ParentExpression->impl.operation.impl.arithmetic = Add; break; case AST_Sub: ParentExpression->impl.operation.impl.arithmetic = Sub; break; case AST_Mul: ParentExpression->impl.operation.impl.arithmetic = Mul; break; case AST_Div: ParentExpression->impl.operation.impl.arithmetic = Div; break; case AST_Negate: ParentExpression->impl.operation.impl.arithmetic = Negate; break; default: PANIC("Current node is not an arithmetic operater"); break; } if (ParentExpression->impl.operation.impl.arithmetic == Negate) { Type* result = g_array_index(ParentExpression->impl.operation.operands, Expression*, 0) ->result; result->nodePtr = currentNode; if (result->kind == TypeKindReference || result->kind == TypeKindBox) { print_diagnostic(¤tNode->location, Error, "Invalid type for arithmetic operation"); return SEMANTIC_ERROR; } else if (result->kind == TypeKindComposite) { result->impl.composite.sign = Signed; } ParentExpression->result = result; } else { Type* LeftOperandType = g_array_index(ParentExpression->impl.operation.operands, Expression*, 0) ->result; Type* RightOperandType = g_array_index(ParentExpression->impl.operation.operands, Expression*, 1) ->result; ParentExpression->result = createTypeFromOperands( LeftOperandType, RightOperandType, currentNode); } if (ParentExpression->result == NULL) { return SEMANTIC_ERROR; } for (size_t i = 0; i < ParentExpression->impl.operation.operands->len; i++) { Expression* operand = g_array_index( ParentExpression->impl.operation.operands, Expression*, i); if (!compareTypes(operand->result, ParentExpression->result)) { Expression* result; int status = createTypeCastFromExpression( operand, ParentExpression->result, &result); if (status == SEMANTIC_ERROR) { return SEMANTIC_ERROR; } g_array_index(ParentExpression->impl.operation.operands, Expression*, i) = result; } } return SEMANTIC_OK; } int createRelationalOperation(Expression* ParentExpression, AST_NODE_PTR currentNode) { // fill kind and Nodeptr ParentExpression->impl.operation.kind = Relational; ParentExpression->impl.operation.nodePtr = currentNode; ParentExpression->impl.operation.operands = mem_new_g_array(MemoryNamespaceSet, sizeof(Expression*)); // fill Operands for (size_t i = 0; i < currentNode->children->len; i++) { Expression* expression = createExpression(AST_get_node(currentNode, i)); if (NULL == expression) { return SEMANTIC_ERROR; } g_array_append_val(ParentExpression->impl.operation.operands, expression); } // fill impl switch (currentNode->kind) { case AST_Eq: ParentExpression->impl.operation.impl.relational = Equal; break; case AST_Less: ParentExpression->impl.operation.impl.relational = Less; break; case AST_Greater: ParentExpression->impl.operation.impl.relational = Greater; break; default: PANIC("Current node is not an relational operater"); break; } Type* result = mem_alloc(MemoryNamespaceSet, sizeof(Type)); result->impl.primitive = Int; result->kind = TypeKindPrimitive; result->nodePtr = currentNode; ParentExpression->result = result; for (size_t i = 0; i < ParentExpression->impl.operation.operands->len; i++) { Expression* operand = g_array_index( ParentExpression->impl.operation.operands, Expression*, i); if (!compareTypes(operand->result, ParentExpression->result)) { Expression* expr; int status = createTypeCastFromExpression( operand, ParentExpression->result, &expr); if (status == SEMANTIC_ERROR) { return SEMANTIC_ERROR; } g_array_index(ParentExpression->impl.operation.operands, Expression*, i) = expr; } } return 0; } int createBoolOperation(Expression* ParentExpression, AST_NODE_PTR currentNode) { // fill kind and Nodeptr ParentExpression->impl.operation.kind = Boolean; ParentExpression->impl.operation.nodePtr = currentNode; ParentExpression->impl.operation.operands = mem_new_g_array(MemoryNamespaceSet, sizeof(Expression*)); // fill Operands for (size_t i = 0; i < currentNode->children->len; i++) { Expression* expression = createExpression(AST_get_node(currentNode, i)); if (NULL == expression) { return SEMANTIC_ERROR; } g_array_append_val(ParentExpression->impl.operation.operands, expression); } switch (currentNode->kind) { case AST_BoolAnd: ParentExpression->impl.operation.impl.boolean = BooleanAnd; break; case AST_BoolOr: ParentExpression->impl.operation.impl.boolean = BooleanOr; break; case AST_BoolXor: ParentExpression->impl.operation.impl.boolean = BooleanXor; break; default: PANIC("Current node is not an boolean operator"); break; } Expression* lhs = g_array_index(ParentExpression->impl.operation.operands, Expression*, 0); Expression* rhs = g_array_index(ParentExpression->impl.operation.operands, Expression*, 1); Type* LeftOperandType = lhs->result; Type* RightOperandType = rhs->result; // should not be a box or a reference if (LeftOperandType->kind != TypeKindPrimitive && LeftOperandType->kind != TypeKindComposite) { print_diagnostic(&lhs->nodePtr->location, Error, "invalid type for boolean operation"); return SEMANTIC_ERROR; } if (RightOperandType->kind != TypeKindPrimitive && RightOperandType->kind != TypeKindComposite) { print_diagnostic(&rhs->nodePtr->location, Error, "invalid type for boolean operation"); return SEMANTIC_ERROR; } // should not be a float if (LeftOperandType->kind == TypeKindComposite) { if (LeftOperandType->impl.composite.primitive == Float) { print_diagnostic(&lhs->nodePtr->location, Error, "operand must not be a float"); return SEMANTIC_ERROR; } } else if (LeftOperandType->kind == TypeKindPrimitive) { if (LeftOperandType->impl.primitive == Float) { print_diagnostic(&lhs->nodePtr->location, Error, "operand must not be a float"); return SEMANTIC_ERROR; } } else if (RightOperandType->kind == TypeKindComposite) { if (RightOperandType->impl.composite.primitive == Float) { print_diagnostic(&rhs->nodePtr->location, Error, "operand must not be a float"); return SEMANTIC_ERROR; } } else if (RightOperandType->kind == TypeKindPrimitive) { if (RightOperandType->impl.primitive == Float) { print_diagnostic(&rhs->nodePtr->location, Error, "operand must not be a float"); return SEMANTIC_ERROR; } } ParentExpression->result = createTypeFromOperands(LeftOperandType, RightOperandType, currentNode); for (size_t i = 0; i < ParentExpression->impl.operation.operands->len; i++) { Expression* operand = g_array_index( ParentExpression->impl.operation.operands, Expression*, i); if (!compareTypes(operand->result, ParentExpression->result)) { Expression* expr; int status = createTypeCastFromExpression( operand, ParentExpression->result, &expr); if (status == SEMANTIC_ERROR) { return SEMANTIC_ERROR; } g_array_index(ParentExpression->impl.operation.operands, Expression*, i) = expr; } } return SEMANTIC_OK; } int createBoolNotOperation(Expression* ParentExpression, AST_NODE_PTR currentNode) { // fill kind and Nodeptr ParentExpression->impl.operation.kind = Boolean; ParentExpression->impl.operation.nodePtr = currentNode; ParentExpression->impl.operation.operands = mem_new_g_array(MemoryNamespaceSet, sizeof(Expression*)); // fill Operand Expression* expression = createExpression(AST_get_node(currentNode, 0)); if (NULL == expression) { return SEMANTIC_ERROR; } g_array_append_val(ParentExpression->impl.operation.operands, expression); ParentExpression->impl.operation.impl.boolean = BooleanNot; Type* Operand = g_array_index(ParentExpression->impl.operation.operands, Expression*, 0) ->result; Type* result = mem_alloc(MemoryNamespaceSet, sizeof(Type)); result->nodePtr = currentNode; if (Operand->kind == TypeKindBox || Operand->kind == TypeKindReference) { print_diagnostic(&Operand->nodePtr->location, Error, "Operand must be a variant of primitive type int"); return SEMANTIC_ERROR; } if (Operand->kind == TypeKindPrimitive) { if (Operand->impl.primitive == Float) { print_diagnostic(&Operand->nodePtr->location, Error, "Operand must be a variant of primitive type int"); return SEMANTIC_ERROR; } result->kind = Operand->kind; result->impl = Operand->impl; } else if (Operand->kind == TypeKindComposite) { if (Operand->impl.composite.primitive == Float) { print_diagnostic(&Operand->nodePtr->location, Error, "Operand must be a variant of primitive type int"); return SEMANTIC_ERROR; } result->kind = Operand->kind; result->impl = Operand->impl; } ParentExpression->result = result; for (size_t i = 0; i < ParentExpression->impl.operation.operands->len; i++) { Expression* operand = g_array_index( ParentExpression->impl.operation.operands, Expression*, i); if (!compareTypes(operand->result, ParentExpression->result)) { Expression* expr; int status = createTypeCastFromExpression( operand, ParentExpression->result, &expr); if (status == SEMANTIC_ERROR) { return SEMANTIC_ERROR; } g_array_index(ParentExpression->impl.operation.operands, Expression*, i) = expr; } } return SEMANTIC_OK; } bool isScaleEqual(double leftScale, double rightScale) { int leftIntScale = (int) (leftScale * BASE_BYTES); int rightIntScale = (int) (rightScale * BASE_BYTES); return leftIntScale == rightIntScale; } int createBitOperation(Expression* ParentExpression, AST_NODE_PTR currentNode) { // fill kind and Nodeptr ParentExpression->impl.operation.kind = Boolean; ParentExpression->impl.operation.nodePtr = currentNode; ParentExpression->impl.operation.operands = mem_new_g_array(MemoryNamespaceSet, sizeof(Expression*)); // fill Operands for (size_t i = 0; i < currentNode->children->len; i++) { Expression* expression = createExpression(AST_get_node(currentNode, i)); if (NULL == expression) { return SEMANTIC_ERROR; } g_array_append_val(ParentExpression->impl.operation.operands, expression); } switch (currentNode->kind) { case AST_BitAnd: ParentExpression->impl.operation.impl.bitwise = BitwiseAnd; break; case AST_BitOr: ParentExpression->impl.operation.impl.bitwise = BitwiseOr; break; case AST_BitXor: ParentExpression->impl.operation.impl.bitwise = BitwiseXor; break; default: PANIC("Current node is not an bitwise operater"); break; } Type* result = mem_alloc(MemoryNamespaceSet, sizeof(Type)); result->nodePtr = currentNode; Expression* lhs = g_array_index(ParentExpression->impl.operation.operands, Expression*, 0); Expression* rhs = g_array_index(ParentExpression->impl.operation.operands, Expression*, 1); Type* LeftOperandType = lhs->result; Type* RightOperandType = rhs->result; // should not be a box or a reference if (LeftOperandType->kind != TypeKindPrimitive && LeftOperandType->kind != TypeKindComposite) { print_diagnostic(&lhs->nodePtr->location, Error, "Must be a type variant of int"); return SEMANTIC_ERROR; } if (RightOperandType->kind != TypeKindPrimitive && RightOperandType->kind != TypeKindComposite) { print_diagnostic(&rhs->nodePtr->location, Error, "Must be a type variant of int"); return SEMANTIC_ERROR; } if (LeftOperandType->kind == TypeKindPrimitive && RightOperandType->kind == TypeKindPrimitive) { if (LeftOperandType->impl.primitive == Float) { print_diagnostic(&lhs->nodePtr->location, Error, "Must be a type variant of int"); return SEMANTIC_ERROR; } if (RightOperandType->impl.primitive == Float) { print_diagnostic(&rhs->nodePtr->location, Error, "Must be a type variant of int"); return SEMANTIC_ERROR; } result->kind = TypeKindPrimitive; result->impl.primitive = Int; } else if (LeftOperandType->kind == TypeKindPrimitive && RightOperandType->kind == TypeKindComposite) { if (LeftOperandType->impl.primitive == Float) { print_diagnostic(&lhs->nodePtr->location, Error, "Must be a type variant of int"); return SEMANTIC_ERROR; } if (RightOperandType->impl.composite.primitive == Float) { print_diagnostic(&rhs->nodePtr->location, Error, "Must be a type variant of int"); return SEMANTIC_ERROR; } result->kind = TypeKindPrimitive; result->impl.primitive = Int; } else if (LeftOperandType->kind == TypeKindComposite && RightOperandType->kind == TypeKindPrimitive) { if (LeftOperandType->impl.composite.primitive == Float) { print_diagnostic(&lhs->nodePtr->location, Error, "Must be a type variant of int"); return SEMANTIC_ERROR; } if (RightOperandType->impl.primitive == Float) { print_diagnostic(&rhs->nodePtr->location, Error, "Must be a type variant of int"); return SEMANTIC_ERROR; } result->kind = TypeKindPrimitive; result->impl.primitive = Int; } else { if (RightOperandType->impl.composite.primitive == Float) { print_diagnostic(&rhs->nodePtr->location, Error, "Must be a type variant of int"); return SEMANTIC_ERROR; } if (LeftOperandType->impl.composite.primitive == Float) { print_diagnostic(&lhs->nodePtr->location, Error, "Must be a type variant of int"); return SEMANTIC_ERROR; } if (!isScaleEqual(LeftOperandType->impl.composite.scale, RightOperandType->impl.composite.scale)) { print_diagnostic(¤tNode->location, Error, "Operands must be of equal size"); return SEMANTIC_ERROR; } result->kind = TypeKindComposite; result->impl.composite.nodePtr = currentNode; result->impl.composite.scale = LeftOperandType->impl.composite.scale; result->impl.composite.sign = MAX(LeftOperandType->impl.composite.sign, RightOperandType->impl.composite.sign); } ParentExpression->result = result; for (size_t i = 0; i < ParentExpression->impl.operation.operands->len; i++) { Expression* operand = g_array_index( ParentExpression->impl.operation.operands, Expression*, i); if (!compareTypes(operand->result, ParentExpression->result)) { Expression* expr; int status = createTypeCastFromExpression( operand, ParentExpression->result, &expr); if (status == SEMANTIC_ERROR) { return SEMANTIC_ERROR; } g_array_index(ParentExpression->impl.operation.operands, Expression*, i) = expr; } } return 0; } int createBitNotOperation(Expression* ParentExpression, AST_NODE_PTR currentNode) { // fill kind and Nodeptr ParentExpression->impl.operation.kind = Bitwise; ParentExpression->impl.operation.nodePtr = currentNode; ParentExpression->impl.operation.operands = mem_new_g_array(MemoryNamespaceSet, sizeof(Expression*)); // fill Operand Expression* expression = createExpression(AST_get_node(currentNode, 0)); if (NULL == expression) { return SEMANTIC_ERROR; } g_array_append_val(ParentExpression->impl.operation.operands, expression); ParentExpression->impl.operation.impl.bitwise = BitwiseNot; Type* Operand = g_array_index(ParentExpression->impl.operation.operands, Expression*, 0) ->result; Type* result = mem_alloc(MemoryNamespaceSet, sizeof(Type)); result->nodePtr = currentNode; if (Operand->kind == TypeKindPrimitive) { if (Operand->impl.primitive == Float) { print_diagnostic(&Operand->nodePtr->location, Error, "Operand type must be a variant of int"); return SEMANTIC_ERROR; } result->kind = TypeKindPrimitive; result->impl.primitive = Int; } else if (Operand->kind == TypeKindComposite) { if (Operand->impl.composite.primitive == Float) { print_diagnostic(&Operand->nodePtr->location, Error, "Operand type must be a variant of int"); return SEMANTIC_ERROR; } result->kind = TypeKindComposite; result->impl.composite.nodePtr = currentNode; result->impl.composite.primitive = Int; result->impl.composite.sign = Operand->impl.composite.sign; result->impl.composite.scale = Operand->impl.composite.scale; } ParentExpression->result = result; for (size_t i = 0; i < ParentExpression->impl.operation.operands->len; i++) { Expression* operand = g_array_index( ParentExpression->impl.operation.operands, Expression*, i); if (!compareTypes(operand->result, ParentExpression->result)) { Expression* expr; int status = createTypeCastFromExpression( operand, ParentExpression->result, &expr); if (status == SEMANTIC_ERROR) { return SEMANTIC_ERROR; } g_array_index(ParentExpression->impl.operation.operands, Expression*, i) = expr; } } return SEMANTIC_OK; } /** * @brief Return a copy of all BoxMembers specified by their name in names from * a boxes type Will run recursively in case the first name refers to a subbox * @param currentBoxType * @param names * @return */ GArray* getBoxMember(Type* currentBoxType, GArray* names) { GArray* members = mem_new_g_array(MemoryNamespaceSet, sizeof(BoxMember)); // list of members of the type GHashTable* memberList = currentBoxType->impl.box->member; // name of member to extract const char* currentName = g_array_index(names, const char*, 0); // look for member of this name if (g_hash_table_contains(memberList, currentName)) { // get member and store in array BoxMember* currentMember = g_hash_table_lookup(memberList, currentName); g_array_append_val(members, currentMember); // last name in list, return g_array_remove_index(names, 0); if (names->len == 0) { return members; } // other names may refer to members of child boxes if (currentMember->type->kind == TypeKindBox) { GArray* otherMember = getBoxMember(currentMember->type, names); if (NULL == otherMember) { return NULL; } g_array_append_vals(members, (BoxMember*) otherMember->data, otherMember->len); return members; } } return NULL; } int createBoxAccess(Expression* ParentExpression, AST_NODE_PTR currentNode) { const char* boxname = AST_get_node(currentNode, 0)->value; Variable* boxVariable = NULL; int status = getVariableFromScope(boxname, &boxVariable); if (status == SEMANTIC_ERROR) { print_diagnostic(&AST_get_node(currentNode, 0)->location, Error, "Variable of name `%s` does not exist"); return SEMANTIC_ERROR; } Type* boxType; if (boxVariable->kind == VariableKindDeclaration) { boxType = boxVariable->impl.declaration.type; } else if (boxVariable->kind == VariableKindDefinition) { boxType = boxVariable->impl.definiton.declaration.type; } else { return SEMANTIC_ERROR; } if (boxType->kind != TypeKindBox) { return SEMANTIC_ERROR; } // filling boxAccess variable ParentExpression->impl.variable->kind = VariableKindBoxMember; ParentExpression->impl.variable->nodePtr = currentNode; ParentExpression->impl.variable->name = NULL; ParentExpression->impl.variable->impl.member.nodePtr = currentNode; // filling boxacces.variable ParentExpression->impl.variable->impl.member.variable = boxVariable; // first one is the box itself GArray* names = mem_alloc(MemoryNamespaceSet, sizeof(GArray)); if (currentNode->kind == AST_IdentList) { for (size_t i = 1; i < currentNode->children->len; i++) { g_array_append_val(names, AST_get_node(currentNode, i)->value); } } else if (currentNode->kind == AST_List) { for (size_t i = 1; i < AST_get_node(currentNode, 1)->children->len; i++) { g_array_append_val( names, AST_get_node(AST_get_node(currentNode, 1), i)->value); } } else { PANIC("current Node is not an Access"); } GArray* boxMember = getBoxMember(boxType, names); ParentExpression->impl.variable->impl.member.member = boxMember; ParentExpression->result = g_array_index(boxMember, BoxMember, boxMember->len).type; return SEMANTIC_OK; } int createTypeCast(Expression* ParentExpression, AST_NODE_PTR currentNode) { DEBUG("create type cast"); ParentExpression->impl.typecast.nodePtr = currentNode; ParentExpression->impl.typecast.operand = createExpression(AST_get_node(currentNode, 0)); if (ParentExpression->impl.typecast.operand == NULL) { return SEMANTIC_ERROR; } if (ParentExpression->impl.typecast.operand->result->kind != TypeKindComposite && ParentExpression->impl.typecast.operand->result->kind != TypeKindPrimitive && ParentExpression->impl.typecast.operand->result->kind != TypeKindReference) { print_diagnostic( ¤tNode->location, Error, "cannot cast type: `%s`", type_to_string(ParentExpression->impl.typecast.operand->result)); return SEMANTIC_ERROR; } Type* target = mem_alloc(MemoryNamespaceSet, sizeof(Type)); int status = set_get_type_impl(AST_get_node(currentNode, 1), &target); if (status) { return SEMANTIC_ERROR; } ParentExpression->impl.typecast.targetType = target; ParentExpression->result = target; return SEMANTIC_OK; } int createTransmute(Expression* ParentExpression, AST_NODE_PTR currentNode) { ParentExpression->impl.transmute.nodePtr = currentNode; ParentExpression->impl.transmute.operand = createExpression(AST_get_node(currentNode, 0)); if (ParentExpression->impl.transmute.operand == NULL) { return SEMANTIC_ERROR; } Type* target = mem_alloc(MemoryNamespaceSet, sizeof(Type)); int status = set_get_type_impl(AST_get_node(currentNode, 1), &target); if (status) { print_diagnostic(&AST_get_node(currentNode, 1)->location, Error, "Unknown type"); return SEMANTIC_ERROR; } ParentExpression->impl.typecast.targetType = target; ParentExpression->result = target; return SEMANTIC_OK; } int createDeref(Expression* ParentExpression, AST_NODE_PTR currentNode) { assert(currentNode->children->len == 2); Dereference deref; deref.nodePtr = currentNode; AST_NODE_PTR expression_node = AST_get_node(currentNode, 1); deref.index = createExpression(expression_node); // index has to be made if (deref.index == NULL) { return SEMANTIC_ERROR; } Type* indexType = deref.index->result; // indexType can only be a composite or a primitive if (indexType->kind != TypeKindComposite && indexType->kind != TypeKindPrimitive) { print_diagnostic(&expression_node->location, Error, "Index must a primitive int or composite variation"); return SEMANTIC_ERROR; } // indexType can only be int if (indexType->kind == TypeKindPrimitive) { if (indexType->impl.primitive != Int) { print_diagnostic( &AST_get_node(currentNode, 1)->location, Error, "Index must a primitive int or composite variation"); return SEMANTIC_ERROR; } } if (indexType->kind == TypeKindComposite) { if (indexType->impl.composite.primitive != Int) { print_diagnostic( &AST_get_node(currentNode, 1)->location, Error, "Index must a primitive int or composite variation"); return SEMANTIC_ERROR; } } deref.variable = createExpression(AST_get_node(currentNode, 0)); // variable has to be made if (deref.index == NULL) { print_diagnostic(&AST_get_node(currentNode, 0)->location, Error, "Invalid index"); return SEMANTIC_ERROR; } // variable can only be a reference if (deref.variable->result->kind != TypeKindReference) { print_diagnostic(&AST_get_node(currentNode, 0)->location, Error, "Only references can be dereferenced"); return SEMANTIC_ERROR; } ParentExpression->impl.dereference = deref; ParentExpression->result = deref.variable->result->impl.reference; return SEMANTIC_OK; } int createAddressOf(Expression* ParentExpression, AST_NODE_PTR currentNode) { assert(currentNode != NULL); assert(currentNode->children->len == 1); AddressOf address_of; address_of.node_ptr = currentNode; address_of.variable = createExpression(AST_get_node(currentNode, 0)); if (address_of.variable == NULL) { return SEMANTIC_ERROR; } Type* resultType = mem_alloc(MemoryNamespaceSet, sizeof(Type)); resultType->nodePtr = currentNode; resultType->kind = TypeKindReference; resultType->impl.reference = address_of.variable->result; ParentExpression->impl.addressOf = address_of; ParentExpression->result = resultType; return SEMANTIC_OK; } IO_Qualifier getParameterQualifier(Parameter* parameter) { if (parameter->kind == ParameterDeclarationKind) { return parameter->impl.declaration.qualifier; } else { return parameter->impl.definiton.declaration.qualifier; } } int createfuncall(FunctionCall* funcall, AST_NODE_PTR currentNode); Expression* createExpression(AST_NODE_PTR currentNode) { DEBUG("create Expression"); Expression* expression = mem_alloc(MemoryNamespaceSet, sizeof(Expression)); expression->nodePtr = currentNode; switch (currentNode->kind) { case AST_Int: case AST_Float: case AST_Char: expression->kind = ExpressionKindConstant; expression->impl.constant = createTypeValue(currentNode); expression->result = expression->impl.constant.type; break; case AST_String: expression->kind = ExpressionKindConstant; expression->impl.constant = createString(currentNode); expression->result = expression->impl.constant.type; break; case AST_Ident: DEBUG("find var"); expression->kind = ExpressionKindVariable; int status = getVariableFromScope(currentNode->value, &expression->impl.variable); if (status == SEMANTIC_ERROR) { expression->kind = ExpressionKindParameter; status = getParameter(currentNode->value, &expression->impl.parameter); if (status == SEMANTIC_ERROR) { DEBUG("Identifier is not in current scope"); print_diagnostic(¤tNode->location, Error, "Unknown identifier: `%s`", currentNode->value); return NULL; } if (getParameterQualifier(expression->impl.parameter) == Out) { print_diagnostic(¤tNode->location, Error, "Parameter is write-only: `%s`", currentNode->value); return NULL; } if (expression->impl.parameter->kind == ParameterDeclarationKind) { expression->result = expression->impl.parameter->impl.declaration.type; } else { expression->result = expression->impl.parameter->impl .definiton.declaration.type; } } else { if (expression->impl.variable->kind == VariableKindDeclaration) { expression->result = expression->impl.variable->impl.declaration.type; } else { expression->result = expression->impl.variable->impl .definiton.declaration.type; } } break; case AST_Add: case AST_Sub: case AST_Mul: case AST_Div: expression->kind = ExpressionKindOperation; if (createArithOperation(expression, currentNode, 2)) { return NULL; } break; case AST_Negate: expression->kind = ExpressionKindOperation; if (createArithOperation(expression, currentNode, 1)) { return NULL; } break; case AST_Eq: case AST_Less: case AST_Greater: expression->kind = ExpressionKindOperation; if (createRelationalOperation(expression, currentNode)) { return NULL; } break; case AST_BoolAnd: case AST_BoolOr: case AST_BoolXor: expression->kind = ExpressionKindOperation; if (createBoolOperation(expression, currentNode)) { return NULL; } break; case AST_BoolNot: expression->kind = ExpressionKindOperation; if (createBoolNotOperation(expression, currentNode)) { return NULL; } break; case AST_BitAnd: case AST_BitOr: case AST_BitXor: expression->kind = ExpressionKindOperation; if (createBitOperation(expression, currentNode)) { return NULL; } break; case AST_BitNot: expression->kind = ExpressionKindOperation; if (createBitNotOperation(expression, currentNode)) { return NULL; } break; case AST_IdentList: case AST_List: expression->kind = ExpressionKindVariable; if (createBoxAccess(expression, currentNode)) { return NULL; } break; case AST_Typecast: expression->kind = ExpressionKindTypeCast; if (createTypeCast(expression, currentNode)) { return NULL; } break; case AST_Transmute: expression->kind = ExpressionKindTransmute; if (createTransmute(expression, currentNode)) { return NULL; } break; case AST_Dereference: expression->kind = ExpressionKindDereference; if (createDeref(expression, currentNode)) { return NULL; } break; case AST_AddressOf: expression->kind = ExpressionKindAddressOf; if (createAddressOf(expression, currentNode)) { return NULL; } break; case AST_Call: expression->kind = ExpressionKindFunctionCall; expression->impl.call = mem_alloc(MemoryNamespaceSet, sizeof(FunctionCall)); if (createfuncall(expression->impl.call, currentNode) == SEMANTIC_ERROR) { return NULL; } expression->result = SET_function_get_return_type(expression->impl.call->function); break; default: PANIC("Node is not an expression but from kind: %i", currentNode->kind); break; } DEBUG("expression result typekind: %d", expression->result->kind); DEBUG("successfully created Expression"); return expression; } bool compareTypes(Type* leftType, Type* rightType) { if (leftType->kind == TypeKindPrimitive && rightType->kind == TypeKindPrimitive) { return leftType->impl.primitive == rightType->impl.primitive; } if (leftType->kind == TypeKindComposite) { if (rightType->kind == TypeKindPrimitive) { CompositeType leftComposite = leftType->impl.composite; if (leftComposite.scale == 1 && leftComposite.sign == Signed) { return leftComposite.primitive == rightType->impl.primitive; } return FALSE; } else if (rightType->kind == TypeKindComposite) { // Compare composites CompositeType leftComposite = leftType->impl.composite; CompositeType rightComposite = rightType->impl.composite; if (leftComposite.primitive != rightComposite.primitive) { return FALSE; } if (leftComposite.sign != rightComposite.sign) { return FALSE; } if (leftComposite.scale != rightComposite.scale) { return FALSE; } return TRUE; } return FALSE; } if (leftType->kind == TypeKindBox && rightType->kind == TypeKindBox) { if (leftType->impl.box != rightType->impl.box) { return FALSE; } return TRUE; } if (leftType->kind == TypeKindReference && rightType->kind == TypeKindReference) { bool result = compareTypes(leftType->impl.reference, rightType->impl.reference); return result; } return FALSE; } Type* getVariableType(Variable* variable) { if (variable->kind == VariableKindDeclaration) { return variable->impl.declaration.type; } else { return variable->impl.definiton.declaration.type; } } Type* getParameterType(Parameter* parameter) { if (parameter->kind == ParameterDeclarationKind) { return parameter->impl.declaration.type; } else { return parameter->impl.definiton.declaration.type; } } int createStorageExpr(StorageExpr* expr, AST_NODE_PTR node) { switch (node->kind) { case AST_Ident: expr->kind = StorageExprKindVariable; int status = getVariableFromScope(node->value, &expr->impl.variable); if (status == SEMANTIC_ERROR) { expr->kind = StorageExprKindParameter; status = getParameter(node->value, &expr->impl.parameter); if (status == SEMANTIC_ERROR) { print_diagnostic(&node->location, Error, "Unknown token: `%s`", node->value); return SEMANTIC_ERROR; } else { expr->target_type = getParameterType(expr->impl.parameter); } } else { expr->target_type = getVariableType(expr->impl.variable); } break; case AST_Dereference: expr->kind = StorageExprKindDereference; AST_NODE_PTR array_node = AST_get_node(node, 0); AST_NODE_PTR index_node = AST_get_node(node, 1); expr->impl.dereference.index = createExpression(index_node); expr->impl.dereference.array = mem_alloc(MemoryNamespaceSet, sizeof(StorageExpr)); if (createStorageExpr(expr->impl.dereference.array, array_node) == SEMANTIC_ERROR) { return SEMANTIC_ERROR; } if (expr->impl.dereference.array->target_type->kind == TypeKindReference) { expr->target_type = expr->impl.dereference.array->target_type->impl.reference; } else { print_diagnostic( &array_node->location, Error, "Cannot dereference non reference type: %s", type_to_string(expr->impl.dereference.array->target_type)); return SEMANTIC_ERROR; }; break; default: print_message(Error, "Unimplemented"); return SEMANTIC_ERROR; break; } return SEMANTIC_OK; } int createAssign(Statement* ParentStatement, AST_NODE_PTR currentNode) { DEBUG("create Assign"); Assignment assign; assign.nodePtr = currentNode; assign.destination = mem_alloc(MemoryNamespaceSet, sizeof(StorageExpr)); AST_NODE_PTR strg_expr = AST_get_node(currentNode, 0); int status = createStorageExpr(assign.destination, strg_expr); if (status == SEMANTIC_ERROR) { return SEMANTIC_ERROR; } if (strg_expr->kind == AST_Parameter) { if (getParameterQualifier(assign.destination->impl.parameter) == In) { print_diagnostic(¤tNode->location, Error, "Parameter is read-only: `%s`", assign.destination->impl.parameter->name); return SEMANTIC_ERROR; } } assign.value = createExpression(AST_get_node(currentNode, 1)); if (assign.value == NULL) { return SEMANTIC_ERROR; } if (!compareTypes(assign.destination->target_type, assign.value->result)) { print_diagnostic(&assign.value->nodePtr->location, Error, "assignment requires `%s` but got `%s`", type_to_string(assign.destination->target_type), type_to_string(assign.value->result)); return SEMANTIC_ERROR; } ParentStatement->impl.assignment = assign; return SEMANTIC_OK; } int createStatement(Block* block, AST_NODE_PTR currentNode); int fillBlock(Block* block, AST_NODE_PTR currentNode) { DEBUG("start filling Block"); block->nodePtr = currentNode; block->statemnts = mem_new_g_array(MemoryNamespaceSet, sizeof(Statement*)); GHashTable* lowerScope = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); g_array_append_val(Scope, lowerScope); for (size_t i = 0; i < currentNode->children->len; i++) { AST_NODE_PTR stmt_node = AST_get_node(currentNode, i); int signal = createStatement(block, stmt_node); if (signal) { return SEMANTIC_ERROR; } } mem_free(lowerScope); g_array_remove_index(Scope, Scope->len - 1); DEBUG("created Block successfully"); return SEMANTIC_OK; } int createWhile(Statement* ParentStatement, AST_NODE_PTR currentNode) { assert(ParentStatement != NULL); assert(currentNode != NULL); assert(currentNode->kind == AST_While); While whileStruct; whileStruct.nodePtr = currentNode; whileStruct.conditon = createExpression(AST_get_node(currentNode, 0)); if (NULL == whileStruct.conditon) { return SEMANTIC_ERROR; } AST_NODE_PTR statementList = AST_get_node(currentNode, 1); int signal = fillBlock(&whileStruct.block, statementList); if (signal) { return SEMANTIC_ERROR; } ParentStatement->impl.whileLoop = whileStruct; return SEMANTIC_OK; } int createIf(Branch* Parentbranch, AST_NODE_PTR currentNode) { If ifbranch; ifbranch.nodePtr = currentNode; Expression* expression = createExpression(AST_get_node(currentNode, 0)); if (NULL == expression) { return SEMANTIC_ERROR; } ifbranch.conditon = expression; int status = fillBlock(&ifbranch.block, AST_get_node(currentNode, 1)); if (status) { return SEMANTIC_ERROR; } Parentbranch->ifBranch = ifbranch; return SEMANTIC_OK; } int createElse(Branch* Parentbranch, AST_NODE_PTR currentNode) { Else elseBranch; elseBranch.nodePtr = currentNode; int status = fillBlock(&elseBranch.block, AST_get_node(currentNode, 0)); if (status) { return SEMANTIC_ERROR; } Parentbranch->elseBranch = elseBranch; return SEMANTIC_OK; } int createElseIf(Branch* Parentbranch, AST_NODE_PTR currentNode) { ElseIf elseIfBranch; elseIfBranch.nodePtr = currentNode; if (Parentbranch->elseIfBranches == NULL) { Parentbranch->elseIfBranches = mem_new_g_array(MemoryNamespaceSet, sizeof(ElseIf)); } Expression* expression = createExpression(AST_get_node(currentNode, 0)); if (NULL == expression) { return SEMANTIC_ERROR; } elseIfBranch.conditon = expression; int status = fillBlock(&elseIfBranch.block, AST_get_node(currentNode, 1)); if (status) { return SEMANTIC_ERROR; } g_array_append_val(Parentbranch->elseIfBranches, elseIfBranch); return SEMANTIC_OK; } int createBranch(Statement* ParentStatement, AST_NODE_PTR currentNode) { Branch branch; branch.nodePtr = currentNode; branch.elseBranch.block.statemnts = NULL; branch.elseIfBranches = NULL; for (size_t i = 0; i < currentNode->children->len; i++) { switch (AST_get_node(currentNode, i)->kind) { case AST_If: if (createIf(&branch, AST_get_node(currentNode, i))) { return SEMANTIC_ERROR; } break; case AST_IfElse: if (createElseIf(&branch, AST_get_node(currentNode, i))) { return SEMANTIC_ERROR; } break; case AST_Else: if (createElse(&branch, AST_get_node(currentNode, i))) { return SEMANTIC_ERROR; } break; default: PANIC("current node is not part of a Branch"); break; } } ParentStatement->impl.branch = branch; return SEMANTIC_OK; } int getFunction(const char* name, Function** function); Parameter get_param_from_func(Function* func, size_t index) { if (func->kind == FunctionDeclarationKind) { return g_array_index(func->impl.declaration.parameter, Parameter, index); } else { return g_array_index(func->impl.definition.parameter, Parameter, index); } } char* module_ref_to_string(AST_NODE_PTR node) { switch (node->kind) { case AST_Ident: return mem_strdup(MemoryNamespaceSet, node->value); case AST_ModuleRef: char* submodule = module_ref_to_string(AST_get_last_node(node)); char* curmodule = module_ref_to_string(AST_get_node(node, 0)); char* composed = g_strjoin("::", curmodule, submodule, NULL); char* cached_composed = mem_strdup(MemoryNamespaceSet, composed); mem_free(composed); mem_free(curmodule); mem_free(submodule); return cached_composed; default: return NULL; } } int createfuncall(FunctionCall* funcall, AST_NODE_PTR currentNode) { assert(currentNode != NULL); assert(currentNode->children->len == 2); AST_NODE_PTR argsListNode = AST_get_node(currentNode, 1); AST_NODE_PTR nameNode = AST_get_node(currentNode, 0); char* function_name = module_ref_to_string(nameNode); Function* fun = NULL; if (nameNode->kind == AST_ModuleRef || nameNode->kind == AST_Ident) { int result = getFunction(function_name, &fun); if (result == SEMANTIC_ERROR) { print_diagnostic(¤tNode->location, Error, "Unknown function: `%s`", function_name); return SEMANTIC_ERROR; } } if (nameNode->kind == AST_IdentList) { assert(nameNode->children->len > 1); // idents.boxname.funname() // only boxname and funname are needed, because the combination is // unique const char* boxName = AST_get_node(nameNode, (nameNode->children->len - 2))->value; const char* name = g_strjoin("", boxName, ".", function_name, NULL); int result = getFunction(name, &fun); if (result) { print_diagnostic(¤tNode->location, Error, "Unknown function: `%s`", nameNode); return SEMANTIC_ERROR; } } funcall->function = fun; funcall->nodePtr = currentNode; size_t paramCount = 0; if (fun->kind == FunctionDeclarationKind) { paramCount = fun->impl.declaration.parameter->len; } else if (fun->kind == FunctionDefinitionKind) { paramCount = fun->impl.definition.parameter->len; } size_t count = 0; for (size_t i = 0; i < argsListNode->children->len; i++) { count += AST_get_node(argsListNode, i)->children->len; } if (count != paramCount) { print_diagnostic(¤tNode->location, Error, "Expected %d arguments instead of %d", paramCount, count); return SEMANTIC_ERROR; } GArray* expressions = mem_new_g_array(MemoryNamespaceSet, (sizeof(Expression*))); // exprlists for (size_t i = 0; i < argsListNode->children->len; i++) { AST_NODE_PTR currentExprList = AST_get_node(argsListNode, i); for (int j = ((int) currentExprList->children->len) - 1; j >= 0; j--) { AST_NODE_PTR expr_node = AST_get_node(currentExprList, j); Expression* expr = createExpression(expr_node); if (expr == NULL) { return SEMANTIC_ERROR; } Parameter param = get_param_from_func( fun, i + currentExprList->children->len - j - 1); if (!compareTypes(expr->result, param.impl.declaration.type)) { print_diagnostic(&expr_node->location, Error, "parameter and argument `%s` type mismatch, " "expected `%s` got `%s`", param.name, type_to_string(param.impl.declaration.type), type_to_string(expr->result)); return SEMANTIC_ERROR; } g_array_append_val(expressions, expr); } } funcall->expressions = expressions; return SEMANTIC_OK; } int createStatement(Block* Parentblock, AST_NODE_PTR currentNode) { DEBUG("create Statement"); switch (currentNode->kind) { case AST_Decl: { GArray* variable = mem_new_g_array(MemoryNamespaceSet, sizeof(Variable*)); int status = createDecl(currentNode, &variable); if (status) { return SEMANTIC_ERROR; } for (size_t i = 0; i < variable->len; i++) { Statement* statement = mem_alloc(MemoryNamespaceSet, sizeof(Statement)); statement->nodePtr = currentNode; statement->kind = StatementKindDeclaration; statement->impl.variable = g_array_index(variable, Variable*, i); g_array_append_val(Parentblock->statemnts, statement); } } break; case AST_Def: { GArray* variable = mem_new_g_array(MemoryNamespaceSet, sizeof(Variable*)); if (createDef(currentNode, &variable)) { return SEMANTIC_ERROR; } for (size_t i = 0; i < variable->len; i++) { Statement* statement = mem_alloc(MemoryNamespaceSet, sizeof(Statement)); statement->nodePtr = currentNode; statement->kind = StatementKindDefinition; statement->impl.variable = g_array_index(variable, Variable*, i); g_array_append_val(Parentblock->statemnts, statement); } } break; case AST_While: { Statement* statement = mem_alloc(MemoryNamespaceSet, sizeof(Statement)); statement->nodePtr = currentNode; statement->kind = StatementKindWhile; if (createWhile(statement, currentNode)) { return SEMANTIC_ERROR; } g_array_append_val(Parentblock->statemnts, statement); } break; case AST_Stmt: { Statement* statement = mem_alloc(MemoryNamespaceSet, sizeof(Statement)); statement->nodePtr = currentNode; statement->kind = StatementKindBranch; if (createBranch(statement, currentNode)) { return SEMANTIC_ERROR; } g_array_append_val(Parentblock->statemnts, statement); } break; case AST_Assign: { Statement* statement = mem_alloc(MemoryNamespaceSet, sizeof(Statement)); statement->nodePtr = currentNode; statement->kind = StatementKindAssignment; if (createAssign(statement, currentNode)) { return SEMANTIC_ERROR; } g_array_append_val(Parentblock->statemnts, statement); } break; case AST_Call: { Statement* statement = mem_alloc(MemoryNamespaceSet, sizeof(Statement)); statement->nodePtr = currentNode; statement->kind = StatementKindFunctionCall; int result = createfuncall(&statement->impl.call, currentNode); if (result == SEMANTIC_ERROR) { return SEMANTIC_ERROR; } g_array_append_val(Parentblock->statemnts, statement); break; } case AST_Return: { Statement* statement = mem_alloc(MemoryNamespaceSet, sizeof(Statement)); statement->nodePtr = currentNode; statement->kind = StatementKindReturn; AST_NODE_PTR expr_node = AST_get_node(currentNode, 0); statement->impl.returnStmt.value = createExpression(expr_node); statement->impl.returnStmt.nodePtr = currentNode; if (statement->impl.returnStmt.value == NULL) { return SEMANTIC_ERROR; } // TODO: compare result and function return type g_array_append_val(Parentblock->statemnts, statement); break; } default: PANIC("Node is not a statement: %s", AST_node_to_string(currentNode)); break; } return SEMANTIC_OK; } int createParam(GArray* Paramlist, AST_NODE_PTR currentNode) { assert(currentNode->kind == AST_Parameter); DEBUG("start param"); DEBUG("current node child count: %i", currentNode->children->len); AST_NODE_PTR paramdecl = AST_get_node(currentNode, 1); AST_NODE_PTR ioQualifierList = AST_get_node(currentNode, 0); ParameterDeclaration decl; decl.nodePtr = paramdecl; DEBUG("iolistnode child count: %i", ioQualifierList->children->len); if (ioQualifierList->children->len == 2) { decl.qualifier = InOut; } else if (ioQualifierList->children->len == 1) { if (strcmp(AST_get_node(ioQualifierList, 0)->value, "in") == 0) { decl.qualifier = In; } else if (strcmp(AST_get_node(ioQualifierList, 0)->value, "out") == 0) { decl.qualifier = Out; } else { PANIC("IO_Qualifier is not in or out"); } } else { PANIC("IO_Qualifier has not the right amount of children"); } if (set_get_type_impl(AST_get_node(paramdecl, 0), &(decl.type))) { return SEMANTIC_ERROR; } Parameter* param = mem_alloc(MemoryNamespaceSet, sizeof(Parameter)); param->nodePtr = currentNode; param->kind = ParameterDeclarationKind; param->impl.declaration = decl; param->name = AST_get_node(paramdecl, 1)->value; DEBUG("param name: %s", param->name); g_array_append_val(Paramlist, *param); if (g_hash_table_contains(functionParameter, param->name)) { print_diagnostic(¶m->nodePtr->location, Error, "Names of function parameters must be unique: %s", param->name); return SEMANTIC_ERROR; } g_hash_table_insert(functionParameter, (gpointer) param->name, param); DEBUG("created param successfully"); return SEMANTIC_OK; } int createFunDef(Function* Parentfunction, AST_NODE_PTR currentNode) { DEBUG("start fundef"); AST_NODE_PTR nameNode = AST_get_node(currentNode, 0); AST_NODE_PTR return_value_node = AST_get_node(currentNode, 1); AST_NODE_PTR paramlistlist = AST_get_node(currentNode, 2); AST_NODE_PTR statementlist = AST_get_node(currentNode, 3); FunctionDefinition fundef; fundef.nodePtr = currentNode; fundef.name = nameNode->value; fundef.body = mem_alloc(MemoryNamespaceSet, sizeof(Block)); fundef.parameter = mem_new_g_array(MemoryNamespaceSet, sizeof(Parameter)); fundef.return_value = NULL; if (set_get_type_impl(return_value_node, &fundef.return_value) == SEMANTIC_ERROR) { print_diagnostic(&return_value_node->location, Error, "Unknown return value type"); return SEMANTIC_ERROR; } DEBUG("paramlistlist child count: %i", paramlistlist->children->len); for (size_t i = 0; i < paramlistlist->children->len; i++) { // all parameterlists AST_NODE_PTR paramlist = AST_get_node(paramlistlist, i); DEBUG("paramlist child count: %i", paramlist->children->len); for (int j = ((int) paramlist->children->len) - 1; j >= 0; j--) { DEBUG("param child count: %i", AST_get_node(paramlist, j)->children->len); if (createParam(fundef.parameter, AST_get_node(paramlist, j))) { return SEMANTIC_ERROR; } } DEBUG("End of Paramlist"); } if (fillBlock(fundef.body, statementlist)) { return SEMANTIC_ERROR; } Parentfunction->nodePtr = currentNode; Parentfunction->kind = FunctionDefinitionKind; Parentfunction->impl.definition = fundef; Parentfunction->name = fundef.name; return SEMANTIC_OK; } bool compareParameter(GArray* leftParameter, GArray* rightParameter) { if (leftParameter->len != rightParameter->len) { return FALSE; } for (size_t i = 0; i < leftParameter->len; i++) { Parameter currentLeftParam = g_array_index(leftParameter, Parameter, i); Parameter currentRightParam = g_array_index(leftParameter, Parameter, i); if (strcmp(currentLeftParam.name, currentRightParam.name) != 0) { return FALSE; } if (currentLeftParam.kind != currentRightParam.kind) { return FALSE; } if (currentLeftParam.kind == ParameterDeclarationKind) { ParameterDeclaration leftDecl = currentLeftParam.impl.declaration; ParameterDeclaration rightDecl = currentLeftParam.impl.declaration; if (leftDecl.qualifier != rightDecl.qualifier) { return FALSE; } if (compareTypes(leftDecl.type, rightDecl.type) == FALSE) { return FALSE; } } } return TRUE; } int addFunction(const char* name, Function* function) { if (function->kind == FunctionDefinitionKind) { if (g_hash_table_contains(definedFunctions, name)) { print_diagnostic(&function->nodePtr->location, Error, "Multiple definition of function: `%s`", function->name); return SEMANTIC_ERROR; } g_hash_table_insert(definedFunctions, (gpointer) name, function); } else if (function->kind == FunctionDeclarationKind) { if (g_hash_table_contains(declaredFunctions, name)) { Function* declaredFunction = g_hash_table_lookup(declaredFunctions, name); bool result = compareParameter(declaredFunction->impl.declaration.parameter, function->impl.declaration.parameter); // a function can have multiple declartations but all have to be // identical if (result == FALSE) { print_diagnostic(&function->nodePtr->location, Error, "Divergent declaration of function: `%s`", function->name); return SEMANTIC_ERROR; } } g_hash_table_insert(declaredFunctions, (gpointer) name, function); } return SEMANTIC_OK; } int getFunction(const char* name, Function** function) { if (g_hash_table_contains(definedFunctions, name)) { Function* fun = g_hash_table_lookup(definedFunctions, name); *function = fun; return SEMANTIC_OK; } if (g_hash_table_contains(declaredFunctions, name)) { Function* fun = g_hash_table_lookup(declaredFunctions, name); *function = fun; return SEMANTIC_OK; } return SEMANTIC_ERROR; } int createProcDef(Function* Parentfunction, AST_NODE_PTR currentNode) { DEBUG("start fundef"); AST_NODE_PTR nameNode = AST_get_node(currentNode, 0); AST_NODE_PTR paramlistlist = AST_get_node(currentNode, 1); AST_NODE_PTR statementlist = AST_get_node(currentNode, 2); FunctionDefinition fundef; fundef.nodePtr = currentNode; fundef.name = nameNode->value; fundef.body = mem_alloc(MemoryNamespaceSet, sizeof(Block)); fundef.parameter = mem_new_g_array(MemoryNamespaceSet, sizeof(Parameter)); fundef.return_value = NULL; DEBUG("paramlistlist child count: %i", paramlistlist->children->len); for (size_t i = 0; i < paramlistlist->children->len; i++) { // all parameterlists AST_NODE_PTR paramlist = AST_get_node(paramlistlist, i); DEBUG("paramlist child count: %i", paramlist->children->len); for (int j = ((int) paramlist->children->len) - 1; j >= 0; j--) { DEBUG("param child count: %i", AST_get_node(paramlist, j)->children->len); if (createParam(fundef.parameter, AST_get_node(paramlist, j))) { return SEMANTIC_ERROR; } } DEBUG("End of Paramlist"); } if (fillBlock(fundef.body, statementlist)) { return SEMANTIC_ERROR; } Parentfunction->nodePtr = currentNode; Parentfunction->kind = FunctionDefinitionKind; Parentfunction->impl.definition = fundef; Parentfunction->name = fundef.name; return SEMANTIC_OK; } int createProcDecl(Function* Parentfunction, AST_NODE_PTR currentNode) { DEBUG("start fundecl"); AST_NODE_PTR nameNode = AST_get_node(currentNode, 0); AST_NODE_PTR paramlistlist = AST_get_node(currentNode, 1); FunctionDeclaration fundecl; fundecl.nodePtr = currentNode; fundecl.name = nameNode->value; fundecl.parameter = mem_new_g_array(MemoryNamespaceSet, sizeof(Parameter)); fundecl.return_value = NULL; for (size_t i = 0; i < paramlistlist->children->len; i++) { // all parameter lists AST_NODE_PTR paramlist = AST_get_node(paramlistlist, i); for (int j = ((int) paramlist->children->len) - 1; j >= 0; j--) { AST_NODE_PTR param = AST_get_node(paramlist, j); if (createParam(fundecl.parameter, param)) { return SEMANTIC_ERROR; } } } Parentfunction->nodePtr = currentNode; Parentfunction->kind = FunctionDeclarationKind; Parentfunction->impl.declaration = fundecl; Parentfunction->name = fundecl.name; return SEMANTIC_OK; } int createFunDecl(Function* Parentfunction, AST_NODE_PTR currentNode) { DEBUG("start fundecl"); AST_NODE_PTR nameNode = AST_get_node(currentNode, 0); AST_NODE_PTR return_value_node = AST_get_node(currentNode, 1); AST_NODE_PTR paramlistlist = AST_get_node(currentNode, 2); FunctionDeclaration fundecl; fundecl.nodePtr = currentNode; fundecl.name = nameNode->value; fundecl.parameter = mem_new_g_array(MemoryNamespaceSet, sizeof(Parameter)); fundecl.return_value = NULL; if (set_get_type_impl(return_value_node, &fundecl.return_value) == SEMANTIC_ERROR) { print_diagnostic(&return_value_node->location, Error, "Unknown return value type"); return SEMANTIC_ERROR; } for (size_t i = 0; i < paramlistlist->children->len; i++) { // all parameter lists AST_NODE_PTR paramlist = AST_get_node(paramlistlist, i); for (int j = ((int) paramlist->children->len) - 1; j >= 0; j--) { AST_NODE_PTR param = AST_get_node(paramlist, j); if (createParam(fundecl.parameter, param)) { return SEMANTIC_ERROR; } } } Parentfunction->nodePtr = currentNode; Parentfunction->kind = FunctionDeclarationKind; Parentfunction->impl.declaration = fundecl; Parentfunction->name = fundecl.name; return SEMANTIC_OK; } int createFunction(Function* function, AST_NODE_PTR currentNode) { functionParameter = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); switch (currentNode->kind) { case AST_FunDecl: if (createFunDecl(function, currentNode)) { return SEMANTIC_ERROR; } break; case AST_FunDef: if (createFunDef(function, currentNode)) { return SEMANTIC_ERROR; } break; case AST_ProcDecl: if (createProcDecl(function, currentNode)) { return SEMANTIC_ERROR; } break; case AST_ProcDef: if (createProcDef(function, currentNode)) { return SEMANTIC_ERROR; } break; default: ERROR("invalid AST node type: %s", AST_node_to_string(currentNode)); return SEMANTIC_ERROR; } if (!(currentNode->annotation.kind == AnnotationKindArray && AST_annotation_array_contains_flag(¤tNode->annotation, "nomangle"))) { // compose function name by appending parent modules char* modules = module_ref_to_str(currentNode->location.module_ref); char* composed_name = g_strjoin("", modules, "::", function->name, NULL); char* cached_composed_name = mem_strdup(MemoryNamespaceSet, composed_name); g_free(composed_name); function->name = cached_composed_name; } mem_free(functionParameter); functionParameter = NULL; int result = addFunction(function->name, function); if (result == SEMANTIC_ERROR) { return SEMANTIC_ERROR; } return SEMANTIC_OK; } int createDeclMember(BoxType* ParentBox, AST_NODE_PTR currentNode) { Type* declType = mem_alloc(MemoryNamespaceSet, sizeof(Type)); int status = set_get_type_impl(AST_get_node(currentNode, 0), &declType); if (status) { return SEMANTIC_ERROR; } AST_NODE_PTR nameList = AST_get_node(currentNode, 1); for (size_t i = 0; i < nameList->children->len; i++) { BoxMember* decl = mem_alloc(MemoryNamespaceSet, sizeof(BoxMember)); decl->name = AST_get_node(nameList, i)->value; decl->nodePtr = currentNode; decl->box = ParentBox; decl->initalizer = NULL; decl->type = declType; if (g_hash_table_contains(ParentBox->member, (gpointer) decl->name)) { return SEMANTIC_ERROR; } g_hash_table_insert(ParentBox->member, (gpointer) decl->name, decl); } return SEMANTIC_OK; } int createDefMember(BoxType* ParentBox, AST_NODE_PTR currentNode) { AST_NODE_PTR declNode = AST_get_node(currentNode, 0); AST_NODE_PTR expressionNode = AST_get_node(currentNode, 1); AST_NODE_PTR nameList = AST_get_node(declNode, 1); Type* declType = mem_alloc(MemoryNamespaceSet, sizeof(Type)); int status = set_get_type_impl(AST_get_node(currentNode, 0), &declType); if (status) { return SEMANTIC_ERROR; } Expression* init = createExpression(expressionNode); if (init == NULL) { return SEMANTIC_ERROR; } for (size_t i = 0; i < nameList->children->len; i++) { BoxMember* def = mem_alloc(MemoryNamespaceSet, sizeof(BoxMember)); def->box = ParentBox; def->type = declType; def->initalizer = init; def->name = AST_get_node(nameList, i)->value; def->nodePtr = currentNode; if (g_hash_table_contains(ParentBox->member, (gpointer) def->name)) { return SEMANTIC_ERROR; } g_hash_table_insert(ParentBox->member, (gpointer) def->name, def); } return SEMANTIC_OK; } int createBoxFunction(const char* boxName, Type* ParentBoxType, AST_NODE_PTR currentNode) { Function* function = mem_alloc(MemoryNamespaceSet, sizeof(Function)); int result = createFunction(function, currentNode); if (result == SEMANTIC_ERROR) { return SEMANTIC_ERROR; } function->name = g_strjoin("", boxName, ".", function->name, NULL); Parameter param; param.name = "self"; param.nodePtr = currentNode; param.kind = ParameterDeclarationKind; param.impl.declaration.qualifier = In; param.impl.declaration.nodePtr = currentNode; param.impl.declaration.type = ParentBoxType; if (function->kind == FunctionDeclarationKind) { g_array_prepend_val(function->impl.declaration.parameter, param); } else { g_array_append_val(function->impl.definition.parameter, param); } addFunction(function->name, function); return SEMANTIC_OK; } int createBox(GHashTable* boxes, AST_NODE_PTR currentNode) { BoxType* box = mem_alloc(MemoryNamespaceSet, sizeof(BoxType)); box->nodePtr = currentNode; const char* boxName = AST_get_node(currentNode, 0)->value; AST_NODE_PTR boxMemberList = AST_get_node(currentNode, 1); Type* boxType = mem_alloc(MemoryNamespaceSet, sizeof(Type)); boxType->nodePtr = currentNode; boxType->impl.box = box; for (size_t i = 0; boxMemberList->children->len; i++) { switch (AST_get_node(boxMemberList, i)->kind) { case AST_Decl: case AST_Def: if (createDeclMember(box, AST_get_node(boxMemberList, i))) { return SEMANTIC_ERROR; } break; case AST_FunDef: { int result = createBoxFunction( boxName, boxType, AST_get_node(boxMemberList, i)); if (result == SEMANTIC_ERROR) { return SEMANTIC_ERROR; } } default: break; } } if (g_hash_table_contains(boxes, (gpointer) boxName)) { return SEMANTIC_ERROR; } g_hash_table_insert(boxes, (gpointer) boxName, box); return SEMANTIC_OK; } int createTypeDef(GHashTable* types, AST_NODE_PTR currentNode) { DEBUG("create Type define"); AST_NODE_PTR typeNode = AST_get_node(currentNode, 0); AST_NODE_PTR nameNode = AST_get_node(currentNode, 1); Type* type = mem_alloc(MemoryNamespaceSet, sizeof(Type)); int status = set_get_type_impl(typeNode, &type); if (status) { return SEMANTIC_ERROR; } Typedefine* def = mem_alloc(MemoryNamespaceSet, sizeof(Typedefine)); def->name = nameNode->value; def->nodePtr = currentNode; def->type = type; if (g_hash_table_contains(types, (gpointer) def->name)) { print_diagnostic(¤tNode->location, Error, "Multiple definition of type: `%s`", nameNode->value); return SEMANTIC_ERROR; } g_hash_table_insert(types, (gpointer) def->name, def); if (g_hash_table_contains(declaredComposites, (gpointer) def->name)) { print_diagnostic(¤tNode->location, Error, "Multiple definition of type: `%s`", nameNode->value); return SEMANTIC_ERROR; } g_hash_table_insert(declaredComposites, (gpointer) def->name, def->type); return SEMANTIC_OK; } Module* create_set(AST_NODE_PTR currentNode) { DEBUG("create root Module"); // create tables for types declaredComposites = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); declaredBoxes = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); declaredFunctions = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); definedFunctions = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); // create scope Scope = mem_new_g_array(MemoryNamespaceSet, sizeof(GHashTable*)); // building current scope for module GHashTable* globalscope = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); globalscope = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); g_array_append_val(Scope, globalscope); Module* rootModule = mem_alloc(MemoryNamespaceSet, sizeof(Module)); GHashTable* boxes = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); GHashTable* types = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); GHashTable* functions = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); GHashTable* variables = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal); GArray* imports = mem_new_g_array(MemoryNamespaceSet, sizeof(const char*)); GArray* includes = mem_new_g_array(MemoryNamespaceSet, sizeof(const char*)); rootModule->boxes = boxes; rootModule->types = types; rootModule->functions = functions; rootModule->variables = variables; rootModule->imports = imports; rootModule->includes = includes; DEBUG("created Module struct"); for (size_t i = 0; i < currentNode->children->len; i++) { DEBUG("created Child with type: %i", AST_get_node(currentNode, i)->kind); switch (AST_get_node(currentNode, i)->kind) { case AST_Decl: { GArray* vars = NULL; int status = createDecl(AST_get_node(currentNode, i), &vars); if (status) { return NULL; } if (fillTablesWithVars(variables, vars) == SEMANTIC_ERROR) { INFO("var already exists"); break; } DEBUG("filled successfull the module and scope with vars"); break; } case AST_Def: { GArray* vars; int status = createDef(AST_get_node(currentNode, i), &vars); if (status) { return NULL; } if (fillTablesWithVars(variables, vars) == SEMANTIC_ERROR) { INFO("var already exists"); break; } DEBUG("created Definition successfully"); break; } case AST_Box: { int status = createBox(boxes, AST_get_node(currentNode, i)); if (status) { return NULL; } DEBUG("created Box successfully"); break; } case AST_FunDef: case AST_FunDecl: case AST_ProcDef: case AST_ProcDecl: { DEBUG("start function"); Function* function = mem_alloc(MemoryNamespaceSet, sizeof(Function)); if (createFunction(function, AST_get_node(currentNode, i)) == SEMANTIC_ERROR) { return NULL; } g_hash_table_insert(rootModule->functions, function->name, function); DEBUG("created function successfully"); break; } case AST_Typedef: { int status = createTypeDef(types, AST_get_node(currentNode, i)); if (status) { return NULL; } DEBUG("created Typedef successfully"); break; } case AST_Import: DEBUG("create Import"); g_array_append_val(imports, AST_get_node(currentNode, i)->value); break; case AST_Include: DEBUG("create Include"); g_array_append_val(includes, AST_get_node(currentNode, i)->value); break; default: INFO("Provided source file could not be parsed because of " "semantic " "error."); break; } } DEBUG("created set successfully"); return rootModule; }