commit ed06275ff7d99a4d9a133ab9c789f435d529449e
parent 516a961cdf2e2ac3351685cfdf3af6400b36b68c
Author: Drew DeVault <sir@cmpwn.com>
Date: Wed, 30 Dec 2020 13:32:09 -0500
parse: implement assertion expressions
Diffstat:
6 files changed, 79 insertions(+), 14 deletions(-)
diff --git a/include/ast.h b/include/ast.h
@@ -112,6 +112,12 @@ struct ast_expression_access {
};
};
+struct ast_expression_assert {
+ struct ast_expression *cond;
+ struct ast_expression *message;
+ bool is_static;
+};
+
struct ast_expression_assign {
struct ast_expression *object, *value;
bool indirect;
@@ -227,6 +233,7 @@ struct ast_expression {
enum expr_type type;
union {
struct ast_expression_access access;
+ struct ast_expression_assert assert;
struct ast_expression_assign assign;
struct ast_expression_binarithm binarithm;
struct ast_expression_binding binding;
diff --git a/include/expr.h b/include/expr.h
@@ -48,6 +48,12 @@ struct expression_access {
};
};
+struct expression_assert {
+ struct expression *cond;
+ struct expression *message;
+ bool is_static;
+};
+
struct expression_assign {
struct expression *object, *value;
bool indirect;
@@ -179,6 +185,7 @@ struct expression {
bool terminates;
union {
struct expression_access access;
+ struct expression_assert assert;
struct expression_assign assign;
struct expression_binarithm binarithm;
struct expression_binding binding;
diff --git a/include/lex.h b/include/lex.h
@@ -5,14 +5,14 @@
// Keep sorted
enum lexical_token {
- T_AS,
- T_ABORT,
- T_ASSERT,
T_ATTR_FINI,
T_ATTR_INIT,
T_ATTR_NORETURN,
T_ATTR_SYMBOL,
T_ATTR_TEST,
+ T_ABORT,
+ T_AS,
+ T_ASSERT,
T_BOOL,
T_BREAK,
T_CHAR,
diff --git a/src/lex.c b/src/lex.c
@@ -14,7 +14,12 @@
#include "util.h"
static const char *tokens[] = {
- // Must be alpha sorted
+ // Must be alpha sorted and match lex.h
+ [T_ATTR_FINI] = "@fini",
+ [T_ATTR_INIT] = "@init",
+ [T_ATTR_NORETURN] = "@noreturn",
+ [T_ATTR_SYMBOL] = "@symbol",
+ [T_ATTR_TEST] = "@test",
[T_ABORT] = "abort",
[T_AS] = "as",
[T_ASSERT] = "assert",
@@ -64,11 +69,6 @@ static const char *tokens[] = {
[T_USE] = "use",
[T_VOID] = "void",
[T_WHILE] = "while",
- [T_ATTR_FINI] = "@fini",
- [T_ATTR_INIT] = "@init",
- [T_ATTR_NORETURN] = "@noreturn",
- [T_ATTR_SYMBOL] = "@symbol",
- [T_ATTR_TEST] = "@test",
// Operators
[T_ANDEQ] = "&=",
@@ -985,7 +985,8 @@ token_str(const struct token *tok)
int bytes = 0;
switch (tok->token) {
case T_NAME:
- return tok->name;
+ snprintf(buf, sizeof(buf), "name %s", tok->name);
+ return buf;
case T_LABEL:
snprintf(buf, sizeof(buf), ":%s", tok->name);
return buf;
diff --git a/src/main.c b/src/main.c
@@ -121,7 +121,7 @@ main(int argc, char *argv[])
lex_finish(&lexer);
}
- if (stage == STAGE_PARSE) {
+ if (stage == STAGE_PARSE || stage == STAGE_LEX) {
return 0;
}
diff --git a/src/parse.c b/src/parse.c
@@ -328,6 +328,8 @@ parse_primitive_type(struct lexer *lexer)
static struct ast_expression *parse_simple_expression(struct lexer *lexer);
static struct ast_expression *parse_complex_expression(struct lexer *lexer);
static struct ast_expression *parse_compound_expression(struct lexer *lexer);
+static struct ast_expression *parse_postfix_expression(struct lexer *lexer,
+ struct ast_expression *exp);
static struct ast_expression *parse_scope_expression(struct lexer *lexer);
static struct ast_expression *parse_binding_list(struct lexer *lexer);
@@ -888,8 +890,55 @@ parse_plain_expression(struct lexer *lexer)
assert(0); // Unreachable
}
-static struct ast_expression *parse_postfix_expression(struct lexer *lexer,
- struct ast_expression *exp);
+static struct ast_expression *
+parse_assertion_expression(struct lexer *lexer)
+{
+ trace(TR_PARSE, "assertion");
+
+ struct ast_expression *exp = xcalloc(1, sizeof(struct ast_expression));
+ exp->type = EXPR_ASSERT;
+
+ struct token tok;
+ switch (lex(lexer, &tok)) {
+ case T_STATIC:
+ exp->assert.is_static = true;
+ lex(lexer, &tok);
+ break;
+ case T_ASSERT:
+ case T_ABORT:
+ break;
+ default:
+ synassert(false, &tok, T_STATIC, T_ASSERT, T_ABORT, T_EOF);
+ }
+
+ switch (tok.token) {
+ case T_ASSERT:
+ want(lexer, T_LPAREN, &tok);
+ exp->assert.cond = parse_simple_expression(lexer);
+ if (lex(lexer, &tok) == T_COMMA) {
+ exp->assert.message = parse_constant(lexer);
+ } else {
+ unlex(lexer, &tok);
+ }
+ want(lexer, T_RPAREN, &tok);
+ break;
+ case T_ABORT:
+ if (exp->assert.is_static) {
+ synassert(false, &tok, T_ASSERT, T_EOF);
+ }
+ want(lexer, T_LPAREN, &tok);
+ if (lex(lexer, &tok) != T_RPAREN) {
+ unlex(lexer, &tok);
+ exp->assert.message = parse_constant(lexer);
+ want(lexer, T_RPAREN, &tok);
+ }
+ break;
+ default:
+ assert(0); // Invariant
+ }
+
+ return exp;
+}
static struct ast_expression *
parse_measurement_expression(struct lexer *lexer)
@@ -1036,7 +1085,8 @@ parse_postfix_expression(struct lexer *lexer, struct ast_expression *lvalue)
case T_ABORT:
case T_ASSERT:
case T_STATIC:
- assert(0); // TODO: assertion expression
+ unlex(lexer, &tok);
+ return parse_assertion_expression(lexer);
case T_SIZE:
case T_LEN:
case T_OFFSET: