(* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. *) module import common, cstdlib, lexer, ast, symbol, diagnostic proc elna_name_type_expression*(parser_node: ^ElnaTreeTypeExpression; error_list: ^ElnaList) -> ^ElnaType var result: ^ElnaType := nil begin if parser_node <> nil then case parser_node^.kind of ElnaTreeKind.named_type_expression: result := elna_name_named_type_expression(cast(parser_node: ^ElnaTreeNamedTypeExpression), error_list) | ElnaTreeKind.enumeration_type_expression: result := malloc#[ElnaType](#size(ElnaTypeEnumeration)); result^.kind := ElnaTypeKind.enumeration; elna_name_enumeration_type_expression(cast(parser_node: ^ElnaTreeEnumerationTypeExpression), error_list, cast(result: ^ElnaTypeEnumeration)) | ElnaTreeKind.record_type_expression: result := malloc#[ElnaType](#size(ElnaTypeRecord)); result^.kind := ElnaTypeKind._record; elna_name_record_type_expression(cast(parser_node: ^ElnaTreeRecordTypeExpression), error_list, cast(result: ^ElnaTypeRecord)) | ElnaTreeKind.pointer_type_expression: result := malloc#[ElnaType](#size(ElnaTypePointer)); result^.kind := ElnaTypeKind.pointer; elna_name_pointer_type_expression(cast(parser_node: ^ElnaTreePointerTypeExpression), error_list, cast(result: ^ElnaTypePointer)) | ElnaTreeKind.array_type_expression: result := malloc#[ElnaType](#size(ElnaTypeArray)); result^.kind := ElnaTypeKind.array; elna_name_array_type_expression(cast(parser_node: ^ElnaTreeArrayTypeExpression), error_list, cast(result: ^ElnaTypeArray)) else end end return result proc elna_name_named_type_expression*(parser_node: ^ElnaTreeNamedTypeExpression; error_list: ^ElnaList) -> ^ElnaType var symbol_info: ^ElnaSymbolInfo type_info: ^ElnaSymbolTypeInfo undefined_symbol: ^ElnaErrorUndefinedSymbol result: ^ElnaType := nil begin symbol_info := elna_symbol_table_lookup(symbol_table_global, parser_node^.name); if symbol_info <> nil then type_info := cast(symbol_info: ^ElnaSymbolTypeInfo); result := type_info^._type else undefined_symbol := elna_error_undefined_symbol_create(parser_node^.position, parser_node^.name); elna_list_append(error_list, cast(undefined_symbol: ^ElnaListNode)) end return result proc elna_name_alias_type_expression*(parser_node: ^ElnaTreeNamedTypeExpression; error_list: ^ElnaList; result: ^ElnaTypeAlias) var base: ^ElnaType begin base := elna_name_named_type_expression(parser_node, error_list); if base <> nil then result^.size := base^.size; result^.alignment := base^.alignment; result^.base := base end return proc elna_name_enumeration_type_expression*(parser_node: ^ElnaTreeEnumerationTypeExpression; error_list: ^ElnaList; result: ^ElnaTypeEnumeration) var tree_member: ^ElnaTreeEnumeration i: Word := 0u begin result^.size := 8u; result^.alignment := 8u; result^.length := parser_node^.length; result^.members := malloc#[[]const Word8](parser_node^.length * #size([]const Word8)); tree_member := parser_node^.members; while i < parser_node^.length & tree_member <> nil do (result^.members + i)^ := tree_member^.name; tree_member := tree_member^.next; i := i + 1u end return proc elna_name_pointer_type_expression*(parser_node: ^ElnaTreePointerTypeExpression; error_list: ^ElnaList; result: ^ElnaTypePointer) begin result^.size := 8u; result^.alignment := 8u; result^.base := elna_name_type_expression(parser_node^.base, error_list) return proc elna_name_array_type_expression*(parser_node: ^ElnaTreeArrayTypeExpression; error_list: ^ElnaList; result: ^ElnaTypeArray) var base: ^ElnaType len_lit: ^ElnaTreeIntegerLiteral begin base := elna_name_type_expression(parser_node^.base, error_list); len_lit := cast(parser_node^.length: ^ElnaTreeIntegerLiteral); if base <> nil & len_lit <> nil then result^.size := base^.size * len_lit^.value; result^.alignment := base^.alignment; result^.base := base; result^.length := len_lit^.value end return proc elna_name_record_type_expression*(parser_node: ^ElnaTreeRecordTypeExpression; error_list: ^ElnaList; result: ^ElnaTypeRecord) var tree_field: ^ElnaTreeField member_array_current: ^ElnaTypeField field_type: ^ElnaType begin result^.size := 0u; result^.alignment := 0u; result^.length := 0u; result^.members := malloc#[ElnaTypeField](parser_node^.length * #size(ElnaTypeField)); tree_field := parser_node^.members; member_array_current := result^.members; while result^.length < parser_node^.length & tree_field <> nil do member_array_current^.name := tree_field^.name; field_type := elna_name_type_expression(tree_field^.type_expression, error_list); if field_type <> nil then result^.size := result^.size + field_type^.size; if field_type^.alignment > result^.alignment then result^.alignment := field_type^.alignment end; member_array_current^.field_type := field_type; member_array_current := member_array_current + 1u; tree_field := tree_field^.next; result^.length := result^.length + 1u else tree_field := nil end end return proc elna_name_procedure_temporary*(parser_node: ^ElnaTreeVariableDeclaration; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) var info: ^ElnaSymbolTemporaryInfo variable_type: ^ElnaType declaration_error: ^ElnaErrorDuplicateDeclaration begin info := cast(elna_symbol_table_lookup(symbol_table, parser_node^.name): ^ElnaSymbolTemporaryInfo); if info = nil then variable_type := elna_name_type_expression(parser_node^.type_expression, error_list); info := elna_symbol_temporary_info_create(0u, variable_type); elna_symbol_table_enter(symbol_table, parser_node^.name, cast(info: ^ElnaSymbolInfo)) else declaration_error := elna_error_duplicate_declaration_create(parser_node^.position, parser_node^.name); elna_list_append(error_list, cast(declaration_error: ^ElnaListNode)) end return proc elna_name_procedure_temporaries*(parser_node: ^ElnaTreeVariableDeclaration; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) var current: ^ElnaTreeVariableDeclaration begin current := parser_node; while current <> nil do elna_name_procedure_temporary(current, symbol_table, error_list); current := cast(current^.next: ^ElnaTreeVariableDeclaration) end return proc elna_name_type_declaration*(parser_node: ^ElnaTreeTypeDeclaration; error_list: ^ElnaList) var type_info: ^ElnaSymbolTypeInfo type_stub: ^ElnaType type_expression: ^ElnaTreeTypeExpression begin type_info := cast(elna_symbol_table_lookup(symbol_table_global, parser_node^.name): ^ElnaSymbolTypeInfo); if type_info <> nil then type_stub := type_info^._type; type_expression := parser_node^.type_expression; if type_stub^.kind = ElnaTypeKind.alias then elna_name_alias_type_expression(cast(type_expression: ^ElnaTreeNamedTypeExpression), error_list, cast(type_stub: ^ElnaTypeAlias)) elsif type_stub^.kind = ElnaTypeKind.enumeration then elna_name_enumeration_type_expression(cast(type_expression: ^ElnaTreeEnumerationTypeExpression), error_list, cast(type_stub: ^ElnaTypeEnumeration)) elsif type_stub^.kind = ElnaTypeKind._record then elna_name_record_type_expression(cast(type_expression: ^ElnaTreeRecordTypeExpression), error_list, cast(type_stub: ^ElnaTypeRecord)) elsif type_stub^.kind = ElnaTypeKind.pointer then elna_name_pointer_type_expression(cast(type_expression: ^ElnaTreePointerTypeExpression), error_list, cast(type_stub: ^ElnaTypePointer)) elsif type_stub^.kind = ElnaTypeKind.array then elna_name_array_type_expression(cast(type_expression: ^ElnaTreeArrayTypeExpression), error_list, cast(type_stub: ^ElnaTypeArray)) end end return proc elna_name_variable_expression*(parser_node: ^ElnaTreeVariableExpression; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) var symbol_info: ^ElnaSymbolInfo undefined_symbol: ^ElnaErrorUndefinedSymbol begin symbol_info := elna_symbol_table_lookup(symbol_table, parser_node^.name); if symbol_info = nil then undefined_symbol := elna_error_undefined_symbol_create(parser_node^.position, parser_node^.name); elna_list_append(error_list, cast(undefined_symbol: ^ElnaListNode)) end return proc elna_name_cast_expression*(parser_node: ^ElnaTreeCastExpression; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) begin elna_name_binary_expression(parser_node^.expression, symbol_table, error_list); parser_node^.type_decoration := elna_name_type_expression(parser_node^.type_expression, error_list) return proc elna_name_simple_expression*(parser_node: ^ElnaTreeExpression; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) begin if parser_node^.kind = ElnaTreeKind._cast then elna_name_cast_expression(cast(parser_node: ^ElnaTreeCastExpression), symbol_table, error_list) elsif parser_node^.kind = ElnaTreeKind.variable_expression then elna_name_variable_expression(cast(parser_node: ^ElnaTreeVariableExpression), symbol_table, error_list) end return proc elna_name_call*(parser_node: ^ElnaTreeCall; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) var argument_tree: ^ElnaTreeExpressionList begin elna_name_variable_expression(parser_node^.callee, symbol_table, error_list); argument_tree := parser_node^.arguments; while argument_tree <> nil do elna_name_binary_expression(argument_tree^.expression, symbol_table, error_list); argument_tree := argument_tree^.next end return proc elna_name_dereference_expression*(parser_node: ^ElnaTreeDereferenceExpression; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) begin elna_name_designator(parser_node^.pointer, symbol_table, error_list) return proc elna_name_field_access_expression*(parser_node: ^ElnaTreeFieldAccessExpression; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) var variable_expression: ^ElnaTreeVariableExpression identifier_symbol: ^ElnaSymbolInfo type_info: ^ElnaSymbolTypeInfo undefined_member_error: ^ElnaErrorUndefinedMember enumeration_type: ^ElnaTypeEnumeration member_count: Word current_member: ^[]const Word8 found: Bool := false begin if parser_node^.aggregate^.kind = ElnaTreeKind.variable_expression then variable_expression := cast(parser_node^.aggregate: ^ElnaTreeVariableExpression); identifier_symbol := elna_symbol_table_lookup(symbol_table, variable_expression^.name); if identifier_symbol <> nil & identifier_symbol^.kind = ElnaSymbolInfoKind.type_info then type_info := cast(identifier_symbol: ^ElnaSymbolTypeInfo); if type_info^._type^.kind = ElnaTypeKind.enumeration then enumeration_type := cast(type_info^._type: ^ElnaTypeEnumeration); current_member := enumeration_type^.members; member_count := enumeration_type^.length; while member_count > 0u & ~found do if current_member^ = parser_node^.field then found := true end; member_count := member_count - 1u; current_member := current_member + 1u end end; if ~found then undefined_member_error := elna_error_undefined_member_create(variable_expression^.position, variable_expression^.name, parser_node^.field); elna_list_append(error_list, cast(undefined_member_error: ^ElnaListNode)) end else elna_name_designator(cast(variable_expression: ^ElnaTreeExpression), symbol_table, error_list) end else elna_name_designator(parser_node^.aggregate, symbol_table, error_list) end return proc elna_name_array_access_expression*(parser_node: ^ElnaTreeArrayAccessExpression; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) begin elna_name_designator(parser_node^.array, symbol_table, error_list); elna_name_binary_expression(parser_node^.index, symbol_table, error_list) return proc elna_name_designator*(parser_node: ^ElnaTreeExpression; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) begin if parser_node^.kind = ElnaTreeKind.dereference_expression then elna_name_dereference_expression(cast(parser_node: ^ElnaTreeDereferenceExpression), symbol_table, error_list) elsif parser_node^.kind = ElnaTreeKind.field_access_expression then elna_name_field_access_expression(cast(parser_node: ^ElnaTreeFieldAccessExpression), symbol_table, error_list) elsif parser_node^.kind = ElnaTreeKind.array_access_expression then elna_name_array_access_expression(cast(parser_node: ^ElnaTreeArrayAccessExpression), symbol_table, error_list) elsif parser_node^.kind = ElnaTreeKind.call then elna_name_call(cast(parser_node: ^ElnaTreeCall), symbol_table, error_list) else elna_name_simple_expression(parser_node, symbol_table, error_list) end return proc elna_name_unary_expression*(parser_node: ^ElnaTreeExpression; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) var unary_node: ^ElnaTreeUnaryExpression begin if parser_node^.kind = ElnaTreeKind.unary_expression then unary_node := cast(parser_node: ^ElnaTreeUnaryExpression); elna_name_designator(unary_node^.operand, symbol_table, error_list) else elna_name_designator(parser_node, symbol_table, error_list) end return proc elna_name_binary_expression*(parser_node: ^ElnaTreeExpression; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) var bin_node: ^ElnaTreeBinaryExpression begin if parser_node^.kind = ElnaTreeKind.binary_expression then bin_node := cast(parser_node: ^ElnaTreeBinaryExpression); elna_name_unary_expression(bin_node^.lhs, symbol_table, error_list); elna_name_unary_expression(bin_node^.rhs, symbol_table, error_list) else elna_name_unary_expression(parser_node, symbol_table, error_list) end return proc elna_name_conditional_statements*(parser_node: ^ElnaTreeConditionalStatements; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) var current: ^ElnaTreeConditionalStatements begin current := parser_node; while current <> nil do elna_name_binary_expression(current^.condition, symbol_table, error_list); elna_name_statements(current^.statements, symbol_table, error_list); current := current^.next end return proc elna_name_if_statement*(parser_node: ^ElnaTreeIfStatement; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) begin elna_name_conditional_statements(parser_node^.conditionals, symbol_table, error_list); if parser_node^._else <> nil then elna_name_statements(parser_node^._else, symbol_table, error_list) end return proc elna_name_return_statement*(parser_node: ^ElnaTreeReturnStatement; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) begin elna_name_binary_expression(parser_node^.returned, symbol_table, error_list) return proc elna_name_assign_statement*(parser_node: ^ElnaTreeAssignStatement; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) begin elna_name_designator(parser_node^.assignee, symbol_table, error_list); elna_name_binary_expression(parser_node^.assignment, symbol_table, error_list) return proc elna_name_statement*(parser_node: ^ElnaTreeStatement; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) var call_statement: ^ElnaTreeCallStatement begin if parser_node^.kind = ElnaTreeKind.if_statement then elna_name_if_statement(cast(parser_node: ^ElnaTreeIfStatement), symbol_table, error_list) elsif parser_node^.kind = ElnaTreeKind.return_statement then elna_name_return_statement(cast(parser_node: ^ElnaTreeReturnStatement), symbol_table, error_list) elsif parser_node^.kind = ElnaTreeKind.call_statement then call_statement := cast(parser_node: ^ElnaTreeCallStatement); elna_name_call(call_statement^.call, symbol_table, error_list) elsif parser_node^.kind = ElnaTreeKind.assign_statement then elna_name_assign_statement(cast(parser_node: ^ElnaTreeAssignStatement), symbol_table, error_list) end return proc elna_name_statements*(parser_node: ^ElnaTreeStatement; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) var current: ^ElnaTreeStatement begin current := parser_node; while current <> nil do elna_name_statement(current, symbol_table, error_list); current := current^.next end return proc elna_name_procedure_declaration*(parser_node: ^ElnaTreeProcedureDeclaration; error_list: ^ElnaList) var new_symbol_table: ^ElnaSymbolTable symbol_info: ^ElnaSymbolProcedureInfo proc_type: ^ElnaTypeProcedure begin symbol_info := cast(elna_symbol_table_lookup(symbol_table_global, parser_node^.name): ^ElnaSymbolProcedureInfo); proc_type := malloc#[ElnaTypeProcedure](#size(ElnaTypeProcedure)); proc_type^.kind := ElnaTypeKind.procedure; proc_type^.size := 8u; proc_type^.alignment := 8u; if parser_node^.return_type = nil then proc_type^.return_type := nil else proc_type^.return_type := elna_name_type_expression(parser_node^.return_type, error_list) end; symbol_info^.procedure_type := proc_type; if ~symbol_info^.is_extern then new_symbol_table := elna_symbol_table_create(symbol_table_global); symbol_info^.symbol_table := new_symbol_table; elna_name_procedure_temporaries(parser_node^.parameters, new_symbol_table, error_list); elna_name_procedure_temporaries(parser_node^.temporaries, new_symbol_table, error_list); elna_name_statements(parser_node^.body, new_symbol_table, error_list) end return proc elna_name_program_body*(parser_node: ^ElnaTreeStatement) var symbol_info: ^ElnaSymbolProcedureInfo begin symbol_info := elna_symbol_procedure_info_create(false); symbol_info^.symbol_table := elna_symbol_table_create(symbol_table_global); elna_symbol_table_enter(symbol_table_global, "main", cast(symbol_info: ^ElnaSymbolInfo)) return proc elna_declaration_type_declaration*(parser_node: ^ElnaTreeTypeDeclaration; error_list: ^ElnaList) var type_info: ^ElnaSymbolTypeInfo result: ^ElnaType := nil type_expression: ^ElnaTreeTypeExpression declaration_error: ^ElnaErrorDuplicateDeclaration begin type_info := cast(elna_symbol_table_lookup(symbol_table_global, parser_node^.name): ^ElnaSymbolTypeInfo); if type_info = nil then type_expression := parser_node^.type_expression; if type_expression^.kind = ElnaTreeKind.named_type_expression then result := malloc#[ElnaType](#size(ElnaTypeAlias)); result^.kind := ElnaTypeKind.alias elsif type_expression^.kind = ElnaTreeKind.enumeration_type_expression then result := malloc#[ElnaType](#size(ElnaTypeEnumeration)); result^.kind := ElnaTypeKind.enumeration elsif type_expression^.kind = ElnaTreeKind.record_type_expression then result := malloc#[ElnaType](#size(ElnaTypeRecord)); result^.kind := ElnaTypeKind._record elsif type_expression^.kind = ElnaTreeKind.pointer_type_expression then result := malloc#[ElnaType](#size(ElnaTypePointer)); result^.kind := ElnaTypeKind.pointer elsif type_expression^.kind = ElnaTreeKind.array_type_expression then result := malloc#[ElnaType](#size(ElnaTypeArray)); result^.kind := ElnaTypeKind.array end; type_info := elna_symbol_type_info_create(result); elna_symbol_table_enter(symbol_table_global, parser_node^.name, cast(type_info: ^ElnaSymbolInfo)) else declaration_error := elna_error_duplicate_declaration_create(parser_node^.position, parser_node^.name); elna_list_append(error_list, cast(declaration_error: ^ElnaListNode)) end return proc elna_declaration_procedure_declaration*(parser_node: ^ElnaTreeProcedureDeclaration; error_list: ^ElnaList) var symbol_info: ^ElnaSymbolProcedureInfo declaration_error: ^ElnaErrorDuplicateDeclaration begin symbol_info := cast(elna_symbol_table_lookup(symbol_table_global, parser_node^.name): ^ElnaSymbolProcedureInfo); if symbol_info = nil then symbol_info := elna_symbol_procedure_info_create(parser_node^.is_extern); symbol_info^.symbol_table := elna_symbol_table_create(symbol_table_global); elna_symbol_table_enter(symbol_table_global, parser_node^.name, cast(symbol_info: ^ElnaSymbolInfo)) else declaration_error := elna_error_duplicate_declaration_create(parser_node^.position, parser_node^.name); elna_list_append(error_list, cast(declaration_error: ^ElnaListNode)) end return proc elna_declaration_module_declaration*(parser_node: ^ElnaTreeModuleDeclaration; error_list: ^ElnaList) var current_type: ^ElnaTreeDeclaration current_proc: ^ElnaTreeDeclaration begin current_type := parser_node^.types; while current_type <> nil do elna_declaration_type_declaration(cast(current_type: ^ElnaTreeTypeDeclaration), error_list); current_type := current_type^.next end; current_proc := cast(parser_node^.procedures: ^ElnaTreeDeclaration); while current_proc <> nil do elna_declaration_procedure_declaration(cast(current_proc: ^ElnaTreeProcedureDeclaration), error_list); current_proc := current_proc^.next end return proc elna_name_module_declaration*(parser_node: ^ElnaTreeModuleDeclaration; error_list: ^ElnaList) var current_type: ^ElnaTreeDeclaration current_global: ^ElnaTreeVariableDeclaration current_proc: ^ElnaTreeProcedureDeclaration begin current_type := parser_node^.types; while current_type <> nil do elna_name_type_declaration(cast(current_type: ^ElnaTreeTypeDeclaration), error_list); current_type := current_type^.next end; current_global := parser_node^.globals; while current_global <> nil do elna_name_procedure_temporary(current_global, symbol_table_global, error_list); current_global := cast(current_global^.next: ^ElnaTreeVariableDeclaration) end; current_proc := parser_node^.procedures; while current_proc <> nil do elna_name_procedure_declaration(current_proc, error_list); current_proc := cast(current_proc^.next: ^ElnaTreeProcedureDeclaration) end; if parser_node^.body <> nil then elna_name_program_body(parser_node^.body) end return end.