12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 | // This file defines how to compile field accessing like `foo.x`
#include "../ast.h"
#include "../config.h"
#include "../environment.h"
#include "../stdlib/table.h"
#include "../stdlib/text.h"
#include "../typecheck.h"
#include "../util.h"
#include "compilation.h"
Text_t compile_field_access(env_t *env, ast_t *ast) {
DeclareMatch(f, ast, FieldAccess);
binding_t *subcommand = get_subcommand_binding(env, ast);
if (subcommand) return subcommand->code;
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);
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")) {
// The cast matters: `.length` is a bitfield, and bitfield lvalues
// can't be used with `__typeof`/`stack()` or have their address
// taken, which every generic API here needs.
return Texts("((Int64_t)(", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)");
}
code_err(ast, "There is no '", f->field, "' field on ", type_to_text(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("((Int64_t)(", compile_to_pointer_depth(env, f->fielded, 0, false), ").length)");
code_err(ast, "There is no ", f->field, " field on lists");
}
case TableType: {
if (streq(f->field, "length")) {
return Texts("((Int64_t)(", 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:
fail_if_optional_field_access(ast, fielded_t, f->field);
code_err(ast, "Field accesses are not supported on ", type_to_text(fielded_t), " values");
}
}
|