/[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.6 - (hide annotations) (download) (as text)
Fri Apr 25 13:42:51 2008 UTC (18 years, 6 months ago) by wakaba
Branch: MAIN
Changes since 1.5: +103 -14 lines
File MIME type: text/html
<script src> in parsing algorithm is now supported

1 wakaba 1.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 wakaba 1.4 white-space: -moz-pre-wrap;
17     white-space: pre-wrap;
18 wakaba 1.1 }
19     </style>
20     <script>
21     function update () {
22     document.logElement.textContent = '';
23 wakaba 1.2 var p = new Parser (new InputStream (document.sourceElement.value));
24 wakaba 1.4 var doc = p.doc;
25 wakaba 1.2 p.parse ();
26 wakaba 1.4 log (dumpTree (doc, ''));
27 wakaba 1.1 } // update
28    
29 wakaba 1.6 var logIndentLevel = 0;
30 wakaba 1.1 function log (s) {
31 wakaba 1.6 for (var i = 0; i < logIndentLevel; i++) {
32     s = ' ' + s;
33     }
34 wakaba 1.1 document.logElement.appendChild (document.createTextNode (s + "\n"));
35     } // log
36    
37     function InputStream (s) {
38     this.s = s;
39     } // InputStream
40    
41 wakaba 1.4 function Parser (i, doc) {
42 wakaba 1.1 this.parseMode = 'pcdata';
43 wakaba 1.4 if (!doc) {
44     doc = new JSDocument (this);
45     doc.manakaiIsHTML = true;
46     }
47     this.doc = doc;
48     this.openElements = [doc];
49 wakaba 1.2 this.in = i;
50 wakaba 1.4 this.scriptsExecutedAfterParsing = [];
51 wakaba 1.1 } // Parser
52    
53 wakaba 1.2 Parser.prototype.getNextToken = function () {
54 wakaba 1.3 var p = this;
55 wakaba 1.2 var i = this.in;
56 wakaba 1.1 if (this.parseMode == 'script') {
57     var token;
58 wakaba 1.3 if (p.insertionPoint <= 0) {
59     return {type: 'abort'};
60     }
61 wakaba 1.4 i.s = i.s.replace (/^([^<]+)/,
62 wakaba 1.1 function (s, t) {
63 wakaba 1.3 if (0 < p.insertionPoint && p.insertionPoint < t.length) {
64     token = {type: 'char', value: t.substring (0, p.insertionPoint)};
65     var ip = p.insertionPoint;
66     p.insertionPoint = 0;
67 wakaba 1.4 return t.substring (ip, t.length);
68 wakaba 1.3 }
69 wakaba 1.1 token = {type: 'char', value: t};
70 wakaba 1.4 p.insertionPoint -= t.length;
71     return '';
72 wakaba 1.1 });
73     if (token) return token;
74 wakaba 1.3 i.s = i.s.replace (/^<\/[Ss][Cc][Rr][Ii][Pp][Tt]>/, function (s) {
75 wakaba 1.4 if (p.insertionPoint < s.length) {
76 wakaba 1.3 token = {type: 'abort'};
77     return s;
78     }
79 wakaba 1.1 token = {type: 'end-tag', value: 'script'};
80 wakaba 1.3 p.insertionPoint -= s.length;
81 wakaba 1.1 return '';
82     });
83     if (token) return token;
84 wakaba 1.5 var m;
85     if ((p.insertionPoint < '</script'.length) &&
86     (m = i.s.match (/^<\/([SCRIPTscript]+)/))) {
87     var v = m[1].substring (0, p.insertionPoint).toLowerCase ();
88     if (v == 'script'.substring (0, p.insertionPoint - '</'.length)) {
89     return {type: 'abort'};
90     }
91     }
92 wakaba 1.4 i.s = i.s.replace (/^</,
93     function (s) {
94     token = {type: 'char', value: s};
95     p.insertionPoint -= s.length;
96     return '';
97     });
98     if (token) return token;
99 wakaba 1.1 return {type: 'eof'};
100     }
101    
102     var token;
103 wakaba 1.5 i.s = i.s.replace (/^<\/([^>]+)(?:>|$)/, function (s, e) {
104     if (p.insertionPoint < s.length ||
105     (p.insertionPoint <= s.length &&
106     s.substring (s.length - 1, 1) != '>')) {
107 wakaba 1.3 token = {type: 'abort'};
108     return s;
109     }
110 wakaba 1.1 token = {type: 'end-tag', value: e.toLowerCase ()};
111 wakaba 1.3 p.insertionPoint -= s.length;
112 wakaba 1.1 return '';
113     });
114     if (token) return token;
115 wakaba 1.5 i.s = i.s.replace (/^<([^>]+)(?:>|$)/, function (s, e) {
116     if (p.insertionPoint < s.length ||
117     (p.insertionPoint <= s.length &&
118     s.substring (s.length - 1, 1) != '>')) {
119 wakaba 1.3 token = {type: 'abort'};
120     return s;
121     }
122 wakaba 1.4 var tagName;
123     var attrs = {};
124     e = e.replace (/^[\S]+/, function (v) {
125     tagName = v.toLowerCase ();
126     return '';
127     });
128 wakaba 1.6 e = e.replace (/^\s*([^\s=]+)\s*(?:=\s*(?:"([^"]*)"|'([^']*)'|([^"']+)))?/,
129 wakaba 1.4 function (x, attrName, attrValue1, attrValue2, attrValue3) {
130 wakaba 1.6 v = attrValue1 || attrValue2 || attrValue3;
131     v = v.replace (/&quot;/g, '"').replace (/&apos;/g, "'")
132     .replace (/&amp;/g, '&');
133     attrs[attrName.toLowerCase ()] = v;
134 wakaba 1.4 return '';
135     });
136 wakaba 1.6 if (e.length) {
137     log ('Broken start tag: "' + e + '"');
138     }
139 wakaba 1.4 token = {type: 'start-tag', value: tagName, attrs: attrs};
140 wakaba 1.3 p.insertionPoint -= s.length;
141</