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
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.
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 ***** */
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");
50 // parse / function call tables
51 var op_table
:Array = [];
52 var operator
:Array = [];
55 // expression stacks used while parsing
56 var tStack
:Array = [];
57 var exprStack
:Array = [];
60 var contexts
:Array = [];
61 var currentOutput
:String = "";
62 var showStatus
:Boolean = false;
63 var debug
:Boolean = false;
65 while(i
< System.argv
.length
)
67 if (System.argv
[i
].charAt
(0) == "+")
70 if (System.argv
[i
]=="+s")
72 else if (System.argv
[i
]=="+d")
78 var context
:XML = <x file
={System.argv
[i
++]} this_file
='trn.as' />;
80 contexts
.push
(context
);
83 for each (var item
:XML in context
..Generate
.children
())
85 var name
= item
.@name
;
86 if (item
.@disable
== "true")
89 var content
:String = express
(item
);
91 if (item
.name
() == "File")
92 File.write
(name
, content
);
98 // create and push a new context node for any loops i.e. 'repeats'
99 function acquireContext
():XML
101 var ctx
:XML = <context
/>;
106 function releaseContext
(ctx
:XML)
108 assert
(ctx
== contexts
[contexts
.length
-1]); // pop them off in order please
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;
126 print
("ERROR: in repeat attribute, '"+repeatName
+"' not found");
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
139 // put parent in current context
140 x
.prependChild
(<count
>{count
}</count
>);
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
]));
154 ctx
[mergeName
].appendChild
(node
);
157 print
("Warning: no node with "+String(mergeAttr
)+" = '"+String(item
.@[mergeAttr
])+"' in "+usedMergeName
+" while merging with "+repeatName
);
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.
177 if (mergeWith
!= null) delete ctx
[mergeName
].*;
179 if (debug
) print
("Context post-resolve "+ctx
.toXMLString
());
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
>);
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
];
203 if (String(val
) == attrValue
)
211 function lookup
(r
:XML):XML
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()
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)
240 function argsFor
(r
:XML, tag
:String="__comma"):Array
243 while(r
.name
() == tag
)
251 function contextFor
(s
:String):XML
253 if (s
== null || s
.length
== 0)
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
))
270 print
("ERROR: Can't find xml node "+s
);
272 if (x
instanceof XMLList)
278 function express
(n
:XML):String
280 if (debug
) print
("expressing '"+n
+"'");
282 // special processing directives?
283 contexts
.push
(<contexts
>{n
}</contexts
>);
285 if (n
.attribute
("repeat").length
() > 0)
289 var x
:XML = parse
(n
.toString
());
296 function resolve
(r
:XML):String
299 for each(var item
:XML in r
.children
())
307 function evaluate
(r
:XML):String
310 var f
= op_table
[r
.name
()];
312 print
("Warning: function '"+r
.name
()+"' unknown for "+r
.toXMLString
());
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
);
331 i
= parseExpr
(s
, i
+2, len
);
332 tree
.appendChild
( exprStack
.pop
() );
333 assert
(exprStack
.length
== 0 && tStack
.length
== 0);
340 appendConst
(tree
, subs
);
344 function parseVar
(s
:String):XML
346 var len
:int = s
.length
;
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
))
372 while(s
.charAt
(i
++) != ";")
374 var x
= new XML(s
.substring
(at
,i
));
380 var n
:XML = opFor
(ch
+s
.charAt
(i
+1));
389 if (n
.attribute
("twoToken") == "true")
390 i
++; // consumed 2 chars?
392 if (n
.name
() == "CloseExpr")
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
() );
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
417 var opPrec
= op
.attribute
("prec");
418 while( (tStack
.length
>1) && (tStack
[tStack
.length
-1].attribute
("prec") >= opPrec
) )
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
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
() );
433 var nm
:XML = exprStack
.pop
();
434 var name
:String = "__" + nm
.toString
();
435 tStack
[tStack
.length
-1].setName
(name
);
436 exprStack
.push
( tStack
.pop
() );
446 function opFor
(c
:String)
448 var op
:XML = operator
[c
];
450 op
= operator
[c
.charAt
(0)];
452 if (op
!= null && op
.name
() == "__ignore")
454 return (op
== null) ? null : new XML(op
);
457 function addOperand
(s
:String)
460 exprStack
.push
( <__oprnd prec
='18' >{s
}</__oprnd
> );
463 function appendConst
(tree
:XML, s
:String)
465 XML.ignoreWhitespace
= false;
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") )
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" ;
497 // children reside in another file?
498 if (x
.attribute
("file").length
() > 0)
500 if (x
.attribute
("loaded") == 'true')
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
);
517 for each (var item
in x
.children
())
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
='<' prec
='10'/>;
573 operator
[">"] = <__GT view
='>' prec
='10'/>;
574 operator
["<="] = <__LTEq view
='<=' prec
='10' twoToken
='true'/>;
575 operator
[">="] = <__GTEq view
='>=' prec
='10' twoToken
='true'/>;
576 operator
["<<"] = <__LShift view
='<<' prec
='11' twoToken
='true'/>;
577 operator
[">>"] = <__RShift view
='>>' 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
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
635 s
= ""; // lookup has already issued a warning
636 else if (r
instanceof XML)
643 function f__oprnd
(x
:XML):String
645 var s
:String = String(x
);
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];
657 // three args or 1 arg
658 charsToEscape
= evaluate
(args
[1].*[1]);
659 withSeq
= evaluate
(args
[0].*[1]);
662 var s
= evaluate
(arg0
);
664 var len
:int = s
.length
;
665 for(var i
:int=0; i
<len
; i
++)
670 c
= String.fromCharCode
((64*s
.charAt
(i
+1))+(8*s
.charAt
(i
+2))+s
.charAt
(i
+2));
673 else if (charsToEscape
.indexOf
(c
) > -1)
681 function f__substring
(x
:XML):String
683 // <substring><comma><comma><arg0/><arg1></comma><arg2></comma></substring>
684 var args
= argsFor
(x
.*[0]);
687 print
("WARNING: substring requires at least 1 argument");
690 else if (args
.length
<2)
692 var from
= Number( evaluate
(args
[0].*[1]) );
693 return evaluate
(args
[0].*[0]).substring
(from
);
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]) );
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);
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
738 function f__showTree
(x
:XML, d
:int=0):String
741 if (x
.children
().length
() > 0)
743 var paren
:Boolean = x
.attribute
("view") == "(" ? true : false;
744 var len
:int = x
.children
().length
();
746 s
= f__showTree
(x
.*[0]);
748 s
= f__showTree
(x
.*[0]) + x
.attribute
("view") + f__showTree
(x
.*[1]);
751 for(var i
:int=0; i
<len
; i
++)
752 s
+= f__showTree
(x
.*[i
]);