(* 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 cstdlib, common, ast type ElnaSymbolInfoKind* = (type_info, temporary_info, procedure_info) ElnaSymbolInfo* = record kind: ElnaSymbolInfoKind end ElnaSymbolTypeInfo* = record(ElnaSymbolInfo) _type: ^ElnaType end ElnaSymbolTemporaryInfo* = record(ElnaSymbolInfo) attr: Word; variable_type: ^ElnaType end ElnaSymbolProcedureInfo* = record(ElnaSymbolInfo) symbol_table: ^ElnaSymbolTable; procedure_type: ^ElnaTypeProcedure; is_extern: Bool end ElnaSymbolEntry* = record name: []const Word8; symbol_info: ^ElnaSymbolInfo end ElnaSymbolTable* = record count: Word; capacity: Word; parent: ^ElnaSymbolTable; symbols: ^ElnaSymbolEntry end var symbol_table_global*: ^ElnaSymbolTable word_type*: ^ElnaType int_type*: ^ElnaType pointer_type*: ^ElnaType bool_type*: ^ElnaType char_type*: ^ElnaType string_type*: ^ElnaTypeRecord proc elna_symbol_type_info_create*(type_representation: ^ElnaType) -> ^ElnaSymbolTypeInfo var result: ^ElnaSymbolTypeInfo begin result := malloc#[ElnaSymbolTypeInfo](#size(ElnaSymbolTypeInfo)); result^.kind := ElnaSymbolInfoKind.type_info; result^._type := type_representation return result proc elna_symbol_temporary_info_create*(attr: Word; temporary_type: ^ElnaType) -> ^ElnaSymbolTemporaryInfo var result: ^ElnaSymbolTemporaryInfo begin result := malloc#[ElnaSymbolTemporaryInfo](#size(ElnaSymbolTemporaryInfo)); result^.kind := ElnaSymbolInfoKind.temporary_info; result^.variable_type := temporary_type; result^.attr := attr return result proc elna_symbol_procedure_info_create*(is_extern: Bool) -> ^ElnaSymbolProcedureInfo var result: ^ElnaSymbolProcedureInfo begin result := malloc#[ElnaSymbolProcedureInfo](#size(ElnaSymbolProcedureInfo)); result^.kind := ElnaSymbolInfoKind.procedure_info; result^.procedure_type := nil; result^.symbol_table := nil; result^.is_extern := is_extern return result proc elna_symbol_table_create*(parent: ^ElnaSymbolTable) -> ^ElnaSymbolTable var new_symbol_table: ^ElnaSymbolTable begin new_symbol_table := malloc#[ElnaSymbolTable](#size(ElnaSymbolTable)); new_symbol_table^.capacity := 64u; new_symbol_table^.symbols := malloc#[ElnaSymbolEntry](new_symbol_table^.capacity * #size(ElnaSymbolEntry)); new_symbol_table^.count := 0u; new_symbol_table^.parent := parent return new_symbol_table proc elna_symbol_table_enter*(symbol_table: ^ElnaSymbolTable; symbol_name: []const Word8; symbol: ^ElnaSymbolInfo) var entry: ^ElnaSymbolEntry begin if symbol_table^.count >= symbol_table^.capacity then symbol_table^.capacity := symbol_table^.capacity * 2u; symbol_table^.symbols := realloc#[ElnaSymbolEntry](symbol_table^.symbols, symbol_table^.capacity * #size(ElnaSymbolEntry)) end; entry := symbol_table^.symbols + symbol_table^.count; entry^.name := symbol_name; entry^.symbol_info := symbol; symbol_table^.count := symbol_table^.count + 1u return proc elna_symbol_table_lookup_local*(symbol_table: ^ElnaSymbolTable; symbol_name: []const Word8) -> ^ElnaSymbolInfo var i: Word := 0u entry: ^ElnaSymbolEntry result: ^ElnaSymbolInfo := nil begin while i < symbol_table^.count & result = nil do entry := symbol_table^.symbols + i; if entry^.name = symbol_name then result := entry^.symbol_info end; i := i + 1u end return result proc elna_symbol_table_lookup*(symbol_table: ^ElnaSymbolTable; symbol_name: []const Word8) -> ^ElnaSymbolInfo var current: ^ElnaSymbolTable found: ^ElnaSymbolInfo := nil begin current := symbol_table; while current <> nil & found = nil do found := elna_symbol_table_lookup_local(current, symbol_name); current := current^.parent end return found proc elna_symbol_string_build() var current_field: ^ElnaTypeField char_pointer: ^ElnaTypePointer begin string_type := malloc#[ElnaTypeRecord](#size(ElnaTypeRecord)); string_type^.kind := ElnaTypeKind._record; string_type^.size := 16u; string_type^.alignment := 8u; string_type^.members := malloc#[ElnaTypeField](2u * #size(ElnaTypeField)); string_type^.length := 2u; char_pointer := malloc#[ElnaTypePointer](#size(ElnaTypePointer)); char_pointer^.kind := ElnaTypeKind.pointer; char_pointer^.size := 8u; char_pointer^.alignment := 8u; char_pointer^.base := char_type; current_field := string_type^.members; current_field^.name := "ptr"; current_field^.field_type := cast(char_pointer: ^ElnaType); current_field := current_field + 1u; current_field^.name := "length"; current_field^.field_type := word_type return proc elna_symbol_table_build*() var current_info: ^ElnaSymbolTypeInfo begin symbol_table_global := elna_symbol_table_create(nil); word_type := malloc#[ElnaType](#size(ElnaType)); word_type^.kind := ElnaTypeKind.primitive; word_type^.size := 8u; word_type^.alignment := 8u; current_info := elna_symbol_type_info_create(word_type); elna_symbol_table_enter(symbol_table_global, "Word", cast(current_info: ^ElnaSymbolInfo)); int_type := malloc#[ElnaType](#size(ElnaType)); int_type^.kind := ElnaTypeKind.primitive; int_type^.size := 8u; int_type^.alignment := 8u; current_info := elna_symbol_type_info_create(int_type); elna_symbol_table_enter(symbol_table_global, "Int", cast(current_info: ^ElnaSymbolInfo)); pointer_type := malloc#[ElnaType](#size(ElnaType)); pointer_type^.kind := ElnaTypeKind.primitive; pointer_type^.size := 8u; pointer_type^.alignment := 8u; current_info := elna_symbol_type_info_create(pointer_type); elna_symbol_table_enter(symbol_table_global, "Pointer", cast(current_info: ^ElnaSymbolInfo)); bool_type := malloc#[ElnaType](#size(ElnaType)); bool_type^.kind := ElnaTypeKind.primitive; bool_type^.size := 1u; bool_type^.alignment := 1u; current_info := elna_symbol_type_info_create(bool_type); elna_symbol_table_enter(symbol_table_global, "Bool", cast(current_info: ^ElnaSymbolInfo)); char_type := malloc#[ElnaType](#size(ElnaType)); char_type^.kind := ElnaTypeKind.primitive; char_type^.size := 1u; char_type^.alignment := 1u; current_info := elna_symbol_type_info_create(char_type); elna_symbol_table_enter(symbol_table_global, "Char", cast(current_info: ^ElnaSymbolInfo)); elna_symbol_string_build(); current_info := elna_symbol_type_info_create(cast(string_type: ^ElnaType)); elna_symbol_table_enter(symbol_table_global, "String", cast(current_info: ^ElnaSymbolInfo)) return end.