218 lines
4.3 KiB
Odin
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
|
|
}
|
|
|