// Return a reference to the given declaration. // // FIXME: Specialize the reference based on whether it's a variable // or function? Also, handle all of the other things that can be // referred to (e.g., overload sets, parameters, etc). Expr& make_reference(Context& cxt, Decl& d) { // TODO: What other kinds of objects do we have here... // // TODO: Dispatch. if (Variable_decl* v = as<Variable_decl>(&d)) return cxt.make_reference(*v); if (Object_parm* p = as<Object_parm>(&d)) return cxt.make_reference(*p); if (Function_decl* f = as<Function_decl>(&d)) return cxt.make_reference(*f); // If it's a template name, then it must almost certainly // refer to a function template. #if 0 if (Template_decl* t = as<Template_decl>(&d)) { Decl& p = t->parameterized_declaration(); if (is<Function_decl>(&p)) return cxt.make_reference(*t); throw Type_error("'{}' cannot be used as an expression"); } #endif // Here are some things that lookup can find that are not // valid expressions. // // TODO: Diagnose the error and point to the declaration. if (Type_decl* t = as<Type_decl>(&d)) throw Type_error("'{}' is not an object or function", t->name()); banjo_unhandled_case(d); }
// Perform unqualified lookup. Expr& make_reference(Context& cxt, Simple_id& id) { Decl_list decls = unqualified_lookup(cxt, id); if (decls.size() == 1) return make_reference(cxt, decls.front()); // TODO: Return a reference to an overload set. banjo_unhandled_case(id); }
// Load the value of an object corresponding to the // given declaration. Value Evaluator::load(Decl const& d) { // If the expression refers to an object, then produce // a reference to its stored value. if (Object_decl const* var = as<Object_decl>(&d)) return stack.lookup(var)->second; // What else? banjo_unhandled_case(d); }
// Returns a reference to the object or function corresponding // do the declaration `d`. // // FIXME: If d refers to a global variable, then we may not // have a binding for for it. We most definitely should. Value Evaluator::alias(Decl const& d) { // If the expression refers to an object, then produce // a reference to its stored value. if (Object_decl const* var = as<Object_decl>(&d)) return &stack.lookup(var)->second; // If the expression refers to a function, then produce // a reference to that function. if (Function_decl const* fn = as<Function_decl>(&d)) return fn; // Is there anything else? banjo_unhandled_case(d); }
// Expand the concept by substituting the template arguments // throughthe concept's definition and normalizing the result. // // TODO: Memoize the expansions. Cons& expand(Context& cxt, Concept_cons& c) { Concept_decl& d = c.declaration(); Decl_list& tparms = d.parameters(); Term_list& targs = c.arguments(); // NOTE: Template arguments must have been checked (in kind?) // prior to the formation of the constraint. It's should be // a semantic requirement of the original check expression. Substitution sub(tparms, targs); Def& def = d.definition(); if (Expression_def* expr = as<Expression_def>(&def)) return expand_expr(cxt, *expr, sub); if (Concept_def* body = as<Concept_def>(&def)) return expand_def(cxt, *body, sub); banjo_unhandled_case(def); }
// Determine if e can be contextually converted to bool, and if so, // returns the expression that produces a boolean value from `e`. Expr& contextual_conversion_to_bool(Context& cxt, Expr& e) { Builder b(cxt); // Contextual conversion to bool tries to do this: // // bool b(e); // // so we preform direct initialization. Expr& init = direct_initialize(cxt, b.get_bool_type(), e); // Based on the initializer selected, we can either // 1. return the converted value directly // 2. synthesize an object using a constructor // 3. invoke a user-defined conversion if (Copy_init* i = as<Copy_init>(&init)) return i->expression(); banjo_unhandled_case(init); }
Cons& operator()(Deduction_req& r) { banjo_unhandled_case(r); }
Cons& operator()(Semantic_req& r) { banjo_unhandled_case(r); }
Expr& operator()(Name& n) { banjo_unhandled_case(n); }
Cons& operator()(Cons& c) { banjo_unhandled_case(c); }
std::size_t operator()(Cons const& c) const { banjo_unhandled_case(c); }
std::size_t operator()(Expr const& e) const { banjo_unhandled_case(e); }
Expr* operator()(Expr& e) { banjo_unhandled_case(e); }
Value operator()(Expr const& e) { banjo_unhandled_case(e); }
Value operator()(Type const& t) { banjo_unhandled_case(t); }
void operator()(Decl const& d) { banjo_unhandled_case(d); }