aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compile/expressions.c82
-rw-r--r--src/compile/fieldaccess.c91
-rw-r--r--src/compile/fieldaccess.h8
3 files changed, 101 insertions, 80 deletions
diff --git a/src/compile/expressions.c b/src/compile/expressions.c
index a6bcff75..ce22042f 100644
--- a/src/compile/expressions.c
+++ b/src/compile/expressions.c
@@ -4,7 +4,6 @@
#include "../ast.h"
#include "../config.h"
#include "../environment.h"
-#include "../stdlib/tables.h"
#include "../stdlib/text.h"
#include "../stdlib/util.h"
#include "../typecheck.h"
@@ -14,6 +13,7 @@
#include "conditionals.h"
#include "declarations.h"
#include "enums.h"
+#include "fieldaccess.h"
#include "functions.h"
#include "indexing.h"
#include "integers.h"
@@ -254,85 +254,7 @@ Text_t compile(env_t *env, ast_t *ast) {
case When: return compile_when_statement(env, ast);
case If: return compile_if_expression(env, ast);
case Reduction: return compile_reduction(env, ast);
- case FieldAccess: {
- DeclareMatch(f, ast, FieldAccess);
- type_t *fielded_t = get_type(env, f->fielded);
- type_t *value_t = value_type(fielded_t);
- switch (value_t->tag) {
- case TypeInfoType: {
- DeclareMatch(info, value_t, TypeInfoType);
- if (f->field[0] == '_') {
- if (!type_eq(env->current_type, info->type))
- code_err(ast, "Fields that start with underscores are not "
- "accessible "
- "on types outside of the type definition.");
- }
- binding_t *b = get_binding(info->env, f->field);
- if (!b) code_err(ast, "I couldn't find the field '", f->field, "' on this type");
- if (b->code.length == 0) code_err(ast, "I couldn't figure out how to compile this field");
- return b->code;
- }
- case TextType: {
- const char *lang = Match(value_t, TextType)->lang;
- if (lang && streq(f->field, "text")) {
- Text_t text = compile_to_pointer_depth(env, f->fielded, 0, false);
- return Texts("((Text_t)", text, ")");
- } else if (streq(f->field, "length")) {
- return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)");
- }
- code_err(ast, "There is no '", f->field, "' field on ", type_to_str(value_t), " values");
- }
- case StructType: {
- return compile_struct_field_access(env, ast);
- }
- case EnumType: {
- return compile_enum_field_access(env, ast);
- }
- case ListType: {
- if (streq(f->field, "length"))
- return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)");
- code_err(ast, "There is no ", f->field, " field on lists");
- }
- case SetType: {
- if (streq(f->field, "items"))
- return Texts("LIST_COPY((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries)");
- else if (streq(f->field, "length"))
- return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false),
- ").entries.length)");
- code_err(ast, "There is no '", f->field, "' field on sets");
- }
- case TableType: {
- if (streq(f->field, "length")) {
- return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false),
- ").entries.length)");
- } else if (streq(f->field, "keys")) {
- return Texts("LIST_COPY((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries)");
- } else if (streq(f->field, "values")) {
- DeclareMatch(table, value_t, TableType);
- Text_t offset = Texts("offsetof(struct { ", compile_declaration(table->key_type, Text("k")), "; ",
- compile_declaration(table->value_type, Text("v")), "; }, v)");
- return Texts("({ List_t *entries = &(", compile_to_pointer_depth(env, f->fielded, 0, false),
- ").entries;\n"
- "LIST_INCREF(*entries);\n"
- "List_t values = *entries;\n"
- "values.data += ",
- offset,
- ";\n"
- "values; })");
- } else if (streq(f->field, "fallback")) {
- return Texts("({ Table_t *_fallback = (", compile_to_pointer_depth(env, f->fielded, 0, false),
- ").fallback; _fallback ? *_fallback : NONE_TABLE; })");
- }
- code_err(ast, "There is no '", f->field, "' field on tables");
- }
- case ModuleType: {
- const char *name = Match(value_t, ModuleType)->name;
- env_t *module_env = Table$str_get(*env->imports, name);
- return compile(module_env, WrapAST(ast, Var, f->field));
- }
- default: code_err(ast, "Field accesses are not supported on ", type_to_str(fielded_t), " values");
- }
- }
+ case FieldAccess: return compile_field_access(env, ast);
case Index: return compile_indexing(env, ast);
case InlineCCode: {
type_t *t = get_type(env, ast);
diff --git a/src/compile/fieldaccess.c b/src/compile/fieldaccess.c
new file mode 100644
index 00000000..93b31665
--- /dev/null
+++ b/src/compile/fieldaccess.c
@@ -0,0 +1,91 @@
+// This file defines how to compile field accessing like `foo.x`
+#include "../ast.h"
+#include "../config.h"
+#include "../environment.h"
+#include "../stdlib/tables.h"
+#include "../stdlib/text.h"
+#include "../stdlib/util.h"
+#include "../typecheck.h"
+#include "declarations.h"
+#include "enums.h"
+#include "expressions.h"
+#include "pointers.h"
+#include "structs.h"
+
+Text_t compile_field_access(env_t *env, ast_t *ast) {
+ DeclareMatch(f, ast, FieldAccess);
+ type_t *fielded_t = get_type(env, f->fielded);
+ type_t *value_t = value_type(fielded_t);
+ switch (value_t->tag) {
+ case TypeInfoType: {
+ DeclareMatch(info, value_t, TypeInfoType);
+ if (f->field[0] == '_') {
+ if (!type_eq(env->current_type, info->type))
+ code_err(ast, "Fields that start with underscores are not "
+ "accessible "
+ "on types outside of the type definition.");
+ }
+ binding_t *b = get_binding(info->env, f->field);
+ if (!b) code_err(ast, "I couldn't find the field '", f->field, "' on this type");
+ if (b->code.length == 0) code_err(ast, "I couldn't figure out how to compile this field");
+ return b->code;
+ }
+ case TextType: {
+ const char *lang = Match(value_t, TextType)->lang;
+ if (lang && streq(f->field, "text")) {
+ Text_t text = compile_to_pointer_depth(env, f->fielded, 0, false);
+ return Texts("((Text_t)", text, ")");
+ } else if (streq(f->field, "length")) {
+ return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)");
+ }
+ code_err(ast, "There is no '", f->field, "' field on ", type_to_str(value_t), " values");
+ }
+ case StructType: {
+ return compile_struct_field_access(env, ast);
+ }
+ case EnumType: {
+ return compile_enum_field_access(env, ast);
+ }
+ case ListType: {
+ if (streq(f->field, "length"))
+ return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)");
+ code_err(ast, "There is no ", f->field, " field on lists");
+ }
+ case SetType: {
+ if (streq(f->field, "items"))
+ return Texts("LIST_COPY((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries)");
+ else if (streq(f->field, "length"))
+ return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries.length)");
+ code_err(ast, "There is no '", f->field, "' field on sets");
+ }
+ case TableType: {
+ if (streq(f->field, "length")) {
+ return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries.length)");
+ } else if (streq(f->field, "keys")) {
+ return Texts("LIST_COPY((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries)");
+ } else if (streq(f->field, "values")) {
+ DeclareMatch(table, value_t, TableType);
+ Text_t offset = Texts("offsetof(struct { ", compile_declaration(table->key_type, Text("k")), "; ",
+ compile_declaration(table->value_type, Text("v")), "; }, v)");
+ return Texts("({ List_t *entries = &(", compile_to_pointer_depth(env, f->fielded, 0, false),
+ ").entries;\n"
+ "LIST_INCREF(*entries);\n"
+ "List_t values = *entries;\n"
+ "values.data += ",
+ offset,
+ ";\n"
+ "values; })");
+ } else if (streq(f->field, "fallback")) {
+ return Texts("({ Table_t *_fallback = (", compile_to_pointer_depth(env, f->fielded, 0, false),
+ ").fallback; _fallback ? *_fallback : NONE_TABLE; })");
+ }
+ code_err(ast, "There is no '", f->field, "' field on tables");
+ }
+ case ModuleType: {
+ const char *name = Match(value_t, ModuleType)->name;
+ env_t *module_env = Table$str_get(*env->imports, name);
+ return compile(module_env, WrapAST(ast, Var, f->field));
+ }
+ default: code_err(ast, "Field accesses are not supported on ", type_to_str(fielded_t), " values");
+ }
+}
diff --git a/src/compile/fieldaccess.h b/src/compile/fieldaccess.h
new file mode 100644
index 00000000..849df080
--- /dev/null
+++ b/src/compile/fieldaccess.h
@@ -0,0 +1,8 @@
+// This file defines how to compile field accessing like `foo.x`
+#pragma once
+
+#include "../ast.h"
+#include "../environment.h"
+#include "../stdlib/datatypes.h"
+
+Text_t compile_field_access(env_t *env, ast_t *ast);