aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ast.h2
-rw-r--r--compile.c18
-rw-r--r--enums.c4
-rw-r--r--parse.c7
-rw-r--r--structs.c22
-rw-r--r--structs.h2
-rw-r--r--typecheck.c11
-rw-r--r--types.h3
8 files changed, 36 insertions, 33 deletions
diff --git a/ast.h b/ast.h
index 5ae03bb1..76485a28 100644
--- a/ast.h
+++ b/ast.h
@@ -293,7 +293,7 @@ struct ast_s {
const char *name;
arg_ast_t *fields;
ast_t *namespace;
- bool secret:1;
+ bool secret:1, external:1;
} StructDef;
struct {
const char *name;
diff --git a/compile.c b/compile.c
index 4c97c577..203c44aa 100644
--- a/compile.c
+++ b/compile.c
@@ -547,6 +547,7 @@ CORD compile_type(type_t *t)
case PointerType: return CORD_cat(compile_type(Match(t, PointerType)->pointed), "*");
case StructType: {
auto s = Match(t, StructType);
+ if (s->external) return CORD_all("struct ", s->name);
return CORD_all("struct ", namespace_prefix(s->env, s->env->namespace->parent), s->name, "$$struct");
}
case EnumType: {
@@ -3395,10 +3396,15 @@ CORD compile(env_t *env, ast_t *ast)
return "\"\"";
else if (call->args->value->tag == TextJoin && Match(call->args->value, TextJoin)->children->next == NULL)
return compile_string_literal(Match(Match(call->args->value, TextJoin)->children->ast, TextLiteral)->cord);
- return CORD_all("Text$as_c_string(", expr_as_text(env, compile(env, call->args->value), actual, "no"), ")");
- } else {
- code_err(ast, "I could not find a constructor matching these arguments for %T", t);
+ return CORD_all("Text$as_c_string(", expr_as_text(compile(env, call->args->value), actual, "no"), ")");
+ } else if (t->tag == StructType) {
+ auto struct_ = Match(t, StructType);
+ if (!struct_->opaque && is_valid_call(env, struct_->fields, call->args, true)) {
+ return CORD_all("((", compile_type(t), "){",
+ compile_arguments(env, ast, struct_->fields, call->args), "})");
+ }
}
+ code_err(ast, "I could not find a constructor matching these arguments for %T", t);
} else if (fn_t->tag == ClosureType) {
fn_t = Match(fn_t, ClosureType)->fn;
arg_t *type_args = Match(fn_t, FunctionType)->args;
@@ -4258,7 +4264,9 @@ CORD compile_top_level_code(env_t *env, ast_t *ast)
}
case StructDef: {
auto def = Match(ast, StructDef);
- CORD code = compile_struct_typeinfo(env, ast);
+ type_t *t = Table$str_get(*env->types, def->name);
+ assert(t && t->tag == StructType);
+ CORD code = compile_struct_typeinfo(env, t, def->name, def->fields, def->secret);
env_t *ns_env = namespace_env(env, def->name);
return CORD_all(code, def->namespace ? compile_top_level_code(ns_env, def->namespace) : CORD_EMPTY);
}
@@ -4277,6 +4285,7 @@ CORD compile_top_level_code(env_t *env, ast_t *ast)
env_t *ns_env = namespace_env(env, def->name);
return CORD_all(code, def->namespace ? compile_top_level_code(ns_env, def->namespace) : CORD_EMPTY);
}
+ case Extern: return CORD_EMPTY;
case Block: {
CORD code = CORD_EMPTY;
for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) {
@@ -4536,6 +4545,7 @@ static void _make_typedefs(compile_typedef_info_t *info, ast_t *ast)
{
if (ast->tag == StructDef) {
auto def = Match(ast, StructDef);
+ if (def->external) return;
CORD full_name = CORD_cat(namespace_prefix(info->env, info->env->namespace), def->name);
*info->header = CORD_all(*info->header, "typedef struct ", full_name, "$$struct ", full_name, "$$type;\n");
} else if (ast->tag == EnumDef) {
diff --git a/enums.c b/enums.c
index 9cb7a66b..811b42b7 100644
--- a/enums.c
+++ b/enums.c
@@ -24,8 +24,10 @@ CORD compile_enum_typeinfo(env_t *env, ast_t *ast)
if (!tag->fields) continue;
const char *tag_name = heap_strf("%s$%s", def->name, tag->name);
+ type_t *tag_type = Table$str_get(*env->types, tag_name);
+ assert(tag_type && tag_type->tag == StructType);
member_typeinfos = CORD_all(
- member_typeinfos, compile_struct_typeinfo(env, WrapAST(ast, StructDef, .name=tag_name, .fields=tag->fields, .secret=tag->secret)));
+ member_typeinfos, compile_struct_typeinfo(env, tag_type, tag_name, tag->fields, tag->secret));
}
int num_tags = 0;
diff --git a/parse.c b/parse.c
index ed8d041b..81b239a5 100644
--- a/parse.c
+++ b/parse.c
@@ -2111,12 +2111,14 @@ PARSER(parse_struct_def) {
arg_ast_t *fields = parse_args(ctx, &pos);
whitespace(&pos);
- bool secret = false;
+ bool secret = false, external = false;
if (match(&pos, ";")) { // Extra flags
whitespace(&pos);
for (;;) {
if (match_word(&pos, "secret"))
secret = true;
+ else if (match_word(&pos, "extern"))
+ external = true;
else
break;
@@ -2139,7 +2141,8 @@ PARSER(parse_struct_def) {
}
if (!namespace)
namespace = NewAST(ctx->file, pos, pos, Block, .statements=NULL);
- return NewAST(ctx->file, start, pos, StructDef, .name=name, .fields=fields, .namespace=namespace, .secret=secret);
+ return NewAST(ctx->file, start, pos, StructDef, .name=name, .fields=fields, .namespace=namespace,
+ .secret=secret, .external=external);
}
PARSER(parse_enum_def) {
diff --git a/structs.c b/structs.c
index cf86e312..27f3a295 100644
--- a/structs.c
+++ b/structs.c
@@ -12,17 +12,14 @@
#include "typecheck.h"
#include "stdlib/util.h"
-CORD compile_struct_typeinfo(env_t *env, ast_t *ast)
+CORD compile_struct_typeinfo(env_t *env, type_t *t, const char *name, arg_ast_t *fields, bool is_secret)
{
- auto def = Match(ast, StructDef);
- CORD full_name = CORD_cat(namespace_prefix(env, env->namespace), def->name);
+ CORD full_name = CORD_cat(namespace_prefix(env, env->namespace), name);
- type_t *t = Table$str_get(*env->types, def->name);
- assert(t && t->tag == StructType);
int num_fields = 0;
- for (arg_ast_t *f = def->fields; f; f = f->next)
+ for (arg_ast_t *f = fields; f; f = f->next)
num_fields += 1;
- const char *short_name = def->name;
+ const char *short_name = name;
if (strchr(short_name, '$'))
short_name = strrchr(short_name, '$') + 1;
@@ -30,11 +27,11 @@ CORD compile_struct_typeinfo(env_t *env, ast_t *ast)
CORD typeinfo = CORD_asprintf("public const TypeInfo_t %r$$info = {.size=%zu, .align=%zu, .metamethods=%s, "
".tag=StructInfo, .StructInfo.name=\"%s\"%s, "
".StructInfo.num_fields=%ld",
- full_name, type_size(t), type_align(t), metamethods, short_name, def->secret ? ", .StructInfo.is_secret=true" : "",
+ full_name, type_size(t), type_align(t), metamethods, short_name, is_secret ? ", .StructInfo.is_secret=true" : "",
num_fields);
- if (def->fields) {
+ if (fields) {
typeinfo = CORD_asprintf("%r, .StructInfo.fields=(NamedType_t[%d]){", typeinfo, num_fields);
- for (arg_ast_t *f = def->fields; f; f = f->next) {
+ for (arg_ast_t *f = fields; f; f = f->next) {
type_t *field_type = get_arg_ast_type(env, f);
typeinfo = CORD_all(typeinfo, "{\"", f->name, "\", ", compile_type_info(field_type), "}");
if (f->next) typeinfo = CORD_all(typeinfo, ", ");
@@ -61,11 +58,8 @@ CORD compile_struct_header(env_t *env, ast_t *ast)
"struct ", full_name, "$$struct {\n",
fields,
"};\n",
- "DEFINE_OPTIONAL_TYPE(", full_name, "$$type, ", heap_strf("%zu", unpadded_struct_size(t)),
+ "DEFINE_OPTIONAL_TYPE(", compile_type(t), ", ", heap_strf("%zu", unpadded_struct_size(t)),
", ", namespace_prefix(env, env->namespace), "$Optional", def->name, "$$type);\n"
- // Constructor macro:
- "#define ", namespace_prefix(env, env->namespace), def->name,
- "(...) ((", namespace_prefix(env, env->namespace), def->name, "$$type){__VA_ARGS__})\n"
"extern const TypeInfo_t ", full_name, "$$info;\n");
}
diff --git a/structs.h b/structs.h
index d38f7c43..b189b0db 100644
--- a/structs.h
+++ b/structs.h
@@ -7,7 +7,7 @@
#include "ast.h"
#include "environment.h"
-CORD compile_struct_typeinfo(env_t *env, ast_t *ast);
+CORD compile_struct_typeinfo(env_t *env, type_t *t, const char *name, arg_ast_t *fields, bool is_secret);
CORD compile_struct_header(env_t *env, ast_t *ast);
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/typecheck.c b/typecheck.c
index 3f95168f..c69432de 100644
--- a/typecheck.c
+++ b/typecheck.c
@@ -232,7 +232,7 @@ void prebind_statement(env_t *env, ast_t *statement)
code_err(statement, "A %T called '%s' has already been defined", get_binding(env, def->name)->type, def->name);
env_t *ns_env = namespace_env(env, def->name);
- type_t *type = Type(StructType, .name=def->name, .opaque=true, .env=ns_env); // placeholder
+ type_t *type = Type(StructType, .name=def->name, .opaque=true, .external=def->external, .env=ns_env); // placeholder
Table$str_set(env->types, def->name, type);
set_binding(env, def->name, Type(TypeInfoType, .name=def->name, .type=type, .env=ns_env),
CORD_all(namespace_prefix(env, env->namespace), def->name, "$$info"));
@@ -355,15 +355,8 @@ void bind_statement(env_t *env, ast_t *statement)
type->__data.StructType.fields = fields; // populate placeholder
type->__data.StructType.opaque = false;
- // Default constructor:
- type_t *constructor_t = Type(FunctionType, .args=fields, .ret=type);
- Array$insert(&ns_env->namespace->constructors,
- new(binding_t, .code=CORD_all(namespace_prefix(env, env->namespace), def->name), .type=constructor_t),
- I(0), sizeof(binding_t));
-
- for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next) {
+ for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next)
bind_statement(ns_env, stmt->ast);
- }
break;
}
case EnumDef: {
diff --git a/types.h b/types.h
index e72aa3e1..780c4d5c 100644
--- a/types.h
+++ b/types.h
@@ -91,6 +91,7 @@ struct type_s {
} SetType;
struct {
type_t *key_type, *value_type;
+ struct env_s *env;
ast_t *default_value;
} TableType;
struct {
@@ -108,7 +109,7 @@ struct type_s {
const char *name;
arg_t *fields;
struct env_s *env;
- bool opaque;
+ bool opaque:1, external:1;
} StructType;
struct {
const char *name;