Multiline Strings

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

Multiline Strings

Florian Bösch
I'm sorry if that's been asked before (I looked trough the archives trough to 2012 and couldn't find a thread on it).

Are there any plans on adding multiline strings?

Some examples of multiline strings below.

Lua:
foo = [[A
Multiline
String]]

Python:
foo = '''A
Multiline
String'''

Coffeescript:
foo = '''A
Multiline
String'''

Dart:
foo = ''''A
Multiline
String'''

C++11:
foo = R"bar(A
Multiline
String)bar";

Ruby:
foo = 'A
Multiline
String'



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Multiline Strings

Claude Pache
We precisely discussed templates on es-discuss tonight. If I believe what I just read on [1], you will be able to write:

foo = `A
Multiline
String`

—Claude

[1] http://www.slideshare.net/domenicdenicola/es6-the-awesome-parts/23



Le 7 mars 2014 à 08:21, Florian Bösch <[hidden email]> a écrit :

> I'm sorry if that's been asked before (I looked trough the archives trough to 2012 and couldn't find a thread on it).
>
> Are there any plans on adding multiline strings?
>
> Some examples of multiline strings below.
>
> Lua:
> foo = [[A
> Multiline
> String]]
>
> Python:
> foo = '''A
> Multiline
> String'''
>
> Coffeescript:
> foo = '''A
> Multiline
> String'''
>
> Dart:
> foo = ''''A
> Multiline
> String'''
>
> C++11:
> foo = R"bar(A
> Multiline
> String)bar";
>
> Ruby:
> foo = 'A
> Multiline
> String'
>
>
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Multiline Strings

Florian Bösch
On Fri, Mar 7, 2014 at 8:36 AM, Claude Pache <[hidden email]> wrote:
We precisely discussed templates on es-discuss tonight. If I believe what I just read on [1], you will be able to write:
Ah cool, sorry :)

A follow up question on that has to do with line number/column.

If you're doing things like this in say myfile.js (line numbers leading)

01: compileShader('''essl
02:  void main(){
03:    gl_FragColor = vec3(1.0); // would be an error
04:  } 
05: ''');

Then the function that gets such a string would very much like to say something like:

Error in GLSL File: myfile.js, Line: 3
...

There's two complications with that. A string doesn't carry the line number it comes from. Also, myfile.js might get concated with other files. And lastly strings might get pasted together from smaller snippets.

The solution to this issue I'm using at the moment translates things like that to:

compileShader('''#line 1 file myfile.js
#line 2 myfile.js
  void main(){
#line 3 myfile.js
    gl_FragColor = vec3(1.0); // would be an error
#line 4 myfile.js
  } 
#line 5 myfile.js
''');

I'm wondering if there's interest to address this issue within ES? I'm also wondering if Multiline strings are the right tool to address them?



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Multiline Strings

Peter van der Zee
On Fri, Mar 7, 2014 at 8:56 AM, Florian Bösch <[hidden email]> wrote:

> There's two complications with that. A string doesn't carry the line number
> it comes from. Also, myfile.js might get concated with other files. And
> lastly strings might get pasted together from smaller snippets.

I think you want to take a look at "source maps". They're specifically
designed to deal with this problem.
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Multiline Strings

Florian Bösch
On Fri, Mar 7, 2014 at 8:52 PM, Peter van der Zee <[hidden email]> wrote:
I think you want to take a look at "source maps". They're specifically
designed to deal with this problem.

The problem is that a function like compileShader would look like this:

var compileShader(source){
   var shader = gl.createShader(gl.VERTEX_SHADER);
   gl.shaderSource(shader, source);
   gl.compileShader(shader);
   if(!gl.getShaderParameter(GL_COMPILE_STATUS)){
     var error = glGetShaderInfoLog(shader);
     // now what?
     // need file of source
     // need lines # of source
   }
}

And you'd do things like:

var source = """
   void main(){
      #{someSnippet}
      gl_FragColor = whatever;
   }
"""
compileShader(source);

I don't see how source maps help either.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Multiline Strings

John Barton
You may like to take a look at how the traceur compiler (https://github.com/google/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 ;-)



jjb


On Sat, Mar 8, 2014 at 3:41 AM, Florian Bösch <[hidden email]> wrote:
On Fri, Mar 7, 2014 at 8:52 PM, Peter van der Zee <[hidden email]> wrote:
I think you want to take a look at "source maps". They're specifically
designed to deal with this problem.

The problem is that a function like compileShader would look like this:

var compileShader(source){
   var shader = gl.createShader(gl.VERTEX_SHADER);
   gl.shaderSource(shader, source);
   gl.compileShader(shader);
   if(!gl.getShaderParameter(GL_COMPILE_STATUS)){
     var error = glGetShaderInfoLog(shader);
     // now what?
     // need file of source
     // need lines # of source
   }
}

And you'd do things like:

var source = """
   void main(){
      #{someSnippet}
      gl_FragColor = whatever;
   }
"""
compileShader(source);

I don't see how source maps help either.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Multiline Strings

Florian Bösch
On Sat, Mar 8, 2014 at 6:10 PM, John Barton <[hidden email]> wrote:
You may like to take a look at how the traceur compiler (https://github.com/google/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?

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Multiline Strings

Mark S. Miller-2
On Sat, Mar 8, 2014 at 9:30 AM, Florian Bösch <[hidden email]> wrote:
On Sat, Mar 8, 2014 at 6:10 PM, John Barton <[hidden email]> wrote:
You may like to take a look at how the traceur compiler (https://github.com/google/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 <http://www.slideshare.net/domenicdenicola/es6-the-awesome-parts/23>, 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:


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 __LINE__.

4) Browsers are still all over the place in how they report Error stack trace information. Even after all the renormalizing done at <https://code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/debug.js#157>, 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 <https://code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/startSES.js#856> I'm adding the source info that eval is supposed to use, as explained at [3], where the alleged source file is <http://example.com/fake1.js> and <http://example.com/fake2.js>. (See <https://code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/explicit.html#183>.) 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(
    Object.freeze({
      raw:    Object.freeze(['', ' + ', '\\n = ', '']),
      cooked: Object.freeze(['', ' + ', '\n = ', ''])
    }),
    x,
    y,
    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.

Opera20: <https://drive.google.com/file/d/0Bw0VXJKBgYPMUjVtdWxBR0hRTUE> (Unsurprisingly, essentially the same as Chrome)


--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Multiline Strings

Mark Miller-2
On Sat, Mar 8, 2014 at 11:05 AM, Mark S. Miller <[hidden email]> wrote:
On Sat, Mar 8, 2014 at 9:30 AM, Florian Bösch <[hidden email]> wrote:
On Sat, Mar 8, 2014 at 6:10 PM, John Barton <[hidden email]> wrote:
You may like to take a look at how the traceur compiler (https://github.com/google/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 <http://www.slideshare.net/domenicdenicola/es6-the-awesome-parts/23>, 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:


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 __LINE__.

4) Browsers are still all over the place in how they report Error stack trace information. Even after all the renormalizing done at <https://code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/debug.js#157>, 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.

To see these for yourself in your own browsers, visit <http://google-caja.googlecode.com/svn/trunk/src/com/google/caja/ses/explicit.html>.

 

5) At <https://code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/startSES.js#856> I'm adding the source info that eval is supposed to use, as explained at [3], where the alleged source file is <http://example.com/fake1.js> and <http://example.com/fake2.js>. (See <https://code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/explicit.html#183>.) 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(
    Object.freeze({
      raw:    Object.freeze(['', ' + ', '\\n = ', '']),
      cooked: Object.freeze(['', ' + ', '\n = ', ''])
    }),
    x,
    y,
    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.

Opera20: <https://drive.google.com/file/d/0Bw0VXJKBgYPMUjVtdWxBR0hRTUE> (Unsurprisingly, essentially the same as Chrome)


--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss




--
Text by me above is hereby placed in the public domain

  Cheers,
  --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Multiline Strings

Mark Miller-2
On Sat, Mar 8, 2014 at 11:14 AM, Mark Miller <[hidden email]> wrote:
[...]
To see these for yourself in your own browsers, visit <http://google-caja.googlecode.com/svn/trunk/src/com/google/caja/ses/explicit.html>.

and click of the last two "[+]"s to expand these.
 
--

  Cheers,
  --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Multiline Strings

Allen Wirfs-Brock
In reply to this post by Mark S. Miller-2

On Mar 8, 2014, at 11:05 AM, Mark S. Miller wrote:



[1] A more correct expansion is:

  var whatsThis = func(
    Object.freeze({
      raw:    Object.freeze(['', ' + ', '\\n = ', '']),
      cooked: Object.freeze(['', ' + ', '\n = ', ''])
    }),
    x,
    y,
    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.

Actually, more like:

  var whatsThis = func(
    Object.freeze(
      Object.defineOwnProperty(['', ' + ', '\n = ', ''],'raw', {value: Object.freeze(['', ' + ', '\\n = ', ''])}
    ),
    x,
    y,
    x + y
  );


As the "cooked" array itself is now specified as the call site object. See http://people.mozilla.org/~jorendorff/es6-draft.html#sec-runtime-semantics-runtime-semantics-argumentlistevaluation 

I'll add a note about possible future properties.  Also,  current spec. says the raw property is enumberable.  That sounds like a bug I'll fix. (don't want "raw" showing up if somebody for-in enumerates the call-site object.

Allen


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss