Add extern structs

This commit is contained in:
Bruce Hill 2025-03-11 17:03:03 -04:00
parent 888a977132
commit fb2d7b5379
8 changed files with 36 additions and 33 deletions

2
ast.h
View File

@ -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;

View File

@ -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) {

View File

@ -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;

View File

@ -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) {

View File

@ -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");
}

View File

@ -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

View File

@ -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: {

View File

@ -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;