예제 #1
0
        public BlockScope(ActivationObject parent, Context context, CodeSettings settings)
            : base(parent, settings)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            m_context = context.Clone();
        }
예제 #2
0
        internal FunctionScope(ActivationObject parent, bool isExpression, CodeSettings settings, FunctionObject funcObj)
            : base(parent, settings)
        {
            m_refScopes = new HashSet<ActivationObject>();
            if (isExpression)
            {
                // parent scopes automatically reference enclosed function expressions
                AddReference(Parent);
            }

            FunctionObject = funcObj;
        }
예제 #3
0
        public static void Apply(AstNode node, ActivationObject scope, CodeSettings settings)
        {
            if (node != null && scope != null)
            {
                // create the visitor and run it. This will create all the child
                // scopes and populate all the scopes with the var-decl, lex-decl,
                // and lookup references within them.
                var visitor = new ResolutionVisitor(scope, settings);
                node.Accept(visitor);

                // now that all the scopes are created and they all know what decls
                // they contains, create all the fields
                CreateFields(scope);

                // now that all the fields have been created in all the scopes,
                // let's go through and resolve all the references
                ResolveLookups(scope, settings);

                // now that everything is declared and resolved as per the language specs,
                // we need to go back and add ghosted fields for older versions of IE that
                // incorrectly implement catch-variables and named function expressions.
                AddGhostedFields(scope);
            }
        }
예제 #4
0
 public WithScope(ActivationObject parent, Context context, CodeSettings settings)
     : base(parent, context, settings)
 {
     IsInWithScope = true;
 }
        private ResolutionVisitor(ActivationObject rootScope, CodeSettings settings)
        {
            // create the lexical and variable scope stacks and push the root scope onto them
            m_lexicalStack = new Stack<ActivationObject>();
            m_lexicalStack.Push(rootScope);

            m_variableStack = new Stack<ActivationObject>();
            m_variableStack.Push(rootScope);

            m_settings = settings;
        }
예제 #6
0
        private static void ResolveLookup(ActivationObject scope, Lookup lookup, CodeSettings settings)
        {
            // resolve lookup via the lexical scope
            lookup.VariableField = scope.FindReference(lookup.Name);
            if (lookup.VariableField.FieldType == FieldType.UndefinedGlobal)
            {
                // couldn't find it.
                // if the lookup isn't generated and isn't the object of a typeof operator,
                // then we want to throw an error.
                if (!lookup.IsGenerated)
                {
                    var parentUnaryOp = lookup.Parent as UnaryOperator;
                    if (parentUnaryOp != null && parentUnaryOp.OperatorToken == JSToken.TypeOf)
                    {
                        // this undefined lookup is the target of a typeof operator.
                        // I think it's safe to assume we're going to use it. Don't throw an error
                        // and instead add it to the "known" expected globals of the global scope
                        MakeExpectedGlobal(lookup.VariableField);
                    }
                    else
                    {
                        // report this undefined reference
                        lookup.Context.ReportUndefined(lookup);

                        // possibly undefined global (but definitely not local).
                        // see if this is a function or a variable.
                        var callNode   = lookup.Parent as CallNode;
                        var isFunction = callNode != null && callNode.Function == lookup;
                        lookup.Context.HandleError((isFunction ? JSError.UndeclaredFunction : JSError.UndeclaredVariable), false);
                    }
                }
            }
            else if (lookup.VariableField.FieldType == FieldType.Predefined)
            {
                if (string.CompareOrdinal(lookup.Name, "window") == 0)
                {
                    // it's the global window object
                    // see if it's the child of a member or call-brackets node
                    var member = lookup.Parent as Member;
                    if (member != null)
                    {
                        // we have window.XXXX. Add XXXX to the known globals if it
                        // isn't already a known item.
                        scope.AddGlobal(member.Name);
                    }
                    else
                    {
                        var callNode = lookup.Parent as CallNode;
                        if (callNode != null && callNode.InBrackets &&
                            callNode.Arguments.Count == 1 &&
                            callNode.Arguments[0] is ConstantWrapper &&
                            callNode.Arguments[0].FindPrimitiveType() == PrimitiveType.String)
                        {
                            // we have window["XXXX"]. See if XXXX is a valid identifier.
                            // TODO: we could get rid of the ConstantWrapper restriction and use an Evaluate visitor
                            // to evaluate the argument, since we know for sure that it's a string.
                            var identifier = callNode.Arguments[0].ToString();
                            if (JSScanner.IsValidIdentifier(identifier))
                            {
                                // Add XXXX to the known globals if it isn't already a known item.
                                scope.AddGlobal(identifier);
                            }
                        }
                    }
                }
                else if (settings.EvalTreatment != EvalTreatment.Ignore &&
                         string.CompareOrdinal(lookup.Name, "eval") == 0)
                {
                    // it's an eval -- but are we calling it?
                    // TODO: what if we are assigning it to a variable? Should we track that variable and see if we call it?
                    // What about passing it as a parameter to a function? track that as well in case the function calls it?
                    var parentCall = lookup.Parent as CallNode;
                    if (parentCall != null && parentCall.Function == lookup)
                    {
                        scope.IsKnownAtCompileTime = false;
                    }
                }
            }

            // add the reference
            lookup.VariableField.AddReference(lookup);

            // we are actually referencing this field, so it's no longer a placeholder field if it
            // happens to have been one.
            lookup.VariableField.IsPlaceholder = false;
        }
예제 #7
0
 public SwitchParser(CodeSettings scriptSettings, CssSettings cssSettings)
 {
     // apply the switches to these two settings objects
     JSSettings = scriptSettings ?? new CodeSettings();
     CssSettings = cssSettings ?? new CssSettings();
 }
        protected ActivationObject(ActivationObject parent, CodeSettings codeSettings)
        {
            m_isKnownAtCompileTime = true;
            m_useStrict = false;
            m_settings = codeSettings;

            Parent = parent;
            NameTable = new Dictionary<string, JSVariableField>();
            ChildScopes = new List<ActivationObject>();

            // if our parent is a scope....
            if (parent != null)
            {
                // add us to the parent's list of child scopes
                parent.ChildScopes.Add(this);

                // if the parent is strict, so are we
                UseStrict = parent.UseStrict;
            }

            // create the two lists of declared items for this scope
            ScopeLookups = new HashSet<Lookup>();
            VarDeclaredNames = new HashSet<INameDeclaration>();
            LexicallyDeclaredNames = new HashSet<INameDeclaration>();

            GhostedCatchParameters = new HashSet<ParameterDeclaration>();
            GhostedFunctions = new HashSet<FunctionObject>();
        }
예제 #9
0
        /// <summary>
        /// Minifies the CSS stylesheet passes to it using the given settings, returning the minified results
        /// The ErrorList property will be set with any errors found during the minification process.
        /// </summary>
        /// <param name="source">CSS Source</param>
        /// <param name="settings">CSS minification settings</param>
        /// <param name="scriptSettings">JS minification settings to use for expression-minification</param>
        /// <returns>Minified StyleSheet</returns>
        public string MinifyStyleSheet(string source, CssSettings settings, CodeSettings scriptSettings)
        {
            // initialize some values, including the error list (which shoudl start off empty)
            string minifiedResults = string.Empty;
            m_errorList = new List<ContextError>();

            // create the parser object and if we specified some settings,
            // use it to set the Parser's settings object
            CssParser parser = new CssParser();
            parser.FileContext = FileName;

            if (settings != null)
            {
                parser.Settings = settings;
            }

            if (scriptSettings != null)
            {
                parser.JSSettings = scriptSettings;
            }

            // hook the error handler
            parser.CssError += new EventHandler<CssErrorEventArgs>(OnCssError);

            // try parsing the source and return the results
            try
            {
                minifiedResults = parser.Parse(source);
            }
            catch (Exception e)
            {
                m_errorList.Add(new ContextError(
                    true,
                    0,
                    null,
                    null,
                    null,
                    this.FileName,
                    0,
                    0,
                    0,
                    0,
                    e.Message));
                throw;
            }
            return minifiedResults;
        }
예제 #10
0
 internal CatchScope(ActivationObject parent, Context catchContext, CodeSettings settings, ParameterDeclaration catchParameter)
     : base(parent, catchContext, settings)
 {
     CatchParameter = catchParameter;
 }
예제 #11
0
 public Block ParseExpression(CodeSettings settings)
 {
     // we need to make sure the settings object has the expression source mode property set,
     // but let's not modify the settings object passed in. So clone it, set the property on the
     // clone, and use that object for parsing.
     settings = settings == null ? new CodeSettings() : settings.Clone();
     settings.SourceMode = JavaScriptSourceMode.Expression;
     return Parse(settings);
 }
예제 #12
0
        /// <summary>
        /// Parse the source code using the given settings, getting back an abstract syntax tree Block node as the root
        /// representing the list of statements in the source code.
        /// </summary>
        /// <param name="settings">code settings to use to process the source code</param>
        /// <returns>root Block node representing the top-level statements</returns>
        public Block Parse(CodeSettings settings)
        {
            // initialize the scanner with our settings
            // make sure the RawTokens setting is OFF or we won't be able to create our AST
            InitializeScanner(settings);

            // make sure we initialize the global scope's strict mode to our flag, whether or not it
            // is true. This means if the setting is false, we will RESET the flag to false if we are 
            // reusing the scope and a previous Parse call had code that set it to strict with a 
            // program directive. 
            GlobalScope.UseStrict = m_settings.StrictMode;

            // make sure the global scope knows about our known global names
            GlobalScope.SetAssumedGlobals(m_settings);

            // start of a new module
            m_newModule = true;

            Block scriptBlock;
            Block returnBlock;
            switch (m_settings.SourceMode)
            {
                case JavaScriptSourceMode.Program:
                    // simply parse a block of statements
                    returnBlock = scriptBlock = ParseStatements();
                    break;
                    
                case JavaScriptSourceMode.Expression:
                    // create a block, get the first token, add in the parse of a single expression, 
                    // and we'll go fron there.
                    returnBlock = scriptBlock = new Block(CurrentPositionContext(), this);
                    GetNextToken();
                    try
                    {
                        var expr = ParseExpression();
                        if (expr != null)
                        {
                            scriptBlock.Append(expr);
                            scriptBlock.UpdateWith(expr.Context);
                        }
                    }
                    catch (EndOfFileException)
                    {
                        Debug.WriteLine("EOF");
                    }
                    break;

                case JavaScriptSourceMode.EventHandler:
                    // we're going to create the global block, add in a function expression with a single
                    // parameter named "event", and then we're going to parse the input as the body of that
                    // function expression. We're going to resolve the global block, but only return the body
                    // of the function.
                    scriptBlock = new Block(null, this);

                    var parameters = new AstNodeList(null, this);
                    parameters.Append(new ParameterDeclaration(null, this)
                        {
                            Name = "event",
                            RenameNotAllowed = true
                        });

                    var funcExpression = new FunctionObject(null, this)
                        {
                            FunctionType = FunctionType.Expression, 
                            ParameterDeclarations = parameters
                        };
                    scriptBlock.Append(funcExpression);

                    returnBlock = ParseStatements();
                    funcExpression.Body = returnBlock;
                    break;

                default:
                    Debug.Fail("Unexpected source mode enumeration");
                    return null;
            }

            // resolve everything
            ResolutionVisitor.Apply(scriptBlock, GlobalScope, m_settings);

            if (scriptBlock != null && Settings.MinifyCode)
            {
                // this visitor doesn't just reorder scopes. It also combines the adjacent var variables,
                // unnests blocks, identifies prologue directives, and sets the strict mode on scopes. 
                ReorderScopeVisitor.Apply(scriptBlock, this);

                // analyze the entire node tree (needed for hypercrunch)
                // root to leaf (top down)
                var analyzeVisitor = new AnalyzeNodeVisitor(this);
                scriptBlock.Accept(analyzeVisitor);

                // analyze the scope chain (also needed for hypercrunch)
                // root to leaf (top down)
                m_globalScope.AnalyzeScope();

                // if we want to crunch any names....
                if (m_settings.LocalRenaming != LocalRenaming.KeepAll
                    && m_settings.IsModificationAllowed(TreeModifications.LocalRenaming))
                {
                    // then do a top-down traversal of the scope tree. For each field that had not
                    // already been crunched (globals and outers will already be crunched), crunch
                    // the name with a crunch iterator that does not use any names in the verboten set.
                    m_globalScope.AutoRenameFields();
                }

                // if we want to evaluate literal expressions, do so now
                if (m_settings.EvalLiteralExpressions)
                {
                    var visitor = new EvaluateLiteralVisitor(this);
                    scriptBlock.Accept(visitor);
                }

                // if any of the conditions we check for in the final pass are available, then
                // make the final pass
                if (m_settings.IsModificationAllowed(TreeModifications.BooleanLiteralsToNotOperators))
                {
                    var visitor = new FinalPassVisitor(this);
                    scriptBlock.Accept(visitor);
                }

                // we want to walk all the scopes to make sure that any generated
                // variables that haven't been crunched have been assigned valid
                // variable names that don't collide with any existing variables.
                m_globalScope.ValidateGeneratedNames();
            }

            if (returnBlock.Parent != null)
            {
                returnBlock.Parent = null;
            }

            return returnBlock;
        }
예제 #13
0
        /// <summary>
        /// Preprocess the input only - don't generate a syntax tree or do any other code analysis. Just write the processed
        /// code to the provided text stream.
        /// </summary>
        /// <param name="settings">settings to use in the scanner</param>
        /// <param name="outputStream">output stream to which to write the processed source</param>
        public void PreprocessOnly(CodeSettings settings, TextWriter outputStream)
        {
            if (outputStream != null)
            {
                // initialize the scanner
                // make sure the RawTokens setting is on so that the scanner
                // just returns everything (after doing preprocessor evaluations)
                InitializeScanner(settings);

                // get the first token, which might be a regular expression
                // (since it makes no sense to start off script with a divide-operator)
                var scanRegExp = true;
                var tokenContext = m_scanner.ScanNextToken(scanRegExp);

                // until we hit the end of the file...
                int lastEndPosition = tokenContext.EndPosition;
                while (tokenContext.Token != JSToken.EndOfFile)
                {
                    // just output the token and grab the next one.
                    // but skip preprocessor directives!
                    if (tokenContext.Token != JSToken.PreprocessorDirective)
                    {
                        outputStream.Write(tokenContext.Code);
                    }

                    // if this the kind of token we want to know about the next time, then save it
                    switch (tokenContext.Token)
                    {
                        case JSToken.WhiteSpace:
                        case JSToken.EndOfLine:
                        case JSToken.AspNetBlock:
                        case JSToken.SingleLineComment:
                        case JSToken.MultipleLineComment:
                        case JSToken.PreprocessorDirective:
                        case JSToken.ConditionalCompilationOn:
                        case JSToken.ConditionalCompilationSet:
                        case JSToken.ConditionalCompilationIf:
                        case JSToken.ConditionalCompilationElseIf:
                        case JSToken.ConditionalCompilationElse:
                        case JSToken.ConditionalCompilationEnd:
                            // don't change the regexp flag for these tokens
                            break;

                        default:
                            scanRegExp = RegExpCanFollow(tokenContext.Token);
                            break;
                    }

                    tokenContext = m_scanner.ScanNextToken(scanRegExp);
                    if (!m_scanner.IsEndOfFile && tokenContext.EndPosition == lastEndPosition)
                    {
                        // didn't get anything, but not at the end of the file. infinite loop?
                        tokenContext.HandleError(JSError.ApplicationError, true);
                        break;
                    }
                    else
                    {
                        lastEndPosition = tokenContext.EndPosition;
                    }
                }
            }
        }
예제 #14
0
        /// <summary>
        /// Preprocess the input only - don't generate an AST tree or do any other code analysis, just return the processed code as a string. 
        /// </summary>
        /// <param name="settings">settings to use in the scanner</param>
        /// <returns>the source as processed by the preprocessor</returns>
        public string PreprocessOnly(CodeSettings settings)
        {
            // create an empty string builder
            using (var outputStream = new StringWriter(CultureInfo.InvariantCulture))
            {
                // output to the string builder
                PreprocessOnly(settings, outputStream);

                // return the resulting text
                return outputStream.ToString();
            }
        }
예제 #15
0
        private void InitializeScanner(CodeSettings settings)
        {
            // save the settings
            // if we are passed null, just create a default settings object
            m_settings = settings = settings ?? new CodeSettings();

            // if the settings list is not null, use it to initialize a new list
            // with the same settings. If it is null, initialize an empty list 
            // because we already determined that we want to strip debug statements,
            // and the scanner might add items to the list as it scans the source.
            DebugLookups = new HashSet<string>(m_settings.DebugLookupCollection);

            // pass our list to the scanner -- it might add more as we encounter special comments
            m_scanner.DebugLookupCollection = DebugLookups;

            m_scanner.AllowEmbeddedAspNetBlocks = m_settings.AllowEmbeddedAspNetBlocks;
            m_scanner.IgnoreConditionalCompilation = m_settings.IgnoreConditionalCompilation;

            // set any defines
            m_scanner.UsePreprocessorDefines = !m_settings.IgnorePreprocessorDefines;
            if (m_scanner.UsePreprocessorDefines)
            {
                m_scanner.SetPreprocessorDefines(m_settings.PreprocessorValues);
            }

            // if we want to strip debug statements, let's also strip ///#DEBUG comment
            // blocks for legacy reasons. ///#DEBUG will get stripped ONLY is this
            // flag is true AND the name "DEBUG" is not in the preprocessor defines.
            // Alternately, we will keep those blocks in the output is this flag is
            // set to false OR we define "DEBUG" in the preprocessor defines.
            m_scanner.StripDebugCommentBlocks = m_settings.StripDebugStatements;
        }
예제 #16
0
 internal CatchScope(ActivationObject parent, Context catchContext, CodeSettings settings, ParameterDeclaration catchParameter)
     : base(parent, catchContext, settings)
 {
     CatchParameter = catchParameter;
 }
예제 #17
0
 public WithScope(ActivationObject parent, Context context, CodeSettings settings)
     : base(parent, context, settings)
 {
     IsInWithScope = true;
 }
예제 #18
0
        /// <summary>
        /// Crunched JS string passed to it, returning crunched string.
        /// The ErrorList property will be set with any errors found during the minification process.
        /// </summary>
        /// <param name="source">source Javascript</param>
        /// <param name="codeSettings">code minification settings</param>
        /// <returns>minified Javascript</returns>
        public string MinifyJavaScript(string source, CodeSettings codeSettings)
        {
            // default is an empty string
            var crunched = string.Empty;

            // reset the errors builder
            m_errorList = new List <ContextError>();

            // create the parser from the source string.
            // pass null for the assumed globals array
            var parser = new JSParser(source);

            // file context is a property on the parser
            parser.FileContext = FileName;

            // hook the engine error event
            parser.CompilerError += OnJavaScriptError;

            try
            {
                if (codeSettings != null && codeSettings.PreprocessOnly)
                {
                    // just run through the preprocessor only
                    crunched = parser.PreprocessOnly(codeSettings);
                }
                else
                {
                    // parse the input
                    var scriptBlock = parser.Parse(codeSettings);
                    if (scriptBlock != null)
                    {
                        // we'll return the crunched code
                        if (codeSettings != null && codeSettings.Format == JavaScriptFormat.JSON)
                        {
                            // we're going to use a different output visitor -- one
                            // that specifically returns valid JSON.
                            var sb = new StringBuilder();
                            using (var stringWriter = new StringWriter(sb, CultureInfo.InvariantCulture))
                            {
                                if (!JSONOutputVisitor.Apply(stringWriter, scriptBlock))
                                {
                                    m_errorList.Add(new ContextError(
                                                        true,
                                                        0,
                                                        null,
                                                        null,
                                                        null,
                                                        this.FileName,
                                                        0,
                                                        0,
                                                        0,
                                                        0,
                                                        JScript.InvalidJSONOutput));
                                }
                            }

                            crunched = sb.ToString();
                        }
                        else
                        {
                            // just use the normal output visitor
                            crunched = scriptBlock.ToCode();
                        }
                    }
                }
            }
            catch (Exception e)
            {
                m_errorList.Add(new ContextError(
                                    true,
                                    0,
                                    null,
                                    null,
                                    null,
                                    this.FileName,
                                    0,
                                    0,
                                    0,
                                    0,
                                    e.Message));
                throw;
            }

            return(crunched);
        }
예제 #19
0
        /// <summary>
        /// Crunched JS string passed to it, returning crunched string.
        /// The ErrorList property will be set with any errors found during the minification process.
        /// </summary>
        /// <param name="source">source Javascript</param>
        /// <param name="codeSettings">code minification settings</param>
        /// <returns>minified Javascript</returns>
        public string MinifyJavaScript(string source, CodeSettings codeSettings)
        {
            // default is an empty string
            var crunched = string.Empty;

            // reset the errors builder
            m_errorList = new List<ContextError>();

            // create the parser from the source string.
            // pass null for the assumed globals array
            var parser = new JSParser(source);

            // file context is a property on the parser
            parser.FileContext = FileName;

            // hook the engine error event
            parser.CompilerError += OnJavaScriptError;

            try
            {
                if (codeSettings != null && codeSettings.PreprocessOnly)
                {
                    // just run through the preprocessor only
                    crunched = parser.PreprocessOnly(codeSettings);
                }
                else
                {
                    // parse the input
                    var scriptBlock = parser.Parse(codeSettings);
                    if (scriptBlock != null)
                    {
                        // we'll return the crunched code
                        if (codeSettings != null && codeSettings.Format == JavaScriptFormat.JSON)
                        {
                            // we're going to use a different output visitor -- one
                            // that specifically returns valid JSON.
                            var sb = new StringBuilder();
                            using (var stringWriter = new StringWriter(sb, CultureInfo.InvariantCulture))
                            {
                                if (!JSONOutputVisitor.Apply(stringWriter, scriptBlock))
                                {
                                    m_errorList.Add(new ContextError(
                                        true,
                                        0,
                                        null,
                                        null,
                                        null,
                                        this.FileName,
                                        0,
                                        0,
                                        0,
                                        0,
                                        JScript.InvalidJSONOutput));
                                }
                            }

                            crunched = sb.ToString();
                        }
                        else
                        {
                            // just use the normal output visitor
                            crunched = scriptBlock.ToCode();
                        }
                    }
                }
            }
            catch (Exception e)
            {
                m_errorList.Add(new ContextError(
                    true,
                    0,
                    null,
                    null,
                    null,
                    this.FileName,
                    0,
                    0,
                    0,
                    0,
                    e.Message));
                throw;
            }

            return crunched;
        }
        public static void Apply(AstNode node, ActivationObject scope, CodeSettings settings)
        {
            if (node != null && scope != null)
            {
                // create the visitor and run it. This will create all the child
                // scopes and populate all the scopes with the var-decl, lex-decl,
                // and lookup references within them.
                var visitor = new ResolutionVisitor(scope, settings);
                node.Accept(visitor);

                // now that all the scopes are created and they all know what decls
                // they contains, create all the fields
                CreateFields(scope);

                // now that all the fields have been created in all the scopes,
                // let's go through and resolve all the references
                ResolveLookups(scope, settings);

                // now that everything is declared and resolved as per the language specs,
                // we need to go back and add ghosted fields for older versions of IE that
                // incorrectly implement catch-variables and named function expressions.
                AddGhostedFields(scope);
            }
        }
예제 #21
0
        public SwitchParser()
        {
            // initialize with default values
            JSSettings = new CodeSettings();
            CssSettings = new CssSettings();

            // see if this is running under the Mono runtime (on UNIX)
            m_isMono = Type.GetType("Mono.Runtime") != null;
        }
        private static void ResolveLookups(ActivationObject scope, CodeSettings settings)
        {
            // resolve each lookup this scope contains
            foreach (var lookup in scope.ScopeLookups)
            {
                ResolveLookup(scope, lookup, settings);
            }

            // and recurse
            foreach (var childScope in scope.ChildScopes)
            {
                ResolveLookups(childScope, settings);
            }
        }
예제 #23
0
        /// <summary>
        /// Instantiate a new CodeSettings object with the same settings as the current object.
        /// </summary>
        /// <returns>a copy CodeSettings object</returns>
        public CodeSettings Clone()
        {
            // create a new settings object and set all the properties using this settings object
            var newSettings = new CodeSettings()
            {
                // set the field, not the property. Setting the property will set a bunch of
                // other properties, which may not represent their actual values.
                m_minify = this.m_minify,

                AllowEmbeddedAspNetBlocks = this.AllowEmbeddedAspNetBlocks,
                CollapseToLiteral = this.CollapseToLiteral,
                ConstStatementsMozilla = this.ConstStatementsMozilla,
                DebugLookupList = this.DebugLookupList,
                EvalLiteralExpressions = this.EvalLiteralExpressions,
                EvalTreatment = this.EvalTreatment,
                Format = this.Format,
                IgnoreConditionalCompilation = this.IgnoreConditionalCompilation,
                IgnoreAllErrors = this.IgnoreAllErrors,
                IgnoreErrorList = this.IgnoreErrorList,
                IgnorePreprocessorDefines = this.IgnorePreprocessorDefines,
                IndentSize = this.IndentSize,
                InlineSafeStrings = this.InlineSafeStrings,
                KillSwitch = this.KillSwitch,
                KnownGlobalNamesList = this.KnownGlobalNamesList,
                LineBreakThreshold = this.LineBreakThreshold,
                LocalRenaming = this.LocalRenaming,
                MacSafariQuirks = this.MacSafariQuirks,
                ManualRenamesProperties = this.ManualRenamesProperties,
                NoAutoRenameList = this.NoAutoRenameList,
                OutputMode = this.OutputMode,
                PreprocessOnly = this.PreprocessOnly,
                PreprocessorDefineList = this.PreprocessorDefineList,
                PreserveFunctionNames = this.PreserveFunctionNames,
                PreserveImportantComments = this.PreserveImportantComments,
                QuoteObjectLiteralProperties = this.QuoteObjectLiteralProperties,
                RemoveFunctionExpressionNames = this.RemoveFunctionExpressionNames,
                RemoveUnneededCode = this.RemoveUnneededCode,
                RenamePairs = this.RenamePairs,
                ReorderScopeDeclarations = this.ReorderScopeDeclarations,
                SourceMode = this.SourceMode,
                StrictMode = this.StrictMode,
                StripDebugStatements = this.StripDebugStatements,
                TermSemicolons = this.TermSemicolons,
                BlocksStartOnSameLine = this.BlocksStartOnSameLine,
                ErrorIfNotInlineSafe = this.ErrorIfNotInlineSafe,
                SymbolsMap = this.SymbolsMap,
            };

            // set the resource strings if there are any
            newSettings.AddResourceStrings(this.ResourceStrings);

            return newSettings;
        }
        private static void ResolveLookup(ActivationObject scope, Lookup lookup, CodeSettings settings)
        {
            // resolve lookup via the lexical scope
            lookup.VariableField = scope.FindReference(lookup.Name);
            if (lookup.VariableField.FieldType == FieldType.UndefinedGlobal)
            {
                // couldn't find it.
                // if the lookup isn't generated and isn't the object of a typeof operator,
                // then we want to throw an error.
                if (!lookup.IsGenerated)
                {
                    var parentUnaryOp = lookup.Parent as UnaryOperator;
                    if (parentUnaryOp != null && parentUnaryOp.OperatorToken == JSToken.TypeOf)
                    {
                        // this undefined lookup is the target of a typeof operator.
                        // I think it's safe to assume we're going to use it. Don't throw an error
                        // and instead add it to the "known" expected globals of the global scope
                        MakeExpectedGlobal(lookup.VariableField);
                    }
                    else
                    {
                        // report this undefined reference
                        lookup.Context.ReportUndefined(lookup);

                        // possibly undefined global (but definitely not local).
                        // see if this is a function or a variable.
                        var callNode = lookup.Parent as CallNode;
                        var isFunction = callNode != null && callNode.Function == lookup;
                        lookup.Context.HandleError((isFunction ? JSError.UndeclaredFunction : JSError.UndeclaredVariable), false);
                    }
                }
            }
            else if (lookup.VariableField.FieldType == FieldType.Predefined)
            {
                if (string.CompareOrdinal(lookup.Name, "window") == 0)
                {
                    // it's the global window object
                    // see if it's the child of a member or call-brackets node
                    var member = lookup.Parent as Member;
                    if (member != null)
                    {
                        // we have window.XXXX. Add XXXX to the known globals if it
                        // isn't already a known item.
                        scope.AddGlobal(member.Name);
                    }
                    else
                    {
                        var callNode = lookup.Parent as CallNode;
                        if (callNode != null && callNode.InBrackets
                            && callNode.Arguments.Count == 1
                            && callNode.Arguments[0] is ConstantWrapper
                            && callNode.Arguments[0].FindPrimitiveType() == PrimitiveType.String)
                        {
                            // we have window["XXXX"]. See if XXXX is a valid identifier.
                            // TODO: we could get rid of the ConstantWrapper restriction and use an Evaluate visitor
                            // to evaluate the argument, since we know for sure that it's a string.
                            var identifier = callNode.Arguments[0].ToString();
                            if (JSScanner.IsValidIdentifier(identifier))
                            {
                                // Add XXXX to the known globals if it isn't already a known item.
                                scope.AddGlobal(identifier);
                            }
                        }
                    }
                }
                else if (settings.EvalTreatment != EvalTreatment.Ignore
                    && string.CompareOrdinal(lookup.Name, "eval") == 0)
                {
                    // it's an eval -- but are we calling it?
                    // TODO: what if we are assigning it to a variable? Should we track that variable and see if we call it?
                    // What about passing it as a parameter to a function? track that as well in case the function calls it?
                    var parentCall = lookup.Parent as CallNode;
                    if (parentCall != null && parentCall.Function == lookup)
                    {
                        scope.IsKnownAtCompileTime = false;
                    }
                }
            }

            // add the reference
            lookup.VariableField.AddReference(lookup);

            // we are actually referencing this field, so it's no longer a placeholder field if it
            // happens to have been one.
            lookup.VariableField.IsPlaceholder = false;
        }