aboutsummaryrefslogtreecommitdiff
path: root/src/parser.c
diff options
context:
space:
mode:
authorZac Pierson <zacpiersonhehe@gmail.com>2017-03-21 14:16:42 -0500
committerZac Pierson <zacpiersonhehe@gmail.com>2017-03-21 14:16:42 -0500
commitc7bb861d3ca19f1a81043b8ad1e014ad10aa225f (patch)
tree56719cc445ebe06b4d2e486e2da3c17c57e216c2 /src/parser.c
parentd890731716ea96fd69d7543c7d7225702cbd7268 (diff)
parent188b290dd50664aa8a89955ac2ab7dbebf7a653d (diff)
Merge https://github.com/gingerBill/Odin
"Fixed" a proc overload bug. Still needs a *real* fix.
Diffstat (limited to 'src/parser.c')
-rw-r--r--src/parser.c222
1 files changed, 124 insertions, 98 deletions
diff --git a/src/parser.c b/src/parser.c
index 160b72ef3..a41fc5c06 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -139,6 +139,10 @@ AstNodeArray make_ast_node_array(AstFile *f) {
AstNodeArray elems; \
Token open, close; \
}) \
+ AST_NODE_KIND(Alias, "alias", struct { \
+ Token token; \
+ AstNode *expr; \
+ }) \
AST_NODE_KIND(_ExprBegin, "", i32) \
AST_NODE_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \
AST_NODE_KIND(TagExpr, "tag expression", struct { Token token, name; AstNode *expr; }) \
@@ -215,6 +219,7 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
}) \
AST_NODE_KIND(ForStmt, "for statement", struct { \
Token token; \
+ AstNode *label; \
AstNode *init; \
AstNode *cond; \
AstNode *post; \
@@ -222,6 +227,7 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
}) \
AST_NODE_KIND(RangeStmt, "range statement", struct { \
Token token; \
+ AstNode *label; \
AstNode *value; \
AstNode *index; \
Token in_token; \
@@ -235,20 +241,22 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
}) \
AST_NODE_KIND(MatchStmt, "match statement", struct { \
Token token; \
+ AstNode *label; \
AstNode *init; \
AstNode *tag; \
AstNode *body; \
}) \
AST_NODE_KIND(TypeMatchStmt, "type match statement", struct { \
Token token; \
+ AstNode *label; \
AstNode *tag; \
AstNode *body; \
}) \
AST_NODE_KIND(DeferStmt, "defer statement", struct { Token token; AstNode *stmt; }) \
- AST_NODE_KIND(BranchStmt, "branch statement", struct { Token token; }) \
+ AST_NODE_KIND(BranchStmt, "branch statement", struct { Token token; AstNode *label; }) \
AST_NODE_KIND(UsingStmt, "using statement", struct { \
Token token; \
- AstNode *node; \
+ AstNodeArray list; \
}) \
AST_NODE_KIND(AsmOperand, "assembly operand", struct { \
Token string; \
@@ -301,6 +309,10 @@ AST_NODE_KIND(_DeclBegin, "", i32) \
AstNode *cond; \
bool is_system; \
}) \
+ AST_NODE_KIND(Label, "label", struct { \
+ Token token; \
+ AstNode *name; \
+ }) \
AST_NODE_KIND(_DeclEnd, "", i32) \
AST_NODE_KIND(Field, "field", struct { \
AstNodeArray names; \
@@ -398,7 +410,6 @@ String const ast_node_strings[] = {
typedef struct AstNode {
AstNodeKind kind;
- // AstNode *prev, *next; // NOTE(bill): allow for Linked list
u32 stmt_state_flags;
union {
#define AST_NODE_KIND(_kind_name_, name, ...) GB_JOIN2(AstNode, _kind_name_) _kind_name_;
@@ -410,7 +421,9 @@ typedef struct AstNode {
#define ast_node(n_, Kind_, node_) GB_JOIN2(AstNode, Kind_) *n_ = &(node_)->Kind_; GB_ASSERT((node_)->kind == GB_JOIN2(AstNode_, Kind_))
#define case_ast_node(n_, Kind_, node_) case GB_JOIN2(AstNode_, Kind_): { ast_node(n_, Kind_, node_);
+#ifndef case_end
#define case_end } break;
+#endif
gb_inline bool is_ast_node_expr(AstNode *node) {
@@ -445,6 +458,8 @@ Token ast_node_token(AstNode *node) {
return ast_node_token(node->CompoundLit.type);
}
return node->CompoundLit.open;
+ case AstNode_Alias: return node->Alias.token;
+
case AstNode_TagExpr: return node->TagExpr.token;
case AstNode_RunExpr: return node->RunExpr.token;
case AstNode_BadExpr: return node->BadExpr.begin;
@@ -492,6 +507,7 @@ Token ast_node_token(AstNode *node) {
case AstNode_ValueDecl: return ast_node_token(node->ValueDecl.names.e[0]);
case AstNode_ImportDecl: return node->ImportDecl.token;
case AstNode_ForeignLibrary: return node->ForeignLibrary.token;
+ case AstNode_Label: return node->Label.token;
case AstNode_Field:
@@ -771,6 +787,13 @@ AstNode *ast_compound_lit(AstFile *f, AstNode *type, AstNodeArray elems, Token o
result->CompoundLit.close = close;
return result;
}
+AstNode *ast_alias(AstFile *f, Token token, AstNode *expr) {
+ AstNode *result = make_ast_node(f, AstNode_Alias);
+ result->Alias.token = token;
+ result->Alias.expr = expr;
+ return result;
+}
+
AstNode *ast_ternary_expr(AstFile *f, AstNode *cond, AstNode *x, AstNode *y) {
AstNode *result = make_ast_node(f, AstNode_TernaryExpr);
@@ -910,19 +933,21 @@ AstNode *ast_defer_stmt(AstFile *f, Token token, AstNode *stmt) {
return result;
}
-AstNode *ast_branch_stmt(AstFile *f, Token token) {
+AstNode *ast_branch_stmt(AstFile *f, Token token, AstNode *label) {
AstNode *result = make_ast_node(f, AstNode_BranchStmt);
result->BranchStmt.token = token;
+ result->BranchStmt.label = label;
return result;
}
-AstNode *ast_using_stmt(AstFile *f, Token token, AstNode *node) {
+AstNode *ast_using_stmt(AstFile *f, Token token, AstNodeArray list) {
AstNode *result = make_ast_node(f, AstNode_UsingStmt);
result->UsingStmt.token = token;
- result->UsingStmt.node = node;
+ result->UsingStmt.list = list;
return result;
}
+
AstNode *ast_asm_operand(AstFile *f, Token string, AstNode *operand) {
AstNode *result = make_ast_node(f, AstNode_AsmOperand);
result->AsmOperand.string = string;
@@ -1124,6 +1149,13 @@ AstNode *ast_foreign_library(AstFile *f, Token token, Token filepath, Token libr
return result;
}
+AstNode *ast_label_decl(AstFile *f, Token token, AstNode *name) {
+ AstNode *result = make_ast_node(f, AstNode_Label);
+ result->Label.token = token;
+ result->Label.name = name;
+ return result;
+}
+
bool next_token(AstFile *f) {
Token prev = f->curr_token;
@@ -1762,6 +1794,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
} else if (str_eq(name.string, str_lit("line"))) { return ast_basic_directive(f, token, name.string);
} else if (str_eq(name.string, str_lit("procedure"))) { return ast_basic_directive(f, token, name.string);
} else if (str_eq(name.string, str_lit("type"))) { return ast_helper_type(f, token, parse_type(f));
+ } else if (!lhs && str_eq(name.string, str_lit("alias"))) { return ast_alias(f, token, parse_expr(f, false));
} else {
operand = ast_tag_expr(f, token, name, parse_expr(f, false));
}
@@ -2129,7 +2162,7 @@ AstNode *parse_expr(AstFile *f, bool lhs) {
AstNodeArray parse_expr_list(AstFile *f, bool lhs) {
AstNodeArray list = make_ast_node_array(f);
- do {
+ for (;;) {
AstNode *e = parse_expr(f, lhs);
array_add(&list, e);
if (f->curr_token.kind != Token_Comma ||
@@ -2137,7 +2170,7 @@ AstNodeArray parse_expr_list(AstFile *f, bool lhs) {
break;
}
next_token(f);
- } while (true);
+ }
return list;
}
@@ -2320,7 +2353,7 @@ AstNode *parse_block_stmt(AstFile *f, b32 is_when) {
return parse_body(f);
}
-AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind separator, TokenKind follow);
+AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow);
AstNode *parse_results(AstFile *f) {
@@ -2339,7 +2372,7 @@ AstNode *parse_results(AstFile *f) {
AstNode *list = NULL;
expect_token(f, Token_OpenParen);
- list = parse_field_list(f, NULL, 0, Token_Comma, Token_CloseParen);
+ list = parse_field_list(f, NULL, 0, Token_CloseParen);
expect_token_after(f, Token_CloseParen, "parameter list");
return list;
}
@@ -2350,7 +2383,7 @@ AstNode *parse_proc_type(AstFile *f, AstNode **foreign_library_, String *foreign
Token proc_token = expect_token(f, Token_proc);
expect_token(f, Token_OpenParen);
- params = parse_field_list(f, NULL, FieldFlag_Signature, Token_Comma, Token_CloseParen);
+ params = parse_field_list(f, NULL, FieldFlag_Signature, Token_CloseParen);
expect_token_after(f, Token_CloseParen, "parameter list");
results = parse_results(f);
@@ -2369,17 +2402,6 @@ AstNode *parse_proc_type(AstFile *f, AstNode **foreign_library_, String *foreign
return ast_proc_type(f, proc_token, params, results, tags, cc);
}
-bool parse_expect_separator(AstFile *f, TokenKind separator, AstNode *param) {
- if (separator == Token_Semicolon) {
- expect_semicolon(f, param);
- } else {
- if (!allow_token(f, separator)) {
- return true;
- }
- }
- return false;
-}
-
AstNode *parse_var_type(AstFile *f, bool allow_ellipsis) {
if (allow_ellipsis && f->curr_token.kind == Token_Ellipsis) {
Token tok = f->curr_token;
@@ -2490,7 +2512,22 @@ AstNodeArray convert_to_ident_list(AstFile *f, AstNodeAndFlagsArray list, bool i
return idents;
}
-AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind separator, TokenKind follow) {
+
+bool parse_expect_field_separator(AstFile *f, AstNode *param) {
+ Token token = f->curr_token;
+ if (allow_token(f, Token_Comma)) {
+ return true;
+ }
+ if (token.kind == Token_Semicolon) {
+ next_token(f);
+ error(f->curr_token, "Expected a comma, got a semicolon");
+ return true;
+ }
+ return false;
+}
+
+AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow) {
+ TokenKind separator = Token_Comma;
Token start_token = f->curr_token;
AstNodeArray params = make_ast_node_array(f);
@@ -2528,7 +2565,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
AstNode *param = ast_field(f, names, type, set_flags);
array_add(&params, param);
- parse_expect_separator(f, separator, type);
+ parse_expect_field_separator(f, type);
while (f->curr_token.kind != follow &&
f->curr_token.kind != Token_EOF) {
@@ -2546,7 +2583,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
AstNode *param = ast_field(f, names, type, set_flags);
array_add(&params, param);
- if (parse_expect_separator(f, separator, param)) {
+ if (!parse_expect_field_separator(f, param)) {
break;
}
}
@@ -2575,7 +2612,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
AstNode *parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) {
- return parse_field_list(f, field_count_, flags, Token_Comma, Token_CloseBrace);
+ return parse_field_list(f, field_count_, flags, Token_CloseBrace);
}
AstNode *parse_type_or_ident(AstFile *f) {
@@ -3041,46 +3078,6 @@ AstNode *parse_for_stmt(AstFile *f) {
cond = convert_stmt_to_expr(f, cond, str_lit("boolean expression"));
return ast_for_stmt(f, token, init, cond, post, body);
-
-#if 0
- Token token = expect_token(f, Token_for);
- AstNodeArray names = parse_ident_list(f);
- parse_check_name_list_for_reserves(f, names);
- Token colon = expect_token_after(f, Token_in, "for name list");
-
- isize prev_level = f->expr_level;
- f->expr_level = -1;
- AstNode *expr = parse_expr(f, false);
- switch (f->curr_token.kind) {
- case Token_HalfOpenRange:
- case Token_Ellipsis: {
- Token op = f->curr_token;
- next_token(f);
- AstNode *right = parse_expr(f, false);
- expr = ast_interval_expr(f, op, expr, right);
- } break;
- }
- f->expr_level = prev_level;
-
- AstNode *value = NULL;
- AstNode *index = NULL;
- AstNode *body = parse_block_stmt(f, false);
-
- switch (names.count) {
- case 1:
- value = names.e[0];
- break;
- case 2:
- value = names.e[0];
- index = names.e[1];
- break;
- default:
- error(token, "Expected at 1 or 2 identifiers");
- return ast_bad_stmt(f, token, f->curr_token);
- }
-
- return ast_range_stmt(f, token, value, index, expr, body);
-#endif
}
@@ -3102,9 +3099,17 @@ AstNode *parse_case_clause(AstFile *f) {
AstNode *parse_type_case_clause(AstFile *f) {
Token token = f->curr_token;
- AstNodeArray clause = make_ast_node_array(f);
+ AstNodeArray list = make_ast_node_array(f);
if (allow_token(f, Token_case)) {
- array_add(&clause, parse_type(f));
+ for (;;) {
+ AstNode *t = parse_type(f);
+ array_add(&list, t);
+ if (f->curr_token.kind != Token_Comma ||
+ f->curr_token.kind == Token_EOF) {
+ break;
+ }
+ next_token(f);
+ }
} else {
expect_token(f, Token_default);
}
@@ -3112,7 +3117,7 @@ AstNode *parse_type_case_clause(AstFile *f) {
// expect_token(f, Token_ArrowRight); // TODO(bill): Is this the best syntax?
AstNodeArray stmts = parse_stmt_list(f);
- return ast_case_clause(f, token, clause, stmts);
+ return ast_case_clause(f, token, list, stmts);
}
@@ -3256,43 +3261,47 @@ AstNode *parse_stmt(AstFile *f) {
case Token_break:
case Token_continue:
- case Token_fallthrough:
+ case Token_fallthrough: {
+ AstNode *label = NULL;
next_token(f);
- s = ast_branch_stmt(f, token);
+ if (token.kind != Token_fallthrough &&
+ f->curr_token.kind == Token_Ident) {
+ label = parse_ident(f);
+ }
+ s = ast_branch_stmt(f, token, label);
expect_semicolon(f, s);
return s;
+ }
case Token_using: {
// TODO(bill): Make using statements better
Token token = expect_token(f, Token_using);
- AstNode *node = parse_stmt(f);
+ AstNodeArray list = parse_lhs_expr_list(f);
+ if (list.count == 0) {
+ syntax_error(token, "Illegal use of `using` statement");
+ expect_semicolon(f, NULL);
+ return ast_bad_stmt(f, token, f->curr_token);
+ }
- switch (node->kind) {
- case AstNode_ValueDecl:
- if (!node->ValueDecl.is_var) {
+ if (f->curr_token.kind != Token_Colon) {
+ expect_semicolon(f, list.e[list.count-1]);
+ return ast_using_stmt(f, token, list);
+ }
+
+ AstNode *decl = parse_simple_stmt(f, false);
+ expect_semicolon(f, decl);
+
+ if (decl->kind == AstNode_ValueDecl) {
+ if (!decl->ValueDecl.is_var) {
syntax_error(token, "`using` may not be applied to constant declarations");
- } else {
- if (f->curr_proc == NULL) {
- syntax_error(token, "`using` is not allowed at the file scope");
- } else {
- node->ValueDecl.flags |= VarDeclFlag_using;
- }
+ return decl;
}
- return node;
- case AstNode_ExprStmt: {
- AstNode *e = unparen_expr(node->ExprStmt.expr);
- while (e->kind == AstNode_SelectorExpr) {
- e = unparen_expr(e->SelectorExpr.selector);
- }
- if (e->kind == AstNode_Ident) {
- return ast_using_stmt(f, token, node);
- } else if (e->kind == AstNode_Implicit) {
- syntax_error(token, "Illegal use of `using` statement with implicit value `%.*s`", LIT(e->Implicit.string));
- return ast_bad_stmt(f, token, f->curr_token);
+ if (f->curr_proc == NULL) {
+ syntax_error(token, "`using` is not allowed at the file scope");
+ } else {
+ decl->ValueDecl.flags |= VarDeclFlag_using;
}
- } break;
-
-
+ return decl;
}
syntax_error(token, "Illegal use of `using` statement");
@@ -3345,7 +3354,25 @@ AstNode *parse_stmt(AstFile *f) {
Token name = expect_token(f, Token_Ident);
String tag = name.string;
- if (str_eq(tag, str_lit("import"))) {
+ if (str_eq(tag, str_lit("label"))) {
+ AstNode *name = parse_ident(f);
+ AstNode *label = ast_label_decl(f, token, name);
+ AstNode *stmt = parse_stmt(f);
+
+ #define _SET_LABEL(Kind_, label_) case GB_JOIN2(AstNode_, Kind_): (stmt->Kind_).label = label_; break
+ switch (stmt->kind) {
+ _SET_LABEL(ForStmt, label);
+ _SET_LABEL(RangeStmt, label);
+ _SET_LABEL(MatchStmt, label);
+ _SET_LABEL(TypeMatchStmt, label);
+ default:
+ syntax_error(token, "#label may only be applied to a loop");
+ break;
+ }
+ #undef _SET_LABEL
+
+ return stmt;
+ } else if (str_eq(tag, str_lit("import"))) {
AstNode *cond = NULL;
Token import_name = {0};
@@ -3505,7 +3532,6 @@ AstNode *parse_stmt(AstFile *f) {
return s;
}
-
if (str_eq(tag, str_lit("include"))) {
syntax_error(token, "#include is not a valid import declaration kind. Use #load instead");
s = ast_bad_stmt(f, token, f->curr_token);
@@ -3827,7 +3853,7 @@ ParseFileError parse_files(Parser *p, char *init_filename) {
gb_printf_err("File permissions problem");
break;
case ParseFile_NotFound:
- gb_printf_err("File cannot be found");
+ gb_printf_err("File cannot be found (`%.*s`)", LIT(import_path));
break;
case ParseFile_InvalidToken:
gb_printf_err("Invalid token found in file");