Bug 591908: Remove Math.floor from microbenchmark iterations/sec calculation (r=fklockii)
[tamarin-stm.git] / utils / errorgen.as
blob87d5ea610a93567ca8ea5aba8f28530db8ca1768
1 /* -*- 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) 2004-2006
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 import avmplus.*
42 function assert(b) { if (!b) {throw new Error("Asserted");} }
44 if (System.argv.length<1)
46 print("You need to specific at least one xml file");
47 System.exit(1);
50 // parse / function call tables
51 var op_table:Array = [];
52 var operator:Array = [];
53 initTables();
55 // expression stacks used while parsing
56 var tStack:Array = [];
57 var exprStack:Array = [];
59 // main
60 var contexts:Array = [];
61 var currentOutput:String = "";
62 var showStatus:Boolean = false;
63 var debug:Boolean = false;
64 var i:int = 0;
65 while(i < System.argv.length)
67 if (System.argv[i].charAt(0) == "+")
69 // option paramters
70 if (System.argv[i]=="+s")
71 showStatus = true;
72 else if (System.argv[i]=="+d")
73 debug = true;
74 i++;
75 continue;
78 var context:XML = <x file={System.argv[i++]} this_file='trn.as' />;
79 load(context);
80 contexts.push(context);
82 // generate
83 for each (var item:XML in context..Generate.children())
85 var name = item.@name;
86 if (item.@disable == "true")
87 continue;
89 var content:String = express(item);
91 if (item.name() == "File")
92 File.write(name, content);
93 else
94 print(content);
98 // create and push a new context node for any loops i.e. 'repeats'
99 function acquireContext():XML
101 var ctx:XML = <context/>;
102 contexts.push(ctx);
103 return ctx;
106 function releaseContext(ctx:XML)
108 assert(ctx == contexts[contexts.length-1]); // pop them off in order please
109 contexts.pop();
112 function repeat(x:XML):String
114 var repeatName:String = x.attribute("repeat");
115 var mergeName:String = x.attribute("mergeWith");
116 var usedMergeName:String = mergeName;
117 var skip:Boolean = (x.attribute("skipUnattributed") == "false") ? false : true;
118 var useOrig:Boolean = (x.attribute("useOriginalIfMergeFail") == "false") ? false : true;
120 var over:XML = lookup( parseVar(repeatName) );
121 var mergeWith:XML = lookup( parseVar(mergeName) );
123 var mergeAttr:String = (mergeWith != null) ? x.attribute("mergeAttribute") : null;
125 if (over==null)
126 print("ERROR: in repeat attribute, '"+repeatName+"' not found");
128 var n:String = "";
129 var count:int = 0;
131 var us:XML = parse(x.toString());
132 // print("repeat "+us+" on "+x.toString()+" named "+repeatName+" over "+over.children().toXMLString());
133 // set up a new context for lookups
134 var ctx:XML = acquireContext();
136 // use pseudo name for merge node
137 mergeName = "merge";
139 // put parent in current context
140 x.prependChild(<count>{count}</count>);
141 ctx.prependChild(x);
142 if (mergeWith != null) ctx.prependChild(<{mergeName}/>);
144 for each (var item:XML in over.children())
146 if (skip && String(item.attributes()).length < 1)
147 continue; // skip un-attributed nodes
149 // make the merge node available
150 if (mergeWith != null)
152 var node = childMatchingAttribute(mergeWith, String(mergeAttr), String(item.@[mergeAttr]));
153 if (node != null)
154 ctx[mergeName].appendChild(node);
155 else
157 print("Warning: no node with "+String(mergeAttr)+" = '"+String(item.@[mergeAttr])+"' in "+usedMergeName+" while merging with "+repeatName);
158 if (useOrig)
160 ctx[mergeName].appendChild(item[0]);
161 if (showStatus) print("Using "+item.toXMLString());
166 // make nodes visible in our context
167 x.replace("count", <count>{count}</count>);
168 ctx.prependChild(item);
170 if (debug) print("Context pre-resolve "+ctx.toXMLString());
172 // now that our state is current we can expand the text of the node.
173 n += resolve(us);
174 count++;
176 delete ctx.*[0];
177 if (mergeWith != null) delete ctx[mergeName].*;
179 if (debug) print("Context post-resolve "+ctx.toXMLString());
182 // trim the output?
183 if (x.attribute("trim") > 0)
184 n = n.slice(0, n.length-Number(x.attribute("trim")));
186 // make repeat count available in 'global'
187 delete contexts[0].*[0].last_repeat_count;
188 contexts[0].*[0].prependChild(<last_repeat_count>{count}</last_repeat_count>);
190 delete x.count;
191 releaseContext(ctx);
192 return n;
195 function childMatchingAttribute(x:XML, attrName:String, attrValue:String):XML
197 // find a child that has an attribute of a specific value
198 for each (var item in x.children())
200 var val = item.@[attrName];
201 if (val)
203 if (String(val) == attrValue)
204 return item;
207 return null;
211 function lookup(r:XML):XML
213 if (r == null)
214 return null;
216 // resolve lhs
217 var arr:Array = argsFor(r, "__dot");
218 var x:XML = arr.pop();
219 var ref:String = evaluate(x.*[0]);
220 var ctx = contextFor(ref);
221 var name:String = ref;
224 ref = evaluate(x.*[1]);
225 assert(x.*[1].name() != "__dot"); // shouldn't recurse in lookup()
226 name += "."+ref;
227 ctx = ctx[ref];
228 x = arr.pop();
230 while(x != null && ctx != null);
232 if (ctx == null || ctx.length() == 0)
233 print("Warning: Could not find '"+name+"'");
234 else if (ctx instanceof XMLList)
235 ctx = ctx[0];
237 return ctx;
240 function argsFor(r:XML, tag:String="__comma"):Array
242 var arr:Array = [];
243 while(r.name() == tag)
245 arr.push(r);
246 r = r.*[0];
248 return arr;
251 function contextFor(s:String):XML
253 if (s == null || s.length == 0)
254 return null;
256 // try each context
257 var x = null;
258 var len:int = contexts.length;
259 for(var i:int=len-1; i>-1; i--)
261 var context = contexts[i];
262 if (s == "*" || (context[s].length() == 1 && context[s].name() == s))
264 x = context[s];
265 break;
269 if (x == null)
270 print("ERROR: Can't find xml node "+s);
272 if (x instanceof XMLList)
273 x = x[0];
275 return x;
278 function express(n:XML):String
280 if (debug) print("expressing '"+n+"'");
282 // special processing directives?
283 contexts.push(<contexts>{n}</contexts>);
284 var s:String = "";
285 if (n.attribute("repeat").length() > 0)
286 s = repeat(n);
287 else
289 var x:XML = parse(n.toString());
290 s = resolve(x);
292 contexts.pop();
293 return s;
296 function resolve(r:XML):String
298 var s:String = "";
299 for each(var item:XML in r.children())
301 s += evaluate(item);
302 currentOutput = s;
304 return s;
307 function evaluate(r:XML):String
309 var s:String = "";
310 var f = op_table[r.name()];
311 if (f == null)
312 print("Warning: function '"+r.name()+"' unknown for "+r.toXMLString());
313 else
314 s = f.call(this, r);
315 return s;
318 function parse(s:String):XML
320 var subs:String = "";
321 var len:int = s.length;
322 var tree:XML = <root/>;
323 for(var i:int=0; i<len; i++)
325 var ch:String = s.charAt(i);
326 var n:XML = opFor(ch+s.charAt(i+1));
327 if (n != null && n.name() == "__OpenExpr")
329 appendConst(tree, subs);
330 addOp(n);
331 i = parseExpr(s, i+2, len);
332 tree.appendChild( exprStack.pop() );
333 assert(exprStack.length == 0 && tStack.length == 0);
334 subs = "";
336 else
337 subs += ch;
340 appendConst(tree, subs);
341 return tree;
344 function parseVar(s:String):XML
346 var len:int = s.length;
347 if (len<1)
348 return null;
349 addOp( opFor("{{") );
350 parseExpr(s, 0, len);
351 addOp( opFor("}}") ); // force expression to resolve fully
352 assert(exprStack.length == 1 && tStack.length == 0);
353 return exprStack.pop().*[0];
356 function parseExpr(s:String, start:int, max:int):int
358 var subs:String = "";
359 for(var i:int=start; i<max; i++)
361 var ch:String = s.charAt(i);
362 if (isWhitespace(ch))
364 addOperand(subs);
365 subs = "";
366 continue;
368 else if (ch == "&")
370 // xml escape chars
371 var at:int = i;
372 while(s.charAt(i++) != ";")
374 var x = new XML(s.substring(at,i));
375 ch = x.toString();
376 subs += ch;
377 continue;
380 var n:XML = opFor(ch+s.charAt(i+1));
381 if (n == null)
382 subs += ch;
383 else
385 addOperand(subs);
386 subs = "";
388 addOp(n);
389 if (n.attribute("twoToken") == "true")
390 i++; // consumed 2 chars?
392 if (n.name() == "CloseExpr")
393 break;
397 addOperand(subs);
398 return i;
401 function popOperation()
403 var op:XML = tStack.pop();
404 op.prependChild( exprStack.pop() );
406 if (op.attribute("singleOperand") != "true" )
407 op.prependChild( exprStack.pop() );
408 exprStack.push(op);
411 function addOp(op:XML)
413 if (String(op.name()).indexOf("__Open") == 0)
414 tStack.push(op); // marker with low precedence forces pops when close is hit
415 else
417 var opPrec = op.attribute("prec");
418 while( (tStack.length>1) && (tStack[tStack.length-1].attribute("prec") >= opPrec) )
419 popOperation();
421 if (String(op.name()).indexOf("Close") == 0)
423 // we stopped popping up to the close, so we need to peel off the open which is tos
424 popOperation();
426 // mondo hack that causes issues with expressions such as g + (2) but
427 // allows us to easily support function-like notation such as g(2)
428 var at = exprStack.length-2;
429 if ( (at>-1) && (exprStack[at].name() == "__oprnd") && !Number(exprStack[at]) )
431 tStack.push( exprStack.pop() );
432 // popOperation();
433 var nm:XML = exprStack.pop();
434 var name:String = "__" + nm.toString();
435 tStack[tStack.length-1].setName(name);
436 exprStack.push( tStack.pop() );
439 else
441 tStack.push(op);
446 function opFor(c:String)
448 var op:XML = operator[c];
449 if (op == null)
450 op = operator[c.charAt(0)];
452 if (op != null && op.name() == "__ignore")
453 op = null;
454 return (op == null) ? null : new XML(op);
457 function addOperand(s:String)
459 if (s.length>0)
460 exprStack.push( <__oprnd prec='18' >{s}</__oprnd> );
463 function appendConst(tree:XML, s:String)
465 XML.ignoreWhitespace = false;
466 if (s.length>0)
468 var str = <__str/>;
469 str.appendChild( new XML("<![CDATA["+s+"]]>") );
470 tree.appendChild( str );
472 XML.ignoreWhitespace = true;
475 function isWhitespace(c:String)
477 var itIs:Boolean = false
478 if ( (c == " ") || (c == "\r") || (c == "\n") || (c == "\t") )
479 itIs = true;
480 return itIs;
483 function shows(s:String=""):String
485 for(var i:int=0; i<tStack.length;i++)
486 s += " tStack["+i+"] = "+tStack[i].toXMLString()+"\n" ;
487 for(var i:int=0; i<exprStack.length;i++)
488 s += " exprStack["+i+"] = "+exprStack[i].toXMLString()+"\n" ;
489 return s;
492 function load(x:XML)
494 if (x == null)
495 return;
497 // children reside in another file?
498 if (x.attribute("file").length() > 0)
500 if (x.attribute("loaded") == 'true')
501 return;
503 var fn = x.attribute("file");
504 if (showStatus) print("Loading "+fn);
505 var c:XML = XML(File.read(fn));
506 if (c.toXMLString().length == 0)
508 print("ERROR: Unable to find file "+fn);
509 System.exit(2);
512 x.@loaded='true';
513 x.appendChild(c);
516 // expand children
517 for each (var item in x.children())
518 load(item);
521 // ops
523 function f__OpenParen(x:XML) { assert(x.*[1] == null); return String(evaluate(x.*[0])); }
524 function f__OpenExpr(x:XML) { assert(x.*[1] == null); return String(evaluate(x.*[0])); }
525 function f__comma(x:XML) { assert(false); }
526 function f__Assignment(x:XML) { assert(false); } //String( evaluate(x.*[0]) = evaluate(x.*[1]) ); }
527 function f__LogicOr(x:XML) { return String( Boolean(evaluate(x.*[0])) || Boolean(evaluate(x.*[1])) ); }
528 function f__LogicAnd(x:XML) { return String( Boolean(evaluate(x.*[0])) && Boolean(evaluate(x.*[1])) ); }
529 function f__Or(x:XML) { return String( Number(evaluate(x.*[0])) | Number(evaluate(x.*[1])) ); }
530 function f__Xor(x:XML) { return String( Number(evaluate(x.*[0])) ^ Number(evaluate(x.*[1])) ); }
531 function f__And(x:XML) { return String( Number(evaluate(x.*[0])) & Number(evaluate(x.*[1])) ); }
532 function f__Eq(x:XML) { return String( Boolean(evaluate(x.*[0])) == Boolean(evaluate(x.*[1])) ); }
533 function f__Neq(x:XML) { return String( Boolean(evaluate(x.*[0])) != Boolean(evaluate(x.*[1])) ); }
534 function f__LT(x:XML) { return String( Boolean(evaluate(x.*[0])) < Boolean(evaluate(x.*[1])) ); }
535 function f__GT(x:XML) { return String( Boolean(evaluate(x.*[0])) > Boolean(evaluate(x.*[1])) ); }
536 function f__LTEq(x:XML) { return String( Boolean(evaluate(x.*[0])) <= Boolean(evaluate(x.*[1])) ); }
537 function f__GTEq(x:XML) { return String( Boolean(evaluate(x.*[0])) >= Boolean(evaluate(x.*[1])) ); }
538 function f__LShift(x:XML) { return String( Number(evaluate(x.*[0])) << Number(evaluate(x.*[1])) ); }
539 function f__RShift(x:XML) { return String( Number(evaluate(x.*[0])) >> Number(evaluate(x.*[1])) ); }
540 function f__Add(x:XML) { return String( Number(evaluate(x.*[0])) + Number(evaluate(x.*[1])) ); }
541 function f__Sub(x:XML) { return String( Number(evaluate(x.*[0])) - Number(evaluate(x.*[1])) ); }
542 function f__Mult(x:XML) { return String( Number(evaluate(x.*[0])) * Number(evaluate(x.*[1])) ); }
543 function f__Div(x:XML) { return String( Number(evaluate(x.*[0])) / Number(evaluate(x.*[1])) ); }
544 function f__Mod(x:XML) { return String( Number(evaluate(x.*[0])) % Number(evaluate(x.*[1])) ); }
545 function f__LogicNot(x:XML) { return String( !Boolean(evaluate(x.*[0])) ); }
546 function f__BitNot(x:XML) { return String( ~Number(evaluate(x.*[0])) ); }
547 function f__array(x:XML) { return String(x); }
548 function f__str(x:XML):String { return String(x); }
549 function f__strlen(x:XML):String { return String ( evaluate(x.*[0]).length ); }
551 function initTables()
553 operator["tree"] = <tree prec='-15' singleOperand='true'/>; // fake node which forces expressions to resolve
554 operator["}}"] = <CloseExpr view='}}' prec='-10' singleOperand='true' twoToken='true'/>;
555 operator["{{"] = <__OpenExpr view='}}' prec='-9' singleOperand='true' twoToken='true'/>;
557 operator[")"] = <CloseParen view=')' prec='-2' singleOperand='true' />;
558 operator["("] = <__OpenParen view='(' prec='-1' singleOperand='true' />;
560 operator["]"] = <CloseBracket view=']' prec='-2' singleOperand='true'/>
561 operator["["] = <__OpenBracket view='[' prec='-1' singleOperand='true' />
563 operator[","] = <__comma view=',' prec='1'/>;
564 operator["="] = <__Assignment view='=' prec='2'/>;
565 operator["||"] = <__LogicOr view='||' prec ='4' twoToken='true'/>;
566 operator["&&"] = <__LogicAnd view='&&' prec='5' twoToken='true'/>;
567 operator["|"] = <__Or view='|' prec='6'/>;
568 operator["^"] = <__Xor view='^' prec='7'/>;
569 operator["&"] = <__And view='&' prec='8'/>;
570 operator["=="] = <__Eq view='==' prec='9' twoToken='true'/>;
571 operator["!="] = <__Neq view='!=' prec='9' twoToken='true'/>;
572 operator["<"] = <__LT view='&lt;' prec='10'/>;
573 operator[">"] = <__GT view='&gt;' prec='10'/>;
574 operator["<="] = <__LTEq view='&lt;=' prec='10' twoToken='true'/>;
575 operator[">="] = <__GTEq view='&gt;=' prec='10' twoToken='true'/>;
576 operator["<<"] = <__LShift view='&lt;&lt;' prec='11' twoToken='true'/>;
577 operator[">>"] = <__RShift view='&gt;&gt;' prec='11' twoToken='true'/>;
578 operator["+"] = <__Add view='+' prec='12'/>;
579 operator["-"] = <__Sub view='-' prec='12'/>;
580 operator["*"] = <__Mult view='*' prec='13'/>;
581 operator["/"] = <__Div view='/' prec='13'/>;
582 operator["%"] = <__Mod view='%' prec='13'/>;
583 operator["!"] = <__LogicNot view='!' prec='15' singleOperand='true'/>;
584 operator["~"] = <__BitNot view='~' prec='15' singleOperand='true'/>;
585 operator["."] = <__dot view='.' prec='17'/>;
586 operator["array"] = <array view='array' prec='19'/>;
587 operator["*."] = <__ignore />; // allow * in dot expressions
589 // functions
590 op_table["__OpenExpr"] = f__OpenExpr;
591 op_table["__OpenParen"] = f__OpenParen;
592 // op_table["__OpenBracket"] = f__OpenBracket;
593 op_table["__comma"] = f__comma;
594 op_table["__Assignment"] = null; //f__Assignment;
595 op_table["__LogicOr"] = f__LogicOr;
596 op_table["__LogicAnd"] = f__LogicAnd;
597 op_table["__Or"] = f__Or;
598 op_table["__Xor"] = f__Xor;
599 op_table["__And"] = f__And;
600 op_table["__Eq"] = f__Eq;
601 op_table["__Neq"] = f__Neq;
602 op_table["__LT"] = f__LT;
603 op_table["__GT"] = f__GT;
604 op_table["__LTEq"] = f__LTEq;
605 op_table["__GTEq"] = f__GTEq;
606 op_table["__LShift"] = f__LShift;
607 op_table["__RShift"] = f__RShift;
608 op_table["__Add"] = f__Add;
609 op_table["__Sub"] = f__Sub;
610 op_table["__Mult"] = f__Mult;
611 op_table["__Div"] = f__Div;
612 op_table["__Mod"] = f__Mod;
613 op_table["__LogicNot"] = f__LogicNot;
614 op_table["__BitNot"] = f__BitNot;
615 op_table["__dot"] = f__dot;
616 op_table["__array"] = f__array;
617 op_table["__str"] = f__str;
618 op_table["__oprnd"] = f__oprnd;
619 op_table["__strlen"] = f__strlen;
620 op_table["__substring"] = f__substring;
621 op_table["__escape"] = f__escape;
622 op_table["__spaces"] = f__spaces;
623 op_table["__column"] = f__column;
624 op_table["__context"] = f__context;
625 op_table["__parseTree"] = f__parseTree;
626 op_table["__showTree"] = f__showTree;
629 function f__dot(x:XML):String
631 var r = lookup(x);
632 var s:String = "";
634 if (r == null)
635 s = ""; // lookup has already issued a warning
636 else if (r instanceof XML)
637 s = express(r);
638 else
639 s = String(r);
640 return s;
643 function f__oprnd(x:XML):String
645 var s:String = String(x);
646 return s;
649 function f__escape(x:XML):String
651 var args = argsFor(x.*[0]);
652 var charsToEscape:String = "\"";
653 var withSeq:String = "\\\"";
654 var arg0:XML = x.*[0];
655 if (args.length>1)
657 // three args or 1 arg
658 charsToEscape = evaluate(args[1].*[1]);
659 withSeq = evaluate(args[0].*[1]);
660 arg0 = args[1].*[0];
662 var s = evaluate(arg0);
663 var n:String = "";
664 var len:int = s.length;
665 for(var i:int=0; i<len; i++)
667 var c = s.charAt(i);
668 if (c == "\\")
670 c = String.fromCharCode((64*s.charAt(i+1))+(8*s.charAt(i+2))+s.charAt(i+2));
671 i += 3;
673 else if (charsToEscape.indexOf(c) > -1)
674 n += withSeq;
675 else
676 n += c;
678 return n;
681 function f__substring(x:XML):String
683 // <substring><comma><comma><arg0/><arg1></comma><arg2></comma></substring>
684 var args = argsFor(x.*[0]);
685 if (args.length<1)
687 print("WARNING: substring requires at least 1 argument");
688 return "";
690 else if (args.length<2)
692 var from = Number( evaluate(args[0].*[1]) );
693 return evaluate(args[0].*[0]).substring(from);
695 else
697 var from = Number( evaluate(args[1].*[1]) );
698 var to = Number ( evaluate(args[0].*[1]) );
699 return evaluate(args[1].*[0]).substring(from, to);
703 function f__spaces(x:XML):String
705 var c:Number = Number( evaluate(x.*[0]) );
706 var n:String="";
707 while(c-->0)
708 n+= " ";
709 return n;
712 function f__column(x:XML):String
714 var num:Number = Number( evaluate(x.*[0]) );
716 // lets figure out which column we're at and the appropriate amount of padding
717 var cr:int = currentOutput.lastIndexOf("\n");
718 var c:int = num-(currentOutput.length-int(cr)-1);
719 var n:String="";
720 while(c-->0)
721 n+= " ";
722 return n;
725 function f__context(x:XML):String
727 var num:Number = Number( evaluate(x.*[0]) );
728 if (isNaN(num) || (num<0) || (num>(contexts.length-1)) )
729 num = contexts.length-1;
730 return contexts[num].toString();
733 function f__parseTree(x:XML):String
735 return x.toString();
738 function f__showTree(x:XML, d:int=0):String
740 var s:String="";
741 if (x.children().length() > 0)
743 var paren:Boolean = x.attribute("view") == "(" ? true : false;
744 var len:int = x.children().length();
745 if (len == 1)
746 s = f__showTree(x.*[0]);
747 else if (len == 2)
748 s = f__showTree(x.*[0]) + x.attribute("view") + f__showTree(x.*[1]);
749 else
751 for(var i:int=0; i<len; i++)
752 s += f__showTree(x.*[i]);
754 if (paren)
755 s += ") ";
757 else
759 s = x.toString();
761 return s;