Add declaration parsing
This commit is contained in:
parent
8c8a395193
commit
90a495ba1b
20
ast.odin
20
ast.odin
@ -25,6 +25,7 @@ NodeKind :: enum {
|
||||
Use,
|
||||
|
||||
If,
|
||||
VariableDeclaration,
|
||||
}
|
||||
|
||||
Node :: struct {
|
||||
@ -116,6 +117,7 @@ node_print :: proc(node: ^Node, indent := 0) {
|
||||
}
|
||||
if node == nil {
|
||||
fmt.println("nil")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.printf("{}: {} ", node.kind, "TODO")
|
||||
@ -195,3 +197,21 @@ node_create_if :: proc(range: TextRange, condition, then, else_: ^Node) -> (ret:
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -181,6 +181,7 @@ lexer_next :: proc(lexer: ^Lexer) -> (ret: Token) {
|
||||
case '?': ret = token_create(.Question, crange)
|
||||
case ':': ret = token_create(.Colon, crange)
|
||||
case '.': ret = token_create(.Dot, crange)
|
||||
case ',': ret = token_create(.Comma, crange)
|
||||
case ';': ret = token_create(.Semicolon, crange)
|
||||
|
||||
case '"': ret = lexer_read_string(lexer, .String, '\"')
|
||||
@ -276,6 +277,7 @@ lexer_read_identifier :: proc(lexer: ^Lexer) -> Token {
|
||||
else if compare_dyn_arr_string(&str, "ret") { return token_create(.Ret, crange) }
|
||||
else if compare_dyn_arr_string(&str, "static") { return token_create(.Static, crange) }
|
||||
else if compare_dyn_arr_string(&str, "defer") { return token_create(.Defer, crange) }
|
||||
else if compare_dyn_arr_string(&str, "let") { return token_create(.Let, crange) }
|
||||
else if compare_dyn_arr_string(&str, "and") { return token_create(.And, crange) }
|
||||
else if compare_dyn_arr_string(&str, "or") { return token_create(.Or, crange) }
|
||||
|
||||
|
90
parser.odin
90
parser.odin
@ -53,9 +53,17 @@ parser_parse_block :: proc(parser: ^Parser, end: TokenKind) -> (ret: ^Node) {
|
||||
range := parser.tok.range
|
||||
statements : [dynamic]^Node
|
||||
for parser.tok.kind != end && parser.tok.kind != .EOF {
|
||||
stmt := parser_parse_statement(parser)
|
||||
if stmt != nil {
|
||||
append(&statements, stmt)
|
||||
if accept(parser, .Let) {
|
||||
ret := parser_parse_definitions(parser)
|
||||
expect(parser, .Semicolon)
|
||||
for stmt in ret {
|
||||
append(&statements, stmt)
|
||||
}
|
||||
} else {
|
||||
stmt := parser_parse_statement(parser)
|
||||
if stmt != nil {
|
||||
append(&statements, stmt)
|
||||
}
|
||||
}
|
||||
}
|
||||
expect(parser, end)
|
||||
@ -80,6 +88,76 @@ parser_parse_statement :: proc(parser: ^Parser) -> (ret: ^Node) {
|
||||
return
|
||||
}
|
||||
|
||||
@(private = "file")
|
||||
parser_parse_type :: proc(parser: ^Parser) -> (ret: ^Node) {
|
||||
// FIXME: Add more types
|
||||
range := parser.tok.range
|
||||
if parser.tok.kind == .Identifier {
|
||||
ret = node_create_value(.Identifier, range, parser.tok.value.([dynamic]u8))
|
||||
parser_next(parser)
|
||||
} else {
|
||||
append(&g_message_list, message_create(
|
||||
.Error,
|
||||
fmt.aprintf("Expected type, got {} at {}", parser.tok.kind, "TODO"),
|
||||
parser.tok.range))
|
||||
ret = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@(private = "file")
|
||||
parser_parse_definitions :: proc(parser: ^Parser, end := TokenKind.Semicolon) -> [dynamic]^Node {
|
||||
range := parser.tok.range
|
||||
vars : [dynamic]^Node
|
||||
type : ^Node = nil
|
||||
are_constants := false
|
||||
uninitialized := false
|
||||
for parser.tok.kind != end && parser.tok.kind != .EOF {
|
||||
names := [dynamic][dynamic]u8{}
|
||||
for parser.tok.kind == .Identifier {
|
||||
tok := parser.tok
|
||||
if !expect(parser, .Identifier) {
|
||||
break
|
||||
}
|
||||
|
||||
append(&names, tok.value.([dynamic]u8))
|
||||
}
|
||||
|
||||
expect(parser, .Colon)
|
||||
|
||||
if parser.tok.kind != .Colon && parser.tok.kind != .Assign {
|
||||
type = parser_parse_type(parser)
|
||||
}
|
||||
|
||||
if accept(parser, .Assign) {
|
||||
are_constants = false
|
||||
} else if accept(parser, .Colon) {
|
||||
are_constants = true
|
||||
} else {
|
||||
uninitialized = true
|
||||
}
|
||||
|
||||
for i in 0..<len(names) {
|
||||
value : ^Node = nil
|
||||
if uninitialized == false {
|
||||
value = parser_parse_expression(parser)
|
||||
}
|
||||
fmt.printf("value: {}\n", value)
|
||||
name_node := node_create_value(.Identifier, range, names[i])
|
||||
append(&vars, node_create_variable(range, name_node, type, value, are_constants))
|
||||
}
|
||||
|
||||
if !accept(parser, .Comma) {
|
||||
break
|
||||
}
|
||||
|
||||
type = nil
|
||||
are_constants = false
|
||||
uninitialized = false
|
||||
}
|
||||
return vars
|
||||
}
|
||||
|
||||
@(private = "file")
|
||||
parser_parse_use_statement :: proc(parser: ^Parser) -> ^Node {
|
||||
range := parser.tok.range
|
||||
@ -144,9 +222,9 @@ parser_parse_arrow :: proc(parser: ^Parser) -> ^Node {
|
||||
for accept(parser, .Arrow) {
|
||||
rhs := parser_parse_assignment(parser)
|
||||
if rhs.kind != .FunctionCall &&
|
||||
rhs.kind != .Identifier &&
|
||||
rhs.kind != .FieldAccess &&
|
||||
rhs.kind != .IndexAccess {
|
||||
rhs.kind != .Identifier &&
|
||||
rhs.kind != .FieldAccess &&
|
||||
rhs.kind != .IndexAccess {
|
||||
append(&g_message_list, message_create(
|
||||
.Error,
|
||||
fmt.aprintf("Expected function call, got {} at {}", rhs.kind, "TODO"),
|
||||
|
5
test.cat
5
test.cat
@ -4,6 +4,11 @@ use lib "directory/long_library_name"
|
||||
fmt.printf "%d + %d = %d File length: %d" a b a + b (io.file_size "file.txt")
|
||||
fmt.println "Hello world!"
|
||||
|
||||
let a := 123
|
||||
let uninitialized : u32
|
||||
let multiple variables here : u32 = 1 2 3
|
||||
let string : str, number : i32
|
||||
|
||||
if a == 1 {
|
||||
lol
|
||||
} elif b == 2 {
|
||||
|
@ -19,7 +19,6 @@ TokenKind :: enum {
|
||||
Type,
|
||||
Use,
|
||||
Pub,
|
||||
Let,
|
||||
Mut,
|
||||
As,
|
||||
In,
|
||||
@ -34,6 +33,7 @@ TokenKind :: enum {
|
||||
Ret,
|
||||
Static,
|
||||
Defer,
|
||||
Let,
|
||||
|
||||
// Logical Operators Keywords
|
||||
And,
|
||||
@ -80,6 +80,7 @@ TokenKind :: enum {
|
||||
Colon,
|
||||
Arrow,
|
||||
Dot,
|
||||
Comma,
|
||||
|
||||
// Other
|
||||
Semicolon,
|
||||
@ -96,6 +97,7 @@ TextRange :: struct {
|
||||
}
|
||||
|
||||
TokenValue :: union {
|
||||
bool,
|
||||
u64,
|
||||
f64,
|
||||
[dynamic]u8,
|
||||
@ -140,3 +142,5 @@ token_create_f64 :: proc(kind: TokenKind, value: f64, range: TextRange) -> Token
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user