aboutsummaryrefslogtreecommitdiff
path: root/src/parser.cpp
diff options
context:
space:
mode:
authorjockus <joakim.hentula@gmail.com>2021-05-27 12:01:28 +0100
committerjockus <joakim.hentula@gmail.com>2021-05-27 12:01:28 +0100
commit4455ba5b6513f69f3d4b1e02d6fa848875f3544d (patch)
treeb60714422d9a06b206d3c615f0ecd77f24f93c52 /src/parser.cpp
parente8aa767c8dbb6e52ca4955fd0f67d90cf09507db (diff)
parentbb7bd94b0ab671513ca2a4e3f9b9973bed87daa6 (diff)
Merge branch 'master' of https://github.com/odin-lang/Odin
Diffstat (limited to 'src/parser.cpp')
-rw-r--r--src/parser.cpp269
1 files changed, 126 insertions, 143 deletions
diff --git a/src/parser.cpp b/src/parser.cpp
index 376ac58dc..a5180b4dd 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -1,109 +1,4 @@
-Token ast_token(Ast *node) {
- switch (node->kind) {
- case Ast_Ident: return node->Ident.token;
- case Ast_Implicit: return node->Implicit;
- case Ast_Undef: return node->Undef;
- case Ast_BasicLit: return node->BasicLit.token;
- case Ast_BasicDirective: return node->BasicDirective.token;
- case Ast_ProcGroup: return node->ProcGroup.token;
- case Ast_ProcLit: return ast_token(node->ProcLit.type);
- case Ast_CompoundLit:
- if (node->CompoundLit.type != nullptr) {
- return ast_token(node->CompoundLit.type);
- }
- return node->CompoundLit.open;
-
- case Ast_TagExpr: return node->TagExpr.token;
- case Ast_BadExpr: return node->BadExpr.begin;
- case Ast_UnaryExpr: return node->UnaryExpr.op;
- case Ast_BinaryExpr: return ast_token(node->BinaryExpr.left);
- case Ast_ParenExpr: return node->ParenExpr.open;
- case Ast_CallExpr: return ast_token(node->CallExpr.proc);
- case Ast_SelectorExpr:
- if (node->SelectorExpr.selector != nullptr) {
- return ast_token(node->SelectorExpr.selector);
- }
- return node->SelectorExpr.token;
- case Ast_SelectorCallExpr:
- if (node->SelectorCallExpr.expr != nullptr) {
- return ast_token(node->SelectorCallExpr.expr);
- }
- return node->SelectorCallExpr.token;
- case Ast_ImplicitSelectorExpr:
- if (node->ImplicitSelectorExpr.selector != nullptr) {
- return ast_token(node->ImplicitSelectorExpr.selector);
- }
- return node->ImplicitSelectorExpr.token;
- case Ast_IndexExpr: return node->IndexExpr.open;
- case Ast_SliceExpr: return node->SliceExpr.open;
- case Ast_Ellipsis: return node->Ellipsis.token;
- case Ast_FieldValue: return node->FieldValue.eq;
- case Ast_DerefExpr: return node->DerefExpr.op;
- case Ast_TernaryIfExpr: return ast_token(node->TernaryIfExpr.x);
- case Ast_TernaryWhenExpr: return ast_token(node->TernaryWhenExpr.x);
- case Ast_TypeAssertion: return ast_token(node->TypeAssertion.expr);
- case Ast_TypeCast: return node->TypeCast.token;
- case Ast_AutoCast: return node->AutoCast.token;
- case Ast_InlineAsmExpr: return node->InlineAsmExpr.token;
-
- case Ast_BadStmt: return node->BadStmt.begin;
- case Ast_EmptyStmt: return node->EmptyStmt.token;
- case Ast_ExprStmt: return ast_token(node->ExprStmt.expr);
- case Ast_TagStmt: return node->TagStmt.token;
- case Ast_AssignStmt: return node->AssignStmt.op;
- case Ast_BlockStmt: return node->BlockStmt.open;
- case Ast_IfStmt: return node->IfStmt.token;
- case Ast_WhenStmt: return node->WhenStmt.token;
- case Ast_ReturnStmt: return node->ReturnStmt.token;
- case Ast_ForStmt: return node->ForStmt.token;
- case Ast_RangeStmt: return node->RangeStmt.token;
- case Ast_UnrollRangeStmt: return node->UnrollRangeStmt.unroll_token;
- case Ast_CaseClause: return node->CaseClause.token;
- case Ast_SwitchStmt: return node->SwitchStmt.token;
- case Ast_TypeSwitchStmt: return node->TypeSwitchStmt.token;
- case Ast_DeferStmt: return node->DeferStmt.token;
- case Ast_BranchStmt: return node->BranchStmt.token;
- case Ast_UsingStmt: return node->UsingStmt.token;
-
- case Ast_BadDecl: return node->BadDecl.begin;
- case Ast_Label: return node->Label.token;
-
- case Ast_ValueDecl: return ast_token(node->ValueDecl.names[0]);
- case Ast_PackageDecl: return node->PackageDecl.token;
- case Ast_ImportDecl: return node->ImportDecl.token;
- case Ast_ForeignImportDecl: return node->ForeignImportDecl.token;
-
- case Ast_ForeignBlockDecl: return node->ForeignBlockDecl.token;
-
- case Ast_Attribute:
- return node->Attribute.token;
-
- case Ast_Field:
- if (node->Field.names.count > 0) {
- return ast_token(node->Field.names[0]);
- }
- return ast_token(node->Field.type);
- case Ast_FieldList:
- return node->FieldList.token;
-
- case Ast_TypeidType: return node->TypeidType.token;
- case Ast_HelperType: return node->HelperType.token;
- case Ast_DistinctType: return node->DistinctType.token;
- case Ast_PolyType: return node->PolyType.token;
- case Ast_ProcType: return node->ProcType.token;
- case Ast_RelativeType: return ast_token(node->RelativeType.tag);
- case Ast_PointerType: return node->PointerType.token;
- case Ast_ArrayType: return node->ArrayType.token;
- case Ast_DynamicArrayType: return node->DynamicArrayType.token;
- case Ast_StructType: return node->StructType.token;
- case Ast_UnionType: return node->UnionType.token;
- case Ast_EnumType: return node->EnumType.token;
- case Ast_BitSetType: return node->BitSetType.token;
- case Ast_MapType: return node->MapType.token;
- }
-
- return empty_token;
-}
+#include "parser_pos.cpp"
Token token_end_of_line(AstFile *f, Token tok) {
u8 const *start = f->tokenizer.start + tok.pos.offset;
@@ -115,6 +10,48 @@ Token token_end_of_line(AstFile *f, Token tok) {
return tok;
}
+gbString get_file_line_as_string(TokenPos const &pos, i32 *offset_) {
+ AstFile *file = get_ast_file_from_id(pos.file_id);
+ if (file == nullptr) {
+ return nullptr;
+ }
+ isize offset = pos.offset;
+
+ u8 *start = file->tokenizer.start;
+ u8 *end = file->tokenizer.end;
+ isize len = end-start;
+ if (len < offset) {
+ return nullptr;
+ }
+
+ u8 *pos_offset = start+offset;
+
+ u8 *line_start = pos_offset;
+ u8 *line_end = pos_offset;
+ while (line_start >= start) {
+ if (*line_start == '\n') {
+ line_start += 1;
+ break;
+ }
+ line_start -= 1;
+ }
+
+ while (line_end < end) {
+ if (*line_end == '\n') {
+ line_end -= 1;
+ break;
+ }
+ line_end += 1;
+ }
+ String the_line = make_string(line_start, line_end-line_start);
+ the_line = string_trim_whitespace(the_line);
+
+ if (offset_) *offset_ = cast(i32)(pos_offset - the_line.text);
+
+ return gb_string_make_length(heap_allocator(), the_line.text, the_line.len);
+}
+
+
isize ast_node_size(AstKind kind) {
return align_formula_isize(gb_size_of(AstCommonStuff) + ast_variant_sizes[kind], gb_align_of(void *));
@@ -432,12 +369,15 @@ Ast *clone_ast(Ast *node) {
void error(Ast *node, char const *fmt, ...) {
Token token = {};
+ TokenPos end_pos = {};
if (node != nullptr) {
token = ast_token(node);
+ end_pos = ast_end_pos(node);
}
+
va_list va;
va_start(va, fmt);
- error_va(token, fmt, va);
+ error_va(token.pos, end_pos, fmt, va);
va_end(va);
if (node != nullptr && node->file != nullptr) {
node->file->error_count += 1;
@@ -451,7 +391,7 @@ void error_no_newline(Ast *node, char const *fmt, ...) {
}
va_list va;
va_start(va, fmt);
- error_no_newline_va(token, fmt, va);
+ error_no_newline_va(token.pos, fmt, va);
va_end(va);
if (node != nullptr && node->file != nullptr) {
node->file->error_count += 1;
@@ -459,16 +399,28 @@ void error_no_newline(Ast *node, char const *fmt, ...) {
}
void warning(Ast *node, char const *fmt, ...) {
+ Token token = {};
+ TokenPos end_pos = {};
+ if (node != nullptr) {
+ token = ast_token(node);
+ end_pos = ast_end_pos(node);
+ }
va_list va;
va_start(va, fmt);
- warning_va(ast_token(node), fmt, va);
+ warning_va(token.pos, end_pos, fmt, va);
va_end(va);
}
void syntax_error(Ast *node, char const *fmt, ...) {
+ Token token = {};
+ TokenPos end_pos = {};
+ if (node != nullptr) {
+ token = ast_token(node);
+ end_pos = ast_end_pos(node);
+ }
va_list va;
va_start(va, fmt);
- syntax_error_va(ast_token(node), fmt, va);
+ syntax_error_va(token.pos, end_pos, fmt, va);
va_end(va);
if (node != nullptr && node->file != nullptr) {
node->file->error_count += 1;
@@ -640,7 +592,7 @@ Ast *ast_basic_lit(AstFile *f, Token basic_lit) {
return result;
}
-Ast *ast_basic_directive(AstFile *f, Token token, String name) {
+Ast *ast_basic_directive(AstFile *f, Token token, Token name) {
Ast *result = alloc_ast_node(f, Ast_BasicDirective);
result->BasicDirective.token = token;
result->BasicDirective.name = name;
@@ -1344,6 +1296,7 @@ Token expect_token_after(AstFile *f, TokenKind kind, char const *msg) {
bool is_token_range(TokenKind kind) {
switch (kind) {
case Token_Ellipsis:
+ case Token_RangeFull:
case Token_RangeHalf:
return true;
}
@@ -1574,6 +1527,10 @@ void expect_semicolon(AstFile *f, Ast *s) {
return;
}
+ if (f->curr_token.kind == Token_EOF) {
+ return;
+ }
+
if (s != nullptr) {
bool insert_semi = (f->tokenizer.flags & TokenizerFlag_InsertSemicolon) != 0;
if (insert_semi) {
@@ -1994,35 +1951,28 @@ Ast *parse_operand(AstFile *f, bool lhs) {
Token name = expect_token(f, Token_Ident);
if (name.string == "type") {
return ast_helper_type(f, token, parse_type(f));
- } /* else if (name.string == "no_deferred") {
- operand = parse_expr(f, false);
- if (unparen_expr(operand)->kind != Ast_CallExpr) {
- syntax_error(operand, "#no_deferred can only be applied to procedure calls");
- operand = ast_bad_expr(f, token, f->curr_token);
- }
- operand->state_flags |= StateFlag_no_deferred;
- } */ else if (name.string == "file") {
- return ast_basic_directive(f, token, name.string);
- } else if (name.string == "line") { return ast_basic_directive(f, token, name.string);
- } else if (name.string == "procedure") { return ast_basic_directive(f, token, name.string);
- } else if (name.string == "caller_location") { return ast_basic_directive(f, token, name.string);
+ } else if (name.string == "file") {
+ return ast_basic_directive(f, token, name);
+ } else if (name.string == "line") { return ast_basic_directive(f, token, name);
+ } else if (name.string == "procedure") { return ast_basic_directive(f, token, name);
+ } else if (name.string == "caller_location") { return ast_basic_directive(f, token, name);
} else if (name.string == "location") {
- Ast *tag = ast_basic_directive(f, token, name.string);
+ Ast *tag = ast_basic_directive(f, token, name);
return parse_call_expr(f, tag);
} else if (name.string == "load") {
- Ast *tag = ast_basic_directive(f, token, name.string);
+ Ast *tag = ast_basic_directive(f, token, name);
return parse_call_expr(f, tag);
} else if (name.string == "assert") {
- Ast *tag = ast_basic_directive(f, token, name.string);
+ Ast *tag = ast_basic_directive(f, token, name);
return parse_call_expr(f, tag);
} else if (name.string == "defined") {
- Ast *tag = ast_basic_directive(f, token, name.string);
+ Ast *tag = ast_basic_directive(f, token, name);
return parse_call_expr(f, tag);
} else if (name.string == "config") {
- Ast *tag = ast_basic_directive(f, token, name.string);
+ Ast *tag = ast_basic_directive(f, token, name);
return parse_call_expr(f, tag);
} else if (name.string == "soa" || name.string == "simd") {
- Ast *tag = ast_basic_directive(f, token, name.string);
+ Ast *tag = ast_basic_directive(f, token, name);
Ast *original_type = parse_type(f);
Ast *type = unparen_expr(original_type);
switch (type->kind) {
@@ -2034,7 +1984,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
}
return original_type;
} else if (name.string == "partial") {
- Ast *tag = ast_basic_directive(f, token, name.string);
+ Ast *tag = ast_basic_directive(f, token, name);
Ast *original_type = parse_type(f);
Ast *type = unparen_expr(original_type);
switch (type->kind) {
@@ -2046,6 +1996,10 @@ Ast *parse_operand(AstFile *f, bool lhs) {
return original_type;
} else if (name.string == "bounds_check") {
Ast *operand = parse_expr(f, lhs);
+ if (operand == nullptr) {
+ syntax_error(token, "Invalid expresssion for #%.*s", LIT(name.string));
+ return nullptr;
+ }
operand->state_flags |= StateFlag_bounds_check;
if ((operand->state_flags & StateFlag_no_bounds_check) != 0) {
syntax_error(token, "#bounds_check and #no_bounds_check cannot be applied together");
@@ -2053,13 +2007,17 @@ Ast *parse_operand(AstFile *f, bool lhs) {
return operand;
} else if (name.string == "no_bounds_check") {
Ast *operand = parse_expr(f, lhs);
+ if (operand == nullptr) {
+ syntax_error(token, "Invalid expresssion for #%.*s", LIT(name.string));
+ return nullptr;
+ }
operand->state_flags |= StateFlag_no_bounds_check;
if ((operand->state_flags & StateFlag_bounds_check) != 0) {
syntax_error(token, "#bounds_check and #no_bounds_check cannot be applied together");
}
return operand;
} else if (name.string == "relative") {
- Ast *tag = ast_basic_directive(f, token, name.string);
+ Ast *tag = ast_basic_directive(f, token, name);
tag = parse_call_expr(f, tag);
Ast *type = parse_type(f);
return ast_relative_type(f, tag, type);
@@ -2314,7 +2272,7 @@ Ast *parse_operand(AstFile *f, bool lhs) {
f->expr_level = prev_level;
}
-
+ skip_possible_newline_for_literal(f);
Token open = expect_token_after(f, Token_OpenBrace, "struct");
isize name_count = 0;
@@ -2674,6 +2632,7 @@ Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) {
switch (f->curr_token.kind) {
case Token_Ellipsis:
+ case Token_RangeFull:
case Token_RangeHalf:
// NOTE(bill): Do not err yet
case Token_Colon:
@@ -2685,6 +2644,7 @@ Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) {
switch (f->curr_token.kind) {
case Token_Ellipsis:
+ case Token_RangeFull:
case Token_RangeHalf:
syntax_error(f->curr_token, "Expected a colon, not a range");
/* fallthrough */
@@ -2723,6 +2683,16 @@ Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) {
}
break;
+ case Token_Increment:
+ case Token_Decrement:
+ if (!lhs) {
+ Token token = advance_token(f);
+ syntax_error(token, "Postfix '%.*s' operator is not supported", LIT(token.string));
+ } else {
+ loop = false;
+ }
+ break;
+
default:
loop = false;
break;
@@ -2753,16 +2723,26 @@ Ast *parse_unary_expr(AstFile *f, bool lhs) {
return ast_auto_cast(f, token, expr);
}
+
case Token_Add:
case Token_Sub:
- case Token_Not:
case Token_Xor:
- case Token_And: {
+ case Token_And:
+ case Token_Not: {
+ Token token = advance_token(f);
+ Ast *expr = parse_unary_expr(f, lhs);
+ return ast_unary_expr(f, token, expr);
+ }
+
+ case Token_Increment:
+ case Token_Decrement: {
Token token = advance_token(f);
+ syntax_error(token, "Unary '%.*s' operator is not supported", LIT(token.string));
Ast *expr = parse_unary_expr(f, lhs);
return ast_unary_expr(f, token, expr);
}
+
case Token_Period: {
Token token = expect_token(f, Token_Period);
Ast *ident = parse_ident(f);
@@ -2791,6 +2771,7 @@ i32 token_precedence(AstFile *f, TokenKind t) {
case Token_when:
return 1;
case Token_Ellipsis:
+ case Token_RangeFull:
case Token_RangeHalf:
if (!f->allow_range) {
return 0;
@@ -3152,6 +3133,13 @@ Ast *parse_simple_stmt(AstFile *f, u32 flags) {
return ast_bad_stmt(f, token, f->curr_token);
}
+ switch (token.kind) {
+ case Token_Increment:
+ case Token_Decrement:
+ advance_token(f);
+ syntax_error(token, "Postfix '%.*s' statement is not supported", LIT(token.string));
+ break;
+ }
#if 0
@@ -3898,12 +3886,6 @@ Ast *parse_return_stmt(AstFile *f) {
while (f->curr_token.kind != Token_Semicolon) {
Ast *arg = parse_expr(f, false);
- // if (f->curr_token.kind == Token_Eq) {
- // Token eq = expect_token(f, Token_Eq);
- // Ast *value = parse_value(f);
- // arg = ast_field_value(f, arg, value, eq);
- // }
-
array_add(&results, arg);
if (f->curr_token.kind != Token_Comma ||
f->curr_token.kind == Token_EOF) {
@@ -4024,7 +4006,7 @@ Ast *parse_case_clause(AstFile *f, bool is_type) {
}
f->allow_range = prev_allow_range;
f->allow_in_expr = prev_allow_in_expr;
- expect_token(f, Token_Colon); // TODO(bill): Is this the best syntax?
+ expect_token(f, Token_Colon);
Array<Ast *> stmts = parse_stmt_list(f);
return ast_case_clause(f, token, list, stmts);
@@ -4482,10 +4464,10 @@ Ast *parse_stmt(AstFile *f) {
}
return s;
} else if (tag == "assert") {
- Ast *t = ast_basic_directive(f, hash_token, tag);
+ Ast *t = ast_basic_directive(f, hash_token, name);
return ast_expr_stmt(f, parse_call_expr(f, t));
} else if (tag == "panic") {
- Ast *t = ast_basic_directive(f, hash_token, tag);
+ Ast *t = ast_basic_directive(f, hash_token, name);
return ast_expr_stmt(f, parse_call_expr(f, t));
} else if (name.string == "force_inline" ||
name.string == "force_no_inline") {
@@ -4572,6 +4554,7 @@ ParseFileError init_ast_file(AstFile *f, String fullpath, TokenPos *err_pos) {
GB_ASSERT(f != nullptr);
f->fullpath = string_trim_whitespace(fullpath); // Just in case
set_file_path_string(f->id, fullpath);
+ set_ast_file_from_id(f->id, f);
if (!string_ends_with(f->fullpath, str_lit(".odin"))) {
return ParseFile_WrongExtension;
}