static void find_arch(ident_t name, int kind, void *context) { lib_search_params_t *params = context; ident_t prefix = ident_until(name, '-'); if ((kind == T_ARCH) && (prefix == params->name)) { tree_t t = lib_get_check_stale(params->lib, name); assert(t != NULL); if (*(params->tree) == NULL) *(params->tree) = t; else { lib_mtime_t old_mtime = lib_mtime(params->lib, tree_ident(*(params->tree))); lib_mtime_t new_mtime = lib_mtime(params->lib, tree_ident(t)); if (new_mtime == old_mtime) { // Analysed at the same time: compare line number // Note this assumes both architectures are from the same // file but this shouldn't be a problem with high-resolution // timestamps uint16_t new_line = tree_loc(t)->first_line; uint16_t old_line = tree_loc(*(params->tree))->first_line; if (new_line > old_line) *(params->tree) = t; } else if (new_mtime > old_mtime) *(params->tree) = t; } } }
static tree_t elab_port_to_signal(tree_t arch, tree_t port, tree_t actual) { assert(tree_kind(port) == T_PORT_DECL); ident_t name = tree_ident(port); const int ndecls = tree_decls(arch); for (int i = 0; i < ndecls; i++) { tree_t d = tree_decl(arch, i); if (tree_ident(d) == name) return d; } type_t port_type = tree_type(port); type_t actual_type = tree_type(actual); type_t type = (type_is_unconstrained(port_type)) ? actual_type : port_type; port_mode_t mode = tree_subkind(port); tree_t s = tree_new(T_SIGNAL_DECL); tree_set_ident(s, tree_ident(port)); tree_set_type(s, type); tree_add_attr_int(s, fst_dir_i, mode); tree_set_loc(s, tree_loc(port)); tree_set_flag(s, tree_flags(port) & TREE_F_LAST_VALUE); if ((mode == PORT_OUT) || (mode == PORT_INOUT) || (mode == PORT_BUFFER)) { if (tree_has_value(port)) tree_add_attr_tree(s, driver_init_i, tree_value(port)); } tree_add_decl(arch, s); return s; }
static void elab_add_context(tree_t t, const elab_ctx_t *ctx) { ident_t cname = tree_ident(t); ident_t lname = ident_until(cname, '.'); lib_t lib = elab_find_lib(lname, ctx); tree_t unit = lib_get(lib, cname); if (unit == NULL) fatal_at(tree_loc(t), "cannot find unit %s", istr(cname)); else if (tree_kind(unit) == T_PACKAGE) { elab_copy_context(unit, ctx); ident_t name = tree_ident(unit); ident_t body_i = ident_prefix(name, ident_new("body"), '-'); tree_t body = lib_get(lib, body_i); if (body != NULL) elab_copy_context(unit, ctx); } // Always use real library name rather than WORK alias tree_set_ident(t, tree_ident(unit)); tree_add_context(ctx->out, t); }
static tree_t get_bool_lit(tree_t t, bool v) { tree_t fdecl = tree_ref(t); assert(tree_kind(fdecl) == T_FUNC_DECL); static type_t bool_type = NULL; if (bool_type == NULL) { lib_t std = lib_find("std", true, true); assert(std != NULL); tree_t standard = lib_get(std, ident_new("STD.STANDARD")); assert(standard != NULL); const int ndecls = tree_decls(standard); for (int i = 0; (i < ndecls) && (bool_type == NULL); i++) { tree_t d = tree_decl(standard, i); if (tree_ident(d) == std_bool_i) bool_type = tree_type(d); } assert(bool_type != NULL); } tree_t lit = type_enum_literal(bool_type, v ? 1 : 0); tree_t b = tree_new(T_REF); tree_set_loc(b, tree_loc(t)); tree_set_ref(b, lit); tree_set_type(b, bool_type); tree_set_ident(b, tree_ident(lit)); return b; }
tree_t get_real_lit(tree_t t, double r) { tree_t f = tree_new(T_LITERAL); tree_set_loc(f, tree_loc(t)); tree_set_subkind(f, L_REAL); tree_set_dval(f, r); tree_set_type(f, tree_type(t)); return f; }
tree_t get_int_lit(tree_t t, int64_t i) { tree_t f = tree_new(T_LITERAL); tree_set_subkind(f, L_INT); tree_set_ival(f, i); tree_set_loc(f, tree_loc(t)); tree_set_type(f, tree_type(t)); return f; }
tree_t get_bool_lit(tree_t t, bool v) { type_t bool_type = tree_type(t); tree_t lit = type_enum_literal(bool_type, v ? 1 : 0); tree_t b = tree_new(T_REF); tree_set_loc(b, tree_loc(t)); tree_set_ref(b, lit); tree_set_type(b, bool_type); tree_set_ident(b, tree_ident(lit)); return b; }
static void fst_process_hier(tree_t h) { const tree_kind_t scope_kind = tree_subkind(h); enum fstScopeType st; switch (scope_kind) { case T_ARCH: st = FST_ST_VHDL_ARCHITECTURE; break; case T_BLOCK: st = FST_ST_VHDL_BLOCK; break; case T_FOR_GENERATE: st = FST_ST_VHDL_FOR_GENERATE; break; case T_PACKAGE: st = FST_ST_VHDL_PACKAGE; break; default: st = FST_ST_VHDL_ARCHITECTURE; warn_at(tree_loc(h), "no FST scope type for %s", tree_kind_str(scope_kind)); break; } const loc_t *loc = tree_loc(h); fstWriterSetSourceStem(fst_ctx, loc->file, loc->first_line, 1); fstWriterSetScope(fst_ctx, st, istr(tree_ident(h)), tree_has_ident2(h) ? istr(tree_ident2(h)) : ""); }
tree_t add_param(tree_t call, tree_t value, param_kind_t kind, tree_t name) { tree_t p = tree_new(T_PARAM); tree_set_loc(p, tree_loc(value)); tree_set_subkind(p, kind); tree_set_value(p, value); if (kind == P_NAMED) { assert(name != NULL); tree_set_name(p, name); } tree_add_param(call, p); return p; }
static tree_t rewrite_refs(tree_t t, void *context) { rewrite_params_t *params = context; if (tree_kind(t) != T_REF) return t; tree_t decl = tree_ref(t); for (int i = 0; i < params->count; i++) { if (decl != params->formals[i]) continue; // Do not rewrite references if they appear as formal names if (tree_attr_int(t, formal_i, 0)) continue; // Skip assignments to OPEN ports if (params->actuals[i] == NULL) continue; switch (tree_kind(params->actuals[i])) { case T_SIGNAL_DECL: case T_ENUM_LIT: tree_set_ref(t, params->actuals[i]); tree_set_type(t, tree_type(params->actuals[i])); return t; case T_LITERAL: case T_AGGREGATE: case T_REF: case T_ARRAY_SLICE: case T_ARRAY_REF: case T_FCALL: case T_CONCAT: return params->actuals[i]; case T_TYPE_CONV: // XXX: this only works in trivial cases return tree_value(tree_param(params->actuals[i], 0)); default: fatal_at(tree_loc(params->actuals[i]), "cannot handle tree kind %s " "in rewrite_refs", tree_kind_str(tree_kind(params->actuals[i]))); } } return t; }
static ident_t elab_formal_name(tree_t t) { tree_kind_t kind; while ((kind = tree_kind(t)) != T_REF) { switch (kind) { case T_ARRAY_REF: case T_ARRAY_SLICE: t = tree_value(t); break; default: fatal_at(tree_loc(t), "sorry, this kind of formal is not supported %s", tree_kind_str(kind)); } } return tree_ident(t); }
static void cover_report_stmts_fn(tree_t t, void *context) { const int32_t *counts = context; const int tag = tree_attr_int(t, stmt_tag_i, -1); if (tag == -1) return; const loc_t *loc = tree_loc(t); cover_file_t *file = cover_file(loc); if (file == NULL) return; assert(loc->first_line < file->n_lines); cover_line_t *l = &(file->lines[loc->first_line - 1]); l->hits = MAX(counts[tag], l->hits); }
int64_t assume_int(tree_t t) { switch (tree_kind(t)) { case T_LITERAL: assert(tree_subkind(t) == L_INT); return tree_ival(t); case T_REF: { tree_t ref = tree_ref(t); assert(tree_kind(ref) == T_ENUM_LIT); return tree_pos(ref); } default: fatal_at(tree_loc(t), "expression cannot be folded to " "an integer constant"); } }
static void group_target(tree_t t, group_nets_ctx_t *ctx) { switch (tree_kind(t)) { case T_REF: group_ref(t, ctx, 0, -1); break; case T_ARRAY_REF: case T_ARRAY_SLICE: case T_RECORD_REF: { type_t type = tree_type(t); if (!type_known_width(type)) ungroup_name(t, ctx); else if (!group_name(t, ctx, 0, type_width(type))) ungroup_name(t, ctx); } break; case T_LITERAL: case T_OPEN: // Constant folding can cause this to appear break; case T_AGGREGATE: { const int nassocs = tree_assocs(t); for (int i = 0; i < nassocs; i++) group_target(tree_value(tree_assoc(t, i)), ctx); } break; default: fmt_loc(stdout, tree_loc(t)); fatal_trace("Cannot handle tree kind %s in group_target", tree_kind_str(tree_kind(t))); } }
static void fst_process_signal(tree_t d) { type_t type = tree_type(d); type_t base = type_base_recur(type); fst_data_t *data = xmalloc(sizeof(fst_data_t)); memset(data, '\0', sizeof(fst_data_t)); int msb = 0, lsb = 0; enum fstVarType vt; enum fstSupplementalDataType sdt; if (type_is_array(type)) { if (type_dims(type) > 1) { warn_at(tree_loc(d), "cannot represent multidimensional arrays " "in FST format"); free(data); return; } range_t r = type_dim(type, 0); int64_t low, high; range_bounds(r, &low, &high); data->dir = r.kind; data->size = high - low + 1; msb = assume_int(r.left); lsb = assume_int(r.right); type_t elem = type_elem(type); if (!fst_can_fmt_chars(elem, data, &vt, &sdt)) { warn_at(tree_loc(d), "cannot represent arrays of type %s " "in FST format", type_pp(elem)); free(data); return; } else { ident_t ident = type_ident(base); if (ident == unsigned_i) sdt = FST_SDT_VHDL_UNSIGNED; else if (ident == signed_i) sdt = FST_SDT_VHDL_SIGNED; } } else { switch (type_kind(base)) { case T_INTEGER: { ident_t ident = type_ident(type); if (ident == natural_i) sdt = FST_SDT_VHDL_NATURAL; else if (ident == positive_i) sdt = FST_SDT_VHDL_POSITIVE; else sdt = FST_SDT_VHDL_INTEGER; int64_t low, high; range_bounds(type_dim(type, 0), &low, &high); vt = FST_VT_VCD_INTEGER; data->size = ilog2(high - low + 1); data->fmt = fst_fmt_int; } break; case T_ENUM: if (!fst_can_fmt_chars(type, data, &vt, &sdt)) { ident_t ident = type_ident(base); if (ident == std_bool_i) sdt = FST_SDT_VHDL_BOOLEAN; else if (ident == std_char_i) sdt = FST_SDT_VHDL_CHARACTER; else sdt = FST_SDT_NONE; vt = FST_VT_GEN_STRING; data->size = 0; data->fmt = fst_fmt_enum; } else data->size = 1; break; case T_PHYSICAL: { sdt = FST_SDT_NONE; vt = FST_VT_GEN_STRING; data->size = 0; data->type.units = fst_make_unit_map(type); data->fmt = fst_fmt_physical; } break; default: warn_at(tree_loc(d), "cannot represent type %s in FST format", type_pp(type)); free(data); return; } } enum fstVarDir dir = FST_VD_IMPLICIT; switch (tree_attr_int(d, fst_dir_i, -1)) { case PORT_IN: dir = FST_VD_INPUT; break; case PORT_OUT: dir = FST_VD_OUTPUT; break; case PORT_INOUT: dir = FST_VD_INOUT; break; case PORT_BUFFER: dir = FST_VD_BUFFER; break; } const char *name_base = strrchr(istr(tree_ident(d)), ':') + 1; const size_t base_len = strlen(name_base); char name[base_len + 64]; strncpy(name, name_base, base_len + 64); if (type_is_array(type)) snprintf(name + base_len, 64, "[%d:%d]\n", msb, lsb); data->handle = fstWriterCreateVar2( fst_ctx, vt, dir, data->size, name, 0, type_pp(type), FST_SVT_VHDL_SIGNAL, sdt); tree_add_attr_ptr(d, fst_data_i, data); data->watch = rt_set_event_cb(d, fst_event_cb, data, true); }
static bool group_name(tree_t target, group_nets_ctx_t *ctx, int start, int n) { switch (tree_kind(target)) { case T_REF: group_ref(target, ctx, start, n); return true; case T_ARRAY_REF: { tree_t value = tree_value(target); type_t type = tree_type(value); if (type_is_unconstrained(type)) return false; int offset = 0; const int nparams = tree_params(target); for (int i = 0; i < nparams; i++) { tree_t index = tree_value(tree_param(target, i)); const int stride = type_width(type_elem(type)); if (tree_kind(index) != T_LITERAL) { if (i > 0) return false; const int twidth = type_width(type); for (int j = 0; j < twidth; j += stride) group_name(value, ctx, start + j, n); return true; } else { if (i > 0) { range_t type_r = range_of(type, i); int64_t low, high; range_bounds(type_r, &low, &high); offset *= high - low + 1; } offset += stride * rebase_index(type, i, assume_int(index)); } } return group_name(value, ctx, start + offset, n); } case T_ARRAY_SLICE: { tree_t value = tree_value(target); type_t type = tree_type(value); if (type_is_unconstrained(type)) return false; // Only in procedure range_t slice = tree_range(target, 0 ); if (tree_kind(slice.left) != T_LITERAL || tree_kind(slice.right) != T_LITERAL) return false; int64_t low, high; range_bounds(slice, &low, &high); const int64_t low0 = rebase_index(type, 0, assume_int(slice.left)); const int stride = type_width(type_elem(type)); return group_name(value, ctx, start + low0 * stride, n); } case T_RECORD_REF: { tree_t value = tree_value(target); type_t rec = tree_type(value); const int offset = record_field_to_net(rec, tree_ident(target)); return group_name(value, ctx, start + offset, n); } case T_AGGREGATE: case T_LITERAL: // This can appear due to assignments to open ports with a // default value return true; default: fatal_at(tree_loc(target), "tree kind %s not yet supported for offset " "calculation", tree_kind_str(tree_kind(target))); } }
static tree_t elab_signal_port(tree_t arch, tree_t formal, tree_t param, map_list_t **maps) { assert(tree_kind(param) == T_PARAM); tree_t actual = tree_value(param); // NULL name means associate the whole port tree_t name = NULL; if (tree_subkind(param) == P_NAMED) { tree_t n = tree_name(param); if (tree_kind(n) != T_REF) name = n; } const bool partial_map = name != NULL; switch (tree_kind(actual)) { case T_REF: case T_ARRAY_REF: case T_ARRAY_SLICE: case T_RECORD_REF: { // Replace the formal port with a signal and connect its nets to // those of the actual tree_t ref = actual; tree_kind_t ref_kind; while ((ref_kind = tree_kind(ref)) != T_REF) { if ((ref_kind == T_AGGREGATE) || (ref_kind == T_LITERAL)) return actual; else ref = tree_value(ref); } tree_t decl = tree_ref(ref); tree_kind_t decl_kind = tree_kind(decl); if (decl_kind == T_SIGNAL_DECL) { tree_t s = elab_port_to_signal(arch, formal, actual); if (partial_map) tree_add_attr_int(s, partial_map_i, 1); map_list_t *m = xmalloc(sizeof(map_list_t)); m->next = *maps; m->formal = formal; m->actual = actual; m->signal = s; m->name = name; *maps = m; return s; } else if (decl_kind == T_PORT_DECL) return NULL; // Port was OPEN at a higher level else return actual; } case T_LITERAL: case T_AGGREGATE: { type_t formal_type = tree_type(formal); if (!type_is_unconstrained(formal_type)) tree_set_type(actual, formal_type); return actual; } case T_OPEN: return NULL; case T_TYPE_CONV: // Only allow simple array type conversions for now { type_t to_type = tree_type(actual); type_t from_type = tree_type(tree_value(tree_param(actual, 0))); if (type_is_array(to_type) && type_is_array(from_type)) return actual; else fatal_at(tree_loc(actual), "sorry, this form of type conversion " "is not supported as an actual"); } default: fatal_at(tree_loc(actual), "tree %s not supported as actual", tree_kind_str(tree_kind(actual))); } }
tree_t make_default_value(type_t type, const loc_t *loc) { type_t base = type_base_recur(type); switch (type_kind(base)) { case T_UARRAY: assert(type_kind(type) == T_SUBTYPE); // Fall-through case T_CARRAY: { tree_t def = NULL; const int ndims = type_dims(type); for (int i = ndims - 1; i >= 0; i--) { tree_t val = (def ? def : make_default_value(type_elem(base), loc)); def = tree_new(T_AGGREGATE); tree_set_type(def, array_aggregate_type(type, i)); tree_t a = tree_new(T_ASSOC); tree_set_subkind(a, A_OTHERS); tree_set_value(a, val); tree_add_assoc(def, a); } tree_set_type(def, type); tree_set_loc(def, loc); return def; } case T_INTEGER: case T_PHYSICAL: case T_REAL: return type_dim(type, 0).left; case T_ENUM: { int64_t val = 0; const bool folded = folded_int(type_dim(type, 0).left, &val); if (folded) return make_ref(type_enum_literal(base, (unsigned) val)); else return type_dim(type, 0).left; } case T_RECORD: { tree_t def = tree_new(T_AGGREGATE); tree_set_loc(def, loc); const int nfields = type_fields(base); for (int i = 0; i < nfields; i++) { tree_t field = type_field(base, i); tree_t a = tree_new(T_ASSOC); tree_set_subkind(a, A_POS); tree_set_value(a, make_default_value(tree_type(field), tree_loc(field))); tree_add_assoc(def, a); } tree_set_type(def, type); return def; } case T_ACCESS: { tree_t null = tree_new(T_LITERAL); tree_set_loc(null, loc); tree_set_subkind(null, L_NULL); tree_set_type(null, type); return null; } case T_UNRESOLVED: return NULL; default: fatal_trace("cannot handle type %s in %s", type_kind_str(type_kind(base)), __func__); } }
void lxt_restart(void) { if (trace == NULL) return; lt_set_timescale(trace, -15); lt_symbol_bracket_stripping(trace, 0); lt_set_clock_compress(trace); const int ndecls = tree_decls(lxt_top); for (int i = 0; i < ndecls; i++) { tree_t d = tree_decl(lxt_top, i); if (tree_kind(d) != T_SIGNAL_DECL) continue; else if (!wave_should_dump(d)) continue; type_t type = tree_type(d); int rows, msb, lsb; if (type_is_array(type)) { rows = type_dims(type) - 1; if ((rows > 0) || type_is_array(type_elem(type))) { warn_at(tree_loc(d), "cannot emit arrays of greater than one " "dimension or arrays of arrays in LXT yet"); continue; } range_t r = type_dim(type, 0); msb = assume_int(r.left); lsb = assume_int(r.right); } else { rows = 0; msb = lsb = -1; } lxt_data_t *data = xmalloc(sizeof(lxt_data_t)); memset(data, '\0', sizeof(lxt_data_t)); int flags = 0; if (type_is_array(type)) { // Only arrays of CHARACTER, BIT, STD_ULOGIC are supported type_t elem = type_base_recur(type_elem(type)); if ((type_kind(elem) != T_ENUM) || !lxt_can_fmt_enum_chars(elem, data, &flags)) { warn_at(tree_loc(d), "cannot represent arrays of type %s " "in LXT format", type_pp(elem)); free(data); continue; } data->dir = type_dim(type, 0).kind; } else { type_t base = type_base_recur(type); switch (type_kind(base)) { case T_INTEGER: data->fmt = lxt_fmt_int; flags = LT_SYM_F_INTEGER; break; case T_ENUM: if (!lxt_can_fmt_enum_chars(base, data, &flags)) { data->fmt = lxt_fmt_enum; flags = LT_SYM_F_STRING; } break; default: warn_at(tree_loc(d), "cannot represent type %s in LXT format", type_pp(type)); free(data); continue; } } char *name = lxt_fmt_name(d); data->sym = lt_symbol_add(trace, name, rows, msb, lsb, flags); free(name); tree_add_attr_ptr(d, lxt_data_i, data); watch_t *w = rt_set_event_cb(d, lxt_event_cb, data, true); (*data->fmt)(d, w, data); } last_time = (lxttime_t)-1; }
tree_t call_builtin(const char *builtin, type_t type, ...) { struct decl_cache { struct decl_cache *next; ident_t bname; tree_t decl; }; char *name = xasprintf("NVC.BUILTIN.%s", builtin); for (char *p = name; *p != '\0'; p++) *p = toupper((int)*p); static struct decl_cache *cache = NULL; ident_t bname = ident_new(builtin); ident_t name_i = ident_new(name); free(name); struct decl_cache *it; tree_t decl = NULL; for (it = cache; it != NULL; it = it->next) { if (it->bname == bname) { decl = it->decl; break; } } if (decl == NULL) { decl = tree_new(T_FUNC_DECL); tree_set_ident(decl, name_i); tree_add_attr_str(decl, builtin_i, ident_new(builtin)); } struct decl_cache *c = xmalloc(sizeof(struct decl_cache)); c->next = cache; c->bname = bname; c->decl = decl; cache = c; tree_t call = tree_new(T_FCALL); tree_set_ident(call, name_i); tree_set_ref(call, decl); if (type != NULL) tree_set_type(call, type); va_list ap; va_start(ap, type); tree_t arg; while ((arg = va_arg(ap, tree_t))) { tree_t p = tree_new(T_PARAM); tree_set_value(p, arg); tree_set_loc(p, tree_loc(arg)); tree_set_subkind(p, P_POS); tree_add_param(call, p); } va_end(ap); return call; }
static void vcd_process_signal(tree_t d, int *next_key) { type_t type = tree_type(d); type_t base = type_base_recur(type); vcd_data_t *data = xmalloc(sizeof(vcd_data_t)); memset(data, '\0', sizeof(vcd_data_t)); int msb = 0, lsb = 0; if (type_is_array(type)) { if (type_dims(type) > 1) { warn_at(tree_loc(d), "cannot represent multidimensional arrays " "in VCD format"); free(data); return; } range_t r = type_dim(type, 0); int64_t low, high; range_bounds(r, &low, &high); data->dir = r.kind; data->size = high - low + 1; msb = assume_int(r.left); lsb = assume_int(r.right); type_t elem = type_elem(type); if (!vcd_can_fmt_chars(elem, data)) { warn_at(tree_loc(d), "cannot represent arrays of type %s " "in VCD format", type_pp(elem)); free(data); return; } } else { switch (type_kind(base)) { case T_INTEGER: { int64_t low, high; range_bounds(type_dim(type, 0), &low, &high); data->size = ilog2(high - low + 1); data->fmt = vcd_fmt_int; } break; case T_ENUM: if (vcd_can_fmt_chars(type, data)) { data->size = 1; break; } // Fall-through default: warn_at(tree_loc(d), "cannot represent type %s in VCD format", type_pp(type)); free(data); return; } } const char *name_base = strrchr(istr(tree_ident(d)), ':') + 1; const size_t base_len = strlen(name_base); char name[base_len + 64]; strncpy(name, name_base, base_len + 64); if (type_is_array(type)) snprintf(name + base_len, 64, "[%d:%d]\n", msb, lsb); tree_add_attr_ptr(d, vcd_data_i, data); data->watch = rt_set_event_cb(d, vcd_event_cb, data, true); vcd_key_fmt(*next_key, data->key); fprintf(vcd_file, "$var reg %d %s %s $end\n", (int)data->size, data->key, name); ++(*next_key); }
tree_t make_default_value(type_t type, const loc_t *loc) { type_t base = type_base_recur(type); switch (type_kind(base)) { case T_UARRAY: assert(type_kind(type) == T_SUBTYPE); // Fall-through case T_CARRAY: { tree_t def = NULL; const int ndims = type_dims(type); for (int i = ndims - 1; i >= 0; i--) { tree_t val = (def ? def : make_default_value(type_elem(base), loc)); def = tree_new(T_AGGREGATE); tree_set_type(def, array_aggregate_type(type, i)); tree_t a = tree_new(T_ASSOC); tree_set_subkind(a, A_OTHERS); tree_set_value(a, val); tree_add_assoc(def, a); } tree_set_type(def, type); tree_set_loc(def, loc); return def; } case T_INTEGER: case T_PHYSICAL: case T_REAL: return type_dim(type, 0).left; case T_ENUM: return make_ref(type_enum_literal(base, 0)); case T_RECORD: { tree_t def = tree_new(T_AGGREGATE); tree_set_loc(def, loc); const int nfields = type_fields(base); for (int i = 0; i < nfields; i++) { tree_t field = type_field(base, i); tree_t a = tree_new(T_ASSOC); tree_set_subkind(a, A_POS); tree_set_value(a, make_default_value(tree_type(field), tree_loc(field))); tree_add_assoc(def, a); } tree_set_type(def, type); return def; } case T_ACCESS: { tree_t null = tree_new(T_LITERAL); tree_set_loc(null, loc); tree_set_subkind(null, L_NULL); tree_set_type(null, type); return null; } default: assert(false); } }