/[suikacvs]/markup/html/scripting-parser/parser.html
Suika

Contents of /markup/html/scripting-parser/parser.html

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.2 - (show annotations) (download) (as text)
Sun Apr 20 07:48:00 2008 UTC (18 years, 3 months ago) by wakaba
Branch: MAIN
Changes since 1.1: +182 -11 lines
File MIME type: text/html
Scripting support, first version (only placeholder for document.write is implemented)

1 <!DOCTYPE HTML>
2 <html lang=en>
3 <head>
4 <title>Demo of HTML5 Parsing Algorithm with Scripting Enabled</title>
5 <style>
6 textarea {
7 display: block;
8 width: 80%;
9 margin-left: auto;
10 margin-right: auto;
11 min-height: 20em;
12 }
13 output {
14 display: block;
15 font-family: monospace;
16 white-space: pre;
17 }
18 </style>
19 <script>
20 function update () {
21 document.logElement.textContent = '';
22 var p = new Parser (new InputStream (document.sourceElement.value));
23 p.parse ();
24 log (dumpTree (p.doc, ''));
25 } // update
26
27 function log (s) {
28 document.logElement.appendChild (document.createTextNode (s + "\n"));
29 } // log
30
31 function InputStream (s) {
32 this.s = s;
33 } // InputStream
34
35 function Parser (i) {
36 this.parseMode = 'pcdata';
37 this.doc = new JSDocument (this);
38 this.openElements = [this.doc];
39 this.in = i;
40 } // Parser
41
42 Parser.prototype.getNextToken = function () {
43 var i = this.in;
44 if (this.parseMode == 'script') {
45 var token;
46 i.s = i.s.replace (/^([\s\S]+?)<\/[Ss][Cc][Rr][Ii][Pp][Tt]>/,
47 function (s, t) {
48 token = {type: 'char', value: t};
49 return '<' + '/script>';
50 });
51 if (token) return token;
52 i.s = i.s.replace (/^<\/[Ss][Cc][Rr][Ii][Pp][Tt]>/, function () {
53 token = {type: 'end-tag', value: 'script'};
54 return '';
55 });
56 if (token) return token;
57 return {type: 'eof'};
58 }
59
60 var token;
61 i.s = i.s.replace (/^<\/([^>]+)>/, function (s, e) {
62 token = {type: 'end-tag', value: e.toLowerCase ()};
63 return '';
64 });
65 if (token) return token;
66 i.s = i.s.replace (/^<([^>]+)>/, function (s, e) {
67 token = {type: 'start-tag', value: e.toLowerCase ()};
68 return '';
69 });
70 if (token) return token;
71 i.s = i.s.replace (/^[^<]+/, function (s) {
72 token = {type: 'char', value: s};
73 return '';
74 });
75 if (token) return token;
76 i.s = i.s.replace (/^[\s\S]/, function (s) {
77 token = {type: 'char', value: s};
78 return '';
79 });
80 if (token) return token;
81 return {type: 'eof'};
82 } // getNextToken
83
84 Parser.prototype.parse = function () {
85 log ('start parsing');
86
87 while (true) {
88 var token = this.getNextToken ();
89 log ('token: ' + token.type + ' "' + token.value + '"');
90
91 if (token.type == 'start-tag') {
92 if (token.value == 'script') {
93 // 1. Create an element for the token in the HTML namespace.
94 var el = new JSElement (this.doc, token.value);
95
96 // 2. Mark the element as being "parser-inserted".
97 el.manakaiParserInserted = true;
98
99 // 3. Switch the tokeniser's content model flag to the CDATA state.
100 this.parseMode = 'script';
101
102 // 4.1. Collect all the character tokens.
103 while (true) {
104 var token = this.getNextToken ();
105 log ('token: ' + token.type + ' "' + token.value + '"');
106
107 if (token.type == 'char') {
108 // 5. Append a single Text node to the script element node.
109 el.manakaiAppendText (token.value);
110
111 // 4.2. Until it returns a token that is not a character token, or
112 // TODO: 4.3. Until it stops tokenising.
113 } else if (token.type == 'eof' ||
114 (token.type == 'end-tag' && token.value == 'script')) {
115 // 6. Switched back to the PCDATA state.
116 this.parseMode = 'pcdata';
117
118 // 7.1. If the next token is not an end tag token with ...
119 if (token.type != 'end-tag') {
120 // 7.2. This is a parse error.
121 log ('Parse error: no </' + 'script>');
122
123 // 7.3. Mark the script element as "already executed".
124 el.manakaiAlreadyExecuted = true;
125 } else {
126 // 7.4. Ignore it.
127 //
128 }
129 break;
130 }
131 }
132
133 // 8.1. If the parser were originally created for the ...
134 if (this.fragmentParsingMode) {
135 // 8.2. Mark the script element as "already executed" and ...
136 el.alreadyExecuted = true;
137 continue;
138 }
139
140 // 9.1. Let the old insertion point have the same value as the ...
141
142 // 9.2. Let the insertion point be just before the next input ...
143
144 // 10. Append the new element to the current node.
145