From 8929fa724f66d3d653cd1b9d4bd119c31697d3f2 Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Sun, 1 Mar 2020 15:47:55 -0500 Subject: constants in structs --- copy.c | 7 +++++++ main.c | 20 ++++++++++++++------ parse.c | 45 +++++++++++++++++++++++++++------------------ test-build.sh | 8 ++++---- test.toc | 11 +++++++++-- types.c | 27 +++++++++++++++++++++++---- types.h | 4 +++- 7 files changed, 87 insertions(+), 35 deletions(-) diff --git a/copy.c b/copy.c index e0306e8..0699474 100644 --- a/copy.c +++ b/copy.c @@ -100,6 +100,13 @@ static void copy_struct(Copier *c, StructDef *out, StructDef *in) { for (size_t i = 0; i < nparams; ++i) { copy_decl(c, &out->params[i], &in->params[i]); } + out->constants = NULL; + size_t nconstants = arr_len(in->constants); + arr_set_lena(&out->constants, nconstants, c->allocr); + for (size_t i = 0; i < nconstants; ++i) { + copy_decl(c, &out->constants[i], &in->constants[i]); + } + c->block = prev; } diff --git a/main.c b/main.c index 41114a0..e4e1a18 100644 --- a/main.c +++ b/main.c @@ -8,14 +8,17 @@ /* TODO: -constants in structs #if variadic fns #foreign variadic fns #returns_code (function/struct body is a block, to be evaluated at compile time, which returns the actual statements -- you can use this for implementation of printf) -switch to / add as an alternative: libffi - +break +continue +switch +enums +macros --- +switch to / add as an alternative: libffi X ::= newtype(int); or something don't allow while {3; 5} or for 0..10 { 3; 5 } (once break is added) do we need was_expr? (now that, presumably, we have struct arguments) @@ -79,12 +82,17 @@ int main(int argc, char **argv) { err_ctx.color_enabled = true; for (int i = 1; i < argc; ++i) { - if (i > 1 && strs_equal(argv[i-1], "-o")) { - out_filename = argv[i]; - } else if ((i == 1 || argv[i-1][0] != '-') && argv[i][0] != '-') { + if ((i == 1 || argv[i-1][0] != '-') && argv[i][0] != '-') { in_filename = argv[i]; } else if (strs_equal(argv[i], "-no-color")) { err_ctx.color_enabled = false; + } else if (strs_equal(argv[i], "-o")) { + if (i == argc-1) { + fprintf(stderr, "-o cannot be the last argument to toc.\n"); + return EXIT_FAILURE; + } + out_filename = argv[i+1]; + ++i; } else { fprintf(stderr, "Unrecognized option: %s.\n", argv[i]); return EXIT_FAILURE; diff --git a/parse.c b/parse.c index bad5956..bdd7608 100644 --- a/parse.c +++ b/parse.c @@ -9,7 +9,8 @@ enum { PARSE_DECL_ALLOW_CONST_WITH_NO_EXPR = 0x01, PARSE_DECL_ALLOW_SEMI_CONST = 0x02, PARSE_DECL_ALLOW_INFER = 0x04, - PARSE_DECL_ALLOW_EXPORT = 0x08 + PARSE_DECL_ALLOW_EXPORT = 0x08, + PARSE_DECL_DONT_SET_IDECLS = 0x10 }; static Status parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, uint16_t flags); static Status parse_decl_list(Parser *p, Declaration **decls, DeclEndKind decl_end); @@ -597,6 +598,7 @@ static Status parse_type(Parser *p, Type *type) { struc->c.id = 0; struc->fields = NULL; struc->params = NULL; + struc->constants = NULL; struc->where = parser_mk_loc(p); struc->where.start = t->token; memset(&struc->scope, 0, sizeof struc->scope); @@ -637,26 +639,33 @@ static Status parse_type(Parser *p, Type *type) { { while (!token_is_kw(t->token, KW_RBRACE)) { Declaration field_decl; - if (!parse_decl(p, &field_decl, DECL_END_SEMICOLON, 0)) { + if (!parse_decl(p, &field_decl, DECL_END_SEMICOLON, PARSE_DECL_DONT_SET_IDECLS)) { goto struct_fail; } if (field_decl.flags & DECL_IS_CONST) { - /* TODO */ - err_print(field_decl.where, "Constant struct members are not supported (yet)."); - goto struct_fail; - } - if (field_decl.flags & DECL_HAS_EXPR) { - err_print(field_decl.where, "struct members cannot have initializers."); - goto struct_fail; + Declaration *d = parser_arr_add(p, &struc->constants); + *d = field_decl; + } else { + if (field_decl.flags & DECL_HAS_EXPR) { + err_print(field_decl.where, "struct members cannot have initializers."); + goto struct_fail; + } + long idx = 0; + arr_foreach(field_decl.idents, Identifier, fident) { + Type *ftype = field_decl.type.kind == TYPE_TUPLE ? &field_decl.type.tuple[idx] : &field_decl.type; + Field *f = parser_arr_add(p, &struc->fields); + f->name = *fident; + f->where = field_decl.where; + f->type = *ftype; + ++idx; + } } - long idx = 0; - arr_foreach(field_decl.idents, Identifier, fident) { - Type *ftype = field_decl.type.kind == TYPE_TUPLE ? &field_decl.type.tuple[idx] : &field_decl.type; - Field *f = parser_arr_add(p, &struc->fields); - f->name = *fident; - f->where = field_decl.where; - f->type = *ftype; - ++idx; + } + arr_foreach(struc->constants, Declaration, c) { + arr_foreach(c->idents, Identifier, ip) { + Identifier i = *ip; + i->decl = c; + i->decl_kind = IDECL_DECL; } } ++t->token; @@ -2181,7 +2190,7 @@ static Status parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, U16 f goto ret_false; } *ident = parser_ident_insert(p, t->token->ident); - if (!ident_eq_str(*ident, "_")) { + if (!(flags & PARSE_DECL_DONT_SET_IDECLS) && !ident_eq_str(*ident, "_")) { Identifier i = *ident; if (!check_ident_redecl(p, i)) goto ret_false; diff --git a/test-build.sh b/test-build.sh index 38f667a..370e329 100755 --- a/test-build.sh +++ b/test-build.sh @@ -1,8 +1,8 @@ #!/bin/sh for CC in tcc gcc clang g++ ; do - CC="$CC" ./build.sh || exit 1 - CC="$CC" ./build.sh release || exit 1 + CC="$CC" CFLAGS='-Werror' ./build.sh || exit 1 + CC="$CC" CFLAGS='-Werror' ./build.sh release || exit 1 done -./build.sh release || exit 1 -./build.sh || exit 1 +CFLAGS='-Werror' ./build.sh release || exit 1 +CFLAGS='-Werror' ./build.sh || exit 1 diff --git a/test.toc b/test.toc index 1e41663..43ed69b 100644 --- a/test.toc +++ b/test.toc @@ -1,8 +1,15 @@ #include "std/io.toc", io; +Foo ::= struct(n::=12) { + x ::= (n as float)*2.3; +}; main ::= fn() { - io.puts("Hello!"); - io.puti(17); + f : Foo(); + io.puti(f.n); + io.puti(f.x as int); + g : Foo(3); + io.puti(g.n); + io.puti(g.x as int); }; main(); \ No newline at end of file diff --git a/types.c b/types.c index 7b323b0..c518768 100644 --- a/types.c +++ b/types.c @@ -81,7 +81,7 @@ static Status struct_find_offsets(StructDef *s) { } s->flags |= STRUCT_DEF_FINDING_OFFSETS; size_t bytes = 0; - size_t total_align = 0; + size_t total_align = 1; arr_foreach(s->fields, Field, f) { size_t size = compiler_sizeof(&f->type); if (size == SIZE_MAX) { @@ -768,6 +768,12 @@ static Status type_resolve(Typer *tr, Type *t, Location where) { return false; } } + arr_foreach(t->struc->constants, Declaration, c) { + if (!types_decl(tr, c)) { + typer_block_exit(tr); + return false; + } + } typer_block_exit(tr); assert(tr->block != &t->struc->scope); t->struc->instance_id = 0; @@ -2480,6 +2486,7 @@ static Status types_expr(Typer *tr, Expression *e) { } } if (!is_field) { +#if 0 Declaration *param = NULL; int ident_idx; arr_foreach(struct_type->struc->params, Declaration, p) { @@ -2499,10 +2506,22 @@ static Status types_expr(Typer *tr, Expression *e) { err_print(e->where, "%s is not a member of structure %s.", member, struc); return false; } - /* replace with parameter value */ +#endif + Identifier i = ident_translate(rhs->ident, &struct_type->struc->scope.idents); + if (!i || i->decl_kind == IDECL_NONE) { + char *member = ident_to_str(rhs->ident); + char *struc_s = type_to_str(struct_type); + err_print(e->where, "%s is not a member of structure %s.", member, struc_s); + free(member); + free(struc_s); + return false; + } + assert((i->decl_kind == IDECL_DECL) && (i->decl->flags & DECL_IS_CONST)); + /* replace with decl value */ + int ident_idx = decl_ident_index(i->decl, i); e->kind = EXPR_VAL; - e->val = *decl_val_at_index(param, ident_idx); - *t = *decl_type_at_index(param, ident_idx); + e->val = *decl_val_at_index(i->decl, ident_idx); + *t = *decl_type_at_index(i->decl, ident_idx); break; } } else if (struct_type->kind == TYPE_SLICE || struct_type->kind == TYPE_ARR) { diff --git a/types.h b/types.h index b7c1b0b..f3fa76c 100644 --- a/types.h +++ b/types.h @@ -501,9 +501,10 @@ enum { }; typedef struct StructDef { Field *fields; + struct Declaration *constants; Location where; U8 flags; - Block scope; /* to make sure that parameters live somewhere. fields are not kept here. */ + Block scope; /* to make sure that parameters and constants live somewhere. fields are not kept here. */ union { HashTable instances; struct { @@ -831,6 +832,7 @@ typedef struct Expression { }; } Expression; + typedef struct Argument { Location where; char *name; /* NULL = no name */ -- cgit v1.2.3