aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimbeer <himbeer@disroot.org>2024-10-07 13:32:07 +0200
committerHimbeer <himbeer@disroot.org>2024-10-07 13:32:07 +0200
commit991d4095ba596c55ef4d043a496d5cf63fd667d1 (patch)
tree81b8cbb600c8c57c00b7df01fa9cea5563de23ee
parent5ba544c4e016de3d61a296ceeaf7c4a143f3c118 (diff)
Implement expression-based language redesign
This is the implementation of commit ce68792c848caee2f184e7a6392d9f1e958da1a1.
-rw-r--r--include/cmd.h66
-rw-r--r--include/expr.h69
-rw-r--r--include/parse.h109
-rw-r--r--src/parse.c94
4 files changed, 183 insertions, 155 deletions
diff --git a/include/cmd.h b/include/cmd.h
new file mode 100644
index 0000000..2cf69b4
--- /dev/null
+++ b/include/cmd.h
@@ -0,0 +1,66 @@
+#ifndef CERC_CMD_H
+#define CERC_CMD_H
+#include "type.h"
+
+struct ast_return {
+ struct ast_expr *value;
+};
+
+struct ast_break {
+ const char *label;
+ struct ast_expr *value;
+};
+
+struct ast_declaration {
+ bool mut;
+ const char *name;
+ struct ast_expr *value;
+};
+
+enum statement {
+ STM_RETURN,
+ STM_BREAK,
+ STM_CONTINUE,
+ STM_DECL,
+ STM_DEFER,
+};
+
+struct ast_statement {
+ enum statement action;
+ union {
+ struct ast_return ret;
+ struct ast_break brk;
+ struct ast_declaration decl;
+ struct assign_e *assign;
+ struct call_e *call;
+ } stmt;
+};
+
+struct ast_func {
+ bool exported;
+ const char *name;
+ struct type *ret;
+ struct ast_param *params;
+ int paramsz, paramlen;
+ struct ast_block *block;
+};
+struct ast_block {
+ const char *label;
+ struct ast_cmd *cmds;
+ int cmdsz, cmdlen;
+};
+
+enum command {
+ CMD_BLOCK,
+ CMD_STATEMENT,
+};
+
+struct ast_cmd {
+ enum command kind;
+ union {
+ struct ast_block blk;
+ struct ast_statement stmt;
+ } cmd;
+};
+
+#endif
diff --git a/include/expr.h b/include/expr.h
index 5a16f30..5f57349 100644
--- a/include/expr.h
+++ b/include/expr.h
@@ -1,6 +1,7 @@
#ifndef CERC_EXPR_H
#define CERC_EXPR_H
#include <stdbool.h>
+#include "cmd.h"
#include "lex.h"
#include "type.h"
@@ -15,6 +16,38 @@ struct array_e {
int elemsz, elemlen;
};
+struct elseif {
+ struct disjunction_e *cond;
+ struct ast_block blk;
+};
+
+struct if_e {
+ struct disjunction_e *cond;
+ struct ast_block blk;
+ struct elseif *alts;
+ struct ast_block *alt;
+ int altsz, altlen;
+};
+
+struct for_e {
+ struct ast_assign *init, *action;
+ struct disjunction_e *cond;
+ struct ast_block blk;
+};
+
+enum control {
+ CTL_IF,
+ CTL_FOR,
+};
+
+struct control_e {
+ enum control kind;
+ union {
+ struct if_e branch;
+ struct for_e loop;
+ } ctl;
+};
+
enum literal {
LIT_BOOL,
LIT_STRING,
@@ -32,26 +65,52 @@ struct literal_e {
} lit;
};
-struct call_e {
+struct location_e {
struct path *path;
+ struct loc_postfix *subs;
+ int subsz, sublen;
+};
+
+struct assign_e {
+ struct location_e dst;
+ struct ast_expr *value;
+};
+
+struct call_e {
+ struct location_e *loc;
struct disjunction_e *args;
int argsz, arglen;
};
+enum named {
+ NMD_ASSIGN,
+ NMD_CALL,
+ NMD_LOCATION,
+};
+
+struct named_e {
+ enum named kind;
+ struct location_e loc;
+ union {
+ struct assign_e assign;
+ struct call_e call;
+ } nmd;
+};
+
enum primary {
+ PRM_CONTROL,
PRM_GROUPING,
PRM_LITERAL,
- PRM_CALL,
- PRM_PATH,
+ PRM_NAMED,
};
struct primary_e {
enum primary kind;
union {
+ struct control_e ctl;
struct disjunction_e *grp;
struct literal_e lit;
- struct call_e call;
- struct path *path;
+ struct named_e nmd;
} prim;
};
diff --git a/include/parse.h b/include/parse.h
index 0889f91..5b97353 100644
--- a/include/parse.h
+++ b/include/parse.h
@@ -18,27 +18,6 @@ struct ast_param {
struct type type;
};
-struct ast_block {
- const char *label;
- struct ast_cmd *cmds;
- int cmdsz, cmdlen;
-};
-
-struct ast_return {
- struct ast_expr *value;
-};
-
-struct ast_break {
- const char *label;
- struct ast_expr *value;
-};
-
-struct ast_declaration {
- bool mut;
- const char *name;
- struct ast_expr value;
-};
-
enum subfield {
SUB_INDEX,
SUB_FIELD,
@@ -52,94 +31,6 @@ struct loc_postfix {
} id;
};
-struct ast_location {
- const char *name;
- struct loc_postfix *subs;
- int subsz, sublen;
-};
-
-struct ast_assign {
- struct ast_location dst;
- struct ast_expr value;
-};
-
-enum statement {
- STM_RETURN,
- STM_BREAK,
- STM_CONTINUE,
- STM_DECL,
- STM_ASSIGN,
- STM_CALL,
- STM_DEFER,
-};
-
-struct ast_statement {
- enum statement action;
- union {
- struct ast_return ret;
- struct ast_break brk;
- struct ast_declaration decl;
- struct ast_assign assign;
- struct call_e call;
- } stmt;
-};
-
-struct ast_elseif {
- struct ast_expr cond;
- struct ast_block blk;
-};
-
-struct ast_if {
- struct ast_expr cond;
- struct ast_block blk;
- struct ast_elseif *alts;
- struct ast_block *alt;
- int altsz, altlen;
-};
-
-struct ast_for {
- struct ast_assign *init, *action;
- struct ast_expr cond;
- struct ast_block blk;
-};
-
-enum control {
- CTL_IF,
- CTL_FOR,
-};
-
-struct ast_control {
- enum control kind;
- union {
- struct ast_if branch;
- struct ast_for loop;
- } ctl;
-};
-
-enum command {
- CMD_BLOCK,
- CMD_STATEMENT,
- CMD_CONTROL,
-};
-
-struct ast_cmd {
- enum command kind;
- union {
- struct ast_block blk;
- struct ast_statement stmt;
- struct ast_control ctl;
- } cmd;
-};
-
-struct ast_func {
- bool exported;
- const char *name;
- struct type ret;
- struct ast_param *params;
- int paramsz, paramlen;
- struct ast_block block;
-};
-
enum const_global {
CST_TYPE,
CST_BOOL,
diff --git a/src/parse.c b/src/parse.c
index ee115d8..c5ced09 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -12,6 +12,9 @@ static bool parse_disjunction_e(struct lexer *lexer,
static bool parse_array(struct lexer *lexer, struct type *out);
static bool parse_type(struct lexer *lexer, struct type *out);
static bool parse_block(struct lexer *lexer, struct ast_block *out);
+static bool parse_control_e(struct lexer *lexer, struct control_e *out);
+static bool parse_location(struct lexer *lexer, struct location_e *out);
+static bool parse_assignment_e(struct lexer *lexer, struct assign_e *out);
static noreturn void
error(struct location loc, const char *fmt, ...)
@@ -188,14 +191,13 @@ parse_literal_e(struct lexer *lexer, struct literal_e *out)
// Invariant: Only called from parse_primary_e with path already consumed.
static bool
-parse_call_e(struct lexer *lexer, struct call_e *out, struct path path)
+parse_call_e(struct lexer *lexer, struct call_e *out, struct location_e *loc)
{
if (!match(lexer, T_LPAREN)) {
return false;
}
- out->path = must_malloc(sizeof(struct path));
- *out->path = path;
+ out->loc = loc;
out->args = must_calloc(1, sizeof(struct disjunction_e));
out->argsz = 1;
@@ -219,8 +221,32 @@ parse_call_e(struct lexer *lexer, struct call_e *out, struct path path)
}
static bool
+parse_named_e(struct lexer *lexer, struct named_e *out)
+{
+ if (!parse_location(lexer, &out->loc)) {
+ return false;
+ }
+
+ if (parse_assignment_e(lexer, &out->nmd.assign)) {
+ out->kind = NMD_ASSIGN;
+ return true;
+ }
+ if (parse_call_e(lexer, &out->nmd.call, &out->loc)) {
+ out->kind = NMD_CALL;
+ return true;
+ }
+
+ out->kind = NMD_LOCATION;
+ return true;
+}
+
+static bool
parse_primary_e(struct lexer *lexer, struct primary_e *out)
{
+ if (parse_control_e(lexer, &out->prim.ctl)) {
+ out->kind = PRM_CONTROL;
+ return true;
+ }
out->prim.grp = must_malloc(sizeof(struct disjunction_e));
if (parse_grouping_e(lexer, out->prim.grp)) {
out->kind = PRM_GROUPING;
@@ -231,14 +257,12 @@ parse_primary_e(struct lexer *lexer, struct primary_e *out)
out->kind = PRM_LITERAL;
return true;
}
- out->prim.path = must_malloc(sizeof(struct path));
- if (parse_path(lexer, out->prim.path)) {
- out->kind = PRM_PATH;
- if (parse_call_e(lexer, &out->prim.call, *out->prim.path)) {
- out->kind = PRM_CALL;
- }
+ if (parse_named_e(lexer, &out->prim.nmd)) {
+ out->kind = PRM_NAMED;
return true;
}
+
+ return false;
}
static bool
@@ -1178,7 +1202,8 @@ parse_declaration(struct lexer *lexer, struct ast_declaration *out)
error(lex_loc(lexer), "syntax error: expected '='");
}
- if (!parse_expr(lexer, &out->value)) {
+ out->value = must_malloc(sizeof(struct ast_expr));
+ if (!parse_expr(lexer, out->value)) {
error(lex_loc(lexer), "syntax error: expected expression");
}
@@ -1235,11 +1260,11 @@ parse_loc_postfix(struct lexer *lexer, struct loc_postfix *out)
}
static bool
-parse_location(struct lexer *lexer, struct ast_location *out)
+parse_location(struct lexer *lexer, struct location_e *out)
{
- struct token name;
- if (lex(lexer, &name) != T_NAME) {
- unlex(lexer, &name);
+ out->path = must_malloc(sizeof(struct path));
+ if (!parse_path(lexer, out->path)) {
+ free(out->path);
return false;
}
@@ -1261,7 +1286,7 @@ parse_location(struct lexer *lexer, struct ast_location *out)
}
static bool
-parse_assignment(struct lexer *lexer, struct ast_assign *out)
+parse_assignment_e(struct lexer *lexer, struct assign_e *out)
{
if (!parse_location(lexer, &out->dst)) {
return false;
@@ -1271,7 +1296,8 @@ parse_assignment(struct lexer *lexer, struct ast_assign *out)
error(lex_loc(lexer), "syntax error: expected '='");
}
- if (!parse_expr(lexer, &out->value)) {
+ out->value = must_malloc(sizeof(struct ast_expr));
+ if (!parse_expr(lexer, out->value)) {
error(lex_loc(lexer), "syntax error: expected expression");
}
@@ -1292,12 +1318,12 @@ parse_defer(struct lexer *lexer, struct call_e *out)
return false;
}
- struct path path;
- if (!parse_path(lexer, &path)) {
+ struct location_e *loc = must_malloc(sizeof(struct location_e));
+ if (!parse_location(lexer, loc)) {
error(lex_loc(lexer), "syntax error: expected path");
}
- if (!parse_call_e(lexer, out, path)) {
+ if (!parse_call_e(lexer, out, loc)) {
error(lex_loc(lexer), "syntax error: expected call");
}
@@ -1335,33 +1361,21 @@ parse_statement(struct lexer *lexer, struct ast_statement *out)
}
return true;
}
- if (parse_assignment(lexer, &out->stmt.assign)) {
- out->action = STM_ASSIGN;
- if (!match(lexer, T_SEMICOLON)) {
- error(lex_loc(lexer), "syntax error: expected semicolon");
- }
- return true;
- }
- if (parse_call(lexer, &out->stmt.call)) {
- out->action = STM_CALL;
- if (!match(lexer, T_SEMICOLON)) {
- error(lex_loc(lexer), "syntax error: expected semicolon");
- }
- return true;
- }
- if (parse_defer(lexer, &out->stmt.call)) {
+ out->stmt.call = must_malloc(sizeof(struct call_e));
+ if (parse_defer(lexer, out->stmt.call)) {
out->action = STM_DEFER;
if (!match(lexer, T_SEMICOLON)) {
error(lex_loc(lexer), "syntax error: expected semicolon");
}
return true;
}
+ free(out->stmt.call);
return false;
}
static bool
-parse_control(struct lexer *lexer, struct ast_control *out)
+parse_control_e(struct lexer *lexer, struct control_e *out)
{
/* TODO */
return false;
@@ -1378,10 +1392,6 @@ parse_command(struct lexer *lexer, struct ast_cmd *out)
out->kind = CMD_STATEMENT;
return true;
}
- if (parse_control(lexer, &out->cmd.ctl)) {
- out->kind = CMD_CONTROL;
- return true;
- }
return false;
}
@@ -1476,9 +1486,11 @@ parse_function(struct lexer *lexer, struct ast_func *out)
error(lex_loc(lexer), "syntax error: expected ')'");
}
- bool nonvoid = parse_type(lexer, &out->ret);
+ out->ret = must_malloc(sizeof(struct type));
+ bool nonvoid = parse_type(lexer, out->ret);
- if (!parse_block(lexer, &out->block)) {
+ out->block = must_malloc(sizeof(struct ast_block));
+ if (!parse_block(lexer, out->block)) {
error(lex_loc(lexer), "syntax error: expected block");
}