Merge remote-tracking branch 'redux/master' into sh4-pool
[tamarin-stm.git] / eval / eval-parse-xml.cpp
blob79a82c27156abdeac0ef346eb46001c8d28c238a
1 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
2 /* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is [Open Source Virtual Machine.].
18 * The Initial Developer of the Original Code is
19 * Adobe System Incorporated.
20 * Portions created by the Initial Developer are Copyright (C) 2008
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Adobe AS3 Team
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "avmplus.h"
42 #ifdef VMCFG_EVAL
44 #include "eval.h"
46 namespace avmplus
48 namespace RTC
50 // xmlInitializer is the only entry point.
52 class XmlContext {
53 public:
54 XmlContext(Compiler* compiler)
55 : allocator(compiler->allocator)
56 , exprs(allocator)
57 , text(compiler)
58 , text_start(0)
62 void addExpr(Expr* e);
63 void addText(Str* s);
64 void addText(const char* s);
65 void addText(wchar c);
66 Seq<Expr*>* get();
68 private:
69 void flush();
71 Allocator * const allocator;
72 SeqBuilder<Expr*> exprs;
73 StringBuilder text;
74 uint32_t text_start;
77 void XmlContext::addExpr(Expr* e)
79 flush();
80 exprs.addAtEnd(e);
83 void XmlContext::addText(Str* s)
85 text.append(s);
88 void XmlContext::addText(const char* s)
90 while (*s)
91 text.append(*s++);
94 void XmlContext::addText(wchar c)
96 text.append(c);
99 Seq<Expr*>* XmlContext::get()
101 flush();
102 return exprs.get();
105 void XmlContext::flush() {
106 if (text.length() > 0) {
107 exprs.addAtEnd(ALLOC(LiteralString, (text.str(), text_start)));
109 char buf[500];
110 getn(buf, text.str(), 500);
111 puts(buf);
113 text.clear();
117 Expr* Parser::xmlInitializer()
119 AvmAssert( T0 == T_BreakLeftAngle && T1 == T_LAST );
121 XmlContext ctx(compiler);
122 bool is_list = false;
123 uint32_t pos = position();
125 xmlPushback('<');
126 xmlAtom();
127 switch (T0) {
128 case T_XmlComment:
129 case T_XmlCDATA:
130 case T_XmlProcessingInstruction:
131 xmlAssert(&ctx, T0);
132 break;
134 case T_XmlLeftAngle:
135 xmlAssert(&ctx, T0);
136 xmlAtomSkipSpace();
137 if (T0 == T_XmlRightAngle) {
138 is_list = true;
139 xmlListInitializer(&ctx);
141 else
142 xmlElement(&ctx);
143 break;
145 default:
146 compiler->internalError(position(), "error state in xml handling");
147 /*NOTREACHED*/
148 break;
151 next(); // Re-synchronize the lexer for normal lexing
152 return ALLOC(XmlInitializer, (ctx.get(), is_list, pos));
155 // IN: T0 is ">"
156 // OUT: T0 is ">"
158 void Parser::xmlListInitializer(XmlContext* ctx)
160 xmlAssert(ctx, T_XmlRightAngle);
161 xmlElementContent(ctx);
162 xmlAssert(ctx, T_XmlLeftAngleSlash);
163 xmlAtomSkipSpace();
164 xmlAssert(ctx, T_XmlRightAngle);
167 // IN: T0 is first non-space token of tag name
168 // OUT: T0 is ">" or "/>"
170 void Parser::xmlElement(XmlContext* ctx)
172 xmlTagName(ctx);
173 if (T0 != T_XmlRightAngle && T0 != T_XmlSlashRightAngle) {
174 ctx->addText(" ");
175 xmlAttributes(ctx);
177 if (T0 == T_XmlRightAngle) {
178 xmlAssert(ctx, T0);
179 xmlElementContent(ctx);
180 xmlAssert(ctx, T_XmlLeftAngleSlash);
181 xmlAtomSkipSpace();
182 xmlTagName(ctx);
183 xmlAssert(ctx, T_XmlRightAngle);
185 else
186 xmlAssert(ctx, T_XmlSlashRightAngle);
189 // IN: T0 is first non-space token of name
190 // OUT: T0 is first non-space token following name
192 void Parser::xmlTagName(XmlContext* ctx)
194 if (T0 == T_XmlLeftBrace)
195 xmlExpression(ctx, ESC_none);
196 else
197 xmlAssert(ctx, T_XmlName);
198 xmlAtomSkipSpace();
201 // IN: T0 is first non-space token of first attribute (or /> or >)
202 // OUT: T0 is /> or >
204 void Parser::xmlAttributes(XmlContext* ctx)
206 bool first = true;
207 while (T0 != T_XmlRightAngle && T0 != T_XmlSlashRightAngle) {
208 if (!first) {
209 ctx->addText(" ");
210 first = false;
212 if (T0 == T_XmlLeftBrace) {
213 xmlExpression(ctx, ESC_attributeValue);
214 xmlAtomSkipSpace();
215 // {E} = V is an extension required by the test suite, not in Ecma-357
216 if (T0 == T_XmlEquals)
217 goto attrvalue;
219 else {
220 xmlAssert(ctx, T_XmlName);
221 xmlAtomSkipSpace();
222 attrvalue:
223 xmlAssert(ctx, T_XmlEquals);
224 xmlAtomSkipSpace();
225 if (T0 == T_XmlLeftBrace) {
226 ctx->addText("\"");
227 xmlExpression(ctx, ESC_attributeValue);
228 ctx->addText("\"");
230 else
231 xmlAssert(ctx, T_XmlString, ESC_attributeValue);
232 xmlAtomSkipSpace();
237 // IN: T0 is ">"
238 // OUT: T0 is "</"
240 void Parser::xmlElementContent(XmlContext* ctx)
242 for (;;) {
243 xmlAtom();
244 switch (T0) {
245 case T_XmlProcessingInstruction:
246 case T_XmlComment:
247 case T_XmlCDATA:
248 case T_XmlName:
249 case T_XmlWhitespace:
250 case T_XmlText:
251 case T_XmlString:
252 case T_XmlRightBrace:
253 case T_XmlRightAngle:
254 case T_XmlSlashRightAngle:
255 case T_XmlEquals:
256 xmlAssert(ctx, T0);
257 continue;
258 case T_XmlLeftBrace:
259 xmlExpression(ctx, ESC_elementValue);
260 continue;
261 case T_XmlLeftAngle:
262 xmlAssert(ctx, T0);
263 xmlAtomSkipSpace();
264 xmlElement(ctx);
265 continue;
266 case T_XmlLeftAngleSlash:
267 return;
268 default:
269 compiler->internalError(position(), "Unexpected state in XML parsing");
274 // IN: T0 is "{"
275 // OUT: T0 is "}"
277 void Parser::xmlExpression(XmlContext* ctx, Escapement esc)
279 AvmAssert( T0 == T_XmlLeftBrace );
280 next(); // re-enter normal lexing
281 Expr* expr = commaExpression(0);
282 if (esc != ESC_none)
283 expr = ALLOC(EscapeExpr, (expr, esc));
284 ctx->addExpr(expr);
285 AvmAssert( T0 == T_RightBrace && T1 == T_LAST );
286 xmlPushback('}');
287 xmlAtom();
288 xmlAssert(ctx, T_XmlRightBrace);
291 void Parser::xmlEscape(XmlContext* ctx, const wchar* cs, const wchar* limit, bool is_attr)
293 while ( cs < limit ) {
294 wchar c;
295 switch (c = *cs++) {
296 case '<':
297 ctx->addText("&lt;");
298 continue;
299 case '&':
300 ctx->addText("&amp;");
301 continue;
302 case '"':
303 if (!is_attr) break;
304 ctx->addText("&quot;");
305 continue;
306 case '>':
307 if (is_attr) break;
308 ctx->addText("&gt;");
309 continue;
310 case '\\':
311 // This is weird but apparently according to spec
312 if (!is_attr) break;
313 if (cs + 5 <= limit &&
314 cs[0] == 'u' &&
315 cs[1] == '0' &&
316 cs[2] == '0' &&
317 cs[3] == '0') {
318 switch (cs[4]) {
319 case 'A': case 'a':
320 cs += 4;
321 ctx->addText("&#xA;");
322 continue;
323 case 'D': case 'd':
324 cs += 4;
325 ctx->addText("&#xD;");
326 continue;
327 case '9':
328 cs += 4;
329 ctx->addText("&#x9;");
330 continue;
331 default:
332 goto add_char;
335 add_char:
336 break;
338 ctx->addText(c);
342 void Parser::xmlAssert(XmlContext* ctx, Token t, Escapement esc)
344 if (T0 != t)
345 compiler->syntaxError(position(), SYNTAXERR_XML_UNEXPECTED_TOKEN);
346 switch (t) {
347 case T_XmlProcessingInstruction:
348 case T_XmlComment:
349 case T_XmlCDATA:
350 case T_XmlLeftBrace:
351 case T_XmlName:
352 case T_XmlWhitespace:
353 case T_XmlText:
354 ctx->addText(V0.s);
355 break;
356 case T_XmlString:
357 switch (esc) {
358 case ESC_attributeValue:
359 case ESC_elementValue:
360 // Spec seems broken
362 ctx->addText(V0.s->s[0]);
363 xmlEscape(ctx, V0.s->s + 1, V0.s->s + V0.s->length - 1, esc == ESC_attributeValue);
364 ctx->addText(V0.s->s[0]);
365 break;
367 default:
368 ctx->addText(V0.s);
369 break;
371 break;
372 case T_XmlRightBrace:
373 // no text added
374 break;
375 case T_XmlRightAngle:
376 ctx->addText(">");
377 break;
378 case T_XmlSlashRightAngle:
379 ctx->addText("/>");
380 break;
381 case T_XmlEquals:
382 ctx->addText("=");
383 break;
384 case T_XmlLeftAngle:
385 ctx->addText("<");
386 break;
387 case T_XmlLeftAngleSlash:
388 ctx->addText("</");
389 break;
390 default:
391 compiler->internalError(position(), "Unexpected token in XML parsing");
395 void Parser::xmlAtomSkipSpace()
397 do {
398 xmlAtom();
399 } while (T0 == T_XmlWhitespace);
404 #endif // VMCFG_EVAL