package main import "core:c/libc" import "core:fmt" NodeKind :: enum { Integer, Float, Character, String, Identifier, Pointer, Array, // Block, BinaryExpression, UnaryExpression, FieldAccess, IndexAccess, FunctionCall, VariableDeclaration, Cast, BitwiseCast, Ret, StructInitializer, // ExternFunction, Function, Struct, Enum, Union, Use, // If, For, // Done at type checking, should replace all instances of FieldAccess with these // The value will be the FULL PATH to the field, only for module access StructFieldAccess, EnumFieldAccess, UnionFieldAccess, ModuleFieldAccess, // ModuleField$Field // Example for std.println: std$println } Node :: struct { kind: NodeKind, range: TextRange, children: [dynamic]^Node, value: TokenValue, value_token_kind: TokenKind, return_type: ^Type, } node_create_value :: proc(kind: NodeKind, range: TextRange, value: TokenValue) -> (ret: ^Node) { ret = new(Node) ret^ = { kind = kind, range = range, value = value, } return } node_create_pointer :: proc(range: TextRange, value: ^Node) -> (ret: ^Node) { ret = new(Node) ret^ = { kind = .Pointer, range = range, children = {value}, } return } node_create_array :: proc(range: TextRange, size: u64, value: ^Node) -> (ret: ^Node) { ret = new(Node) ret^ = { kind = .Array, range = range, children = {value}, value = size, } return } node_create_block :: proc(range: TextRange, children: [dynamic]^Node) -> (ret: ^Node) { ret = new(Node) ret^ = { kind = .Block, range = range, children = children, } return } node_create_binary :: proc(kind: TokenKind, range: TextRange, left: ^Node, right: ^Node) -> (ret: ^Node) { ret = new(Node) ret^ = { kind = .BinaryExpression, range = range, children = {left, right}, value_token_kind = kind, } return } node_create_unary :: proc(kind: TokenKind, range: TextRange, operand: ^Node) -> (ret: ^Node) { ret = new(Node) ret^ = { kind = .UnaryExpression, range = range, children = {operand}, value_token_kind = kind, } return } node_create_field_access :: proc(range: TextRange, left: ^Node, right: ^Node) -> (ret: ^Node) { ret = new(Node) ret^ = { kind = .FieldAccess, range = range, children = {left, right}, } return } node_create_index_access :: proc(range: TextRange, left: ^Node, right: ^Node) -> (ret: ^Node) { ret = new(Node) ret^ = { kind = .IndexAccess, range = range, children = {left, right}, } return } node_create_function_call :: proc(range: TextRange, name: ^Node, args: [dynamic]^Node) -> (ret: ^Node) { ret = new(Node) ret^ = { kind = .FunctionCall, range = range, children = {name}, } for arg in args { append(&ret.children, arg) } return } node_create_extern_function :: proc( range: TextRange, name: [dynamic]u8, return_type: ^Node, args: [dynamic]^Node, ) -> ( ret: ^Node, ) { ret = new(Node) ret^ = { kind = .ExternFunction, range = range, children = {return_type}, value = name, } for arg in args { append(&ret.children, arg) } return } node_create_function :: proc( range: TextRange, name: [dynamic]u8, return_type, body: ^Node, args: [dynamic]^Node, ) -> ( ret: ^Node, ) { ret = new(Node) ret^ = { kind = .Function, range = range, children = {return_type, body}, value = name, } for arg in args { append(&ret.children, arg) } return } node_print :: proc(node: ^Node, indent := 0) { for i in 0 ..< indent { fmt.printf(" ") } if node == nil { fmt.println("nil") return } fmt.printf("{}: {} ", node.kind, "TODO") data, ok := node.value.([dynamic]u8) if ok { fmt.printf("\"") for i in 0 ..< len(data) { fmt.printf("%c", data[i]) } fmt.printf("\" ") } else { fmt.printf("{} ", node.value) } if node.value_token_kind != .Invalid { fmt.printf("{} ", node.value_token_kind) } if node.return_type != nil { fmt.printf("-> {} ", node.return_type) } fmt.println("") for child in node.children { node_print(child, indent + 1) } } parse_use_path :: proc(path: [dynamic]u8) -> (ret: [dynamic]u8) { ret = path // Check if the path ends with ".cat", if not, append it. len_path := len(path) if len(path) < 4 || path[len_path - 4] != '.' || path[len_path - 3] != 'c' || path[len_path - 2] != 'a' || path[len_path - 1] != 't' { append(&ret, '.') append(&ret, 'c') append(&ret, 'a') append(&ret, 't') } return } parse_use_path2 :: proc(path: [dynamic]u8) -> (ret: [dynamic]u8) { ret = path new_alias := [dynamic]u8{} for i in 0 ..< len(path) { if path[i] == '.' { break } if path[i] == '/' { clear(&new_alias) continue } if libc.isalnum(i32(path[i])) == 0 { append(&new_alias, '_') } else { append(&new_alias, path[i]) } } return } node_create_use :: proc(range: TextRange, path, alias: [dynamic]u8) -> (ret: ^Node) { path_ := path // Check if the path ends with ".cat", if not, append it. path_ = parse_use_path(path) ret = new(Node) ret^ = { kind = .Use, range = range, value = path_, } if len(alias) != 0 { append(&ret.children, node_create_value(.Identifier, range, alias)) } else { // Get the filename, and trucate the extension, then replace any special characters with _ new_alias := [dynamic]u8{} new_alias = parse_use_path2(path_) if len(new_alias) == 0 { panic("Invalid alias for use statement") } append(&ret.children, node_create_value(.Identifier, range, new_alias)) } return } node_create_if :: proc(range: TextRange, condition, then, else_: ^Node) -> (ret: ^Node) { ret = new(Node) ret^ = { kind = .If, range = range, children = {condition, then}, } else_mut := else_ if else_mut != nil { if else_.kind == .If { else_mut = node_create_block(else_.range, {else_}) } append(&ret.children, else_mut) } return } node_create_for :: proc(range: TextRange, init, condition, step, body: ^Node) -> (ret: ^Node) { ret = new(Node) ret^ = { kind = .For, range = range, children = {init, condition, step, body}, } return } node_create_variable :: proc(range: TextRange, name, type_, value: ^Node, is_const: bool) -> (ret: ^Node) { ret = new(Node) ret^ = { kind = .VariableDeclaration, range = range, children = {name, type_, value}, value = is_const, } return } node_create_cast :: proc(range: TextRange, value, type_: ^Node) -> (ret: ^Node) { ret = new(Node) ret^ = { kind = .Cast, range = range, children = {value, type_}, } return } node_create_bitwise_cast :: proc(range: TextRange, value, type_: ^Node) -> (ret: ^Node) { ret = new(Node) ret^ = { kind = .BitwiseCast, range = range, children = {value, type_}, } return } node_create_ret :: proc(range: TextRange, value: ^Node) -> (ret: ^Node) { ret = new(Node) ret^ = { kind = .Ret, range = range, children = {value}, } return } node_create_struct_initializer :: proc(range: TextRange, name: [dynamic]u8, fields: [dynamic]^Node) -> (ret: ^Node) { ret = new(Node) if ret == nil { panic("Failed to allocate node") } ret^ = { kind = .StructInitializer, range = range, children = {}, value = name, } for field in fields { append(&ret.children, field) } return } node_create_struct_enum_or_union :: proc( range: TextRange, kind: NodeKind, name: [dynamic]u8, fields: [dynamic]^Node, ) -> ( ret: ^Node, ) { ret = new(Node) ret^ = { kind = kind, range = range, value = name, } append(&ret.children, node_create_value(.Identifier, range, name)) for field in fields { append(&ret.children, field) } return }