speedcat/ast.odin
2024-02-09 01:40:52 +02:00

218 lines
4.3 KiB
Odin

package main
import "core:fmt"
import "core:c/libc"
NodeKind :: enum {
Integer,
Float,
Character,
String,
Identifier,
Block,
BinaryExpression,
UnaryExpression,
FieldAccess,
IndexAccess,
FunctionCall,
Function,
Struct,
Enum,
Union,
Use,
If,
VariableDeclaration,
}
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_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_variable :: proc(range: TextRange, name, type_, value: ^Node, is_const: bool) -> (ret: ^Node) {
fmt.printf("Creating variable declaration for {} with value {}\n", name.value.([dynamic]u8), value)
ret = new(Node)
ret^ = {
kind = .VariableDeclaration,
range = range,
children = { name, type_, value },
value = is_const,
}
//if value != nil {
// fmt.printf("Appending value to variable declaration\n")
// append(&ret.children, value)
//}
return
}