(* 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, lexer, ast, symbol, diagnostic proc elna_type_is_aggregate*(_type: ^ElnaType) -> Bool var result: Bool := false begin if _type <> nil then result := _type^.kind = ElnaTypeKind._record or _type^.kind = ElnaTypeKind.array end return result proc elna_type_character_literal(parser_node: ^ElnaTreeCharacterLiteral) begin parser_node^.type_decoration := char_type return proc elna_type_integer_literal(parser_node: ^ElnaTreeIntegerLiteral) begin parser_node^.type_decoration := word_type return proc elna_type_string_literal(parser_node: ^ElnaTreeStringLiteral) begin parser_node^.type_decoration := cast(string_type: ^ElnaType) return proc elna_type_boolean_literal(parser_node: ^ElnaTreeBooleanLiteral) begin parser_node^.type_decoration := bool_type return proc elna_type_nil_literal(parser_node: ^ElnaTreeNilLiteral) begin parser_node^.type_decoration := pointer_type return proc elna_type_variable_expression(parser_node: ^ElnaTreeVariableExpression; symbol_table: ^ElnaSymbolTable) var variable_info: ^ElnaSymbolInfo temporary_info: ^ElnaSymbolTemporaryInfo procedure_info: ^ElnaSymbolProcedureInfo begin variable_info := elna_symbol_table_lookup(symbol_table, parser_node^.name); if variable_info <> nil then if variable_info^.kind = ElnaSymbolInfoKind.temporary_info then temporary_info := cast(variable_info: ^ElnaSymbolTemporaryInfo); parser_node^.type_decoration := temporary_info^.variable_type elsif variable_info^.kind = ElnaSymbolInfoKind.procedure_info then procedure_info := cast(variable_info: ^ElnaSymbolProcedureInfo); parser_node^.type_decoration := cast(procedure_info^.procedure_type: ^ElnaType) end end return proc elna_type_cast_expression(parser_node: ^ElnaTreeCastExpression; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) begin elna_type_binary_expression(parser_node^.expression, symbol_table, error_list) return proc elna_type_call(parser_node: ^ElnaTreeCall; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) var argument_tree: ^ElnaTreeExpressionList procedure_type: ^ElnaTypeProcedure begin argument_tree := parser_node^.arguments; elna_type_variable_expression(parser_node^.callee, symbol_table); if parser_node^.callee^.type_decoration <> nil & parser_node^.callee^.type_decoration^.kind = ElnaTypeKind.procedure then procedure_type := cast(parser_node^.callee^.type_decoration: ^ElnaTypeProcedure); parser_node^.type_decoration := procedure_type^.return_type end; while argument_tree <> nil do elna_type_binary_expression(argument_tree^.expression, symbol_table, error_list); argument_tree := argument_tree^.next end return proc elna_type_dereference_expression(parser_node: ^ElnaTreeDereferenceExpression; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) var base_type: ^ElnaType := nil pointer_type_node: ^ElnaTypePointer begin elna_type_designator(parser_node^.pointer, symbol_table, error_list); if parser_node^.pointer^.type_decoration <> nil then base_type := parser_node^.pointer^.type_decoration; if base_type^.kind = ElnaTypeKind.pointer then pointer_type_node := cast(base_type: ^ElnaTypePointer); base_type := pointer_type_node^.base end end; parser_node^.type_decoration := base_type return proc elna_type_field_access_expression(parser_node: ^ElnaTreeFieldAccessExpression; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) var variable_expression: ^ElnaTreeVariableExpression base_type: ^ElnaType := nil type_kind: ^ElnaSymbolTypeInfo symbol_info: ^ElnaSymbolInfo aggregate_type: ^ElnaTypeRecord field_count: Word current_field: ^ElnaTypeField begin if parser_node^.aggregate^.kind = ElnaTreeKind.variable_expression then variable_expression := cast(parser_node^.aggregate: ^ElnaTreeVariableExpression); symbol_info := elna_symbol_table_lookup(symbol_table_global, variable_expression^.name); if symbol_info <> nil & symbol_info^.kind = ElnaSymbolInfoKind.type_info then type_kind := cast(symbol_info: ^ElnaSymbolTypeInfo); base_type := type_kind^._type end end; if base_type = nil then elna_type_designator(parser_node^.aggregate, symbol_table, error_list); if parser_node^.aggregate^.type_decoration <> nil & parser_node^.aggregate^.type_decoration^.kind = ElnaTypeKind._record then aggregate_type := cast(parser_node^.aggregate^.type_decoration: ^ElnaTypeRecord); field_count := aggregate_type^.length; current_field := aggregate_type^.members; while field_count > 0u & base_type = nil do if current_field^.name = parser_node^.field then base_type := current_field^.field_type else field_count := field_count - 1u; current_field := current_field + 1u end end end end; parser_node^.type_decoration := base_type return proc elna_type_array_access_expression(parser_node: ^ElnaTreeArrayAccessExpression; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) var aggregate_type: ^ElnaTypeArray begin elna_type_designator(parser_node^.array, symbol_table, error_list); elna_type_binary_expression(parser_node^.index, symbol_table, error_list); if parser_node^.array^.type_decoration <> nil & parser_node^.array^.type_decoration^.kind = ElnaTypeKind.array then aggregate_type := cast(parser_node^.array^.type_decoration: ^ElnaTypeArray); parser_node^.type_decoration := aggregate_type^.base end return proc elna_type_simple_expression(parser_node: ^ElnaTreeExpression; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) begin case parser_node^.kind of ElnaTreeKind.integer_literal: elna_type_integer_literal(cast(parser_node: ^ElnaTreeIntegerLiteral)) | ElnaTreeKind.character_literal: elna_type_character_literal(cast(parser_node: ^ElnaTreeCharacterLiteral)) | ElnaTreeKind.string_literal: elna_type_string_literal(cast(parser_node: ^ElnaTreeStringLiteral)) | ElnaTreeKind.boolean_literal: elna_type_boolean_literal(cast(parser_node: ^ElnaTreeBooleanLiteral)) | ElnaTreeKind.null: elna_type_nil_literal(cast(parser_node: ^ElnaTreeNilLiteral)) | ElnaTreeKind._cast: elna_type_cast_expression(cast(parser_node: ^ElnaTreeCastExpression), symbol_table, error_list) | ElnaTreeKind.variable_expression: elna_type_variable_expression(cast(parser_node: ^ElnaTreeVariableExpression), symbol_table) else end return proc elna_type_designator(parser_node: ^ElnaTreeExpression; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) begin case parser_node^.kind of ElnaTreeKind.dereference_expression: elna_type_dereference_expression(cast(parser_node: ^ElnaTreeDereferenceExpression), symbol_table, error_list) | ElnaTreeKind.field_access_expression: elna_type_field_access_expression(cast(parser_node: ^ElnaTreeFieldAccessExpression), symbol_table, error_list) | ElnaTreeKind.array_access_expression: elna_type_array_access_expression(cast(parser_node: ^ElnaTreeArrayAccessExpression), symbol_table, error_list) | ElnaTreeKind.call: elna_type_call(cast(parser_node: ^ElnaTreeCall), symbol_table, error_list) else elna_type_simple_expression(parser_node, symbol_table, error_list) end return proc elna_type_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_type_designator(unary_node^.operand, symbol_table, error_list); parser_node^.type_decoration := unary_node^.operand^.type_decoration else elna_type_designator(parser_node, symbol_table, error_list) end return proc elna_type_binary_expression(parser_node: ^ElnaTreeExpression; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) var binary_node: ^ElnaTreeBinaryExpression begin if parser_node <> nil then if parser_node^.kind = ElnaTreeKind.binary_expression then binary_node := cast(parser_node: ^ElnaTreeBinaryExpression); elna_type_unary_expression(binary_node^.rhs, symbol_table, error_list); elna_type_unary_expression(binary_node^.lhs, symbol_table, error_list); parser_node^.type_decoration := binary_node^.lhs^.type_decoration else elna_type_unary_expression(parser_node, symbol_table, error_list) end end return proc elna_type_assign_statement(parser_node: ^ElnaTreeAssignStatement; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) begin elna_type_designator(parser_node^.assignee, symbol_table, error_list); elna_type_binary_expression(parser_node^.assignment, symbol_table, error_list) return proc elna_type_conditional_statements(parser_node: ^ElnaTreeConditionalStatements; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) var current: ^ElnaTreeConditionalStatements begin current := parser_node; while current <> nil do elna_type_binary_expression(current^.condition, symbol_table, error_list); elna_type_statements(current^.statements, symbol_table, error_list); current := current^.next end return proc elna_type_if_statement(parser_node: ^ElnaTreeIfStatement; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) begin elna_type_conditional_statements(parser_node^.conditionals, symbol_table, error_list); if parser_node^._else <> nil then elna_type_statements(parser_node^._else, symbol_table, error_list) end return proc elna_type_return_statement(parser_node: ^ElnaTreeReturnStatement; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) begin if parser_node^.returned <> nil then elna_type_binary_expression(parser_node^.returned, symbol_table, error_list) end return proc elna_type_statement(parser_node: ^ElnaTreeStatement; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) var call_statement: ^ElnaTreeCallStatement begin case parser_node^.kind of ElnaTreeKind.if_statement: elna_type_if_statement(cast(parser_node: ^ElnaTreeIfStatement), symbol_table, error_list) | ElnaTreeKind.return_statement: elna_type_return_statement(cast(parser_node: ^ElnaTreeReturnStatement), symbol_table, error_list) | ElnaTreeKind.call_statement: call_statement := cast(parser_node: ^ElnaTreeCallStatement); elna_type_call(call_statement^.call, symbol_table, error_list) | ElnaTreeKind.assign_statement: elna_type_assign_statement(cast(parser_node: ^ElnaTreeAssignStatement), symbol_table, error_list) else end return proc elna_type_statements(parser_node: ^ElnaTreeStatement; symbol_table: ^ElnaSymbolTable; error_list: ^ElnaList) var current: ^ElnaTreeStatement begin current := parser_node; while current <> nil do elna_type_statement(current, symbol_table, error_list); current := current^.next end return proc elna_type_procedure_declaration(parser_node: ^ElnaTreeProcedureDeclaration; error_list: ^ElnaList) var procedure_info: ^ElnaSymbolProcedureInfo symbol_info: ^ElnaSymbolInfo begin symbol_info := elna_symbol_table_lookup(symbol_table_global, parser_node^.name); if symbol_info <> nil & symbol_info^.kind = ElnaSymbolInfoKind.procedure_info then procedure_info := cast(symbol_info: ^ElnaSymbolProcedureInfo); elna_type_statements(parser_node^.body, procedure_info^.symbol_table, error_list) end return proc elna_type_module_declaration*(parser_node: ^ElnaTreeModuleDeclaration; error_list: ^ElnaList) var current_proc: ^ElnaTreeProcedureDeclaration begin current_proc := parser_node^.procedures; while current_proc <> nil do elna_type_procedure_declaration(current_proc, error_list); current_proc := cast(current_proc^.next: ^ElnaTreeProcedureDeclaration) end; if parser_node^.body <> nil then elna_type_statements(parser_node^.body, symbol_table_global, error_list) end return end.