Browse Source

better error handling

Mistivia 1 week ago
parent
commit
d119549933
5 changed files with 81 additions and 106 deletions
  1. 42 90
      src/as_parser.c
  2. 11 0
      src/as_parser.h
  3. 12 16
      src/as_tokenizer.c
  4. 8 0
      src/utils.c
  5. 8 0
      src/utils.h

+ 42 - 90
src/as_parser.c

@@ -17,37 +17,28 @@
 // <op> ::= "add" | "sub" | "mul" | "div" | "mod" | "eq" | ...
 
 struct result parse_prog(struct allocator * alct, struct token_stream * ts) {
-    struct result result;
     struct prog * p = allocate(alct, sizeof(struct prog));
-    result = parse_stmts(alct, ts);
-    if (result.errmsg != NULL) return result;
-    p->stmts = result.value;
-    return (struct result){.value = p, .errmsg = NULL};
+    p->stmts = unwrap(parse_stmts(alct, ts));
+    return ok(p);
 }
 
 struct result parse_stmts(struct allocator * alct, struct token_stream * ts) {
     struct token *token;
-    struct result result;
-    const char* errmsg;
     struct stmts * ss = allocate(alct, sizeof(struct stmts));
+    struct stmt * s;
+
     ss->stmts = allocate(alct, sizeof(struct stmt *));
     ss->stmts[0] = NULL;
     int capacity = 0;
     int len = 0;
 
     while (1) {
-        result = peek_token(alct, ts);
-        if (result.errmsg != NULL) return result;
-        token = result.value;
+        token = unwrap(peek_token(alct, ts));
         if (token->type == TK_ENDOFFILE) {
             break;
         }
-        
-        result = parse_stmt(alct, ts);
-        if (result.errmsg != NULL) {
-            return result;
-        }
-        struct stmt * s = result.value;
+
+        s = unwrap(parse_stmt(alct, ts));
         if (s == NULL) continue;
         if (len == capacity) {
             size_t new_capacity = capacity * 2 + 1;
@@ -57,136 +48,97 @@ struct result parse_stmts(struct allocator * alct, struct token_stream * ts) {
             capacity = new_capacity;
         }
         // expect newline
-        result = peek_token(alct, ts);
-        if (result.errmsg != NULL) return result;
-        token = result.value;
+        token = unwrap(peek_token(alct, ts));
         if (token->type == TK_NEWLINE) {
-            result = next_token(alct, ts);
-            if (result.errmsg != NULL) return result;
+            unwrap(next_token(alct, ts));
         } else {
-            errmsg = safe_sprintf(alct, "%d:%d expect newline.\n", token->line, token->col);
-            return (struct result){.value = NULL, .errmsg = errmsg};
+            return err(safe_sprintf(alct, "%d:%d expect newline.\n", token->line, token->col));
         }
         ss->stmts[len] = s;
         len++;
     }
     ss->stmts[len] = NULL;
-    return (struct result){.value = ss, .errmsg = NULL};
+    return ok(ss);
 }
 
 struct result parse_label(struct allocator * alct, struct token_stream * ts) {
-    const char *errmsg;
-    struct result result;
     struct token * t;
-    result = next_token(alct, ts);
-    if (result.errmsg != NULL) return result;
-    t = result.value;
+    t = unwrap(next_token(alct, ts));
     if (t->type != TK_TAG) {
-        errmsg = safe_sprintf(alct, "%d:%d expect label.\n", t->line, t->col);
-        return (struct result){.value = NULL, .errmsg = errmsg};
+        return err(safe_sprintf(alct, "%d:%d expect label.\n", t->line, t->col));
     }
     struct label * l = allocate(alct, sizeof(struct label *));
     l->name = t->sval;
-    result = next_token(alct, ts);
-    if (result.errmsg != NULL) return result;
-    t = result.value;
+    t = unwrap(next_token(alct, ts));
     if (t->type != TK_COLON) {
-        errmsg = safe_sprintf(alct, "%d:%d expect colon.\n", t->line, t->col);
-        return (struct result){.value = NULL, .errmsg = errmsg};
+        return err(safe_sprintf(alct, "%d:%d expect colon.\n", t->line, t->col));
     }
-    return (struct result){.value = l, .errmsg = NULL};
+    return ok(l);
 }
 
 struct result parse_stmt(struct allocator * alct, struct token_stream * ts) {
     const char *errmsg;
-    struct result result;
-    struct token * t;
-    result = peek_token(alct, ts);
-    if (result.errmsg != NULL) return result;
-    t = result.value;
+    struct token * token;
+    token = unwrap(peek_token(alct, ts));
     struct stmt * stmt = allocate(alct, sizeof(struct stmt));
     stmt->label = NULL;
     stmt->instr = NULL;
-    if (t->type == TK_TAG) {
-        result = parse_label(alct, ts);
-        if (result.errmsg != NULL) return result;
-        stmt->label = result.value;
-        result = peek_token(alct, ts);
-        if (result.errmsg != NULL) return result;
-        t = result.value;
-        if (t->type == TK_NEWLINE) {
-            return (struct result){.value = stmt, .errmsg = NULL};
+    if (token->type == TK_TAG) {
+        stmt->label = unwrap(parse_label(alct, ts));
+        token = unwrap(peek_token(alct, ts));
+        if (token->type == TK_NEWLINE) {
+            return ok(stmt);
         }
-        result = peek_token(alct, ts);
-        if (result.errmsg != NULL) return result;
-        t = result.value;
+        token = unwrap(peek_token(alct, ts));
     }
-    if (t->type == TK_OP) {
-        result = parse_instr(alct, ts);
-        if (result.errmsg != NULL) return result;
-        stmt->instr = result.value;
-
-        result = peek_token(alct, ts);
-        if (result.errmsg != NULL) return result;
-        t = result.value;
-        if (t->type == TK_NEWLINE) {
-            return (struct result){.value = stmt, .errmsg = NULL};
+    if (token->type == TK_OP) {
+        stmt->instr = unwrap(parse_instr(alct, ts));
+        token = unwrap(peek_token(alct, ts));
+        if (token->type == TK_NEWLINE) {
+            return ok(stmt);
         }
     }
-    if (t->type == TK_NEWLINE) {
-        return (struct result){.value = NULL, .errmsg = NULL};
+    if (token->type == TK_NEWLINE) {
+        return ok(NULL);
     }
-    errmsg = safe_sprintf(alct, "%d:%d expect lable + instruction, lable, or instruction.\n", t->line, t->col);
-    return (struct result){.value = NULL, .errmsg = errmsg};
+    return err(safe_sprintf(alct, "%d:%d expect lable + instruction, lable, or instruction.\n", token->line, token->col));
 }
 
 struct result parse_op(struct allocator * alct, struct token_stream * ts) {
-    const char *errmsg;
-    struct result result;
     struct token * t;
-    result = next_token(alct, ts);
-    if (result.errmsg != NULL) return result;
-    t = result.value;
+    t = unwrap(next_token(alct, ts));
     enum op op;
     if (t->type == TK_OP) {
         op = str2op(t->sval);
         if (op == OP_END) {
-            errmsg = safe_sprintf(alct, "%d:%d invalid op.\n", t->line, t->col);
-            return (struct result){.value = NULL, .errmsg = errmsg};
+            return err(safe_sprintf(alct, "%d:%d invalid op.\n", t->line, t->col));
         }
     } else {
-        errmsg = safe_sprintf(alct, "%d:%d expect op.\n", t->line, t->col);
-        return (struct result){.value = NULL, .errmsg = errmsg};
+        return err(safe_sprintf(alct, "%d:%d expect op.\n", t->line, t->col));
     }
-    return (struct result){.value = (void*)op, .errmsg = NULL};
+    return ok((void*)op);
 }
 
 struct result parse_instr(struct allocator * alct, struct token_stream * ts) {
-    struct result result;
     struct token * t;
-    result = peek_token(alct, ts);
-    if (result.errmsg != NULL) return result;
-    t = result.value;
+    t = unwrap(peek_token(alct, ts));
     struct instr * i = allocate(alct, sizeof(struct instr));
     i->tag_name = NULL;
     i->arg = NULL;
     i->op = OP_END;
     if (t->type == TK_OP) {
-        result = parse_op(alct, ts);
-        i->op = (enum op)(result.value);
-        result = peek_token(alct, ts);
-        if (result.errmsg != NULL) return result;
-        t = result.value;
+        i->op = (enum op)unwrap(parse_op(alct, ts));
+        t = unwrap(peek_token(alct, ts));
         if (t->type == TK_ARG) {
             struct arg * a = allocate(alct, sizeof(struct arg));
             a->ival = t->ival;
             a->fval = t->fval;
             i->arg = a;
-            next_token(alct, ts);
+            unwrap(next_token(alct, ts));
         } else if (t->type == TK_TAG) {
             i->tag_name = t->sval;
-            next_token(alct, ts);
+            unwrap(next_token(alct, ts));
         }
     }
-    return (struct result){.value = i, .errmsg = NULL};
+    return ok(i);
 }

+ 11 - 0
src/as_parser.h

@@ -34,11 +34,22 @@ struct prog {
     struct stmts * stmts;
 };
 
+// result<prog>
 struct result parse_prog(struct allocator * alct, struct token_stream * ts);
+
+// result<stmt>
 struct result parse_stmt(struct allocator * alct, struct token_stream * ts);
+
+// result<stmts>
 struct result parse_stmts(struct allocator * alct, struct token_stream * ts);
+
+// result<instr>
 struct result parse_instr(struct allocator * alct, struct token_stream * ts);
+
+// result<label>
 struct result parse_label(struct allocator * alct, struct token_stream * ts);
+
+// result<enum op>
 struct result parse_op(struct allocator * alct, struct token_stream * ts);
 
 #endif

+ 12 - 16
src/as_tokenizer.c

@@ -83,12 +83,12 @@ struct result next_token_impl(struct allocator * alct, struct input_stream * s)
         if (c == '\n') {
             input_stream_next_char(s);
             *t = (struct token){.type = TK_NEWLINE, .line = s->line, .col = s->col};
-            return (struct result){.value = t, .errmsg = NULL};
+            return ok(t);
         }
         if (c == ':') {
             input_stream_next_char(s);
             *t = (struct token){.type = TK_COLON, .line = s->line, .col = s->col};
-            return (struct result){.value = t, .errmsg = NULL};
+            return ok(t);
         }
         if (c == ' ' || c == '\t') {
             input_stream_next_char(s);
@@ -105,7 +105,7 @@ struct result next_token_impl(struct allocator * alct, struct input_stream * s)
                 }
             } 
             *t = (struct token){.type = TK_ARG, .ival = ival, .line = s->line, .col = s->col};
-            return (struct result){.value = t, .errmsg = NULL};
+            return ok(t);
         }
         if (is_start_of_identifier(c)) {
             size_t line = s->line;
@@ -114,8 +114,7 @@ struct result next_token_impl(struct allocator * alct, struct input_stream * s)
             size_t i = 0;
             while (1) {
                 if (i >= 255) {
-                    errmsg = safe_sprintf(alct, "error: identifier too long\n");
-                    return (struct result){.value = NULL, .errmsg = errmsg};
+                    return err(safe_sprintf(alct, "error: identifier too long\n"));
                 }
                 input_stream_next_char(s);
                 sval[i++] = c;
@@ -127,36 +126,33 @@ struct result next_token_impl(struct allocator * alct, struct input_stream * s)
             sval[i] = '\0';
             if (isOp(sval)) {
                 *t = (struct token){.type = TK_OP, .sval = sval, .line = line, .col = col};
-                return (struct result){.value = t, .errmsg = NULL};
+                return ok(t);
             }
             *t = (struct token){.type = TK_TAG, .sval = sval, .line = line, .col = col};
-            return (struct result){.value = t, .errmsg = NULL};
+            return ok(t);
         }
-        errmsg = safe_sprintf(alct, "error: invalid character %c at line %d, col %d\n", c, s->line, s->col);
-        return (struct result){.value = NULL, .errmsg = errmsg};
+        return err(safe_sprintf(alct, "error: invalid character %c at line %d, col %d\n", c, s->line, s->col));
     }
     // end of file
     *t = (struct token){.type = TK_ENDOFFILE};
-    return (struct result){.value = t, .errmsg = NULL};
+    return ok(t);
 }
 
 struct result next_token(struct allocator * alct, struct token_stream * ts) {
     if (ts->buf != NULL) {
         struct token * t = ts->buf;
         ts->buf = NULL;
-        return (struct result){.value = t, .errmsg = NULL};
+        return ok(t);
     }
     return next_token_impl(alct, ts->s);
 }
 
 struct result peek_token(struct allocator * alct, struct token_stream * ts) {
     if (ts->buf != NULL) {
-        return (struct result){.value = ts->buf, .errmsg = NULL};
+        return ok(ts->buf);
     }
-    struct result result = next_token_impl(alct, ts->s);
-    if (result.errmsg != NULL) return result;
-    ts->buf = result.value;
-    return result;
+    ts->buf = unwrap(next_token_impl(alct, ts->s));
+    return ok(ts->buf);
 }
 
 void print_token(struct token  * t) {

+ 8 - 0
src/utils.c

@@ -4,6 +4,14 @@
 #include <assert.h>
 #include <stdarg.h>
 
+struct result ok(void *value) {
+    return (struct result){.value = value, .errmsg = NULL};
+}
+
+struct result err(const char *errmsg) {
+    return (struct result){.value = NULL, .errmsg = errmsg};
+}
+
 struct allocator {
     void** bufs;
     size_t cap;

+ 8 - 0
src/utils.h

@@ -10,6 +10,14 @@ struct result {
     const char* errmsg;
 };
 
+#define unwrap(x__) ({ \
+    struct result res__ = (x__); \
+    if (res__.errmsg != NULL) return res__; \
+    res__.value;})
+
+struct result ok(void *value);
+struct result err(const char *errmsg);
+
 struct allocator * new_allocator();
 void delete_allocator(struct allocator * allocator);