diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2019-10-31 13:28:39 -0400 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2019-10-31 13:28:39 -0400 |
commit | 8ce406bdb55c19d83abb8f7511212ee0c02cb487 (patch) | |
tree | 837e2f0c7b4fb6621ab81ad9cad415a2c2035b0b | |
parent | fc6c746a726b3a56f2489c3db884c8ac2cd491d7 (diff) |
basic . operator
-rw-r--r-- | cgen.c | 11 | ||||
-rw-r--r-- | decls_cgen.c | 7 | ||||
-rw-r--r-- | eval.c | 16 | ||||
-rw-r--r-- | identifiers.c | 18 | ||||
-rw-r--r-- | main.c | 10 | ||||
-rw-r--r-- | parse.c | 42 | ||||
-rw-r--r-- | test.toc | 17 | ||||
-rw-r--r-- | tokenizer.c | 2 | ||||
-rw-r--r-- | typedefs_cgen.c | 7 | ||||
-rw-r--r-- | types.c | 72 | ||||
-rw-r--r-- | types.h | 7 |
11 files changed, 168 insertions, 41 deletions
@@ -698,7 +698,8 @@ static bool cgen_expr_pre(CGenerator *g, Expression *e) { break; case EXPR_BINARY_OP: if (!cgen_expr_pre(g, e->binary.lhs)) return false; - if (!cgen_expr_pre(g, e->binary.rhs)) return false; + if (e->binary.op != BINARY_DOT) + if (!cgen_expr_pre(g, e->binary.rhs)) return false; break; case EXPR_CAST: if (!cgen_expr_pre(g, e->cast.expr)) return false; @@ -862,6 +863,14 @@ static bool cgen_expr(CGenerator *g, Expression *e) { cgen_write(g, ")"); handled = true; break; + case BINARY_DOT: + cgen_write(g, "("); + cgen_expr(g, e->binary.lhs); + cgen_write(g, "."); + cgen_ident(g, e->binary.field->name); + cgen_write(g, ")"); + handled = true; + break; } if (handled) break; cgen_write(g, "("); diff --git a/decls_cgen.c b/decls_cgen.c index dcf5629..0a7a521 100644 --- a/decls_cgen.c +++ b/decls_cgen.c @@ -8,8 +8,11 @@ static bool cgen_decls_expr(CGenerator *g, Expression *e) { return false; break; case EXPR_BINARY_OP: - if (!cgen_decls_expr(g, e->binary.lhs) - || !cgen_decls_expr(g, e->binary.rhs)) + if (!cgen_decls_expr(g, e->binary.lhs)) + return false; + + if (e->binary.op != BINARY_DOT) + if (!cgen_decls_expr(g, e->binary.rhs)) return false; break; case EXPR_CAST: @@ -864,12 +864,22 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { } break; case EXPR_BINARY_OP: { Value lhs, rhs; - /* TODO(eventually): short-circuiting */ + Expression *lhs_expr = e->binary.lhs, *rhs_expr = e->binary.rhs; if (e->binary.op != BINARY_SET) - if (!eval_expr(ev, e->binary.lhs, &lhs)) return false; - if (!eval_expr(ev, e->binary.rhs, &rhs)) return false; + if (!eval_expr(ev, lhs_expr, &lhs)) return false; + if (e->binary.op != BINARY_DOT) + if (!eval_expr(ev, rhs_expr, &rhs)) return false; + BuiltinType builtin = e->binary.lhs->type.builtin; switch (e->binary.op) { + case BINARY_DOT: { + Type *inner_type = &e->binary.lhs->type; + while (inner_type->kind == TYPE_USER) + inner_type = ident_typeval(inner_type->user.name); + eval_struct_find_offsets(inner_type); + + eval_deref(v, (char *)lhs.struc + e->binary.field->offset, &e->type); + } break; case BINARY_ADD: if (e->binary.lhs->type.kind == TYPE_PTR) { v->ptr = (char *)lhs.ptr + val_to_i64(&rhs, e->binary.rhs->type.builtin) diff --git a/identifiers.c b/identifiers.c index c29f8ce..0465e12 100644 --- a/identifiers.c +++ b/identifiers.c @@ -200,3 +200,21 @@ static inline Type *ident_typeval(Identifier i) { if (!val) return NULL; return val->type; } + +static bool ident_eq_str(Identifier i, const char *s) { + const char *t = s + (strlen(s) - 1); + while (1) { + if (!i->parent) { + return false; + } + int c_low = i->parent->index_in_parent; + int c_high = i->index_in_parent; + int c = ident_uchar_to_char(c_low + (c_high << 4)); + if (c != *t) return false; + i = i->parent->parent; + if (t > s) t--; + else break; + } + if (i->parent) return false; /* not at root */ + return true; +} @@ -1,15 +1,19 @@ /* TODO: -dot +dot at run time +dot at compile time +dot + string +. lvalue +using dot with pointers length of slice/arr with .len verify size of struct, align of fields pointers to futurely-declared types don't allow while {3; 5} (once break is added) -allow omission of trailing ; in foo @= fn() {} any odd number of "s for a string modifiable strings: s := ["sakjdfhkjh ksjdahfkjsd ahs ahdf hsdaf khsadkjfh"]; -unicode variable names +unicode variable names (cgen support) +allow omission of trailing ; in foo @= fn() {}? */ #include "toc.c" @@ -55,6 +55,7 @@ static const char *binary_op_to_str(BinaryOp b) { case BINARY_GE: return ">="; case BINARY_EQ: return "=="; case BINARY_NE: return "!="; + case BINARY_DOT: return "."; } assert(0); return ""; @@ -617,18 +618,21 @@ static bool parser_is_definitely_type(Parser *p, Token **end) { if (paren_level == 0) { t->token++; if (token_is_kw(t->token, KW_LBRACE)) goto end; /* void fn expr */ - Token *child_end; - if (parser_is_definitely_type(p, &child_end)) { /* try return type */ - if (token_is_kw(t->token, KW_LBRACE)) { - /* non-void fn expr */ - goto end; - } + Type return_type; + t->token->where.ctx->enabled = false; + if (!parse_type(p, &return_type)) { + /* couldn't parse a return type. void fn type */ + ret = true; + goto end; } - /* it's a function type! */ + + if (token_is_kw(t->token, KW_LBRACE)) { + /* non-void fn expr */ + goto end; + } + /* it's a non-void function type */ ret = true; goto end; - - } break; default: break; @@ -847,7 +851,7 @@ static void fprint_expr(FILE *out, Expression *e); #define NOT_AN_OP -1 /* cast/new aren't really operators since they operate on types, not exprs. */ -#define CAST_PRECEDENCE 2 +#define CAST_PRECEDENCE 45 #define NEW_PRECEDENCE 22 static int op_precedence(Keyword op) { switch (op) { @@ -865,6 +869,7 @@ static int op_precedence(Keyword op) { case KW_ASTERISK: return 30; case KW_SLASH: return 40; case KW_EXCLAMATION: return 50; + case KW_DOT: return 60; case KW_DEL: return 1000; default: return NOT_AN_OP; } @@ -1291,6 +1296,9 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { case KW_SLASH: op = BINARY_DIV; break; + case KW_DOT: + op = BINARY_DOT; + break; case KW_AMPERSAND: case KW_EXCLAMATION: case KW_DEL: @@ -1794,14 +1802,20 @@ static void fprint_expr(FILE *out, Expression *e) { case EXPR_IDENT: fprint_ident(out, e->ident); break; - case EXPR_BINARY_OP: - fprintf(out, "%s", binary_op_to_str(e->binary.op)); + case EXPR_BINARY_OP: { + bool prev = parse_printing_after_types; fprintf(out, "("); fprint_expr(out, e->binary.lhs); - fprintf(out, ","); + fprintf(out, ")%s(", binary_op_to_str(e->binary.op)); + if (e->binary.op == BINARY_DOT) { + parse_printing_after_types = false; /* don't show types for rhs of . */ + } fprint_expr(out, e->binary.rhs); + if (e->binary.op == BINARY_DOT) { + parse_printing_after_types = prev; + } fprintf(out, ")"); - break; + } break; case EXPR_UNARY_OP: fprintf(out, "%s", unary_op_to_str(e->unary.op)); fprintf(out, "("); @@ -4,14 +4,19 @@ puti @= fn(x: int) { }; Point @= struct { - x, y : int; - something:fn(f32); - z,asdfasdfasdf:(int,int); - + x_coordinate, y_coordinate : int; }; main @= fn() { p:Point; -a:p; - // asasdfdsfa:(int,int); + x := p.({ + t @= int; + f @= fn() t { 7 as t }; + if f() as int > 3 { + "x_coordinate" + } else { + "y_coordinate" + } + }); + puti(x); }; diff --git a/tokenizer.c b/tokenizer.c index e6412a8..7ec5f1a 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -1,6 +1,6 @@ static const char *keywords[KW_COUNT] = {";", ":", "@", ",", "(", ")", "{", "}", "[", "]", "==", "!=", "<=", "<", ">=", ">", - "+", "-", "*", "!", "&", "/", + "+", "-", "*", "!", "&", "/", ".", "=", "if", "elif", "else", "while", "return", "fn", "as", "new", "del", "struct", diff --git a/typedefs_cgen.c b/typedefs_cgen.c index d6a3f5e..47122e0 100644 --- a/typedefs_cgen.c +++ b/typedefs_cgen.c @@ -17,9 +17,12 @@ static bool typedefs_expr(CGenerator *g, Expression *e) { return false; break; case EXPR_BINARY_OP: - if (!typedefs_expr(g, e->binary.lhs) - || !typedefs_expr(g, e->binary.rhs)) + if (!typedefs_expr(g, e->binary.lhs)) return false; + + if (e->binary.op != BINARY_DOT) + if (!typedefs_expr(g, e->binary.rhs)) + return false; break; case EXPR_CAST: if (!typedefs_expr(g, e->cast.expr)) @@ -16,6 +16,10 @@ static inline void *typer_arr_add_(Typer *tr, void **arr, size_t sz) { return arr_adda_(arr, sz, &tr->allocr); } +static inline bool type_is_builtin(Type *t, BuiltinType b) { + return t->kind == TYPE_BUILTIN && t->builtin == b; +} + #define typer_arr_add(tr, a) typer_arr_add_(tr, (void **)(a), sizeof **(a)) static bool type_eq(Type *a, Type *b) { @@ -940,13 +944,16 @@ static bool types_expr(Typer *tr, Expression *e) { Expression *rhs = e->binary.rhs; Type *lhs_type = &lhs->type; Type *rhs_type = &rhs->type; - if (!types_expr(tr, lhs) - || !types_expr(tr, rhs)) - return false; - if (lhs_type->kind == TYPE_UNKNOWN || rhs_type->kind == TYPE_UNKNOWN) { - return true; + BinaryOp o = e->binary.op; + if (o != BINARY_DOT) { + if (!types_expr(tr, lhs) + || !types_expr(tr, rhs)) + return false; + if (lhs_type->kind == TYPE_UNKNOWN || rhs_type->kind == TYPE_UNKNOWN) { + return true; + } } - switch (e->binary.op) { + switch (o) { case BINARY_SET: if (!expr_must_lval(e->binary.lhs)) { return false; @@ -972,7 +979,6 @@ static bool types_expr(Typer *tr, Expression *e) { case BINARY_GE: case BINARY_EQ: case BINARY_NE: { - BinaryOp o = e->binary.op; bool valid = false; if (o == BINARY_SET) { valid = type_eq(lhs_type, rhs_type); @@ -1074,6 +1080,58 @@ static bool types_expr(Typer *tr, Expression *e) { } } break; + case BINARY_DOT: { + if (!types_expr(tr, lhs)) return false; + Type *inner_type = lhs_type; + while (inner_type->kind == TYPE_USER) + inner_type = ident_typeval(inner_type->user.name); + if (inner_type->kind == TYPE_STRUCT) { + bool is_field = false; + if (rhs->kind == EXPR_IDENT) { + /* maybe accessing a field? */ + arr_foreach(inner_type->struc.fields, Field, f) { + if (f->name == rhs->ident) { + is_field = true; + *t = *f->type; + e->binary.field = f; + } + } + } + + if (!is_field) { + /* allow some_struct."foo" */ + Value field_name; + if (!types_expr(tr, rhs)) return false; + if (rhs_type->kind != TYPE_SLICE || !type_is_builtin(rhs_type->slice, BUILTIN_CHAR)) { + err_print(e->where, "Invalid field of type %s."); + return false; + + } + if (!eval_expr(tr->evalr, rhs, &field_name)) return false; + arr_foreach(inner_type->struc.fields, Field, f) { + if (ident_eq_str(f->name, field_name.slice.data)) { + is_field = true; + *t = *f->type; + e->binary.field = f; + } + } + if (!is_field) { + char *fstr = err_malloc(field_name.slice.n + 1); + memcpy(fstr, field_name.slice.data, field_name.slice.n); + fstr[field_name.slice.n] = 0; /* null-terminate */ + char *typestr = type_to_str(lhs_type); + err_print(e->where, "%s is not a field of structure %s.", fstr, typestr); + free(fstr); free(typestr); + return false; + } + } + } else { + char *s = type_to_str(lhs_type); + err_print(e->where, "Operator . applied to type %s, which is not a structure.", s); + free(s); + return false; + } + } break; } break; } break; case EXPR_TUPLE: @@ -165,6 +165,7 @@ typedef enum { KW_EXCLAMATION, KW_AMPERSAND, KW_SLASH, + KW_DOT, KW_EQ, KW_LAST_SYMBOL = KW_EQ, /* last one entirely consisting of symbols */ KW_IF, @@ -362,7 +363,8 @@ typedef enum { BINARY_LE, BINARY_EQ, BINARY_NE, - BINARY_AT_INDEX /* e.g. x[i] */ + BINARY_AT_INDEX, /* e.g. x[i] */ + BINARY_DOT } BinaryOp; typedef struct { @@ -436,7 +438,7 @@ typedef struct Expression { Type type; Location where; ExprKind kind; - uint16_t flags; + U16 flags; union { Floating floatl; /* Floating floatl; */ @@ -452,6 +454,7 @@ typedef struct Expression { BinaryOp op; struct Expression *lhs; struct Expression *rhs; + Field *field; /* for . only */ } binary; CallExpr call; DirectExpr direct; |