package main import "core:fmt" import "core:c/libc" NodeKind :: enum { Integer, Float, Character, String, Identifier, // Block, BinaryExpression, UnaryExpression, FieldAccess, IndexAccess, FunctionCall, VariableDeclaration, // Function, Struct, Enum, Union, Use, // If, For, } Node :: struct { kind: NodeKind, range: TextRange, children: [dynamic]^Node, value: TokenValue, value_token_kind: TokenKind, } 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_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_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) } fmt.println("") for child in node.children { node_print(child, indent + 1) } } 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. 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(&path_, '.') append(&path_, 'c') append(&path_, 'a') append(&path_, 't') } 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{} 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]) } } 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}, } if else_ != nil { append(&ret.children, else_) } 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_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, } for field in fields { append(&ret.children, field) } return }