diff options
-rw-r--r-- | cgen.c | 54 | ||||
-rw-r--r-- | decls_cgen.c | 14 | ||||
-rw-r--r-- | eval.c | 93 | ||||
-rw-r--r-- | main.c | 6 | ||||
-rw-r--r-- | parse.c | 31 | ||||
-rw-r--r-- | std/io.toc | 23 | ||||
-rw-r--r-- | test.toc | 20 | ||||
-rw-r--r-- | tokenizer.c | 4 | ||||
-rw-r--r-- | types.c | 25 | ||||
-rw-r--r-- | types.h | 5 |
10 files changed, 199 insertions, 76 deletions
@@ -266,11 +266,11 @@ static inline void cgen_ident_simple(CGenerator *g, Identifier i) { } static void cgen_ident(CGenerator *g, Identifier i) { - if (g->block && (g->block->flags & BLOCK_IS_NMS)) { + if (g->block && (g->block->flags & BLOCK_IS_NMS) && !g->fn) { /* namespace prefix */ cgen_write(g, "%s", g->nms_prefix); } - if (i == g->main_ident) { + if (i == g->main_ident && ident_decl(i) && ident_decl(i)->scope == NULL) { /* don't conflict with C's main! */ cgen_write(g, "main__"); } else { @@ -285,15 +285,21 @@ static inline void cgen_ident_id_to_str(char *buffer, IdentID id) { snprintf(buffer, 32, "a%lu_", (unsigned long)id); } -/* does NOT include __ */ static char *cgen_nms_prefix(CGenerator *g, Namespace *n) { char *s; if (n->associated_ident) { - s = cgen_ident_to_str(n->associated_ident); + size_t ident_len = n->associated_ident->len; + s = malloc(ident_len + 3); + memcpy(s, n->associated_ident->str, ident_len); + s[ident_len] = '_'; + s[ident_len+1] = '_'; + s[ident_len+2] = '\0'; } else { - s = malloc(CGEN_IDENT_ID_STR_SIZE); + s = calloc(CGEN_IDENT_ID_STR_SIZE + 1, 1); if (!n->c.id) n->c.id = ++g->ident_counter; cgen_ident_id_to_str(s, n->c.id); + s[strlen(s)] = '_'; + } return s; } @@ -301,22 +307,17 @@ static char *cgen_nms_prefix(CGenerator *g, Namespace *n) { static void cgen_nms_enter(CGenerator *g, Namespace *n) { char *s = cgen_nms_prefix(g, n); size_t chars_so_far = arr_len(g->nms_prefix) - 1; /* -1 for '\0' byte */ - size_t new_chars = strlen(s); + size_t new_chars = strlen(s) + 1; /* + 1 for '\0' byte */ arr_set_len(&g->nms_prefix, chars_so_far + new_chars); for (size_t i = 0; i < new_chars; ++i) { g->nms_prefix[i+chars_so_far] = s[i]; } - *(char *)arr_add(&g->nms_prefix) = '_'; - if (n->associated_ident) - *(char *)arr_add(&g->nms_prefix) = '_'; - *(char *)arr_add(&g->nms_prefix) = '\0'; free(s); } static void cgen_nms_exit(CGenerator *g, Namespace *n) { char *s = cgen_nms_prefix(g, n); - bool double_underscore = n->associated_ident != NULL; - arr_set_len(&g->nms_prefix, arr_len(g->nms_prefix) - strlen(s) - (double_underscore ? 2 : 1)); + arr_set_len(&g->nms_prefix, arr_len(g->nms_prefix) - strlen(s)); free(s); } @@ -549,7 +550,7 @@ static bool cgen_fn_args(CGenerator *g, FnExpr *f, U64 instance, U64 which_are_c if (!cgen_type_pre(g, type, f->where)) return false; cgen_write(g, " "); - cgen_ident(g, *i); + cgen_ident_simple(g, *i); if (!cgen_type_post(g, type, f->where)) return false; } @@ -1355,6 +1356,8 @@ static bool cgen_expr(CGenerator *g, Expression *e) { s = "*"; break; case BINARY_DIV: s = "/"; break; + case BINARY_MOD: + s = "%"; break; case BINARY_SET: if (!cgen_set(g, e->binary.lhs, NULL, e->binary.rhs, NULL)) return false; handled = true; @@ -1379,6 +1382,8 @@ static bool cgen_expr(CGenerator *g, Expression *e) { s = "*="; break; case BINARY_SET_DIV: s = "/="; break; + case BINARY_SET_MOD: + s = "%="; break; case BINARY_AT_INDEX: cgen_write(g, "("); switch (e->binary.lhs->type.kind) { @@ -1413,13 +1418,22 @@ static bool cgen_expr(CGenerator *g, Expression *e) { handled = true; break; case BINARY_DOT: { - - cgen_write(g, "("); - cgen_expr(g, e->binary.lhs); - bool is_ptr = e->binary.lhs->type.kind == TYPE_PTR; - cgen_write(g, is_ptr ? "->" :"."); - cgen_ident_simple(g, e->binary.dot.field->name); - cgen_write(g, ")"); + Type *struct_type = &e->binary.lhs->type; + if (struct_type->kind == TYPE_PTR) struct_type = struct_type->ptr; + if (struct_type->kind == TYPE_STRUCT) { + cgen_write(g, "("); + cgen_expr(g, e->binary.lhs); + bool is_ptr = e->binary.lhs->type.kind == TYPE_PTR; + cgen_write(g, is_ptr ? "->" :"."); + cgen_ident_simple(g, e->binary.dot.field->name); + cgen_write(g, ")"); + } else { + assert(type_is_builtin(struct_type, BUILTIN_NMS)); + char *prefix = cgen_nms_prefix(g, e->binary.lhs->val.nms); + cgen_write(g, "%s", prefix); + cgen_ident_simple(g, e->binary.rhs->ident); + free(prefix); + } handled = true; } break; } diff --git a/decls_cgen.c b/decls_cgen.c index f815c13..797443d 100644 --- a/decls_cgen.c +++ b/decls_cgen.c @@ -197,7 +197,7 @@ static bool cgen_decls_decl(CGenerator *g, Declaration *d) { if (!cgen_decls_expr(g, &d->expr)) return false; } - if (g->block == NULL && g->fn == NULL) { + if ((g->block == NULL || (g->block->flags & BLOCK_IS_NMS)) && g->fn == NULL) { for (int i = 0, n_idents = (int)arr_len(d->idents); i < n_idents; ++i) { Identifier ident = d->idents[i]; Type *type = decl_type_at_index(d, i); @@ -209,6 +209,18 @@ static bool cgen_decls_decl(CGenerator *g, Declaration *d) { cgen_ident(g, ident); if (!cgen_type_post(g, type, d->where)) return false; + if (g->block) { + assert(g->block->flags & BLOCK_IS_NMS); + if (d->flags & DECL_HAS_EXPR) { + Value *val = decl_val_at_index(d, i); + cgen_write(g, " = "); + if (!cgen_val(g, *val, type, d->where)) + return false; + } else { + cgen_write(g, " = "); + cgen_zero_value(g, type); + } + } cgen_write(g, ";"); cgen_nl(g); } @@ -734,45 +734,69 @@ static bool eval_expr_ptr_at_index(Evaluator *ev, Expression *e, void **ptr, Typ return eval_val_ptr_at_index(e->where, &arr, i, ltype, ptr, type); } +static bool eval_address_of_ident(Identifier i, Type *type, Location where, void **ptr) { + IdentDecl *id = ident_decl(i); + if (!(id->flags & IDECL_HAS_VAL)) { + if (id->kind == IDECL_DECL) { + Declaration *decl = id->decl; + if (!(decl->flags & DECL_IS_CONST) || !(decl->flags & DECL_FOUND_VAL)) goto runtime_var; + id->val = decl->val; + id->flags |= IDECL_HAS_VAL; + } else { + runtime_var: + err_print(where, "Cannot take address of run time variable at compile time."); + return false; + } + } + if (type->kind == TYPE_ARR) + *ptr = id->val.arr; /* point directly to data */ + else if (type->kind == TYPE_STRUCT) + *ptr = id->val.struc; + else + *ptr = &id->val; + return true; +} + static void *eval_ptr_to_struct_field(Evaluator *ev, Expression *dot_expr) { Type *struct_type = &dot_expr->binary.lhs->type; bool is_ptr = struct_type->kind == TYPE_PTR; if (is_ptr) { struct_type = struct_type->ptr; } - assert(struct_type->kind == TYPE_STRUCT); - eval_struct_find_offsets(struct_type->struc); + if (struct_type->kind == TYPE_STRUCT) { + eval_struct_find_offsets(struct_type->struc); - Value struc; - if (!eval_expr(ev, dot_expr->binary.lhs, &struc)) - return NULL; - void *struc_data; - if (is_ptr) { - struc_data = struc.ptr; - if (struc_data == NULL) { - err_print(dot_expr->where, "Attempt to dereference NULL pointer."); + Value struc; + if (!eval_expr(ev, dot_expr->binary.lhs, &struc)) return NULL; + void *struc_data; + if (is_ptr) { + struc_data = struc.ptr; + if (struc_data == NULL) { + err_print(dot_expr->where, "Attempt to dereference NULL pointer."); + return NULL; + } + } else { + struc_data = struc.struc; } + return (char *)struc_data + dot_expr->binary.dot.field->offset; } else { - struc_data = struc.struc; + void *ptr; + assert(type_is_builtin(struct_type, BUILTIN_NMS)); + Identifier translated = ident_translate(dot_expr->binary.rhs->ident, &dot_expr->binary.lhs->val.nms->idents); + if (!eval_address_of_ident(translated, &dot_expr->type, dot_expr->where, &ptr)) { + return NULL; + } + return ptr; } - return (char *)struc_data + dot_expr->binary.dot.field->offset; + } static bool eval_address_of(Evaluator *ev, Expression *e, void **ptr) { switch (e->kind) { case EXPR_IDENT: { - IdentDecl *id = ident_decl(e->ident); - if (!(id->flags & IDECL_HAS_VAL)) { - err_print(e->where, "Cannot take address of run time variable at compile time."); + if (!eval_address_of_ident(e->ident, &e->type, e->where, ptr)) return false; - } - if (e->type.kind == TYPE_ARR) - *ptr = id->val.arr; /* point directly to data */ - else if (e->type.kind == TYPE_STRUCT) - *ptr = id->val.struc; - else - *ptr = &id->val; } break; case EXPR_UNARY_OP: switch (e->unary.op) { @@ -799,10 +823,10 @@ static bool eval_address_of(Evaluator *ev, Expression *e, void **ptr) { Value struc; if (!eval_expr(ev, e->binary.lhs, &struc)) return false; + *ptr = eval_ptr_to_struct_field(ev, e); if (!*ptr) return false; - return true; } break; default: assert(0); return false; } @@ -894,7 +918,7 @@ static void eval_numerical_bin_op(Value lhs, Type *lhs_type, BinaryOp op, Value case BUILTIN_##up: \ out->low = (up)(lhs.low op rhs.low); break -#define eval_binary_op_nums(builtin, op) \ +#define eval_binary_op_ints(builtin, op) \ eval_binary_op_one(i8, I8, op); \ eval_binary_op_one(i16, I16, op); \ eval_binary_op_one(i32, I32, op); \ @@ -902,7 +926,10 @@ static void eval_numerical_bin_op(Value lhs, Type *lhs_type, BinaryOp op, Value eval_binary_op_one(u8, U8, op); \ eval_binary_op_one(u16, U16, op); \ eval_binary_op_one(u32, U32, op); \ - eval_binary_op_one(u64, U64, op); \ + eval_binary_op_one(u64, U64, op); + +#define eval_binary_op_nums(builtin, op) \ + eval_binary_op_ints(builtin, op); \ eval_binary_op_one(f32, F32, op); \ eval_binary_op_one(f64, F64, op) @@ -916,6 +943,15 @@ static void eval_numerical_bin_op(Value lhs, Type *lhs_type, BinaryOp op, Value default: assert(0); break; \ } +#define eval_binary_op_ints_only(op) \ + val_cast(&lhs, lhs_type, &lhs, out_type); \ + val_cast(&rhs, rhs_type, &rhs, out_type); \ + assert(out_type->kind == TYPE_BUILTIN); \ + switch (builtin) { \ + eval_binary_op_ints(builtin, op); \ + default: assert(0); break; \ + } + #define eval_binary_bool_op_one(low, up, op) \ case BUILTIN_##up: \ @@ -974,6 +1010,8 @@ static void eval_numerical_bin_op(Value lhs, Type *lhs_type, BinaryOp op, Value eval_binary_op_nums_only(*); break; case BINARY_DIV: eval_binary_op_nums_only(/); break; + case BINARY_MOD: + eval_binary_op_ints_only(%); break; case BINARY_LT: eval_binary_bool_op(<); break; case BINARY_LE: @@ -1194,6 +1232,7 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { case BINARY_SUB: case BINARY_MUL: case BINARY_DIV: + case BINARY_MOD: case BINARY_LT: case BINARY_LE: case BINARY_GT: @@ -1208,13 +1247,15 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) { case BINARY_SET_ADD: case BINARY_SET_SUB: case BINARY_SET_MUL: - case BINARY_SET_DIV: { + case BINARY_SET_DIV: + case BINARY_SET_MOD: { BinaryOp subop = (BinaryOp)0; switch (e->binary.op) { case BINARY_SET_ADD: subop = BINARY_ADD; break; case BINARY_SET_SUB: subop = BINARY_SUB; break; case BINARY_SET_MUL: subop = BINARY_MUL; break; case BINARY_SET_DIV: subop = BINARY_DIV; break; + case BINARY_SET_MOD: subop = BINARY_MOD; break; default: assert(0); } eval_numerical_bin_op(lhs, &e->binary.lhs->type, subop, rhs, &e->binary.rhs->type, v, &e->binary.lhs->type); @@ -18,14 +18,16 @@ /* TODO: -namespace try to remember why arr_set_len doesn't shrink, then write that reason there +make eval_ptr_to_struct_field return a bool nms["foo"] -make sure nms {foo:= 7; } works for cgen make sure #export still works properly fix cgen_ident_to_str for unicode idents check for leaks --- +nice syntax for importing something into a namespace +run stuff at compile time without assigning it to a constant +#compile_only declarations constants in structs #if @@ -80,6 +80,7 @@ static const char *binary_op_to_str(BinaryOp b) { case BINARY_SET_SUB: return "-="; case BINARY_SET_MUL: return "*="; case BINARY_SET_DIV: return "/="; + case BINARY_SET_MOD: return "%="; case BINARY_AT_INDEX: return "[]"; case BINARY_LT: return "<"; case BINARY_LE: return "<="; @@ -88,6 +89,7 @@ static const char *binary_op_to_str(BinaryOp b) { case BINARY_EQ: return "=="; case BINARY_NE: return "!="; case BINARY_DOT: return "."; + case BINARY_MOD: return "%"; } assert(0); return ""; @@ -931,6 +933,7 @@ static int op_precedence(Keyword op) { case KW_MINUS_EQ: case KW_ASTERISK_EQ: case KW_SLASH_EQ: + case KW_PERCENT_EQ: return 0; case KW_COMMA: return 1; case KW_LT: return 3; @@ -944,6 +947,7 @@ static int op_precedence(Keyword op) { case KW_AMPERSAND: return 25; case KW_ASTERISK: return 30; case KW_SLASH: return 40; + case KW_PERCENT: return 45; case KW_EXCLAMATION: return 50; case KW_DEL: return 1000; default: return NOT_AN_OP; @@ -1501,6 +1505,15 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { case KW_MINUS: op = BINARY_SUB; break; + case KW_ASTERISK: + op = BINARY_MUL; + break; + case KW_SLASH: + op = BINARY_DIV; + break; + case KW_PERCENT: + op = BINARY_MOD; + break; case KW_EQ_EQ: op = BINARY_EQ; break; @@ -1534,11 +1547,8 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { case KW_SLASH_EQ: op = BINARY_SET_DIV; break; - case KW_ASTERISK: - op = BINARY_MUL; - break; - case KW_SLASH: - op = BINARY_DIV; + case KW_PERCENT_EQ: + op = BINARY_SET_MOD; break; case KW_AMPERSAND: case KW_EXCLAMATION: @@ -2021,7 +2031,7 @@ static bool parse_stmt(Parser *p, Statement *s, bool *was_a_statement) { case KW_SEMICOLON: *was_a_statement = false; ++t->token; - return true; + goto success; case KW_RETURN: { s->kind = STMT_RET; ++t->token; @@ -2029,7 +2039,7 @@ static bool parse_stmt(Parser *p, Statement *s, bool *was_a_statement) { if (token_is_kw(t->token, KW_SEMICOLON)) { /* return with no expr */ ++t->token; - return true; + goto success; } s->ret.flags |= RET_HAS_EXPR; Token *end = expr_find_end(p, 0); @@ -2060,7 +2070,7 @@ static bool parse_stmt(Parser *p, Statement *s, bool *was_a_statement) { return false; } ++t->token; - return true; + goto success; } break; default: break; @@ -2079,7 +2089,7 @@ static bool parse_stmt(Parser *p, Statement *s, bool *was_a_statement) { tokr_skip_to_eof(t); return false; } - bool success = parse_expr(p, &s->expr, end); + bool valid = parse_expr(p, &s->expr, end); /* go past end of expr regardless of whether successful or not */ if (token_is_kw(end, KW_SEMICOLON)) { @@ -2089,8 +2099,9 @@ static bool parse_stmt(Parser *p, Statement *s, bool *was_a_statement) { t->token = end; } - if (!success) return false; + if (!valid) return false; } + success: s->where.end = t->token; return true; } @@ -29,6 +29,25 @@ stdout_fwrite ::= fn(data: &u8, size: u64, nmemb: u64) { }; puts ::= fn(x: []char) { - stdout_fwrite(&x[0] as &u8, 1, x.len as u64); - toc_putchar('\n'); + stdout_fwrite(&x[0] as &u8, 1, x.len as u64); + toc_putchar('\n'); }; + +puti ::= fn(x: int) { + if x < 0 { + toc_putchar('-'); + // NOTE: don't do x = -x; here to make sure I64_MIN works + } + abs ::= fn(x: int) int { if x < 0 { -x } else { x } }; + scan_digit := 1000000000000000000; + started := false; + while scan_digit > 0 { + digit := abs((x / scan_digit) % 10); + if digit > 0 { started = true; } + if started { + toc_putchar((('0' as int) + digit) as char); + } + scan_digit /= 10; + } + toc_putchar('\n'); +};
\ No newline at end of file @@ -1,10 +1,16 @@ +n ::= nms { + x := 1; + counter ::= fn() int { x += 1; x }; +}; + main ::= fn() { - x ::= nms { - f ::= fn() { - - }; - }; - // x.g(); -};
\ No newline at end of file + a := counter(); + b := counter(); + counter(); + c := counter(); + puti(a); + puti(b); + puti(c); +}; diff --git a/tokenizer.c b/tokenizer.c index b422f9e..723a4b3 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -5,9 +5,9 @@ */ static const char *const keywords[KW_COUNT] = {";", ":", ",", "(", ")", "{", "}", "[", "]", "==", - "+=", "-=", "*=", "/=", + "+=", "-=", "*=", "/=", "%=", "!=", "<=", "<", ">=", ">", - "+", "-", "*", "!", "&", "/", "..", ".", + "+", "-", "*", "!", "&", "/", "%", "..", ".", "=", "if", "elif", "else", "while", "for", "return", "fn", "as", "new", "del", "struct", @@ -382,9 +382,10 @@ static bool type_of_ident(Typer *tr, Location where, Identifier i, Type *t) { case IDECL_DECL: { Declaration *d = decl->decl; bool captured = false; - if (decl->scope != NULL) { + if (decl->scope != NULL && !(decl->scope->flags & BLOCK_IS_NMS)) { + Block *decl_scope = decl->scope; /* go back through scopes */ - for (Block **block = arr_last(tr->blocks); *block && *block != decl->scope; --block) { + for (Block **block = arr_last(tr->blocks); *block && *block != decl_scope; --block) { if ((*block)->flags & BLOCK_IS_FN) { captured = true; break; @@ -1855,6 +1856,7 @@ static bool types_expr(Typer *tr, Expression *e) { case BINARY_SET_SUB: case BINARY_SET_MUL: case BINARY_SET_DIV: + case BINARY_SET_MOD: if (!expr_must_lval(e->binary.lhs)) { return false; } @@ -1863,6 +1865,7 @@ static bool types_expr(Typer *tr, Expression *e) { case BINARY_SUB: case BINARY_MUL: case BINARY_DIV: + case BINARY_MOD: case BINARY_LT: case BINARY_GT: case BINARY_LE: @@ -1936,6 +1939,11 @@ static bool types_expr(Typer *tr, Expression *e) { /* lhs flexible, rhs ? */ *t = *rhs_type; } + if ((o == BINARY_MOD || o == BINARY_SET_MOD) + && type_builtin_is_float(t->builtin)) { + err_print(e->where, "Cannot use operator % on floating-point numbers."); + valid = false; + } } break; } } @@ -2056,6 +2064,8 @@ static bool types_expr(Typer *tr, Expression *e) { if (!eval_expr(tr->evalr, lhs, &nms_val)) return false; Namespace *nms = nms_val.nms; + lhs->kind = EXPR_VAL; + lhs->val.nms = nms; Identifier translated = ident_translate(rhs->ident, &nms->idents); if (!translated) { char *s = ident_to_str(rhs->ident); @@ -2151,7 +2161,8 @@ static bool types_block(Typer *tr, Block *b, U16 flags) { bool success = true; if (!typer_block_enter(tr, b)) return false; - + if (flags & TYPES_BLOCK_NAMESPACE) + b->flags |= BLOCK_IS_NMS; /* do this after typer_block_enter because otherwise it won't actually enter the block */ arr_foreach(b->stmts, Statement, s) { if (!types_stmt(tr, s)) { success = false; @@ -2185,7 +2196,6 @@ static bool types_block(Typer *tr, Block *b, U16 flags) { ret: if (flags & TYPES_BLOCK_NAMESPACE) { /* don't exit block because we don't want to have to re-enter each time we grab something from the namespace */ - b->flags |= BLOCK_IS_NMS; arr_remove_last(&tr->blocks); tr->block = *(Block **)arr_last(tr->blocks); } else { @@ -2241,7 +2251,10 @@ static bool types_decl(Typer *tr, Declaration *d) { d->type = d->expr.type; d->type.flags &= (TypeFlags)~(TypeFlags)TYPE_IS_FLEXIBLE; /* x := 5; => x is not flexible */ } - if ((d->flags & DECL_IS_CONST) || (tr->block == NULL && tr->fn == NULL)) { + bool need_value = (d->flags & DECL_IS_CONST) || + ((tr->block == NULL || (tr->block->flags & BLOCK_IS_NMS)) && tr->fn == NULL); + + if (need_value) { if (!(d->flags & DECL_FOUND_VAL)) { Value val; if (!eval_expr(tr->evalr, &d->expr, &val)) { @@ -2328,7 +2341,7 @@ static bool types_decl(Typer *tr, Declaration *d) { goto ret; } } - if (n_idents == 1 && d->expr.kind == EXPR_NMS) { + if (n_idents == 1 && (d->flags & DECL_HAS_EXPR) && d->expr.kind == EXPR_NMS) { bool is_at_top_level = true; typedef Block *BlockPtr; arr_foreach(tr->blocks, BlockPtr, b) { @@ -254,6 +254,7 @@ typedef enum { KW_MINUS_EQ, KW_ASTERISK_EQ, KW_SLASH_EQ, + KW_PERCENT_EQ, KW_NE, KW_LE, KW_LT, @@ -265,6 +266,7 @@ typedef enum { KW_EXCLAMATION, KW_AMPERSAND, KW_SLASH, + KW_PERCENT, KW_DOTDOT, KW_DOT, KW_EQ, @@ -532,10 +534,12 @@ typedef enum { BINARY_SUB, BINARY_MUL, BINARY_DIV, + BINARY_MOD, BINARY_SET_ADD, /* e.g. x += y */ BINARY_SET_SUB, BINARY_SET_MUL, BINARY_SET_DIV, + BINARY_SET_MOD, BINARY_GT, BINARY_LT, BINARY_GE, @@ -899,6 +903,7 @@ typedef struct Typer { /* for checking for problematic struct circular dependencies */ bool *is_reference_stack; ParsedFile *parsed_file; + Namespace *nms; } Typer; typedef struct CGenerator { |