summaryrefslogtreecommitdiff
path: root/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'parse.c')
-rw-r--r--parse.c97
1 files changed, 70 insertions, 27 deletions
diff --git a/parse.c b/parse.c
index b754f3f..ac87acc 100644
--- a/parse.c
+++ b/parse.c
@@ -4,7 +4,7 @@
You should have received a copy of the GNU General Public License along with toc. If not, see <https://www.gnu.org/licenses/>.
*/
static bool parse_expr(Parser *p, Expression *e, Token *end);
-static bool parse_stmt(Parser *p, Statement *s);
+static bool parse_stmt(Parser *p, Statement *s, bool *was_a_statement);
enum {
PARSE_DECL_ALLOW_CONST_WITH_NO_EXPR = 0x01,
PARSE_DECL_ALLOW_SEMI_CONST = 0x02,
@@ -787,11 +787,11 @@ static bool parse_block(Parser *p, Block *b) {
Block *prev_block = p->block;
b->flags = 0;
b->ret_expr = NULL;
- p->block = b;
if (!token_is_kw(t->token, KW_LBRACE)) {
tokr_err(t, "Expected '{' to open block.");
return false;
}
+ p->block = b;
b->start = t->token->where;
++t->token; /* move past { */
b->stmts = NULL;
@@ -801,22 +801,28 @@ static bool parse_block(Parser *p, Block *b) {
/* non-empty block */
while (1) {
Statement *stmt = parser_arr_add(p, &b->stmts);
- bool success = parse_stmt(p, stmt);
+ bool was_a_statement;
+ bool success = parse_stmt(p, stmt, &was_a_statement);
if (!success) {
ret = false;
}
+ if (!was_a_statement) {
+ arr_remove_lasta(&b->stmts, p->allocr);
+ }
if (token_is_kw(t->token, KW_RBRACE)) {
break;
}
if (t->token->kind == TOKEN_EOF) {
tokr_err(t, "Expected '}' to close function body.");
- return false;
+ ret = false;
+ goto end;
}
}
}
b->end = t->token->where;
++t->token; /* move past } */
+ end:
p->block = prev_block;
return ret;
}
@@ -1892,7 +1898,8 @@ static bool is_decl(Tokenizer *t) {
}
}
-static bool parse_stmt(Parser *p, Statement *s) {
+/* sets *was_a_statement to false if s was not filled, but the token was advanced */
+static bool parse_stmt(Parser *p, Statement *s, bool *was_a_statement) {
Tokenizer *t = p->tokr;
if (t->token->kind == TOKEN_EOF) {
tokr_err(t, "Expected statement.");
@@ -1900,30 +1907,61 @@ static bool parse_stmt(Parser *p, Statement *s) {
}
s->where = t->token->where;
s->flags = 0;
- if (token_is_kw(t->token, KW_RETURN)) {
- s->kind = STMT_RET;
- ++t->token;
- s->ret.flags = 0;
- if (token_is_kw(t->token, KW_SEMICOLON)) {
- /* return with no expr */
+ *was_a_statement = true;
+ if (t->token->kind == TOKEN_KW) {
+ switch (t->token->kw) {
+ case KW_RETURN: {
+ s->kind = STMT_RET;
++t->token;
- return true;
+ s->ret.flags = 0;
+ if (token_is_kw(t->token, KW_SEMICOLON)) {
+ /* return with no expr */
+ ++t->token;
+ return true;
+ }
+ s->ret.flags |= RET_HAS_EXPR;
+ Token *end = expr_find_end(p, 0);
+ if (!end) {
+ while (t->token->kind != TOKEN_EOF) ++t->token; /* move to end of file */
+ return false;
+ }
+ if (!token_is_kw(end, KW_SEMICOLON)) {
+ err_print(end->where, "Expected ';' at end of return statement.");
+ t->token = end->kind == TOKEN_EOF ? end : end + 1;
+ return false;
+ }
+ bool success = parse_expr(p, &s->ret.expr, end);
+ t->token = end + 1;
+ return success;
}
- s->ret.flags |= RET_HAS_EXPR;
- Token *end = expr_find_end(p, 0);
- if (!end) {
- while (t->token->kind != TOKEN_EOF) ++t->token; /* move to end of file */
- return false;
+ case KW_PKG: {
+ /* declaration of package name */
+ Expression *pkg_name = parser_new_expr(p);
+ ++t->token;
+ Token *end = expr_find_end(p, 0);
+ if (!end || !token_is_kw(end, KW_SEMICOLON)) {
+ tokr_err(t, "No semicolon at end of package name.");
+ tokr_skip_to_eof(t);
+ return false;
+ }
+ if (p->block) {
+ tokr_err(t, "You must set the package name at global scope.");
+ t->token = end + 1;
+ return false;
+ }
+ if (p->file->pkg_name) {
+ tokr_err(t, "You've already set the package name.");
+ t->token = end + 1;
+ return false;
+ }
+ p->file->pkg_name = pkg_name;
+ bool success = parse_expr(p, pkg_name, end);
+ t->token = end + 1;
+ *was_a_statement = false;
+ return success;
}
- if (!token_is_kw(end, KW_SEMICOLON)) {
- err_print(end->where, "Expected ';' at end of return statement.");
- t->token = end->kind == TOKEN_EOF ? end : end + 1;
- return false;
+ default: break;
}
- bool success = parse_expr(p, &s->ret.expr, end);
- t->token = end + 1;
- return success;
-
}
if (is_decl(t)) {
s->kind = STMT_DECL;
@@ -1936,7 +1974,7 @@ static bool parse_stmt(Parser *p, Statement *s) {
Token *end = expr_find_end(p, 0);
if (!end) {
tokr_err(t, "No semicolon found at end of statement.");
- while (t->token->kind != TOKEN_EOF) ++t->token; /* move to end of file */
+ tokr_skip_to_eof(t);
return false;
}
@@ -1963,11 +2001,16 @@ static void parser_create(Parser *p, Tokenizer *t, Allocator *allocr) {
static bool parse_file(Parser *p, ParsedFile *f) {
Tokenizer *t = p->tokr;
f->stmts = NULL;
+ f->pkg_name = NULL;
+ p->file = f;
bool ret = true;
while (t->token->kind != TOKEN_EOF) {
+ bool was_a_statement;
Statement *stmt = parser_arr_add(p, &f->stmts);
- if (!parse_stmt(p, stmt))
+ if (!parse_stmt(p, stmt, &was_a_statement))
ret = false;
+ if (!was_a_statement)
+ arr_remove_lasta(&f->stmts, p->allocr);
if (token_is_kw(t->token, KW_RBRACE)) {
tokr_err(t, "} without a matching {.");
return false;