summaryrefslogtreecommitdiff
path: root/src/runtime/c/pgf/expr.c
diff options
context:
space:
mode:
authorkr.angelov <kr.angelov@gmail.com>2012-01-20 13:41:10 +0000
committerkr.angelov <kr.angelov@gmail.com>2012-01-20 13:41:10 +0000
commit2eee382a62a909d5a3f2f5eda94f30fe68fd5335 (patch)
treeb0b0d513535895f244214aebf6358e172b8dce6d /src/runtime/c/pgf/expr.c
parentb9728357126f8b9a6311cca17d9f0dcc2a7bfb9b (diff)
initial import of the C runtime
Diffstat (limited to 'src/runtime/c/pgf/expr.c')
-rw-r--r--src/runtime/c/pgf/expr.c334
1 files changed, 334 insertions, 0 deletions
diff --git a/src/runtime/c/pgf/expr.c b/src/runtime/c/pgf/expr.c
new file mode 100644
index 000000000..cd5d69928
--- /dev/null
+++ b/src/runtime/c/pgf/expr.c
@@ -0,0 +1,334 @@
+#include "expr.h"
+#include <gu/intern.h>
+#include <gu/assert.h>
+#include <ctype.h>
+
+
+PgfExpr
+pgf_expr_unwrap(PgfExpr expr)
+{
+ while (true) {
+ GuVariantInfo i = gu_variant_open(expr);
+ switch (i.tag) {
+ case PGF_EXPR_IMPL_ARG: {
+ PgfExprImplArg* eimpl = i.data;
+ expr = eimpl->expr;
+ break;
+ }
+ case PGF_EXPR_TYPED: {
+ PgfExprTyped* etyped = i.data;
+ expr = etyped->expr;
+ break;
+ }
+ default:
+ return expr;
+ }
+ }
+}
+
+int
+pgf_expr_arity(PgfExpr expr)
+{
+ int n = 0;
+ while (true) {
+ PgfExpr e = pgf_expr_unwrap(expr);
+ GuVariantInfo i = gu_variant_open(e);
+ switch (i.tag) {
+ case PGF_EXPR_APP: {
+ PgfExprApp* app = i.data;
+ expr = app->fun;
+ n = n + 1;
+ break;
+ }
+ case PGF_EXPR_FUN:
+ return n;
+ default:
+ return -1;
+ }
+ }
+}
+
+PgfApplication*
+pgf_expr_unapply(PgfExpr expr, GuPool* pool)
+{
+ int arity = pgf_expr_arity(expr);
+ if (arity < 0) {
+ return NULL;
+ }
+ PgfApplication* appl = gu_new_flex(pool, PgfApplication, args, arity);
+ appl->n_args = arity;
+ for (int n = arity - 1; n >= 0; n--) {
+ PgfExpr e = pgf_expr_unwrap(expr);
+ gu_assert(gu_variant_tag(e) == PGF_EXPR_APP);
+ PgfExprApp* app = gu_variant_data(e);
+ appl->args[n] = app->arg;
+ expr = app->fun;
+ }
+ PgfExpr e = pgf_expr_unwrap(expr);
+ gu_assert(gu_variant_tag(e) == PGF_EXPR_FUN);
+ PgfExprFun* fun = gu_variant_data(e);
+ appl->fun = fun->fun;
+ return appl;
+}
+
+GU_DEFINE_TYPE(PgfBindType, enum,
+ GU_ENUM_C(PgfBindType, PGF_BIND_TYPE_EXPLICIT),
+ GU_ENUM_C(PgfBindType, PGF_BIND_TYPE_IMPLICIT));
+
+GU_DEFINE_TYPE(PgfLiteral, GuVariant,
+ GU_CONSTRUCTOR_S(PGF_LITERAL_STR, PgfLiteralStr,
+ GU_MEMBER(PgfLiteralStr, val, GuString)),
+ GU_CONSTRUCTOR_S(PGF_LITERAL_INT, PgfLiteralInt,
+ GU_MEMBER(PgfLiteralInt, val, int)),
+ GU_CONSTRUCTOR_S(PGF_LITERAL_FLT, PgfLiteralFlt,
+ GU_MEMBER(PgfLiteralFlt, val, double)));
+
+GU_DECLARE_TYPE(PgfType, struct);
+
+GU_DEFINE_TYPE(PgfHypo, struct,
+ GU_MEMBER(PgfHypo, bindtype, PgfBindType),
+ GU_MEMBER(PgfHypo, cid, PgfCId),
+ GU_MEMBER_P(PgfHypo, type, PgfType));
+
+GU_DEFINE_TYPE(PgfHypos, GuSeq, gu_type(PgfHypo));
+
+GU_DEFINE_TYPE(PgfType, struct,
+ GU_MEMBER(PgfType, hypos, PgfHypos),
+ GU_MEMBER(PgfType, cid, PgfCId),
+ GU_MEMBER(PgfType, n_exprs, GuLength),
+ GU_FLEX_MEMBER(PgfType, exprs, PgfExpr));
+
+GU_DEFINE_TYPE(
+ PgfExpr, GuVariant,
+ GU_CONSTRUCTOR_S(
+ PGF_EXPR_ABS, PgfExprAbs,
+ GU_MEMBER(PgfExprAbs, bind_type, PgfBindType),
+ GU_MEMBER(PgfExprAbs, id, GuStr),
+ GU_MEMBER(PgfExprAbs, body, PgfExpr)),
+ GU_CONSTRUCTOR_S(
+ PGF_EXPR_APP, PgfExprApp,
+ GU_MEMBER(PgfExprApp, fun, PgfExpr),
+ GU_MEMBER(PgfExprApp, arg, PgfExpr)),
+ GU_CONSTRUCTOR_S(
+ PGF_EXPR_LIT, PgfExprLit,
+ GU_MEMBER(PgfExprLit, lit, PgfLiteral)),
+ GU_CONSTRUCTOR_S(
+ PGF_EXPR_META, PgfExprMeta,
+ GU_MEMBER(PgfExprMeta, id, int)),
+ GU_CONSTRUCTOR_S(
+ PGF_EXPR_FUN, PgfExprFun,
+ GU_MEMBER(PgfExprFun, fun, GuStr)),
+ GU_CONSTRUCTOR_S(
+ PGF_EXPR_VAR, PgfExprVar,
+ GU_MEMBER(PgfExprVar, var, int)),
+ GU_CONSTRUCTOR_S(
+ PGF_EXPR_TYPED, PgfExprTyped,
+ GU_MEMBER(PgfExprTyped, expr, PgfExpr),
+ GU_MEMBER_P(PgfExprTyped, type, PgfType)),
+ GU_CONSTRUCTOR_S(
+ PGF_EXPR_IMPL_ARG, PgfExprImplArg,
+ GU_MEMBER(PgfExprImplArg, expr, PgfExpr)));
+
+
+typedef struct PgfExprParser PgfExprParser;
+
+struct PgfExprParser {
+ GuReader* rdr;
+ GuIntern* intern;
+ GuExn* err;
+ GuPool* expr_pool;
+ const char* lookahead;
+ int next_char;
+};
+
+
+static const char pgf_expr_lpar[] = "(";
+static const char pgf_expr_rpar[] = ")";
+static const char pgf_expr_semic[] = ";";
+
+static char
+pgf_expr_parser_next(PgfExprParser* parser)
+{
+ if (parser->next_char >= 0) {
+ char ret = (char) parser->next_char;
+ parser->next_char = -1;
+ return ret;
+ }
+ return gu_getc(parser->rdr, parser->err);
+}
+
+static const char*
+pgf_expr_parser_lookahead(PgfExprParser* parser)
+{
+ if (parser->lookahead != NULL) {
+ return parser->lookahead;
+ }
+ const char* str = NULL;
+ char c;
+ do {
+ c = pgf_expr_parser_next(parser);
+ if (!gu_ok(parser->err)) {
+ return NULL;
+ }
+ } while (isspace(c));
+ switch (c) {
+ case '(':
+ str = pgf_expr_lpar;
+ break;
+ case ')':
+ str = pgf_expr_rpar;
+ break;
+ case ';':
+ str = pgf_expr_semic;
+ break;
+ default:
+ if (isalpha(c)) {
+ GuPool* tmp_pool = gu_new_pool();
+ GuCharBuf* chars = gu_new_buf(char, tmp_pool);
+ while (isalnum(c) || c == '_') {
+ gu_buf_push(chars, char, c);
+ c = pgf_expr_parser_next(parser);
+ if (!gu_ok(parser->err)) {
+ return NULL;
+ }
+ }
+ parser->next_char = (unsigned char) c;
+ char* tmp_str = gu_chars_str(gu_buf_seq(chars),
+ tmp_pool);
+ str = gu_intern_str(parser->intern, tmp_str);
+ gu_pool_free(tmp_pool);
+ }
+ }
+ parser->lookahead = str;
+ return str;
+}
+
+static bool
+pgf_expr_parser_token_is_id(const char* str)
+{
+ if (str == NULL || !str[0]) {
+ return false;
+ }
+ char c = str[0];
+ return (isalpha(c) || c == '_');
+}
+
+static void
+pgf_expr_parser_consume(PgfExprParser* parser)
+{
+ pgf_expr_parser_lookahead(parser);
+ parser->lookahead = NULL;
+}
+
+static PgfExpr
+pgf_expr_parser_expr(PgfExprParser* parser);
+
+static PgfExpr
+pgf_expr_parser_term(PgfExprParser* parser)
+{
+ const char* la = pgf_expr_parser_lookahead(parser);
+
+ if (la == pgf_expr_lpar) {
+ pgf_expr_parser_consume(parser);
+ PgfExpr expr = pgf_expr_parser_expr(parser);
+ la = pgf_expr_parser_lookahead(parser);
+ if (la == pgf_expr_rpar) {
+ pgf_expr_parser_consume(parser);
+ return expr;
+ }
+ } else if (pgf_expr_parser_token_is_id(la)) {
+ pgf_expr_parser_consume(parser);
+ GuString s = gu_str_string(la, parser->expr_pool);
+ return gu_new_variant_i(parser->expr_pool,
+ PGF_EXPR_FUN,
+ PgfExprFun,
+ s);
+ }
+ return gu_null_variant;
+}
+
+static PgfExpr
+pgf_expr_parser_expr(PgfExprParser* parser)
+{
+ PgfExpr expr = pgf_expr_parser_term(parser);
+ if (gu_variant_is_null(expr))
+ {
+ return expr;
+ }
+ while (true) {
+ PgfExpr arg = pgf_expr_parser_term(parser);
+ if (gu_variant_is_null(arg)) {
+ return expr;
+ }
+ expr = gu_new_variant_i(parser->expr_pool,
+ PGF_EXPR_APP,
+ PgfExprApp,
+ expr, arg);
+ }
+}
+
+
+
+PgfExpr
+pgf_read_expr(GuReader* rdr, GuPool* pool, GuExn* err)
+{
+ GuPool* tmp_pool = gu_new_pool();
+ PgfExprParser* parser = gu_new(PgfExprParser, tmp_pool);
+ parser->rdr = rdr;
+ parser->intern = gu_new_intern(pool, tmp_pool);
+ parser->expr_pool = pool;
+ parser->err = err;
+ parser->lookahead = NULL;
+ parser->next_char = -1;
+ PgfExpr expr = pgf_expr_parser_expr(parser);
+ const char* la = pgf_expr_parser_lookahead(parser);
+ if (la == pgf_expr_semic) {
+ pgf_expr_parser_consume(parser);
+ } else {
+ expr = gu_null_variant;
+ }
+ gu_pool_free(tmp_pool);
+ return expr;
+}
+
+static void
+pgf_expr_print_with_paren(PgfExpr expr, bool need_paren,
+ GuWriter* wtr, GuExn* err)
+{
+ GuVariantInfo ei = gu_variant_open(expr);
+ switch (ei.tag) {
+ case PGF_EXPR_FUN: {
+ PgfExprFun* fun = ei.data;
+ gu_string_write(fun->fun, wtr, err);
+ break;
+ }
+ case PGF_EXPR_APP: {
+ PgfExprApp* app = ei.data;
+ if (need_paren) {
+ gu_puts("(", wtr, err);
+ }
+ pgf_expr_print_with_paren(app->fun, false, wtr, err);
+ gu_puts(" ", wtr, err);
+ pgf_expr_print_with_paren(app->arg, true, wtr, err);
+ if (need_paren) {
+ gu_puts(")", wtr, err);
+ }
+ break;
+ }
+ case PGF_EXPR_ABS:
+ case PGF_EXPR_LIT:
+ case PGF_EXPR_META:
+ case PGF_EXPR_VAR:
+ case PGF_EXPR_TYPED:
+ case PGF_EXPR_IMPL_ARG:
+ gu_impossible();
+ break;
+ default:
+ gu_impossible();
+ }
+}
+
+void
+pgf_expr_print(PgfExpr expr, GuWriter* wtr, GuExn* err) {
+ pgf_expr_print_with_paren(expr, false, wtr, err);
+}