GabrielDosReis/ipr

Add a where-expression node

Closed this issue · 4 comments

Add a note for where-expression node to the internal language for regular and principled description of some oddities in the semantics of source-level C++, e.g. injected-class names, etc.

Aggregated notes from several discussion about Where node

At a high level, the idea is to have a construct that introduces a region with a number of local declarations in which a particular expression needs to be interpreted.

(a + b) 
    where 
(int a = 5; double b = 2.0)

One of the uses, would be to represent init-statement-opt added to an if, while and range-based-for statements in C++17.
For example:

if (int a = 5, b = 42; a < b) ++a;

Could be represented as:

if (a < b) ++a; 
   where
(int a = 5; int b = 42)

This simple use case suggests the following interface

struct Where : Category<Category_code::Where> {
   virtual const Scope& locals() const = 0;
   virtual const Expr& body() const = 0;
};

with the implementation probably hosting a region to enable adding declarations local to a Where node.

  impl::Where* where = lexicon.make_where(enclosing_region);
  where->region.declare_var(...);
  where->region.declare_var(...);
  where->body_expr = ...;

Complications 1 (grammar reuse):

This beautiful picture is spoiled by the grammar reuse of init-statement-opt which allows not only declarations, but also arbitrary expressions, as in

if (++argc; argc > 0) --argc;

If we are to use Where to represent this pattern as well, one of the possibilities is to change the type of locals to be an Expr and not Scope. That way, the first argument of Where would be either an expression to evaluate or a scope containing local declarations. This feels suboptimal since as soon as we change the type, the clear meaning of the locals() changes to much more amorphous, locals_or_expr().

Complication 2 (templates)

Another use for Where could be representation of templates (#122). The discussion of issue 122 gravitated towards making the result of the mapping representing a template to be a declaration. The problem in the IPR currently that template declaration does not provide a region to host those declarations. The idea is to use a Where node to provide such a region.

template <typename T = int, typename U = double> struct S { T x; U y; };

will be represented as:

S: mapping<T: typename = int, U: typename = double> => class =
      [typedecl name: S<T,U> init: class { field x: T; field y: U}]
   where
      <nothing???>

or

S: mapping<T: typename = int, U: typename = double> => class =
      as_type(reference to typedecl in locals) ???
   where
      [typedecl name: S<T,U> init: class { field x: T; field y: U}]

or

S: mapping<T: typename = int, U: typename = double> => class =
      as_type(reference to typedecl in locals) ???
   where
      [typedecl name: S<T,U> init: class { field x: T; field y: U}]
      [typedecl name: S init: same type as init in the previous typedecl]

It is not intuitively clear how exactly to represent the body of the template using Where.

Latest version of a where node:

struct Where : Category<Category_code::Where> {
   virtual const Expr& locals() const = 0;
   virtual const Expr& main() const = 0;
};

Representation for primary template:

tempate <typename T, typename U>
struct S { T x; U y; };

will turn into:

S: [mapping params:<T: typename, U: typename>, type:class body:
        [where main: [reference to typedecl#1] locals: [typedecl#1 name: S<T,U> init: class S{x: T; y: U}] 
        ]
    ]

The current implementation puts the manufacturing of sub-Region as a responsibility on the creator of the Where node. Part of this is because a Where node may not always introduce a declaration, but may instead introduce a side condition or an expression in general. That may yield an awkward API invocation ceremony, when the Where nodes does carry declarations. An alternative is to have the Where node always carry a Region into which any declaration is introduced even when none is actually introduced. Yet another alternative is to use a Semicolon node as suggested in the discussion of issue #103.

It looks as if Where can solve both the simple semantics let-in construct and also obviate the need for another Semicolon node. Said differently: Where node unifies both SuchThat and Semicolon nodes as I suggested in the issue mentioned above.

Resolved by check-in #191