Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.javascript > #7529 > unrolled thread

Parsing String of Named Function & Converting To Source

Started bySeni Seven <OneWhoLovesYou@humanitarian.ca.invalid>
First post2011-10-18 13:48 +0000
Last post2011-10-19 20:09 +0100
Articles 6 — 5 participants

Back to article view | Back to comp.lang.javascript


Contents

  Parsing String of Named Function & Converting To Source Seni Seven <OneWhoLovesYou@humanitarian.ca.invalid> - 2011-10-18 13:48 +0000
    Re: Parsing String of Named Function & Converting To Source Andreas Bergmaier <andber93@web.de> - 2011-10-18 16:03 +0200
      Re: Parsing String of Named Function & Converting To Source Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2011-10-18 19:29 +0200
    Re: Parsing String of Named Function & Converting To Source Lasse Reichstein Nielsen <lrn.unread@gmail.com> - 2011-10-18 18:34 +0200
      Re: Parsing String of Named Function & Converting To Source Seni Seven <OneWhoLovesYou@humanitarian.ca.invalid> - 2011-10-19 08:01 +0000
      Re: Parsing String of Named Function & Converting To Source Dr J R Stockton <reply1142@merlyn.demon.co.uk> - 2011-10-19 20:09 +0100

#7529 — Parsing String of Named Function & Converting To Source

FromSeni Seven <OneWhoLovesYou@humanitarian.ca.invalid>
Date2011-10-18 13:48 +0000
SubjectParsing String of Named Function & Converting To Source
Message-ID<Xns9F82AB08718BBSSca@88.198.244.100>
Suppose I have HTML markup with a SCRIPT element as shown below:

  <script type="text/javascript">
  function multiply(a, b) {
     return a * b;
  }
  var i = multiply(2, 5);
  document.write("The value of <i>i</i> is " + i);
  </script>

All of this markup and contained script code is retrieved as a string using 
Ajax.

I have an HTML parser with support for parsing the string containing the 
script code.

In parsing the contained code (using JavaScript, of course), how would you 
convert the contained script code from string into source?

What I have found so far (using Firebug in Firefox for development) is this:

1) Isolating the string "function multiply(a, b) { return a * b; }" and then 
passing that string as an argument to eval() does not cause the definition 
of the function named "multiply," it seems.

2) I can parse the function definition in a way to create the string:

  "var multiply = new Function (\"a\", \"b\", \"{ return a * b; }\");"

and then use eval() on it (without error).  And then when I eval() the 
global level code in a debugger (Firebug in FireFox), as so

   eval("var i = multiply(2, 5); document.write(\"The value " +
     "of <i>i</i> is \" + i);");  // parsed code as string on one line


the value of identifier 'i' is immediately set to 10 in the debugger, but 
the debugger exits with error 'multiply is not defined', which indicates 
multiple levels of execution contexts, I suppose.  In fact, if I just do an 
eval() on the "multiply" assignment of the Function constructor, the 
identifier 'multiply' is still not defined.

QUESTION:  What's the solution to the goal I want to achieve?

[don't worry about the 'document.write()' call for the moment: that string 
pattern gets replaced eventually with a function that injects DOM nodes into 
the tree in the same way document.write() would on document loading]


For those who are curious as to why I would want to do this, there is a 
basis for this.  See BACKGROUND below.



BACKGROUND

I have a modular interactive chemistry calculator running entirely on the 
client side.

The "modularity" is such that a main HTML document provides a base interface 
and I extend functionality by reading in one JS file which specifies a 
document in HTML markup--the markup is valid, but not the document--which is 
read in using Ajax.  The JS file also contains all the code for doing the 
chemistry calculations specific for that module.

The string representing the markup obtained by Ajax retrieval is then passed 
to a parsing function which is supposed to do it all:  parses the HTML 
markup using DOM methods to insert the DocumentFragment into the main 
document tree.  It also parses CSS (stylesheets and style attributes), as 
well as any Javascript contained inside SCRIPT elements.  Everything becomes 
part of the interactive document by using DOM method calls, HTML --> element  
nodes with attributes; CSS --> as stylesheets in LINK element nodes for 
external stylesheets, as style property changes to DOM element nodes where 
style attributes are identified;  JavaScript --> converting strings into 
executable source, parsing named functions from global level source (which 
might be wrapped in anonymous functions and called).

So far there has been no problem with the HTML and CSS.  It's the Javascript 
that remains a barrier now.

Security considerations:  all the module HTML documents and JS files are 
delivered from the same server, the one from which the main document was 
loaded.  Inherent Javascript security features against accessing the file 
system without user permissions are always in play.

[toc] | [next] | [standalone]


#7530

FromAndreas Bergmaier <andber93@web.de>
Date2011-10-18 16:03 +0200
Message-ID<j7k0uo$uee$1@news.albasani.net>
In reply to#7529
Seni Seven schrieb:
> Suppose I have HTML markup with a SCRIPT element as shown below:
>
>    <script type="text/javascript">
>    function multiply(a, b) {
>       return a * b;
>    }
>    var i = multiply(2, 5);
>    document.write("The value of<i>i</i>  is " + i);
>    </script>
>
> All of this markup and contained script code is retrieved as a string using
> Ajax.
>
> I have an HTML parser with support for parsing the string containing the
> script code.
>
> In parsing the contained code (using JavaScript, of course), how would you
> convert the contained script code from string into source?
>
> The string representing the markup obtained by Ajax retrieval is then passed
> to a parsing function which is supposed to do it all:  parses the HTML
> markup using DOM methods to insert the DocumentFragment into the main
> document tree.  It also parses CSS (stylesheets and style attributes), as
> well as any Javascript contained inside SCRIPT elements.  Everything becomes
> part of the interactive document by using DOM method calls, HTML -->  element
> nodes with attributes; CSS -->  as stylesheets in LINK element nodes for
> external stylesheets, as style property changes to DOM element nodes where
> style attributes are identified;  JavaScript -->  converting strings into
> executable source, parsing named functions from global level source (which
> might be wrapped in anonymous functions and called).

Why do you try to build an (x)html parser in javascript (@PE: or one of 
its dialects)?
I see two solutions to your problem:
* Use your parser to append the "script" node from the ajaxed fragment 
into your document, just as style nodes and everything other. The script 
then should be executed in your global environment.
* Why don't you use iframes? Then valid documents were needed (instead 
of your fragments), but you wouldn't have to build a error-prone parser. 
As the fragments load from the same server, you could even copy the 
DOM-tree from the (hidden) iframe into your document if you need that.

  Bergi

[toc] | [prev] | [next] | [standalone]


#7543

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2011-10-18 19:29 +0200
Message-ID<3072618.pbM1GnOhur@PointedEars.de>
In reply to#7530
Andreas Bergmaier wrote:

> Why do you try to build an (x)html parser

Because it is an interesting problem to solve; `innerHTML' is proprietary, 
unreliable and undocumented by comparison.  I would probably skip the XHTML 
part, though, because there's DOMParser.

> in javascript (@PE: or one of its dialects)?

There is no "javascript", so there are no "javascript dialects" :)

I might comment on the rest later.


PointedEars
-- 
Danny Goodman's books are out of date and teach practices that are
positively harmful for cross-browser scripting.
 -- Richard Cornford, cljs, <cife6q$253$1$8300dec7@news.demon.co.uk> (2004)

[toc] | [prev] | [next] | [standalone]


#7541

FromLasse Reichstein Nielsen <lrn.unread@gmail.com>
Date2011-10-18 18:34 +0200
Message-ID<8voi2r92.fsf@gmail.com>
In reply to#7529
Seni Seven <OneWhoLovesYou@humanitarian.ca.invalid> writes:

> Suppose I have HTML markup with a SCRIPT element as shown below:
>
>   <script type="text/javascript">
>   function multiply(a, b) {
>      return a * b;
>   }
>   var i = multiply(2, 5);
>   document.write("The value of <i>i</i> is " + i);

Invalid HTML 4 markup. You should escape the </ inside the string.

>   </script>
>
> All of this markup and contained script code is retrieved as a string using 
> Ajax.

So, it's a string with the above content (newlines and all).

> I have an HTML parser with support for parsing the string containing the 
> script code.

Ok.

> In parsing the contained code (using JavaScript, of course), how would you 
> convert the contained script code from string into source?

What's the difference? I assume your HTML parser extracts the content
of the script element as a string.
What do you want to do with that string?

> What I have found so far (using Firebug in Firefox for development) is this:
>
> 1) Isolating the string "function multiply(a, b) { return a * b; }" and then 
> passing that string as an argument to eval() does not cause the definition 
> of the function named "multiply," it seems.

It probably does, but in the scope where the eval is executed, not at
the global scope.
For that, you can use, e.g., 
  window.eval(sourceString);
(or any other non-direct call to eval).


> 2) I can parse the function definition in a way to create the string:
>
>   "var multiply = new Function (\"a\", \"b\", \"{ return a * b; }\");"

How wasteful :) The function syntax is perfectly fine, no need to make
it more convoluted.

> and then use eval() on it (without error).  And then when I eval() the 
> global level code in a debugger (Firebug in FireFox), as so
>
>    eval("var i = multiply(2, 5); document.write(\"The value " +
>      "of <i>i</i> is \" + i);");  // parsed code as string on one line
>
>
> the value of identifier 'i' is immediately set to 10 in the debugger, but 
> the debugger exits with error 'multiply is not defined', which indicates 
> multiple levels of execution contexts, I suppose.  In fact, if I just do an 
> eval() on the "multiply" assignment of the Function constructor, the 
> identifier 'multiply' is still not defined.
>
> QUESTION:  What's the solution to the goal I want to achieve?

Try:
  var script = document.createElement("script");
  script.textContent = sourceString;
  document.body.appendChild(script);
This executes the code as top-level, non-eval code (which there is no way
to do in pure Javascript).
No guarantees wrt. old browsers, but it seems to work in the current versions.

Alternatively, just use a non-direct call to eval.
 var topLevelEval = eval;
 topLevelEval(sourceString);

> The string representing the markup obtained by Ajax retrieval is then passed 
> to a parsing function which is supposed to do it all:  parses the HTML 
> markup using DOM methods to insert the DocumentFragment into the main 
> document tree.  It also parses CSS (stylesheets and style attributes), as 
> well as any Javascript contained inside SCRIPT elements.  Everything becomes 
> part of the interactive document by using DOM method calls, HTML --> element  
Why not pass it as something easier to parse and separate into
CSS/HTML/JS, e.g., JSON?

/L
-- 
Lasse Reichstein Holst Nielsen
 'Javascript frameworks is a disruptive technology'
  

[toc] | [prev] | [next] | [standalone]


#7560

FromSeni Seven <OneWhoLovesYou@humanitarian.ca.invalid>
Date2011-10-19 08:01 +0000
Message-ID<Xns9F83701848613SSca@88.198.244.100>
In reply to#7541
Lasse Reichstein Nielsen <lrn.unread@gmail.com> wrote on Tue 18 Oct 2011
07:34:17p 

> Seni Seven <OneWhoLovesYou@humanitarian.ca.invalid> writes:
> 
>> Suppose I have HTML markup with a SCRIPT element as shown below:
>>
>>   <script type="text/javascript">
>>   function multiply(a, b) {
>>      return a * b;
>>   }
>>   var i = multiply(2, 5);
>>   document.write("The value of <i>i</i> is " + i);
> 
> Invalid HTML 4 markup. You should escape the </ inside the string.

Yes, my parser actually stopped on the "</i>" etago markup, of all things.

And yes, the HTML 4.1 recommendation specifies this is invalid.

Then I read one article (I believe there are others) on this subject of 
CDATA content inside a SCRIPT element which first asserted that (1) it was 
nonsense to have this in the recommendation and (2) that no browser 
implementation actually followed this part of the recommendation:  that is, 
all textual content between the start and end tag of a SCRIPT element was 
not effectively regarded as part of HTML markup, so I made my parser ignore 
all content between the start and end tag of a SCRIPT element and process it 
as script code.

But even so, I admit that I should backlash the string pattern "</" 
appropriately to be in compliance with the recommendation.

> 
>>   </script>
>>
>> All of this markup and contained script code is retrieved as a string
>> using Ajax.
> 
> So, it's a string with the above content (newlines and all).

Ajax effectively recovers data that become strings if handled by 
ECMAscript/Javascript, doesn't it?

>> I have an HTML parser with support for parsing the string containing
>> the script code.
> 
> Ok.
> 
>> In parsing the contained code (using JavaScript, of course), how would
>> you convert the contained script code from string into source?
> 
> What's the difference? I assume your HTML parser extracts the content
> of the script element as a string.
> What do you want to do with that string?

Well, normally, all script as either elements in HTML documents or loaded 
from external JS files get processed during HTML document loading in the 
browser.  This is before the document.close() call has effectively been 
invoked and completed, right?

But what do you do if you bring in ECMAscript code (as strings via Ajax) 
AFTER the document.close() call has been made?  You want to make function 
definitions (named functions) part of the executable code in the HTML 
document (object?), just as if it were made during document loading.  As for 
script code outside of named function definition scope, you want to parse 
and execute immediately, in order of retrieval via Ajax.

 
>> What I have found so far (using Firebug in Firefox for development) is
>> this: 
>>
>> 1) Isolating the string "function multiply(a, b) { return a * b; }" and
>> then passing that string as an argument to eval() does not cause the
>> definition of the function named "multiply," it seems.
> 
> It probably does, but in the scope where the eval is executed, not at
> the global scope.
> For that, you can use, e.g., 
>   window.eval(sourceString);
> (or any other non-direct call to eval).

Okay.

>> 2) I can parse the function definition in a way to create the string:
>>
>>   "var multiply = new Function (\"a\", \"b\", \"{ return a * b; }\");"
> 
> How wasteful :) The function syntax is perfectly fine, no need to make
> it more convoluted.
> 
>> and then use eval() on it (without error).  And then when I eval() the 
>> global level code in a debugger (Firebug in FireFox), as so
>>
>>    eval("var i = multiply(2, 5); document.write(\"The value " +
>>      "of <i>i</i> is \" + i);");  // parsed code as string on one line
>>
>>
>> the value of identifier 'i' is immediately set to 10 in the debugger,
>> but the debugger exits with error 'multiply is not defined', which
>> indicates multiple levels of execution contexts, I suppose.  In fact,
>> if I just do an eval() on the "multiply" assignment of the Function
>> constructor, the identifier 'multiply' is still not defined.
>>
>> QUESTION:  What's the solution to the goal I want to achieve?
> 
> Try:
>   var script = document.createElement("script");
>   script.textContent = sourceString;
>   document.body.appendChild(script);
> This executes the code as top-level, non-eval code (which there is no
> way to do in pure Javascript).
> No guarantees wrt. old browsers, but it seems to work in the current
> versions. 

Yes, tried, and found it works.

> Alternatively, just use a non-direct call to eval.
>  var topLevelEval = eval;
>  topLevelEval(sourceString);

Yes, tried, and found it works.

I am looking at search results (http://is.gd/jwhNln) to understand why 
indirect calls to eval() work.
> 
>> The string representing the markup obtained by Ajax retrieval is then
>> passed to a parsing function which is supposed to do it all:  parses
>> the HTML markup using DOM methods to insert the DocumentFragment into
>> the main document tree.  It also parses CSS (stylesheets and style
>> attributes), as well as any Javascript contained inside SCRIPT
>> elements.  Everything becomes part of the interactive document by using
>> DOM method calls, HTML --> element  
> Why not pass it as something easier to parse and separate into
> CSS/HTML/JS, e.g., JSON?

I will look into this most certainly and try to make it workable.


The suggestion by poster "Andreas Bergmaier" to use iframes probably is 
worthy of exploring.  Perhaps I made this overly complicated.

[toc] | [prev] | [next] | [standalone]


#7572

FromDr J R Stockton <reply1142@merlyn.demon.co.uk>
Date2011-10-19 20:09 +0100
Message-ID<fyJIlYLACynOFwa3@invalid.uk.co.demon.merlyn.invalid>
In reply to#7541
In comp.lang.javascript message <8voi2r92.fsf@gmail.com>, Tue, 18 Oct
2011 18:34:17, Lasse Reichstein Nielsen <lrn.unread@gmail.com> posted:

>Seni Seven <OneWhoLovesYou@humanitarian.ca.invalid> writes:
>
>> Suppose I have HTML markup with a SCRIPT element as shown below:
>>
>>   <script type="text/javascript">
>>   function multiply(a, b) {
>>      return a * b;
>>   }
>>   var i = multiply(2, 5);
>>   document.write("The value of <i>i</i> is " + i);
>>   </script>
>>
>> All of this markup and contained script code is retrieved as a string using
>> Ajax.

>> I have an HTML parser with support for parsing the string containing the
>> script code.

>> In parsing the contained code (using JavaScript, of course), how would you
>> convert the contained script code from string into source?

>> ...

>> the value of identifier 'i' is immediately set to 10 in the debugger, but
>> the debugger exits with error 'multiply is not defined', which indicates
>> multiple levels of execution contexts, I suppose.  In fact, if I just do an
>> eval() on the "multiply" assignment of the Function constructor, the
>> identifier 'multiply' is still not defined.
>>
>> QUESTION:  What's the solution to the goal I want to achieve?


I've done that, or something rather similar, in
<http://www.merlyn.demon.co.uk/js-randm.htm> - the code for inserting
Johannes Baagoe's (or other) functions.  IIRC, it was necessary to be
slightly subtle about the argument to 'eval', perhaps such as something
like prepending " XXX = " to the function - see the source code of the
page.



>Try:
>  var script = document.createElement("script");
>  script.textContent = sourceString;
>  document.body.appendChild(script);
>This executes the code as top-level, non-eval code (which there is no way
>to do in pure Javascript).
>No guarantees wrt. old browsers, but it seems to work in the current versions.
>
>Alternatively, just use a non-direct call to eval.
> var topLevelEval = eval;
> topLevelEval(sourceString);

Would any of your contribution give a worthwhile improvement in the
cited js-randm.htm, given that the latter works?

-- 
 (c) John Stockton, nr London, UK. ?@merlyn.demon.co.uk  Turnpike 6.05  WinXP.
 Web  <http://www.merlyn.demon.co.uk/> - FAQ-type topics, acronyms, and links.
 Command-prompt MiniTrue is useful for viewing/searching/altering files. Free,
 DOS/Win/UNIX now 2.0.6; see <URL:http://www.merlyn.demon.co.uk/pc-links.htm>.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.javascript


csiph-web