예제 #1
0
 private void transformCompilationUnit (ScriptOrFnNode tree)
 {
     loops = new ObjArray ();
     loopEnds = new ObjArray ();
     // to save against upchecks if no finally blocks are used.
     hasFinally = false;
     
     try {
         transformCompilationUnit_r (tree, tree);
     } catch (Helpers.StackOverflowVerifierException) {
         throw Context.ReportRuntimeError (
             ScriptRuntime.GetMessage ("mag.too.deep.parser.recursion"));
     }
 }
예제 #2
0
 Node enterSwitch (Node switchSelector, int lineno, Node switchLabel)
 {
     Node switchNode = nf.CreateSwitch (switchSelector, lineno);
     if (loopAndSwitchSet == null) {
         loopAndSwitchSet = new ObjArray ();
     }
     loopAndSwitchSet.push (switchNode);
     return switchNode;
 }
예제 #3
0
        Node function (int functionType)
        {
            using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier (1024)) {
                int syntheticType = functionType;
                int baseLineno = ts.Lineno; // line number where source starts

                int functionSourceStart = decompiler.MarkFunctionStart (functionType);
                string name;
                Node memberExprNode = null;
                
                int tt = peekToken ();                
                if (tt == Token.NAME) {
                    consumeToken ();    
                    name = ts.String;
                    decompiler.AddName (name);
                    if (!matchToken (Token.LP)) {
                        if (compilerEnv.isAllowMemberExprAsFunctionName ()) {
                            // Extension to ECMA: if 'function <name>' does not follow
                            // by '(', assume <name> starts memberExpr
                            Node memberExprHead = nf.CreateName (name);
                            name = "";
                            memberExprNode = memberExprTail (false, memberExprHead);
                        }
                        mustMatchToken (Token.LP, "msg.no.paren.parms");
                    }
                }
                else if (matchToken (Token.LP)) {
                    // Anonymous function
                    name = "";
                }
                else {
                    name = "";
                    if (compilerEnv.isAllowMemberExprAsFunctionName ()) {
                        // Note that memberExpr can not start with '(' like
                        // in function (1+2).toString(), because 'function (' already
                        // processed as anonymous function
                        memberExprNode = memberExpr (false);
                    }
                    mustMatchToken (Token.LP, "msg.no.paren.parms");
                }

                if (memberExprNode != null) {
                    syntheticType = FunctionNode.FUNCTION_EXPRESSION;
                }

                bool nested = insideFunction ();

                FunctionNode fnNode = nf.CreateFunction (name);
                if (nested || nestingOfWith > 0) {
                    // 1. Nested functions are not affected by the dynamic scope flag
                    // as dynamic scope is already a parent of their scope.
                    // 2. Functions defined under the with statement also immune to
                    // this setup, in which case dynamic scope is ignored in favor
                    // of with object.
                    fnNode.itsIgnoreDynamicScope = true;
                }

                int functionIndex = currentScriptOrFn.addFunction (fnNode);

                int functionSourceEnd;

                ScriptOrFnNode savedScriptOrFn = currentScriptOrFn;
                currentScriptOrFn = fnNode;
                int savedNestingOfWith = nestingOfWith;
                nestingOfWith = 0;
                Hashtable savedLabelSet = labelSet;
                labelSet = null;
                ObjArray savedLoopSet = loopSet;
                loopSet = null;
                ObjArray savedLoopAndSwitchSet = loopAndSwitchSet;
                loopAndSwitchSet = null;

                Node body;
                try {
                    decompiler.AddToken (Token.LP);
                    if (!matchToken (Token.RP)) {
                        bool first = true;
                        do {
                            if (!first)
                                decompiler.AddToken (Token.COMMA);
                            first = false;
                            mustMatchToken (Token.NAME, "msg.no.parm");
                            string s = ts.String;
                            if (fnNode.hasParamOrVar (s)) {
                                AddWarning ("msg.dup.parms", s);
                            }
                            fnNode.addParam (s);
                            decompiler.AddName (s);
                        }
                        while (matchToken (Token.COMMA));

                        mustMatchToken (Token.RP, "msg.no.paren.after.parms");
                    }
                    decompiler.AddToken (Token.RP);

                    mustMatchToken (Token.LC, "msg.no.brace.body");
                    decompiler.AddEol (Token.LC);
                    body = parseFunctionBody ();
                    mustMatchToken (Token.RC, "msg.no.brace.after.body");

                    decompiler.AddToken (Token.RC);
                    functionSourceEnd = decompiler.MarkFunctionEnd (functionSourceStart);
                    if (functionType != FunctionNode.FUNCTION_EXPRESSION) {
                        if (compilerEnv.LanguageVersion >= Context.Versions.JS1_2) {
                            // function f() {} function g() {} is not allowed in 1.2
                            // or later but for compatibility with old scripts
                            // the check is done only if language is
                            // explicitly set.
                            //  TODO: warning needed if version == VERSION_DEFAULT ?
                            tt = peekTokenOrEOL ();
                            if (tt == Token.FUNCTION) {
                                ReportError ("msg.no.semi.stmt");
                            }
                        }
                        // Add EOL only if function is not part of expression
                        // since it gets SEMI + EOL from Statement in that case
                        decompiler.AddToken (Token.EOL);
                    }
                }
                finally {
                    loopAndSwitchSet = savedLoopAndSwitchSet;
                    loopSet = savedLoopSet;
                    labelSet = savedLabelSet;
                    nestingOfWith = savedNestingOfWith;
                    currentScriptOrFn = savedScriptOrFn;
                }

                fnNode.setEncodedSourceBounds (functionSourceStart, functionSourceEnd);
                fnNode.SourceName = sourceURI;
                fnNode.BaseLineno = baseLineno;
                fnNode.EndLineno = ts.Lineno;

                Node pn = nf.initFunction (fnNode, functionIndex, body, syntheticType);
                if (memberExprNode != null) {
                    pn = nf.CreateAssignment (Token.ASSIGN, memberExprNode, pn, false);
                    if (functionType != FunctionNode.FUNCTION_EXPRESSION) {
                        // TOOD: check JScript behavior: should it be createExprStatement?
                        pn = nf.CreateExprStatementNoReturn (pn, baseLineno);
                    }
                }
                return pn;
            }
        }
예제 #4
0
 Node enterLoop (Node loopLabel)
 {
     Node loop = nf.CreateLoopNode (loopLabel, ts.Lineno);
     if (loopSet == null) {
         loopSet = new ObjArray ();
         if (loopAndSwitchSet == null) {
             loopAndSwitchSet = new ObjArray ();
         }
     }
     loopSet.push (loop);
     loopAndSwitchSet.push (loop);
     return loop;
 }
예제 #5
0
        /// <summary>
        /// Support for non-ecma "get"/"set" spidermonkey extension.
        /// </summary>
        /// <example>
        ///		NAME getter: FUNCTION () SCOPE
        ///		NAME setter: FUNCTION () SCOPE
        /// </example>
        bool CheckForGetterOrSetter (ObjArray elems)
        {
            int tt;

            string name = ts.String;
            consumeToken ();

            tt = peekToken ();
            if (tt != Token.NAME)
                return false;
            string type = ts.String;
            if (type != "getter" && type != "setter") {
                return false;
            }
            consumeToken ();

            matchToken (Token.COLON);
            matchToken (Token.FUNCTION);

            Node func = function (FunctionNode.FUNCTION_EXPRESSION);
            object property = ScriptRuntime.getIndexObject (name);

            elems.add ((type [0] == 'g') ? (object)new Node.GetterPropertyLiteral (property)
                : (object)new Node.SetterPropertyLiteral (property));
            elems.add (func);

            return true;
        }
예제 #6
0
        Node primaryExpr ()
        {
            try {
                if (currentStackIndex++ > ScriptRuntime.MAXSTACKSIZE) {
                    currentStackIndex = 0;
                    throw Context.ReportRuntimeError (
                        ScriptRuntime.GetMessage ("mag.too.deep.parser.recursion"), sourceURI, ts.Lineno, null, 0);
                }

                Node pn;

                int ttFlagged = nextFlaggedToken ();
                int tt = ttFlagged & CLEAR_TI_MASK;

                switch (tt) {


                    case Token.FUNCTION:
                        return function (FunctionNode.FUNCTION_EXPRESSION);


                    case Token.LB: {
                            ObjArray elems = new ObjArray ();
                            int skipCount = 0;
                            decompiler.AddToken (Token.LB);
                            bool after_lb_or_comma = true;
                            for (; ; ) {
                                tt = peekToken ();

                                if (tt == Token.COMMA) {
                                    consumeToken ();
                                    decompiler.AddToken (Token.COMMA);
                                    if (!after_lb_or_comma) {
                                        after_lb_or_comma = true;
                                    }
                                    else {
                                        elems.add ((object)null);
                                        ++skipCount;
                                    }
                                }
                                else if (tt == Token.RB) {
                                    consumeToken ();
                                    decompiler.AddToken (Token.RB);
                                    break;
                                }
                                else {
                                    if (!after_lb_or_comma) {
                                        ReportError ("msg.no.bracket.arg");
                                    }
                                    elems.add (assignExpr (false));
                                    after_lb_or_comma = false;
                                }
                            }
                            return nf.CreateArrayLiteral (elems, skipCount);
                        }


                    case Token.LC: {
                            ObjArray elems = new ObjArray ();
                            decompiler.AddToken (Token.LC);
                            if (!matchToken (Token.RC)) {

                                bool first = true;
                                do {
                                    object property;

                                    if (!first)
                                        decompiler.AddToken (Token.COMMA);
                                    else
                                        first = false;

                                    tt = peekToken ();
                                    switch (tt) {

                                        case Token.NAME:
                                        case Token.STRING:
                                            consumeToken ();
                                            if (compilerEnv.getterAndSetterSupport) {
                                                if (tt == Token.NAME)
                                                    if (CheckForGetOrSet (elems) || CheckForGetterOrSetter (elems))
                                                        goto next_prop;
                                            }


                                            // map NAMEs to STRINGs in object literal context
                                            // but tell the decompiler the proper type
                                            string s = ts.String;
                                            if (tt == Token.NAME) {
                                                decompiler.AddName (s);
                                            }
                                            else {
                                                decompiler.AddString (s);
                                            }
                                            property = ScriptRuntime.getIndexObject (s);

                                            break;


                                        case Token.NUMBER:
                                            consumeToken ();
                                            double n = ts.Number;
                                            decompiler.AddNumber (n);
                                            property = ScriptRuntime.getIndexObject (n);
                                            break;


                                        case Token.RC:
                                            // trailing comma is OK.

                                            goto commaloop_brk;

                                        default:
                                            ReportError ("msg.bad.prop");

                                            goto commaloop_brk;

                                    }
                                    mustMatchToken (Token.COLON, "msg.no.colon.prop");

                                    // OBJLIT is used as ':' in object literal for
                                    // decompilation to solve spacing ambiguity.
                                    decompiler.AddToken (Token.OBJECTLIT);
                                    elems.add (property);
                                    elems.add (assignExpr (false));

                                next_prop:
                                    ;
                                }
                                while (matchToken (Token.COMMA));

                            commaloop_brk:
                                ;


                                mustMatchToken (Token.RC, "msg.no.brace.prop");
                            }
                            decompiler.AddToken (Token.RC);
                            return nf.CreateObjectLiteral (elems);
                        }


                    case Token.LP:

                        /* Brendan's IR-jsparse.c makes a new node tagged with
                        * TOK_LP here... I'm not sure I understand why.  Isn't
                        * the grouping already implicit in the structure of the
                        * parse tree?  also TOK_LP is already overloaded (I
                        * think) in the C IR as 'function call.'  */
                        decompiler.AddToken (Token.LP);
                        pn = expr (false);
                        decompiler.AddToken (Token.RP);
                        mustMatchToken (Token.RP, "msg.no.paren");
                        return pn;


                    case Token.XMLATTR:
                        mustHaveXML ();
                        decompiler.AddToken (Token.XMLATTR);
                        pn = attributeAccess (null, 0);
                        return pn;


                    case Token.NAME: {
                            string name = ts.String;
                            if ((ttFlagged & TI_CHECK_LABEL) != 0) {
                                if (peekToken () == Token.COLON) {
                                    // Do not consume colon, it is used as unwind indicator
                                    // to return to statementHelper.
                                    // TODO: Better way?
                                    return nf.CreateLabel (ts.Lineno);
                                }
                            }

                            decompiler.AddName (name);
                            if (compilerEnv.isXmlAvailable ()) {
                                pn = propertyName (null, name, 0);
                            }
                            else {
                                pn = nf.CreateName (name);
                            }
                            return pn;
                        }


                    case Token.NUMBER: {
                            double n = ts.Number;
                            decompiler.AddNumber (n);
                            return nf.CreateNumber (n);
                        }


                    case Token.STRING: {
                            string s = ts.String;
                            decompiler.AddString (s);
                            return nf.CreateString (s);
                        }


                    case Token.DIV:
                    case Token.ASSIGN_DIV: {
                            // Got / or /= which should be treated as regexp in fact
                            ts.readRegExp (tt);
                            string flags = ts.regExpFlags;
                            ts.regExpFlags = null;
                            string re = ts.String;
                            decompiler.AddRegexp (re, flags);
                            int index = currentScriptOrFn.addRegexp (re, flags);
                            return nf.CreateRegExp (index);
                        }


                    case Token.NULL:
                    case Token.THIS:
                    case Token.FALSE:
                    case Token.TRUE:
                        decompiler.AddToken (tt);
                        return nf.CreateLeaf (tt);


                    case Token.RESERVED:
                        ReportError ("msg.reserved.id");
                        break;


                    case Token.ERROR:
                        /* the scanner or one of its subroutines reported the error. */
                        break;


                    case Token.EOF:
                        ReportError ("msg.unexpected.eof");
                        break;


                    default:
                        ReportError ("msg.syntax");
                        break;

                }
                return null; // should never reach here
            }
            finally {
                currentStackIndex--;
            }
        }
예제 #7
0
 /// <summary> Object Literals
 /// <BR> CreateObjectLiteral rewrites its argument as object
 /// creation plus object property entries, so later compiler
 /// stages don't need to know about object literals.
 /// </summary>
 internal Node CreateObjectLiteral(ObjArray elems)
 {
     int size = elems.size () / 2;
     Node obj = new Node (Token.OBJECTLIT);
     object [] properties;
     if (size == 0) {
         properties = ScriptRuntime.EmptyArgs;
     }
     else {
         properties = new object [size];
         for (int i = 0; i != size; ++i) {
             properties [i] = elems.Get (2 * i);
             Node value = (Node)elems.Get (2 * i + 1);
             obj.addChildToBack (value);
         }
     }
     obj.putProp (Node.OBJECT_IDS_PROP, properties);
     return obj;
 }
예제 #8
0
 internal Node CreateArrayLiteral(ObjArray elems, int skipCount)
 {
     int length = elems.size ();
     int [] skipIndexes = null;
     if (skipCount != 0) {
         skipIndexes = new int [skipCount];
     }
     Node array = new Node (Token.ARRAYLIT);
     for (int i = 0, j = 0; i != length; ++i) {
         Node elem = (Node)elems.Get (i);
         if (elem != null) {
             array.addChildToBack (elem);
         }
         else {
             skipIndexes [j] = i;
             ++j;
         }
     }
     if (skipCount != 0) {
         array.putProp (Node.SKIP_INDEXES_PROP, skipIndexes);
     }
     return array;
 }
예제 #9
0
 public int addRegexp(string str, string flags)
 {
     if (str == null)
         Context.CodeBug ();
     if (regexps == null) {
         regexps = new ObjArray ();
     }
     regexps.add (str);
     regexps.add (flags);
     return regexps.size () / 2 - 1;
 }
예제 #10
0
 public int addFunction(FunctionNode fnNode)
 {
     if (fnNode == null)
         Context.CodeBug ();
     if (functions == null) {
         functions = new ObjArray ();
     }
     functions.add (fnNode);
     return functions.size () - 1;
 }