コード例 #1
0
ファイル: scanner.cpp プロジェクト: davidmueller13/lean
void scanner::next_utf_core(char c, buffer<char> & cs) {
    cs.push_back(c);
    while (m_uskip > 0) {
        next();
        cs.push_back(curr());
    }
}
コード例 #2
0
ファイル: aux_definition.cpp プロジェクト: sakas--/lean
 level collect(level const & l) {
     return replace(l, [&](level const & l) {
             if (is_meta(l)) {
                 name const & id = meta_id(l);
                 if (auto r = m_univ_meta_to_param.find(id)) {
                     return some_level(*r);
                 } else {
                     name n      = m_prefix.append_after(m_next_idx);
                     m_next_idx++;
                     level new_r = mk_param_univ(n);
                     m_univ_meta_to_param.insert(id, new_r);
                     m_univ_meta_to_param_inv.insert(n, l);
                     m_level_params.push_back(n);
                     return some_level(new_r);
                 }
             } else if (is_param(l)) {
                 name const & id = param_id(l);
                 if (!m_found_univ_params.contains(id)) {
                     m_found_univ_params.insert(id);
                     m_level_params.push_back(id);
                 }
             }
             return none_level();
         });
 }
コード例 #3
0
ファイル: aux_definition.cpp プロジェクト: sakas--/lean
 expr collect(expr const & e) {
     return replace(e, [&](expr const & e, unsigned) {
             if (is_metavar(e)) {
                 name const & id = mlocal_name(e);
                 if (auto r = m_meta_to_param.find(id)) {
                     return some_expr(*r);
                 } else {
                     expr type  = m_ctx.infer(e);
                     expr x     = m_ctx.push_local("_x", type);
                     m_meta_to_param.insert(id, x);
                     m_meta_to_param_inv.insert(mlocal_name(x), e);
                     m_params.push_back(x);
                     return some_expr(x);
                 }
             } else if (is_local(e)) {
                 name const & id = mlocal_name(e);
                 if (!m_found_local.contains(id)) {
                     m_found_local.insert(id);
                     m_params.push_back(e);
                 }
             } else if (is_sort(e)) {
                 return some_expr(update_sort(e, collect(sort_level(e))));
             } else if (is_constant(e)) {
                 return some_expr(update_constant(e, collect(const_levels(e))));
             }
             return none_expr();
         });
 }
コード例 #4
0
static name parse_quoted_symbol_or_token(parser & p, buffer<token_entry> & new_tokens, bool & used_default, notation_entry_group grp) {
    used_default = false;
    if (p.curr_is_quoted_symbol()) {
        environment const & env = p.env();
        auto pp_tk = p.get_name_val();
        auto tks   = utf8_trim(pp_tk.to_string());
        auto tkcs  = tks.c_str();
        check_not_forbidden(tkcs);
        p.next();
        if (p.curr_is_token(get_colon_tk())) {
            p.next();
            unsigned prec = parse_precedence(p);
            new_tokens.push_back(mk_token_entry(tkcs, prec, grp));
        } else if (!get_precedence(env, tkcs, grp)) {
            new_tokens.push_back(mk_token_entry(tkcs, LEAN_DEFAULT_PRECEDENCE, grp));
            used_default = true;
        }
        return pp_tk;
    } else if (p.curr_is_keyword()) {
        auto tk = p.get_token_info().token();
        check_not_forbidden(tk.to_string().c_str());
        p.next();
        return tk;
    } else {
        throw parser_error("invalid notation declaration, symbol expected", p.pos());
    }
}
コード例 #5
0
ファイル: vm_list.cpp プロジェクト: soonhokong/lean-osx
unsigned list_cases_on_core(list<A> const & l, buffer<vm_obj> & data) {
    if (empty(l)) {
        return 0;
    } else  {
        data.push_back(to_obj(head(l)));
        data.push_back(list_to_obj(tail(l)));
        return 1;
    }
}
コード例 #6
0
void destruct_structure_instance(expr const & e, expr & t, buffer<name> & field_names,
                                 buffer<expr> & field_values, buffer<expr> & using_exprs) {
    lean_assert(is_structure_instance(e));
    t = macro_arg(e, 0);
    list<name> const & fns = static_cast<structure_instance_macro_cell const*>(macro_def(e).raw())->get_field_names();
    unsigned num_fileds = length(fns);
    to_buffer(fns, field_names);
    for (unsigned i = 1; i < num_fileds+1; i++)
        field_values.push_back(macro_arg(e, i));
    for (unsigned i = num_fileds+1; i < macro_num_args(e); i++)
        using_exprs.push_back(macro_arg(e, i));
}
コード例 #7
0
ファイル: find_cmd.cpp プロジェクト: cpehle/lean
static void parse_filters(parser & p, buffer<std::string> & pos_names, buffer<std::string> & neg_names) {
    name plus("+"); name minus("-");
    while (p.curr_is_token(get_comma_tk())) {
        p.next();
        if (p.curr_is_token(plus)) {
            p.next();
            pos_names.push_back(p.check_id_next("invalid find_decl command, identifier expected").to_string());
        } else if (p.curr_is_token(minus)) {
            p.next();
            neg_names.push_back(p.check_id_next("invalid find_decl command, identifier expected").to_string());
        } else {
            pos_names.push_back(p.check_id_next("invalid find_decl command, '+', '-', or identifier expected").to_string());
        }
    }
}
コード例 #8
0
static transition parse_transition(parser & p, optional<parse_table> const & pt, name const & tk,
                                   buffer<expr> & locals, buffer<token_entry> & new_tokens, notation_entry_group grp,
                                   name const & pp_tk) {
    if (p.curr_is_token_or_id(get_binder_tk())) {
        p.next();
        unsigned rbp = parse_binders_rbp(p);
        return transition(tk, mk_binder_action(rbp), pp_tk);
    } else if (p.curr_is_token_or_id(get_binders_tk())) {
        p.next();
        unsigned rbp = parse_binders_rbp(p);
        return transition(tk, mk_binders_action(rbp), pp_tk);
    } else if (p.curr_is_identifier()) {
        unsigned default_prec = get_default_prec(pt, tk);
        name n   = p.get_name_val();
        p.next();
        action a = parse_action(p, tk, default_prec, locals, new_tokens, grp);
        expr local_type = mk_Prop(); // type used in notation local declarations, it is irrelevant
        expr l = mk_local(n, local_type);
        p.add_local(l);
        locals.push_back(l);
        return transition(tk, a, pp_tk);
    } else if (p.curr_is_quoted_symbol() || p.curr_is_keyword() ||
               p.curr_is_token(get_assign_tk()) || p.curr_is_command() || p.curr_is_eof()) {
        return transition(tk, mk_skip_action(), pp_tk);
    } else {
        throw parser_error("invalid notation declaration, quoted-symbol, identifier, "
                           "'binder', 'binders' expected", p.pos());
    }
}
コード例 #9
0
static notation_entry parse_mixfix_notation(parser & p, mixfix_kind k, bool overload, notation_entry_group grp,
                                            buffer<token_entry> & new_tokens, bool parse_only, unsigned priority) {
    auto nt = parse_mixfix_notation(p, k, overload, grp, parse_only, priority);
    if (nt.second)
        new_tokens.push_back(*nt.second);
    return nt.first;
}
コード例 #10
0
ファイル: util.cpp プロジェクト: cpehle/lean
void get_rec_args(environment const & env, name const & n, buffer<buffer<bool>> & r) {
    lean_assert(inductive::is_inductive_decl(env, n));
    type_checker tc(env);
    name_generator ngen;
    declaration ind_decl   = env.get(n);
    declaration rec_decl   = env.get(inductive::get_elim_name(n));
    unsigned nparams       = *inductive::get_num_params(env, n);
    unsigned nminors       = *inductive::get_num_minor_premises(env, n);
    unsigned ntypeformers  = *inductive::get_num_type_formers(env, n);
    buffer<expr> rec_args;
    to_telescope(ngen, rec_decl.get_type(), rec_args);
    buffer<name> typeformer_names;
    for (unsigned i = nparams; i < nparams + ntypeformers; i++) {
        typeformer_names.push_back(mlocal_name(rec_args[i]));
    }
    lean_assert(typeformer_names.size() == ntypeformers);
    r.clear();
    // add minor premises
    for (unsigned i = nparams + ntypeformers; i < nparams + ntypeformers + nminors; i++) {
        r.push_back(buffer<bool>());
        buffer<bool> & bv = r.back();
        expr minor_type = mlocal_type(rec_args[i]);
        buffer<expr> minor_args;
        to_telescope(ngen, minor_type, minor_args);
        for (expr & minor_arg : minor_args) {
            buffer<expr> minor_arg_args;
            expr minor_arg_type = to_telescope(tc, mlocal_type(minor_arg), minor_arg_args);
            bv.push_back(is_typeformer_app(typeformer_names, minor_arg_type));
        }
    }
}
コード例 #11
0
ファイル: expr.cpp プロジェクト: sakas--/lean
void expr_cell::dec_ref(expr & e, buffer<expr_cell*> & todelete) {
    if (e.m_ptr) {
        expr_cell * c = e.steal_ptr();
        lean_assert(!(e.m_ptr));
        if (c->dec_ref_core())
            todelete.push_back(c);
    }
}
コード例 #12
0
ファイル: level.cpp プロジェクト: pazthor/lean
void push_max_args(level const & l, buffer<level> & r) {
    if (is_max(l)) {
        push_max_args(max_lhs(l), r);
        push_max_args(max_rhs(l), r);
    } else {
        r.push_back(l);
    }
}
コード例 #13
0
ファイル: name.cpp プロジェクト: syohex/lean
 friend void copy_limbs(imp * p, buffer<name::imp *> & limbs) {
     limbs.clear();
     while (p != nullptr) {
         limbs.push_back(p);
         p = p->m_prefix;
     }
     std::reverse(limbs.begin(), limbs.end());
 }
コード例 #14
0
ファイル: calc.cpp プロジェクト: codyroux/lean
static pair<expr, unsigned> extract_arg_types_core(environment const & env, name const & f, buffer<expr> & arg_types) {
    declaration d = env.get(f);
    expr f_type = d.get_type();
    while (is_pi(f_type)) {
        arg_types.push_back(binding_domain(f_type));
        f_type = binding_body(f_type);
    }
    return mk_pair(f_type, length(d.get_univ_params()));
}
コード例 #15
0
void get_simp_extensions_for(environment const & env, name const & head, buffer<unsigned> & ext_ids) {
    simp_ext_state s = simp_ext_ext::get_state(env);
    if (auto q = s.find(head)) {
        buffer<simp_ext_record> records;
        q->for_each([&](simp_ext_record const & r) {
                ext_ids.push_back(r.m_ext_id);
            });
    }
}
コード例 #16
0
ファイル: ast_translation.cpp プロジェクト: jackluo923/juxta
void ast_translation::copy_params(decl * d, unsigned rpos, buffer<parameter> & ps) {
    unsigned num = d->get_num_parameters();
    unsigned j   = rpos;
    for (unsigned i = 0; i < num; i++) {
        parameter const & p = d->get_parameter(i);
        if (p.is_ast()) {
            ps.push_back(parameter(m_result_stack[j]));
            j++;
        }
        else if (p.is_external()) {
            SASSERT(d->get_family_id() != null_family_id);
            decl_plugin & from_plugin = *(m_from_manager.get_plugin(d->get_family_id()));
            decl_plugin & to_plugin   = *(m_to_manager.get_plugin(d->get_family_id()));
            ps.push_back(from_plugin.translate(p, to_plugin));
        }
        else {
            ps.push_back(p);
        }
    }
}
コード例 #17
0
static void parse_notation_local(parser & p, buffer<expr> & locals) {
    if (p.curr_is_identifier()) {
        name n = p.get_name_val();
        p.next();
        expr local_type = mk_Prop(); // type used in notation local declarations, it is irrelevant
        expr l = mk_local(n, local_type); // remark: the type doesn't matter
        p.add_local(l);
        locals.push_back(l);
    } else {
        throw parser_error("invalid notation declaration, identifier expected", p.pos());
    }
}
コード例 #18
0
ファイル: vm_level.cpp プロジェクト: soonhokong/lean-osx
unsigned level_cases_on(vm_obj const & o, buffer<vm_obj> & data) {
    level const & l = to_level(o);
    switch (l.kind()) {
    case level_kind::Zero:
        break;
    case level_kind::Succ:
        data.push_back(to_obj(succ_of(l)));
        break;
    case level_kind::Max:
        data.push_back(to_obj(max_lhs(l)));
        data.push_back(to_obj(max_rhs(l)));
        break;
    case level_kind::IMax:
        data.push_back(to_obj(imax_lhs(l)));
        data.push_back(to_obj(imax_rhs(l)));
        break;
    case level_kind::Param:
        data.push_back(to_obj(param_id(l)));
        break;
    case level_kind::Global:
        data.push_back(to_obj(global_id(l)));
        break;
    case level_kind::Meta:
        data.push_back(to_obj(meta_id(l)));
        break;
    }
    return static_cast<unsigned>(l.kind());
}
コード例 #19
0
ファイル: parse_table.cpp プロジェクト: vishallama/lean
void parse_table::for_each(buffer<transition> & ts,
                           std::function<void(unsigned, transition const *,
                                              list<accepting> const &)> const & fn) const {
    if (!is_nil(m_ptr->m_accept))
        fn(ts.size(), ts.data(), m_ptr->m_accept);
    m_ptr->m_children.for_each([&](name const & k, list<pair<action, parse_table>> const & lst) {
            for (auto const & p : lst) {
                ts.push_back(transition(k, p.first));
                p.second.for_each(ts, fn);
                ts.pop_back();
            }
        });
}
コード例 #20
0
ファイル: structure_instance.cpp プロジェクト: sakas--/lean
void get_structure_instance_info(expr const & e,
                                 name & struct_name,
                                 optional<expr> & source,
                                 buffer<name> & field_names,
                                 buffer<expr> & field_values) {
    lean_assert(is_structure_instance(e));
    struct_name = static_cast<structure_instance_macro_cell const*>(macro_def(e).raw())->get_struct();
    list<name> const & fns = static_cast<structure_instance_macro_cell const*>(macro_def(e).raw())->get_field_names();
    to_buffer(fns, field_names);
    unsigned num_fields = field_names.size();
    lean_assert(macro_num_args(e) == num_fields || macro_num_args(e) == num_fields+1);
    if (num_fields < macro_num_args(e))
        source = macro_arg(e, num_fields);
    for (unsigned i = 0; i < num_fields; i++)
        field_values.push_back(macro_arg(e, i));
}
コード例 #21
0
ファイル: parse_table.cpp プロジェクト: vishallama/lean
parse_table parse_table::add_core(unsigned num, transition const * ts, expr const & a,
                                  unsigned priority, bool overload, buffer<action> & post_buffer) const {
    parse_table r(new cell(*m_ptr));
    if (num == 0) {
        list<action> postponed = to_list(post_buffer);
        if (!overload) {
            r.m_ptr->m_accept = to_list(accepting(priority, postponed, a));
        } else {
            auto new_accept   = filter(r.m_ptr->m_accept, [&](accepting const & p) {
                    return p.get_expr() != a || p.get_postponed() != postponed;
                });
            r.m_ptr->m_accept = insert(new_accept, priority, postponed, a);
        }
    } else {
        list<pair<action, parse_table>> const * it = r.m_ptr->m_children.find(ts->get_token());
        action const & ts_act = ts->get_action();
        action_kind k = ts_act.kind();
        if (k == action_kind::Exprs || k == action_kind::ScopedExpr)
            post_buffer.push_back(ts_act);
        list<pair<action, parse_table>> new_lst;
        if (it) {
            if (contains_equivalent_action(*it, ts_act)) {
                buffer<pair<action, parse_table>> tmp;
                to_buffer(*it, tmp);
                for (pair<action, parse_table> & p : tmp) {
                    if (p.first.is_equivalent(ts_act)) {
                        p.second = p.second.add_core(num-1, ts+1, a, priority, overload, post_buffer);
                        break;
                    }
                }
                new_lst = to_list(tmp);
            } else {
                // remove incompatible actions
                new_lst = filter(*it, [&](pair<action, parse_table> const & p) {
                        return p.first.is_compatible(ts_act);
                    });
                parse_table new_child = parse_table().add_core(num-1, ts+1, a, priority, overload, post_buffer);
                new_lst   = cons(mk_pair(ts_act, new_child), new_lst);
            }
        } else {
            parse_table new_child = parse_table().add_core(num-1, ts+1, a, priority, overload, post_buffer);
            new_lst   = to_list(mk_pair(ts_act, new_child));
        }
        r.m_ptr->m_children.insert(ts->get_token(), new_lst);
    }
    return r;
}
コード例 #22
0
 bool collect(expr cls, expr const & l, buffer<expr> & R, extension_context & ctx) const {
     check_system("resolve macro");
     expr lhs, rhs;
     if (is_or(cls, lhs, rhs)) {
         return collect(lhs, rhs, l, R, ctx);
     } else {
         cls = whnf(cls, ctx);
         if (is_or(cls, lhs, rhs)) {
             return collect(lhs, rhs, l, R, ctx);
         } else if (is_def_eq(cls, l, ctx)) {
             return true; // found literal l
         } else {
             if (!already_contains(cls, R, ctx))
                 R.push_back(cls);
             return false;
         }
     }
 }
コード例 #23
0
ファイル: aux_definition.cpp プロジェクト: sakas--/lean
 /* Collect (and sort) dependencies of collected parameters */
 void collect_and_normalize_dependencies(buffer<expr> & norm_params) {
     name_map<expr> new_types;
     for (unsigned i = 0; i < m_params.size(); i++) {
         expr x = m_params[i];
         expr new_type = collect(m_ctx.instantiate_mvars(m_ctx.infer(x)));
         new_types.insert(mlocal_name(x), new_type);
     }
     local_context const & lctx = m_ctx.lctx();
     std::sort(m_params.begin(), m_params.end(), [&](expr const & l1, expr const & l2) {
             return lctx.get_local_decl(l1)->get_idx() < lctx.get_local_decl(l2)->get_idx();
         });
     for (unsigned i = 0; i < m_params.size(); i++) {
         expr x         = m_params[i];
         expr type      = *new_types.find(mlocal_name(x));
         expr new_type  = replace_locals(type, i, m_params.data(), norm_params.data());
         expr new_param = m_ctx.push_local(local_pp_name(x), new_type, local_info(x));
         norm_params.push_back(new_param);
     }
 }
コード例 #24
0
ファイル: lar_solver.cpp プロジェクト: avigad/lean
void lar_solver::get_infeasibility_evidence_for_inf_sign(buffer<std::pair<mpq, constraint_index>> & evidence,
                                                         const std::vector<std::pair<mpq, unsigned>> & inf_row,
                                                         int inf_sign) {
    for (auto & it : inf_row) {
        mpq coeff = it.first;
        unsigned j = it.second;
        auto it1 = m_map_from_column_indices_to_var_index.find(j);
        lean_assert(it1 != m_map_from_column_indices_to_var_index.end());
        unsigned var_j = it1->second;
        auto it2 = m_map_from_var_index_to_column_info_with_cls.find(var_j);
        lean_assert(it2 != m_map_from_var_index_to_column_info_with_cls.end());
        canonic_left_side * ls = it2->second.m_canonic_left_side;
        int adj_sign = coeff.is_pos() ? inf_sign : -inf_sign;

        lar_normalized_constraint * bound_constr = adj_sign < 0? ls->m_upper_bound_witness : ls->m_low_bound_witness;
        lean_assert(bound_constr != nullptr);
        evidence.push_back(std::make_pair(coeff / bound_constr->m_ratio_to_original, bound_constr->m_index));
    }
}
コード例 #25
0
ファイル: simp_rule_set.cpp プロジェクト: fgdorais/lean
void simp_rule_sets::get_relations(buffer<name> & rs) const {
    m_sets.for_each([&](name const & r, simp_rule_set const &) {
            rs.push_back(r);
        });
}
コード例 #26
0
ファイル: apply_tactic.cpp プロジェクト: fgdorais/lean
static proof_state_seq apply_tactic_core(environment const & env, io_state const & ios, proof_state const & s,
                                         expr const & _e, buffer<constraint> & cs,
                                         add_meta_kind add_meta, subgoals_action_kind subgoals_action,
                                         optional<unifier_kind> const & uk = optional<unifier_kind>()) {
    goals const & gs = s.get_goals();
    if (empty(gs)) {
        throw_no_goal_if_enabled(s);
        return proof_state_seq();
    }
    bool class_inst   = get_apply_class_instance(ios.get_options());
    name_generator ngen = s.get_ngen();
    std::shared_ptr<type_checker> tc(mk_type_checker(env, ngen.mk_child()));
    goal  g           = head(gs);
    goals tail_gs     = tail(gs);
    expr  t           = g.get_type();
    expr  e           = _e;
    auto e_t_cs       = tc->infer(e);
    e_t_cs.second.linearize(cs);
    expr  e_t         = e_t_cs.first;
    buffer<expr> metas;
    local_context ctx;
    bool initialized_ctx = false;
    unifier_config cfg(ios.get_options());
    if (uk)
        cfg.m_kind = *uk;
    if (add_meta != DoNotAdd) {
        unsigned num_e_t = get_expect_num_args(*tc, e_t);
        if (add_meta == AddDiff) {
            unsigned num_t   = get_expect_num_args(*tc, t);
            if (num_t <= num_e_t)
                num_e_t -= num_t;
            else
                num_e_t = 0;
        } else {
            lean_assert(add_meta == AddAll);
        }
        for (unsigned i = 0; i < num_e_t; i++) {
            auto e_t_cs = tc->whnf(e_t);
            e_t_cs.second.linearize(cs);
            e_t        = e_t_cs.first;
            expr meta;
            if (class_inst && binding_info(e_t).is_inst_implicit()) {
                if (!initialized_ctx) {
                    ctx = g.to_local_context();
                    initialized_ctx = true;
                }
                bool use_local_insts = true;
                bool is_strict       = false;
                auto mc = mk_class_instance_elaborator(
                    env, ios, ctx, ngen.next(), optional<name>(),
                    use_local_insts, is_strict,
                    some_expr(head_beta_reduce(binding_domain(e_t))), e.get_tag(), cfg, nullptr);
                meta    = mc.first;
                cs.push_back(mc.second);
            } else {
                meta  = g.mk_meta(ngen.next(), head_beta_reduce(binding_domain(e_t)));
            }
            e          = mk_app(e, meta);
            e_t        = instantiate(binding_body(e_t), meta);
            metas.push_back(meta);
        }
    }
    metavar_closure cls(t);
    cls.mk_constraints(s.get_subst(), justification());
    pair<bool, constraint_seq> dcs = tc->is_def_eq(t, e_t);
    if (!dcs.first) {
        throw_tactic_exception_if_enabled(s, [=](formatter const & fmt) {
                format r = format("invalid 'apply' tactic, failed to unify");
                r       += pp_indent_expr(fmt, t);
                r       += compose(line(), format("with"));
                r       += pp_indent_expr(fmt, e_t);
                return r;
            });
        return proof_state_seq();
    }
    dcs.second.linearize(cs);
    unify_result_seq rseq = unify(env, cs.size(), cs.data(), ngen.mk_child(), s.get_subst(), cfg);
    list<expr> meta_lst   = to_list(metas.begin(), metas.end());
    return map2<proof_state>(rseq, [=](pair<substitution, constraints> const & p) -> proof_state {
            substitution const & subst    = p.first;
            constraints const & postponed = p.second;
            name_generator new_ngen(ngen);
            substitution new_subst = subst;
            expr new_e = new_subst.instantiate_all(e);
            assign(new_subst, g, new_e);
            goals new_gs = tail_gs;
            if (subgoals_action != IgnoreSubgoals) {
                buffer<expr> metas;
                for (auto m : meta_lst) {
                    if (!new_subst.is_assigned(get_app_fn(m)))
                        metas.push_back(m);
                }
                if (subgoals_action == AddRevSubgoals) {
                    for (unsigned i = 0; i < metas.size(); i++)
                        new_gs = cons(goal(metas[i], new_subst.instantiate_all(tc->infer(metas[i]).first)), new_gs);
                } else {
                    lean_assert(subgoals_action == AddSubgoals || subgoals_action == AddAllSubgoals);
                    if (subgoals_action == AddSubgoals)
                        remove_redundant_metas(metas);
                    unsigned i = metas.size();
                    while (i > 0) {
                        --i;
                        new_gs = cons(goal(metas[i], new_subst.instantiate_all(tc->infer(metas[i]).first)), new_gs);
                    }
                }
            }
            return proof_state(s, new_gs, new_subst, new_ngen, postponed);
        });
}
コード例 #27
0
ファイル: vm_array.cpp プロジェクト: avigad/lean
unsigned array_cases_on(vm_obj const & o, buffer<vm_obj> & data) {
    vm_obj d[3] = {o, mk_vm_unit(), mk_vm_unit()};
    vm_obj fn = mk_vm_closure(g_array_read_idx, 3, d);
    data.push_back(fn);
    return 0;
}