package hir import "../source" import "../symbol" import "../target" import "../types" import "core:mem" Expr_Id :: distinct u32 Stmt_Id :: distinct u32 Local_Id :: distinct u32 Function_Id :: distinct u32 Global_Id :: distinct u32 Ref :: distinct u32 INVALID_EXPR :: Expr_Id(0xffff_ffff) INVALID_STMT :: Stmt_Id(0xffff_ffff) INVALID_LOCAL :: Local_Id(0xffff_ffff) INVALID_FUNCTION :: Function_Id(0xffff_ffff) INVALID_GLOBAL :: Global_Id(0xffff_ffff) INVALID_REF :: Ref(0xffff_ffff) expr_id :: proc(index: int) -> Expr_Id { assert(index >= 0 && u64(index) < u64(INVALID_EXPR)) return Expr_Id(index) } stmt_id :: proc(index: int) -> Stmt_Id { assert(index >= 0 && u64(index) < u64(INVALID_STMT)) return Stmt_Id(index) } local_id :: proc(index: int) -> Local_Id { assert(index >= 0 && u64(index) < u64(INVALID_LOCAL)) return Local_Id(index) } function_id :: proc(index: int) -> Function_Id { assert(index >= 0 && u64(index) < u64(INVALID_FUNCTION)) return Function_Id(index) } global_id :: proc(index: int) -> Global_Id { assert(index >= 0 && u64(index) < u64(INVALID_GLOBAL)) return Global_Id(index) } index :: proc(id: $T, invalid: T, count: int) -> (int, bool) { value := int(id) return value, id != invalid && value < count } local_ref :: proc(id: Local_Id) -> Ref {return Ref(id)} function_ref :: proc(id: Function_Id) -> Ref {return Ref(id)} global_ref :: proc(id: Global_Id) -> Ref {return Ref(id)} as_local :: proc(ref: Ref) -> Local_Id {return Local_Id(ref)} as_function :: proc(ref: Ref) -> Function_Id {return Function_Id(ref)} as_global :: proc(ref: Ref) -> Global_Id {return Global_Id(ref)} Calling_Convention :: enum u8 { Brolang, C, } Implementation :: enum u8 { Definition, Declaration, } Linkage :: enum u8 { Internal, External, } Expr_Kind :: enum u8 { Invalid, Integer, Float, String, Bool, Array, Struct, None, Optional_Some, Local, Global, Function, Address, Deref, Index, Slice, Field, Length, Slice_Ptr, Unwrap, Orelse, Widen, C_Vararg_Promote, Weaken_Pointer, Weaken_Slice, Decay_Array_Pointer, Negate, Not, Add, Pointer_Add, Eq, Ne, Lt, Le, Gt, Ge, And, Or, Range, Call, } Expr :: struct { span: source.Span, type: types.Type, integer: i64, args: []Expr_Id, target: Ref, left: Expr_Id, right: Expr_Id, diagnostic: source.Diagnostic_Id, kind: Expr_Kind, } Local :: struct { name: symbol.Id, type: types.Type, mutable: bool, parameter: bool, } Stmt_Kind :: enum u8 { Declaration, Assignment, Return, Expression, Sink, Trap, If, While, For, } Stmt :: struct { kind: Stmt_Kind, span: source.Span, local: Local_Id, index_local: Local_Id, target: Expr_Id, expr: Expr_Id, iterator_type: types.Type, pointer_capture: bool, // `If` statements use `expr` as the condition and `then_body`/`else_body` as // the branch statement lists. // `While` statements use `expr` as the condition, `then_body` as the loop // body, and `update` as the optional post-iteration statement. // `For` statements use `expr` as the iterable, `local` as the item capture, // `index_local` as the optional sequence index, and `iterator_type` as the // normalized many-item pointer type for sequence iteration. then_body: []Stmt_Id, else_body: []Stmt_Id, update: Stmt_Id, diagnostic: source.Diagnostic_Id, } Function :: struct { name: symbol.Id, link_name: string, calling_convention: Calling_Convention, implementation: Implementation, linkage: Linkage, is_main: bool, variadic: bool, params: []Local_Id, result: types.Type, locals: []Local, body: []Stmt_Id, direct_global_reads: [dynamic]Global_Id, calls: []Function_Id, problematic: bool, diagnostic: source.Diagnostic_Id, } Global :: struct { name: symbol.Id, link_name: string, type: types.Type, expr: Expr_Id, static_value: i64, is_static: bool, external: bool, writable: bool, dependencies: [dynamic]Global_Id, calls: []Function_Id, direct_problem: bool, problematic: bool, diagnostic: source.Diagnostic_Id, } Module :: struct { exprs: [dynamic]Expr, statements: [dynamic]Stmt, functions: [dynamic]Function, globals: [dynamic]Global, strings: [dynamic]string, types: types.Store, target: target.Target, allocator: mem.Allocator, } init_module :: proc(selected := target.DEFAULT, allocator := context.allocator) -> Module { module: Module module.target = selected module.types = types.init_store(allocator) module.types.selected = selected module.allocator = allocator module.exprs.allocator = allocator module.statements.allocator = allocator module.functions.allocator = allocator module.globals.allocator = allocator module.strings.allocator = allocator return module } destroy_module :: proc(module: ^Module) { for expr in module.exprs { delete(expr.args, module.allocator) } for statement in module.statements { delete(statement.then_body, module.allocator) delete(statement.else_body, module.allocator) } for function in module.functions { delete(function.link_name, module.allocator) delete(function.params, module.allocator) delete(function.locals, module.allocator) delete(function.body, module.allocator) delete(function.direct_global_reads) delete(function.calls, module.allocator) } for global in module.globals { delete(global.link_name, module.allocator) delete(global.dependencies) delete(global.calls, module.allocator) } for value in module.strings { delete(value, module.allocator) } delete(module.exprs) delete(module.statements) delete(module.functions) delete(module.globals) delete(module.strings) types.destroy_store(&module.types) }