Multiline Strings

Mark S. Miller erights at
Sat Mar 8 11:05:27 PST 2014

On Sat, Mar 8, 2014 at 9:30 AM, Florian Bösch <pyalot at> wrote:

> On Sat, Mar 8, 2014 at 6:10 PM, John Barton <johnjbarton at>wrote:
>> You may like to take a look at how the traceur compiler (
>> works. It allows one to
>> write code like
>>      var statement = parseStatement `${result}[${index}++] =
>> ${expression};`;
>> where the ${} syntax surrounds variables from the caller that are
>> substituted into the string.  In our case the result 'statement' is an AST
>> but it could source code just as well. And source maps work fine for our
>> code. Well as fine a source maps ever work ;-)
> That's a fine approach, and I'm not against preprocessing in any flavor if
> that's your cup-o-tea. The problem rather is that one explicit usecase of
> multiline strings (aka templates) is to make it easier to write DSLs. But
> if you write DSLs and embedd the strings in your JS source somewhere,
> you're gonna have to deal with debugging of any kind.
> For example, WebGL implementations return errors strings like these:
> ERROR: 0:1: 'foobar' : syntax error
> You can imagine that being confronted with a string like that, out of
> thousands of shader code lines in your application, isn't very useful.
> You'll also realize that, not all errors can actually be detected with a
> validator.
> In order to make this a useful piece of error message, you'll need to
> translate whatever WebGL throws back at you, to a sourceline and filename.
> And unless you instrumented this beforehand with a preprocessor, you're not
> gonna get it.
> So my question is this, is everybody happy with the state of affairs that
> a preprocessor is the only viable way to use templates/multiline strings
> for DSLs, or am I the only one who thinks that could somehow be better?

Thanks for raising this. I agree you've identified a real issue. Referring
to slide #28 of Domenic's presentation at <>, we'd
need to add an array of sourcemaps to the frozen[1] record, to parallel the
raw and cooked arrays, that say where each character of the raw and/or
cooked arrays come from in the source. The func, which is the
template-string-parser of the embedded DSL, has no other way to recover
this information. The source-map-array should probably only describe the
origins of the characters in the cooked array, since the origins of the
characters in the raw array can be derived from this but not vice versa.

None of this would effect the use of template strings in Traceur that John
describes, as he's interested in source positions in the file being
translated, not source positions in the template strings within the Traceur
compiler used to describe these translations. But for debugging Traceur
itself, one may well be interested in the latter.

There are several issues with this, none of which are show stoppers:

1) There is not yet a standard for sourcemaps. But see <>,
and <>. Would someone care to
champion this for inclusion in ES7?

2) Since this can be addressed compatibly in ES7, we should note in ES6
that future editions may add more frozen data to this record, that can be
feature tested for.

3) Code doesn't normally know where it came from. Adding these to
template-string records will give JavaScript the power of __FILE__ and

4) Browsers are still all over the place in how they report Error stack
trace information. Even after all the renormalizing done at <>,
we still get the divergent stack traces shown at[2]. For all of these, the
first stack trace comes from within a call to eval. The second from a
dynamically generated script tag.

5) At <>
I'm adding the source info that eval is supposed to use, as explained at
[3], where the alleged source file is <> and <>. (See <>.)
However, that alleged source file name is not showing up in *any* of the
browser stack traces. Am I not using [3] correctly?

I would hope all of these could be addressed in ES7, including the addition
of an array of source maps to the template string record.

[1] A more correct expansion is:

  var whatsThis = func(
      raw:    Object.freeze(['', ' + ', '\\n = ', '']),
      cooked: Object.freeze(['', ' + ', '\n = ', ''])
    x + y

except that the record is evaluated once per evaluation of the enclosing
Program (loading of the compilation unit), rather than per evaluation of
the expression. This allows func to memoize template-string-parsings on the
identity of the record.

[2] chrome-canary-35: <>
FFNightly30-0a1: <>
Safari702: <>
Opera20: <>
(Unsurprisingly, essentially the same as Chrome)

[3] <

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the es-discuss mailing list