aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compile.c115
-rw-r--r--src/compile.h16
-rw-r--r--src/compile/enums.c38
-rw-r--r--src/compile/enums.h4
-rw-r--r--src/compile/pointer.c49
-rw-r--r--src/compile/pointer.h6
-rw-r--r--src/compile/structs.c56
-rw-r--r--src/compile/structs.h3
8 files changed, 172 insertions, 115 deletions
diff --git a/src/compile.c b/src/compile.c
index a81b74d5..c2c931c8 100644
--- a/src/compile.c
+++ b/src/compile.c
@@ -10,6 +10,7 @@
#include "compile.h"
#include "compile/enums.h"
#include "compile/list.h"
+#include "compile/pointer.h"
#include "compile/structs.h"
#include "config.h"
#include "environment.h"
@@ -25,16 +26,13 @@
typedef ast_t *(*comprehension_body_t)(ast_t *, ast_t *);
-static Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool needs_incref);
static Text_t compile_text(env_t *env, ast_t *ast, Text_t color);
static Text_t compile_text_literal(Text_t literal);
-static Text_t compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t *call_args);
static Text_t compile_maybe_incref(env_t *env, ast_t *ast, type_t *t);
static Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target);
static Text_t compile_unsigned_type(type_t *t);
static Text_t promote_to_optional(type_t *t, Text_t code);
static Text_t compile_none(type_t *t);
-static Text_t compile_empty(type_t *t);
static Text_t compile_declared_value(env_t *env, ast_t *declaration_ast);
static Text_t compile_typed_set(env_t *env, ast_t *ast, type_t *set_type);
static Text_t compile_typed_table(env_t *env, ast_t *ast, type_t *table_type);
@@ -2073,42 +2071,6 @@ Text_t compile_text(env_t *env, ast_t *ast, Text_t color) {
return expr_as_text(expr, t, color);
}
-Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool needs_incref) {
- Text_t val = compile(env, ast);
- type_t *t = get_type(env, ast);
- int64_t depth = 0;
- for (type_t *tt = t; tt->tag == PointerType; tt = Match(tt, PointerType)->pointed)
- ++depth;
-
- // Passing a literal value won't trigger an incref, because it's ephemeral,
- // e.g. [10, 20].reversed()
- if (t->tag != PointerType && needs_incref && !can_be_mutated(env, ast)) needs_incref = false;
-
- while (depth != target_depth) {
- if (depth < target_depth) {
- if (ast->tag == Var && target_depth == 1) val = Texts("(&", val, ")");
- else code_err(ast, "This should be a pointer, not ", type_to_str(get_type(env, ast)));
- t = Type(PointerType, .pointed = t, .is_stack = true);
- ++depth;
- } else {
- DeclareMatch(ptr, t, PointerType);
- val = Texts("*(", val, ")");
- t = ptr->pointed;
- --depth;
- }
- }
-
- while (t->tag == PointerType) {
- DeclareMatch(ptr, t, PointerType);
- t = ptr->pointed;
- }
-
- if (needs_incref && t->tag == ListType) val = Texts("LIST_COPY(", val, ")");
- else if (needs_incref && (t->tag == TableType || t->tag == SetType)) val = Texts("TABLE_COPY(", val, ")");
-
- return val;
-}
-
public
Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t) {
assert(!is_incomplete_type(t));
@@ -2370,6 +2332,7 @@ Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target) {
return EMPTY_TEXT;
}
+public
Text_t compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t *call_args) {
Table_t used_args = {};
Text_t code = EMPTY_TEXT;
@@ -2531,6 +2494,7 @@ Text_t compile_none(type_t *t) {
return EMPTY_TEXT;
}
+public
Text_t compile_empty(type_t *t) {
if (t == NULL) compiler_err(NULL, NULL, NULL, "I can't compile a value with no type");
@@ -2567,30 +2531,8 @@ Text_t compile_empty(type_t *t) {
case NumType: {
return Match(t, NumType)->bits == TYPE_NBITS32 ? Text("N32(0.0f)") : Text("N64(0.0)");
}
- case StructType: {
- DeclareMatch(struct_, t, StructType);
- Text_t code = Texts("((", compile_type(t), "){");
- for (arg_t *field = struct_->fields; field; field = field->next) {
- Text_t empty_field =
- field->default_val ? compile(struct_->env, field->default_val) : compile_empty(field->type);
- if (empty_field.length == 0) return EMPTY_TEXT;
-
- code = Texts(code, empty_field);
- if (field->next) code = Texts(code, ", ");
- }
- return Texts(code, "})");
- }
- case EnumType: {
- DeclareMatch(enum_, t, EnumType);
- tag_t *tag = enum_->tags;
- assert(tag);
- assert(tag->type);
- if (Match(tag->type, StructType)->fields)
- return Texts("((", compile_type(t), "){.$tag=", String(tag->tag_value), ", .", tag->name, "=",
- compile_empty(tag->type), "})");
- else if (enum_has_fields(t)) return Texts("((", compile_type(t), "){.$tag=", String(tag->tag_value), "})");
- else return Texts("((", compile_type(t), ")", String(tag->tag_value), ")");
- }
+ case StructType: return compile_empty_struct(t);
+ case EnumType: return compile_empty_enum(t);
default: return EMPTY_TEXT;
}
return EMPTY_TEXT;
@@ -3480,21 +3422,7 @@ Text_t compile(env_t *env, ast_t *ast) {
return Texts("Text$as_c_string(", expr_as_text(compile(env, call->args->value), actual, Text("no")),
")");
} else if (t->tag == StructType) {
- DeclareMatch(struct_, t, StructType);
- if (struct_->opaque) code_err(ast, "This struct is opaque, so I don't know what's inside it!");
-
- call_opts_t constructor_opts = {
- .promotion = true,
- .underscores = (env->current_type != NULL && type_eq(env->current_type, t)),
- };
- if (is_valid_call(env, struct_->fields, call->args, constructor_opts)) {
- return Texts("((", compile_type(t), "){", compile_arguments(env, ast, struct_->fields, call->args),
- "})");
- } else if (!constructor_opts.underscores
- && is_valid_call(env, struct_->fields, call->args,
- (call_opts_t){.promotion = true, .underscores = true})) {
- code_err(ast, "This constructor uses private fields that are not exposed.");
- }
+ return compile_struct_literal(env, ast, t, call->args);
}
code_err(ast,
"I could not find a constructor matching these arguments "
@@ -3809,37 +3737,10 @@ Text_t compile(env_t *env, ast_t *ast) {
code_err(ast, "There is no '", f->field, "' field on ", type_to_str(value_t), " values");
}
case StructType: {
- for (arg_t *field = Match(value_t, StructType)->fields; field; field = field->next) {
- if (streq(field->name, f->field)) {
- if (fielded_t->tag == PointerType) {
- Text_t fielded = compile_to_pointer_depth(env, f->fielded, 1, false);
- return Texts("(", fielded, ")->", valid_c_name(f->field));
- } else {
- Text_t fielded = compile(env, f->fielded);
- return Texts("(", fielded, ").", valid_c_name(f->field));
- }
- }
- }
- code_err(ast, "The field '", f->field, "' is not a valid field name of ", type_to_str(value_t));
+ return compile_struct_field_access(env, ast);
}
case EnumType: {
- DeclareMatch(e, value_t, EnumType);
- for (tag_t *tag = e->tags; tag; tag = tag->next) {
- if (streq(f->field, tag->name)) {
- Text_t tag_name = namespace_name(e->env, e->env->namespace, Texts("tag$", tag->name));
- if (fielded_t->tag == PointerType) {
- Text_t fielded = compile_to_pointer_depth(env, f->fielded, 1, false);
- return Texts("((", fielded, ")->$tag == ", tag_name, ")");
- } else if (enum_has_fields(value_t)) {
- Text_t fielded = compile(env, f->fielded);
- return Texts("((", fielded, ").$tag == ", tag_name, ")");
- } else {
- Text_t fielded = compile(env, f->fielded);
- return Texts("((", fielded, ") == ", tag_name, ")");
- }
- }
- }
- code_err(ast, "The field '", f->field, "' is not a valid tag name of ", type_to_str(value_t));
+ return compile_enum_field_access(env, ast);
}
case ListType: {
if (streq(f->field, "length"))
diff --git a/src/compile.h b/src/compile.h
index 56b522c7..6b0b4dc5 100644
--- a/src/compile.h
+++ b/src/compile.h
@@ -7,18 +7,20 @@
#include "environment.h"
#include "stdlib/datatypes.h"
-Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t);
-Text_t expr_as_text(Text_t expr, type_t *t, Text_t color);
+Text_t compile(env_t *env, ast_t *ast);
+Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const char *version);
+Text_t compile_declaration(type_t *t, Text_t name);
+Text_t compile_empty(type_t *t);
Text_t compile_file(env_t *env, ast_t *ast);
Text_t compile_file_header(env_t *env, Path_t header_path, ast_t *ast);
-Text_t compile_declaration(type_t *t, Text_t name);
-Text_t compile_type(type_t *t);
-Text_t compile(env_t *env, ast_t *ast);
Text_t compile_namespace_header(env_t *env, const char *ns_name, ast_t *block);
Text_t compile_statement(env_t *env, ast_t *ast);
-Text_t compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast);
Text_t compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *ast);
+Text_t compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast);
+Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t);
+Text_t compile_type(type_t *t);
Text_t compile_type_info(type_t *t);
-Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const char *version);
+Text_t expr_as_text(Text_t expr, type_t *t, Text_t color);
+Text_t compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t *call_args);
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/compile/enums.c b/src/compile/enums.c
index 3abe0307..c28aafae 100644
--- a/src/compile/enums.c
+++ b/src/compile/enums.c
@@ -9,6 +9,7 @@
#include "../stdlib/tables.h"
#include "../stdlib/text.h"
#include "../typecheck.h"
+#include "pointer.h"
#include "structs.h"
Text_t compile_enum_typeinfo(env_t *env, ast_t *ast) {
@@ -140,4 +141,41 @@ Text_t compile_enum_header(env_t *env, ast_t *ast) {
return all_defs;
}
+public
+Text_t compile_empty_enum(type_t *t) {
+ DeclareMatch(enum_, t, EnumType);
+ tag_t *tag = enum_->tags;
+ assert(tag);
+ assert(tag->type);
+ if (Match(tag->type, StructType)->fields)
+ return Texts("((", compile_type(t), "){.$tag=", String(tag->tag_value), ", .", tag->name, "=",
+ compile_empty(tag->type), "})");
+ else if (enum_has_fields(t)) return Texts("((", compile_type(t), "){.$tag=", String(tag->tag_value), "})");
+ else return Texts("((", compile_type(t), ")", String(tag->tag_value), ")");
+}
+
+public
+Text_t compile_enum_field_access(env_t *env, ast_t *ast) {
+ DeclareMatch(f, ast, FieldAccess);
+ type_t *fielded_t = get_type(env, ast);
+ type_t *value_t = value_type(fielded_t);
+ DeclareMatch(e, value_t, EnumType);
+ for (tag_t *tag = e->tags; tag; tag = tag->next) {
+ if (streq(f->field, tag->name)) {
+ Text_t tag_name = namespace_name(e->env, e->env->namespace, Texts("tag$", tag->name));
+ if (fielded_t->tag == PointerType) {
+ Text_t fielded = compile_to_pointer_depth(env, f->fielded, 1, false);
+ return Texts("((", fielded, ")->$tag == ", tag_name, ")");
+ } else if (enum_has_fields(value_t)) {
+ Text_t fielded = compile(env, f->fielded);
+ return Texts("((", fielded, ").$tag == ", tag_name, ")");
+ } else {
+ Text_t fielded = compile(env, f->fielded);
+ return Texts("((", fielded, ") == ", tag_name, ")");
+ }
+ }
+ }
+ code_err(ast, "The field '", f->field, "' is not a valid tag name of ", type_to_str(value_t));
+}
+
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/compile/enums.h b/src/compile/enums.h
index 6a42bece..c272086a 100644
--- a/src/compile/enums.h
+++ b/src/compile/enums.h
@@ -6,8 +6,10 @@
#include "../environment.h"
#include "../stdlib/datatypes.h"
-Text_t compile_enum_typeinfo(env_t *env, ast_t *ast);
+Text_t compile_empty_enum(type_t *t);
Text_t compile_enum_constructors(env_t *env, ast_t *ast);
+Text_t compile_enum_field_access(env_t *env, ast_t *ast);
Text_t compile_enum_header(env_t *env, ast_t *ast);
+Text_t compile_enum_typeinfo(env_t *env, ast_t *ast);
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/compile/pointer.c b/src/compile/pointer.c
new file mode 100644
index 00000000..50c267b6
--- /dev/null
+++ b/src/compile/pointer.c
@@ -0,0 +1,49 @@
+// Compilation logic
+#include <gc.h>
+#include <glob.h>
+#include <gmp.h>
+#include <uninorm.h>
+
+#include "../ast.h"
+#include "../compile.h"
+#include "../config.h"
+#include "../environment.h"
+#include "../stdlib/text.h"
+#include "../typecheck.h"
+#include "list.h"
+
+Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool needs_incref) {
+ Text_t val = compile(env, ast);
+ type_t *t = get_type(env, ast);
+ int64_t depth = 0;
+ for (type_t *tt = t; tt->tag == PointerType; tt = Match(tt, PointerType)->pointed)
+ ++depth;
+
+ // Passing a literal value won't trigger an incref, because it's ephemeral,
+ // e.g. [10, 20].reversed()
+ if (t->tag != PointerType && needs_incref && !can_be_mutated(env, ast)) needs_incref = false;
+
+ while (depth != target_depth) {
+ if (depth < target_depth) {
+ if (ast->tag == Var && target_depth == 1) val = Texts("(&", val, ")");
+ else code_err(ast, "This should be a pointer, not ", type_to_str(get_type(env, ast)));
+ t = Type(PointerType, .pointed = t, .is_stack = true);
+ ++depth;
+ } else {
+ DeclareMatch(ptr, t, PointerType);
+ val = Texts("*(", val, ")");
+ t = ptr->pointed;
+ --depth;
+ }
+ }
+
+ while (t->tag == PointerType) {
+ DeclareMatch(ptr, t, PointerType);
+ t = ptr->pointed;
+ }
+
+ if (needs_incref && t->tag == ListType) val = Texts("LIST_COPY(", val, ")");
+ else if (needs_incref && (t->tag == TableType || t->tag == SetType)) val = Texts("TABLE_COPY(", val, ")");
+
+ return val;
+}
diff --git a/src/compile/pointer.h b/src/compile/pointer.h
new file mode 100644
index 00000000..306c3019
--- /dev/null
+++ b/src/compile/pointer.h
@@ -0,0 +1,6 @@
+#include <stdbool.h>
+
+#include "../environment.h"
+#include "../stdlib/datatypes.h"
+
+Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool needs_incref);
diff --git a/src/compile/structs.c b/src/compile/structs.c
index d4bb346c..d7cbcddf 100644
--- a/src/compile/structs.c
+++ b/src/compile/structs.c
@@ -8,7 +8,9 @@
#include "../stdlib/tables.h"
#include "../stdlib/text.h"
#include "../typecheck.h"
+#include "pointer.h"
+public
Text_t compile_struct_typeinfo(env_t *env, type_t *t, const char *name, arg_ast_t *fields, bool is_secret,
bool is_opaque) {
Text_t typeinfo_name = namespace_name(env, env->namespace, Texts(name, "$$info"));
@@ -44,6 +46,7 @@ Text_t compile_struct_typeinfo(env_t *env, type_t *t, const char *name, arg_ast_
return Texts(typeinfo, "};\n");
}
+public
Text_t compile_struct_header(env_t *env, ast_t *ast) {
DeclareMatch(def, ast, StructDef);
Text_t typeinfo_name = namespace_name(env, env->namespace, Texts(def->name, "$$info"));
@@ -77,4 +80,57 @@ Text_t compile_struct_header(env_t *env, ast_t *ast) {
}
return Texts(struct_code, optional_code, typeinfo_code);
}
+
+public
+Text_t compile_empty_struct(type_t *t) {
+ DeclareMatch(struct_, t, StructType);
+ Text_t code = Texts("((", compile_type(t), "){");
+ for (arg_t *field = struct_->fields; field; field = field->next) {
+ Text_t empty_field =
+ field->default_val ? compile(struct_->env, field->default_val) : compile_empty(field->type);
+ if (empty_field.length == 0) return EMPTY_TEXT;
+
+ code = Texts(code, empty_field);
+ if (field->next) code = Texts(code, ", ");
+ }
+ return Texts(code, "})");
+}
+
+public
+Text_t compile_struct_field_access(env_t *env, ast_t *ast) {
+ DeclareMatch(f, ast, FieldAccess);
+ type_t *fielded_t = get_type(env, ast);
+ type_t *value_t = value_type(fielded_t);
+ for (arg_t *field = Match(value_t, StructType)->fields; field; field = field->next) {
+ if (streq(field->name, f->field)) {
+ if (fielded_t->tag == PointerType) {
+ Text_t fielded = compile_to_pointer_depth(env, f->fielded, 1, false);
+ return Texts("(", fielded, ")->", valid_c_name(f->field));
+ } else {
+ Text_t fielded = compile(env, f->fielded);
+ return Texts("(", fielded, ").", valid_c_name(f->field));
+ }
+ }
+ }
+ code_err(ast, "The field '", f->field, "' is not a valid field name of ", type_to_str(value_t));
+}
+
+public
+Text_t compile_struct_literal(env_t *env, ast_t *ast, type_t *t, arg_ast_t *args) {
+ DeclareMatch(struct_, t, StructType);
+ if (struct_->opaque) code_err(ast, "This struct is opaque, so I don't know what's inside it!");
+
+ call_opts_t constructor_opts = {
+ .promotion = true,
+ .underscores = (env->current_type != NULL && type_eq(env->current_type, t)),
+ };
+ if (is_valid_call(env, struct_->fields, args, constructor_opts)) {
+ return Texts("((", compile_type(t), "){", compile_arguments(env, ast, struct_->fields, args), "})");
+ } else if (!constructor_opts.underscores
+ && is_valid_call(env, struct_->fields, args, (call_opts_t){.promotion = true, .underscores = true})) {
+ code_err(ast, "This constructor uses private fields that are not exposed.");
+ }
+ code_err(ast, "I could not find a constructor matching these arguments for the struct ", type_to_str(t));
+}
+
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/compile/structs.h b/src/compile/structs.h
index f24ed15a..8185b561 100644
--- a/src/compile/structs.h
+++ b/src/compile/structs.h
@@ -5,8 +5,11 @@
#include "../ast.h"
#include "../environment.h"
+Text_t compile_empty_struct(type_t *t);
Text_t compile_struct_typeinfo(env_t *env, type_t *t, const char *name, arg_ast_t *fields, bool is_secret,
bool is_opaque);
Text_t compile_struct_header(env_t *env, ast_t *ast);
+Text_t compile_struct_field_access(env_t *env, ast_t *ast);
+Text_t compile_struct_literal(env_t *env, ast_t *ast, type_t *t, arg_ast_t *args);
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0