Some Quasi specification issues

# Allen Wirfs-Brock (13 years ago)

Here are several issues that I've identified with Quasis as I work to integrate the wiki quasi proposal [1] into the ES6 spec..

  1. I think that the default substitutions for untagged quasi should be cooked, not raw.

The wiki defines the default Quasi tag [2] function as producing results based upon "raw" literal text. This means that something like:

const name = "Allen",  value="0.99";
console.log(`\u261E\t${name}\t\$${value}`);

would output: \u261E\tAllen\t$0.99 rather than, what was more likely intended: ☞ Allen $0.99

This seems wrong and error prone. The default substitution should expand escapes rather than using the raw literal text. More generally,

For any ES string literal that does not contain an unescaped ${, replacing the string delimiters (" or ') with back quote () should produce the same string value. EG, "abcdef\nxyz\n" or 'abcdef\nxyz\n' should produce the same values as:abcdef\nxyz\n`

  1. LineContinuations should be removed for cooked quasi literal text.

this is required for consistency with the string replacement principal stated above:

1\ 2\ 3

should yield the same value as: "1
2
3"

which is the same as "123"

Note however that quasis can still contain literal LineTerminators that become part of the string value. EG, 1 2 3

yields the same value as "1\n2\n3" (assuming that linefeed is the new line character used in the program text)

  1. The raw tag should be a property of String.

The wiki suggests [3] that a "raw" tag provides the equivalent to Python raw strings: rawIn JavaScript '\n' is a line-feed. produces the same value as: "In JavaScript '\n' is a line-feed."

However, the wiki doesn't specify where or how raw is defined. Rather than defining a new global or requiring a import I suggest that we make "raw" a property of the String constructor. EG, String.rawIn JavaScript '\n' is a line-feed.

  1. Should we also have a mostly raw tag that treats everything as raw except for explicit line continuation? This would allow raw strings to be spread across multiple lines without inserting newlines that are there solely for source code formatting purposes. EG:

    String.rawLines\ line 1\n\ line 2\n\ line 3\n

produces the same result as "line 1\nline 2\nline 3\n"

  1. Simplify the "call site object" to be an array I think the most common use case is going to be for tag functions to use the cooked text. So let's make the "call site object" [4] be the array of cooked literal portions rather than having to indirect through a "cooked" property. Instead the first argument to tags would be defined equivalently to:

const ungeussableCallSiteId1234 = do { // it would sure be nice to have this in ES let CSid = [literalSegment1, literalSegment2, ...]; / /... is meta CSid.raw = Object.freeze([rawLiteralSegment1, rawLiteralSegment2, ...]); / /... is meta Object.freeze(CSid); };

Most tag functions would then have a signature like: let tag = (lits, subs) => { ... }

and within the body lits can be directly processed as a (frozen) Array. Only if the functions actually uses raw values would it have to do a qualified reference such as lits.raw.

Thoughts? Allen

[1] harmony:quasis [2] harmony:quasis#default_quasi_tag [3] harmony:quasis#raw_strings [4] harmony:quasis#desugaring

# Erik Arvidsson (13 years ago)

On Fri, Jun 29, 2012 at 4:34 PM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

  1. I think that the default substitutions for untagged quasi should be cooked, not raw.

Yes. I think this is a bug in the wiki proposal. Both Mike's implementation and Traceur's uses the cooked string for the default quasi. bit.ly/M260kh

  1. LineContinuations should be removed for cooked quasi literal text.

Yes. Same here. bit.ly/MpJXr4

  1. The raw tag should be a property of String.

Yes. The proposal only allows an identifier before the opening back tick but I'm sure you are taking care of that.

  1. Should we also have a mostly raw tag that treats everything as raw except for explicit line continuation?

I don't care.

  1. Simplify the "call site object" to be an array

I like it.

# Brendan Eich (13 years ago)

Erik Arvidsson wrote:

  1. Should we also have a mostly raw tag that treats everything as raw except

for explicit line continuation?

I don't care.

When in doubt, leave it out.

  1. Simplify the "call site object" to be an array

I like it.

For some engines (perhaps ones that should get busy optimizing), making an array have named expando properties deoptimizes accesses to indexed elements.

On the other hand Allen's proposal makes two objects where the harmony:quasis proposal makes three.

# Allen Wirfs-Brock (13 years ago)

On Jul 2, 2012, at 5:11 PM, Brendan Eich wrote:

Erik Arvidsson wrote:

  1. Should we also have a mostly raw tag that treats everything as raw except

for explicit line continuation?

I don't care.

When in doubt, leave it out.

  1. Simplify the "call site object" to be an array

I like it.

For some engines (perhaps ones that should get busy optimizing), making an array have named expando properties deoptimizes accesses to indexed elements.

On the other hand Allen's proposal makes two objects where the harmony:quasis proposal makes three.

In eiher case, the objects are born frozen so the named properties shouldn't really have to be treated as expandos.

Also, they are probably statically allocable with program duration lifetimes. The wiki spec. is a bit unclear on this point. It says, that the call site objects is logically "hoisted into the top module scope". Presumably the intent of that statement is that there is statically one of these objects per physical call site rather than one per closure per physical call site. From an implementation perspective I'd prefer the one per physical site interpretation. However, the spec also says that a tag function can use these call site objects as cache keys. I can imaging that there might be caching situations where per closure identity would be more desirable.

# Mike Samuel (13 years ago)

2012/7/2 Allen Wirfs-Brock <allen at wirfs-brock.com>:

Presumably the intent of that statement is that there is statically one of these objects per physical call site rather than one per closure per physical call site.

Yes. My intent when writing that was to have one per physical call-site and to not multiply objects per-closure. I explicitly wanted these to be usable to memoize computation that is independent of the values of the holes so they should allow communication between closures.

Given the current module language, I would say that these are unexported const declarations that are hoisted to be children of the closest containing ModuleBody or Program node and precede the sibling out of which they are hoisted.