Feature Request: Quoting Expressions

Hello. I would like to propose a new keyword, quote(), for quoting language expressions into abstract syntax trees or expression trees. This language feature appears to require a standard abstract syntax tree or expression tree model.

The feature resembles:

// returns an AST of the expression
quote(1+1);
// returns an AST which captures utilized variables
quote(data[x] + data[y]);
// works with lambda expressions, captures utilized variables
quote((x, y) => x + y + z);

I hope to find supporters and champions for the proposed language feature. I am looking forward to discussing these ideas with you. Thank you.

1 Like

Interesting idea. What are some use cases for this feature?

A first use case, for discussion, involves enhancing the inspectability and explainability of computer programs.

The following examples explore the scenario where a developer implements a guard section for a function, to check parameters before proceeding to other computation. Below, the variables r1, r2, and r3 are not simply Booleans, but are objects with two properties: value, which is a simple Boolean, and explanation, which could be or utilize an abstract syntax tree or expression tree.

function foo(x, y)
{
  var r1 = reasoning.assert(1+1, 2);
  var r2 = reasoning.assert(x.length, 3);
  var r3 = reasoning.assert(y, 1);

  if(r1.value && r2.value && r3.value)
  {
    // ...
  }

  return reasoning.and(r1, r2, r3);
}

In the above example, the result of the expression x.length is provided to the assert function, and the expression itself is unavailable.

With a quote() keyword, one could enhance the inspectability of the results of these assertions, as the following sketch intends to show:

function foo(x, y)
{
  var r1 = reasoning.assert(1+1, 2, quote(1+1), quote(2));
  var r2 = reasoning.assert(x.length, 3, quote(x.length), quote(3));
  var r3 = reasoning.assert(y, 1, quote(y), quote(1));

  if(r1.value && r2.value && r3.value)
  {
    // ...
  }

  return reasoning.and(r1, r2, r3);
}

If one desired to utilize the runtime evaluation of abstract syntax trees and expression trees, one could design the above scenario to, instead, more succinctly resemble:

function foo(x, y)
{
  var r1 = reasoning.assert(quote(1+1), quote(2));
  var r2 = reasoning.assert(quote(x.length), quote(3));
  var r3 = reasoning.assert(quote(y), quote(1));

  if(r1.value && r2.value && r3.value)
  {
    // ...
  }

  return reasoning.and(r1, r2, r3);
}

So, if one or more assertions should fail in the called function, foo, a calling function could inspect its result's explanation property, utilizing abstract syntax trees or expression trees, to process why. A developer could also print and view a string from such a tree to examine a situation, e.g., while debugging.

This first use case is a general-purpose one which sketches, and hopefully illustrates, how a quote() keyword could be used to enhance the inspectability and explainability of computer programs.

There are also other use cases to consider, some interesting ones involving lambda expressions.

What do you think of this first use case?

2 Likes

I see,, a feature from Julia. But that needs a lot of new syntax, new language semantics and the most tricky thing of all working with the JS AST. Without Julia style macros, I guess this feature won't going to be very useful. I don't know maybe we can bridge that with decorators.

If you haven’t already seen it, you might be interested in https://www.sweetjs.org/

1 Like

@jithujoshyjy, thank you. I will take a closer look at the Julia programming language, its metaprogramming, and its macros. I will also take another look at the decorators proposal.

@aclaymore, thank you. I hadn’t seen Sweet.js before.

Yes, the JS AST would be an important component and would, in theory, include an API for manually creating expression trees.

That is, with an Expression global object with static methods,

var r1 = reasoning.assert(quote(1+1), quote(2));
var r2 = reasoning.assert(quote(x.length), quote(3));
var r3 = reasoning.assert(quote(y), quote(1));

could be described as being semantically equivalent to something resembling:

var r1 = reasoning.assert(Expression.add(Expression.constant(1), Expression.constant(1)), Expression.constant(2));
var r2 = reasoning.assert(Expression.getMember(Expression.constant(x), 'length'), Expression.constant(3));
var r3 = reasoning.assert(Expression.constant(y), Expression.constant(1));

The latter syntactic form is more cumbersome, more error-prone, and less readable.

Also, as envisioned, expected usage would include building and compiling lambda expressions, and invoking compiled functions. For example:

var two = quote( (x, y) => x + y ).compile()(1, 1);

I like this idea, though there's a lot of edge cases and nuances you need to be careful of - JS isn't exactly a Lisp where you can just blindly represent code as S-expressions, and even Clojure's syntax isn't exactly simple (and it's among the simplest).

I started developing a JavaScript expression tree project, including with an evaluate(...) method on the Expressions. I made some solid progress on it including implementing invokable LambdaExpressions.

I am presently working on a toString() method for the various types of Expressions which could be of eventual use in one approach to compiling some lambda expressions. Another approach for compiling some lambda expressions might involve emitting and dynamically loading WebAssembly.

I found one of the edge cases and nuances of JavaScript that @claudiameadows might have been referring to: there is no goto statement in JavaScript but there are labels for nestable loops which work with break and continue statements.

So far, other than that scenario, the expression tree project is coming along nicely.