mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-20 08:26:47 +00:00
Merge branch 'master' into prototype-fmt
This commit is contained in:
@@ -39,7 +39,7 @@ collect_package :: proc(path: string) -> (pkg: ^ast.Package, success: bool) {
|
||||
}
|
||||
file := ast.new(ast.File, NO_POS, NO_POS);
|
||||
file.pkg = pkg;
|
||||
file.src = src;
|
||||
file.src = string(src);
|
||||
file.fullpath = fullpath;
|
||||
pkg.files[fullpath] = file;
|
||||
}
|
||||
|
||||
@@ -8,10 +8,21 @@ import "core:fmt"
|
||||
Warning_Handler :: #type proc(pos: tokenizer.Pos, fmt: string, args: ..any);
|
||||
Error_Handler :: #type proc(pos: tokenizer.Pos, fmt: string, args: ..any);
|
||||
|
||||
Flag :: enum u32 {
|
||||
Optional_Semicolons,
|
||||
}
|
||||
|
||||
Flags :: distinct bit_set[Flag; u32];
|
||||
|
||||
|
||||
Parser :: struct {
|
||||
file: ^ast.File,
|
||||
tok: tokenizer.Tokenizer,
|
||||
|
||||
// If .Optional_Semicolons is true, semicolons are completely as statement terminators
|
||||
// different to .Insert_Semicolon in tok.flags
|
||||
flags: Flags,
|
||||
|
||||
warn: Warning_Handler,
|
||||
err: Error_Handler,
|
||||
|
||||
@@ -100,8 +111,9 @@ end_pos :: proc(tok: tokenizer.Token) -> tokenizer.Pos {
|
||||
return pos;
|
||||
}
|
||||
|
||||
default_parser :: proc() -> Parser {
|
||||
default_parser :: proc(flags := Flags{}) -> Parser {
|
||||
return Parser {
|
||||
flags = flags,
|
||||
err = default_error_handler,
|
||||
warn = default_warning_handler,
|
||||
};
|
||||
@@ -128,6 +140,10 @@ parse_file :: proc(p: ^Parser, file: ^ast.File) -> bool {
|
||||
p.line_comment = nil;
|
||||
}
|
||||
|
||||
if .Optional_Semicolons in p.flags {
|
||||
p.tok.flags += {.Insert_Semicolon};
|
||||
}
|
||||
|
||||
p.file = file;
|
||||
tokenizer.init(&p.tok, file.src, file.fullpath, p.err);
|
||||
if p.tok.ch <= 0 {
|
||||
@@ -400,6 +416,11 @@ is_semicolon_optional_for_node :: proc(p: ^Parser, node: ^ast.Node) -> bool {
|
||||
if node == nil {
|
||||
return false;
|
||||
}
|
||||
|
||||
if .Optional_Semicolons in p.flags {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch n in node.derived {
|
||||
case ast.Empty_Stmt, ast.Block_Stmt:
|
||||
return true;
|
||||
@@ -439,14 +460,34 @@ is_semicolon_optional_for_node :: proc(p: ^Parser, node: ^ast.Node) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
expect_semicolon_newline_error :: proc(p: ^Parser, token: tokenizer.Token, s: ^ast.Node) {
|
||||
if .Optional_Semicolons not_in p.flags && .Insert_Semicolon in p.tok.flags && token.text == "\n" {
|
||||
#partial switch token.kind {
|
||||
case .Close_Brace:
|
||||
case .Close_Paren:
|
||||
case .Else:
|
||||
return;
|
||||
}
|
||||
if is_semicolon_optional_for_node(p, s) {
|
||||
return;
|
||||
}
|
||||
|
||||
tok := token;
|
||||
tok.pos.column -= 1;
|
||||
error(p, tok.pos, "expected ';', got newline");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
expect_semicolon :: proc(p: ^Parser, node: ^ast.Node) -> bool {
|
||||
if allow_token(p, .Semicolon) {
|
||||
expect_semicolon_newline_error(p, p.prev_tok, node);
|
||||
return true;
|
||||
}
|
||||
|
||||
prev := p.prev_tok;
|
||||
if prev.kind == .Semicolon {
|
||||
expect_semicolon_newline_error(p, p.prev_tok, node);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -615,7 +656,7 @@ parse_if_stmt :: proc(p: ^Parser) -> ^ast.If_Stmt {
|
||||
cond = parse_expr(p, false);
|
||||
} else {
|
||||
init = parse_simple_stmt(p, nil);
|
||||
if allow_token(p, .Semicolon) {
|
||||
if parse_control_statement_semicolon_separator(p) {
|
||||
cond = parse_expr(p, false);
|
||||
} else {
|
||||
cond = convert_stmt_to_expr(p, init, "boolean expression");
|
||||
@@ -668,6 +709,18 @@ parse_if_stmt :: proc(p: ^Parser) -> ^ast.If_Stmt {
|
||||
return if_stmt;
|
||||
}
|
||||
|
||||
parse_control_statement_semicolon_separator :: proc(p: ^Parser) -> bool {
|
||||
tok := peek_token(p);
|
||||
if tok.kind != .Open_Brace {
|
||||
return allow_token(p, .Semicolon);
|
||||
}
|
||||
if tok.text == ";" {
|
||||
return allow_token(p, .Semicolon);
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
||||
if p.curr_proc == nil {
|
||||
error(p, p.curr_tok.pos, "you cannot use a for statement in the file scope");
|
||||
@@ -716,7 +769,7 @@ parse_for_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
||||
}
|
||||
}
|
||||
|
||||
if !is_range && allow_token(p, .Semicolon) {
|
||||
if !is_range && parse_control_statement_semicolon_separator(p) {
|
||||
init = cond;
|
||||
cond = nil;
|
||||
if p.curr_tok.kind != .Semicolon {
|
||||
@@ -820,7 +873,7 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
||||
tag = parse_simple_stmt(p, {Stmt_Allow_Flag.In});
|
||||
if as, ok := tag.derived.(ast.Assign_Stmt); ok && as.op.kind == .In {
|
||||
is_type_switch = true;
|
||||
} else if allow_token(p, .Semicolon) {
|
||||
} else if parse_control_statement_semicolon_separator(p) {
|
||||
init = tag;
|
||||
tag = nil;
|
||||
if p.curr_tok.kind != .Open_Brace {
|
||||
@@ -831,6 +884,7 @@ parse_switch_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
||||
}
|
||||
|
||||
|
||||
skip_possible_newline(p);
|
||||
open := expect_token(p, .Open_Brace);
|
||||
|
||||
for p.curr_tok.kind == .Case {
|
||||
@@ -958,6 +1012,7 @@ parse_foreign_block :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Foreign_Bl
|
||||
defer p.in_foreign_block = prev_in_foreign_block;
|
||||
p.in_foreign_block = true;
|
||||
|
||||
skip_possible_newline_for_literal(p);
|
||||
open := expect_token(p, .Open_Brace);
|
||||
for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF {
|
||||
decl := parse_foreign_block_decl(p);
|
||||
@@ -1287,7 +1342,7 @@ token_precedence :: proc(p: ^Parser, kind: tokenizer.Token_Kind) -> int {
|
||||
#partial switch kind {
|
||||
case .Question, .If, .When:
|
||||
return 1;
|
||||
case .Ellipsis, .Range_Half:
|
||||
case .Ellipsis, .Range_Half, .Range_Full:
|
||||
if !p.allow_range {
|
||||
return 0;
|
||||
}
|
||||
@@ -2234,6 +2289,8 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
}
|
||||
body: ^ast.Stmt;
|
||||
|
||||
skip_possible_newline_for_literal(p);
|
||||
|
||||
if allow_token(p, .Undef) {
|
||||
body = nil;
|
||||
if where_token.kind != .Invalid {
|
||||
@@ -2406,6 +2463,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
p.expr_level = where_prev_level;
|
||||
}
|
||||
|
||||
skip_possible_newline_for_literal(p);
|
||||
expect_token(p, .Open_Brace);
|
||||
fields, name_count = parse_field_list(p, .Close_Brace, ast.Field_Flags_Struct);
|
||||
close := expect_token(p, .Close_Brace);
|
||||
@@ -2474,6 +2532,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
|
||||
variants: [dynamic]^ast.Expr;
|
||||
|
||||
skip_possible_newline_for_literal(p);
|
||||
expect_token_after(p, .Open_Brace, "union");
|
||||
|
||||
for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF {
|
||||
@@ -2504,6 +2563,8 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
if p.curr_tok.kind != .Open_Brace {
|
||||
base_type = parse_type(p);
|
||||
}
|
||||
|
||||
skip_possible_newline_for_literal(p);
|
||||
open := expect_token(p, .Open_Brace);
|
||||
fields := parse_elem_list(p);
|
||||
close := expect_token(p, .Close_Brace);
|
||||
@@ -2602,6 +2663,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
}
|
||||
}
|
||||
|
||||
skip_possible_newline_for_literal(p);
|
||||
open := expect_token(p, .Open_Brace);
|
||||
asm_string := parse_expr(p, false);
|
||||
expect_token(p, .Comma);
|
||||
@@ -2812,7 +2874,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
|
||||
open := expect_token(p, .Open_Bracket);
|
||||
|
||||
#partial switch p.curr_tok.kind {
|
||||
case .Colon, .Ellipsis, .Range_Half:
|
||||
case .Colon, .Ellipsis, .Range_Half, .Range_Full:
|
||||
// NOTE(bill): Do not err yet
|
||||
break;
|
||||
case:
|
||||
@@ -2820,7 +2882,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
|
||||
}
|
||||
|
||||
#partial switch p.curr_tok.kind {
|
||||
case .Ellipsis, .Range_Half:
|
||||
case .Ellipsis, .Range_Half, .Range_Full:
|
||||
error(p, p.curr_tok.pos, "expected a colon, not a range");
|
||||
fallthrough;
|
||||
case .Colon:
|
||||
|
||||
Reference in New Issue
Block a user