Example #1
0
        private static ResourceStrings ProcessResXResources(string resourceFileName)
        {
            // default return object is null, meaning we are outputting the JS code directly
            // and don't want to replace any referenced resources in the sources
            var resourceStrings = new ResourceStrings();

            using (ResXResourceReader reader = new ResXResourceReader(resourceFileName))
            {
                foreach (DictionaryEntry item in reader)
                {
                    resourceStrings[item.Key.ToString()] = item.Value.ToString();
                }
            }

            return(resourceStrings.Count == 0 ? null : resourceStrings);
        }
Example #2
0
        private int ProcessCssFile(string sourceFileName, ResourceStrings resourceStrings, StringBuilder outputBuilder, ref long sourceLength)
        {
            int retVal = 0;

            try
            {
                // read our chunk of code
                string source;
                if (sourceFileName.Length > 0)
                {
                    using (StreamReader reader = new StreamReader(sourceFileName, m_encodingInput))
                    {
                        WriteProgress(
                            StringMgr.GetString("CrunchingFile", Path.GetFileName(sourceFileName))
                            );
                        source = reader.ReadToEnd();
                    }

                    // add the actual file length in to the input source length
                    FileInfo inputFileInfo = new FileInfo(sourceFileName);
                    sourceLength += inputFileInfo.Length;
                }
                else
                {
                    WriteProgress(StringMgr.GetString("CrunchingStdIn"));
                    try
                    {
                        // try setting the input encoding
                        Console.InputEncoding = m_encodingInput;
                    }
                    catch (IOException e)
                    {
                        // error setting the encoding input; just use whatever the default is
                        Debug.WriteLine(e.ToString());
                    }
                    source = Console.In.ReadToEnd();

                    if (m_analyze)
                    {
                        // calculate the actual number of bytes read using the input encoding
                        // and the string that we just read and
                        // add the number of bytes read into the input length.
                        sourceLength += Console.InputEncoding.GetByteCount(source);
                    }
                    else
                    {
                        // don't bother calculating the actual bytes -- the number of characters
                        // is sufficient if we're not doing the analysis
                        sourceLength += source.Length;
                    }
                }

                // process input source...
                CssParser parser = new CssParser();
                parser.CssError   += new EventHandler <CssErrorEventArgs>(OnCssError);
                parser.FileContext = sourceFileName;

                parser.Settings.CommentMode               = m_cssComments;
                parser.Settings.ExpandOutput              = m_prettyPrint;
                parser.Settings.IndentSpaces              = m_indentSize;
                parser.Settings.Severity                  = m_warningLevel;
                parser.Settings.TermSemicolons            = m_terminateWithSemicolon;
                parser.Settings.ColorNames                = m_colorNames;
                parser.Settings.MinifyExpressions         = m_minifyExpressions;
                parser.Settings.AllowEmbeddedAspNetBlocks = m_allowAspNet;
                parser.ValueReplacements                  = resourceStrings;

                // if the kill switch was set to 1 (don't preserve important comments), then
                // we just want to set the comment mode to none, regardless of what the actual comment
                // mode may be.
                if ((m_killSwitch & 1) != 0)
                {
                    parser.Settings.CommentMode = CssComment.None;
                }

                // crunch the source and output to the string builder we were passed
                string crunchedStyles = parser.Parse(source);
                if (crunchedStyles != null)
                {
                    Debug.WriteLine(crunchedStyles);
                }
                else
                {
                    // there was an error and no output was generated
                    retVal = 1;
                }

                if (m_echoInput)
                {
                    // just echo the input to the output
                    outputBuilder.Append(source);
                }
                else if (!string.IsNullOrEmpty(crunchedStyles))
                {
                    // send the crunched styles to the output
                    outputBuilder.Append(crunchedStyles);
                }
            }
            catch (IOException e)
            {
                // probably an error with the input file
                retVal = 1;
                System.Diagnostics.Debug.WriteLine(e.ToString());
                WriteError(CreateBuildError(
                               null,
                               null,
                               true,
                               "JS-IO",
                               e.Message
                               ));
            }

            return(retVal);
        }
Example #3
0
        internal override void AnalyzeNode()
        {
            // see if this is a member (we'll need it for a couple checks)
            Member member = m_func as Member;

            if (Parser.Settings.StripDebugStatements && Parser.Settings.IsModificationAllowed(TreeModifications.StripDebugStatements))
            {
                // if this is a member, and it's a debugger object, and it's a constructor....
                if (member != null && member.IsDebuggerStatement && m_isConstructor)
                {
                    // we need to replace our debugger object with a generic Object
                    m_func = new Lookup("Object", m_func.Context, Parser);
                    // and make sure the node list is empty
                    if (m_args != null && m_args.Count > 0)
                    {
                        m_args = new AstNodeList(m_args.Context, Parser);
                    }
                }
            }

            // if this is a constructor and we want to collapse
            // some of them to literals...
            if (m_isConstructor && Parser.Settings.CollapseToLiteral)
            {
                // see if this is a lookup, and if so, if it's pointing to one
                // of the two constructors we want to collapse
                Lookup lookup = m_func as Lookup;
                if (lookup != null)
                {
                    if (lookup.Name == "Object" &&
                        Parser.Settings.IsModificationAllowed(TreeModifications.NewObjectToObjectLiteral))
                    {
                        // no arguments -- the Object constructor with no arguments is the exact same as an empty
                        // object literal
                        if (m_args == null || m_args.Count == 0)
                        {
                            // replace our node with an object literal
                            ObjectLiteral objLiteral = new ObjectLiteral(Context, Parser, null, null);
                            if (Parent.ReplaceChild(this, objLiteral))
                            {
                                // and bail now. No need to recurse -- it's an empty literal
                                return;
                            }
                        }
                        else if (m_args.Count == 1)
                        {
                            // one argument
                            // check to see if it's an object literal.
                            ObjectLiteral objectLiteral = m_args[0] as ObjectLiteral;
                            if (objectLiteral != null)
                            {
                                // the Object constructor with an argument that is a JavaScript object merely returns the
                                // argument. Since the argument is an object literal, it is by definition a JavaScript object
                                // and therefore we can replace the constructor call with the object literal
                                Parent.ReplaceChild(this, objectLiteral);

                                // don't forget to recurse the object now
                                objectLiteral.AnalyzeNode();

                                // and then bail -- we don't want to process this call
                                // operation any more; we've gotten rid of it
                                return;
                            }
                        }
                    }
                    else if (lookup.Name == "Array" &&
                             Parser.Settings.IsModificationAllowed(TreeModifications.NewArrayToArrayLiteral))
                    {
                        // Array is trickier.
                        // If there are no arguments, then just use [].
                        // if there are multiple arguments, then use [arg0,arg1...argN].
                        // but if there is one argument and it's numeric, we can't crunch it.
                        // also can't crunch if it's a function call or a member or something, since we won't
                        // KNOW whether or not it's numeric.
                        //
                        // so first see if it even is a single-argument constant wrapper.
                        ConstantWrapper constWrapper = (m_args != null && m_args.Count == 1 ? m_args[0] as ConstantWrapper : null);

                        // if the argument count is not one, then we crunch.
                        // if the argument count IS one, we only crunch if we have a constant wrapper,
                        // AND it's not numeric.
                        if (m_args == null ||
                            m_args.Count != 1 ||
                            (constWrapper != null && !constWrapper.IsNumericLiteral))
                        {
                            // create the new array literal object
                            ArrayLiteral arrayLiteral = new ArrayLiteral(Context, Parser, m_args);
                            // replace ourself within our parent
                            if (Parent.ReplaceChild(this, arrayLiteral))
                            {
                                // recurse
                                arrayLiteral.AnalyzeNode();
                                // and bail -- we don't want to recurse this node any more
                                return;
                            }
                        }
                    }
                }
            }

            // if we are replacing resource references with strings generated from resource files
            // and this is a brackets call: lookup[args]
            ResourceStrings resourceStrings = Parser.ResourceStrings;

            if (m_inBrackets && resourceStrings != null && resourceStrings.Count > 0)
            {
                // see if the root object is a lookup that corresponds to the
                // global value (not a local field) for our resource object
                // (same name)
                Lookup rootLookup = m_func as Lookup;
                if (rootLookup != null &&
                    rootLookup.LocalField == null &&
                    string.CompareOrdinal(rootLookup.Name, resourceStrings.Name) == 0)
                {
                    // we're going to replace this node with a string constant wrapper
                    // but first we need to make sure that this is a valid lookup.
                    // if the parameter contains anything that would vary at run-time,
                    // then we need to throw an error.
                    // the parser will always have either one or zero nodes in the arguments
                    // arg list. We're not interested in zero args, so just make sure there is one
                    if (m_args.Count == 1)
                    {
                        // must be a constant wrapper
                        ConstantWrapper argConstant = m_args[0] as ConstantWrapper;
                        if (argConstant != null)
                        {
                            string resourceName = argConstant.Value.ToString();

                            // get the localized string from the resources object
                            ConstantWrapper resourceLiteral = new ConstantWrapper(
                                resourceStrings[resourceName],
                                PrimitiveType.String,
                                Context,
                                Parser);

                            // replace this node with localized string, analyze it, and bail
                            // so we don't anaylze the tree we just replaced
                            Parent.ReplaceChild(this, resourceLiteral);
                            resourceLiteral.AnalyzeNode();
                            return;
                        }
                        else
                        {
                            // error! must be a constant
                            Context.HandleError(
                                JSError.ResourceReferenceMustBeConstant,
                                true);
                        }
                    }
                    else
                    {
                        // error! can only be a single constant argument to the string resource object.
                        // the parser will only have zero or one arguments, so this must be zero
                        // (since the parser won't pass multiple args to a [] operator)
                        Context.HandleError(
                            JSError.ResourceReferenceMustBeConstant,
                            true);
                    }
                }
            }

            // and finally, if this is a backets call and the argument is a constantwrapper that can
            // be an identifier, just change us to a member node:  obj["prop"] to obj.prop.
            // but ONLY if the string value is "safe" to be an identifier. Even though the ECMA-262
            // spec says certain Unicode categories are okay, in practice the various major browsers
            // all seem to have problems with certain characters in identifiers. Rather than risking
            // some browsers breaking when we change this syntax, don't do it for those "danger" categories.
            if (m_inBrackets && m_args != null)
            {
                // see if there is a single, constant argument
                string argText = m_args.SingleConstantArgument;
                if (argText != null)
                {
                    // see if we want to replace the name
                    string newName;
                    if (Parser.Settings.HasRenamePairs && Parser.Settings.ManualRenamesProperties &&
                        Parser.Settings.IsModificationAllowed(TreeModifications.PropertyRenaming) &&
                        !string.IsNullOrEmpty(newName = Parser.Settings.GetNewName(argText)))
                    {
                        // yes -- we are going to replace the name, either as a string literal, or by converting
                        // to a member-dot operation.
                        // See if we can't turn it into a dot-operator. If we can't, then we just want to replace the operator with
                        // a new constant wrapper. Otherwise we'll just replace the operator with a new constant wrapper.
                        if (Parser.Settings.IsModificationAllowed(TreeModifications.BracketMemberToDotMember) &&
                            JSScanner.IsSafeIdentifier(newName) &&
                            !JSScanner.IsKeyword(newName))
                        {
                            // the new name is safe to convert to a member-dot operator.
                            // but we don't want to convert the node to the NEW name, because we still need to Analyze the
                            // new member node -- and it might convert the new name to something else. So instead we're
                            // just going to convert this existing string to a member node WITH THE OLD STRING,
                            // and THEN analyze it (which will convert the old string to newName)
                            Member replacementMember = new Member(Context, Parser, m_func, argText);
                            Parent.ReplaceChild(this, replacementMember);

                            // this analyze call will convert the old-name member to the newName value
                            replacementMember.AnalyzeNode();
                            return;
                        }
                        else
                        {
                            // nope; can't convert to a dot-operator.
                            // we're just going to replace the first argument with a new string literal
                            // and continue along our merry way.
                            m_args.ReplaceChild(m_args[0], new ConstantWrapper(newName, PrimitiveType.String, m_args[0].Context, Parser));
                        }
                    }
                    else if (Parser.Settings.IsModificationAllowed(TreeModifications.BracketMemberToDotMember) &&
                             JSScanner.IsSafeIdentifier(argText) &&
                             !JSScanner.IsKeyword(argText))
                    {
                        // not a replacement, but the string literal is a safe identifier. So we will
                        // replace this call node with a Member-dot operation
                        Member replacementMember = new Member(Context, Parser, m_func, argText);
                        Parent.ReplaceChild(this, replacementMember);
                        replacementMember.AnalyzeNode();
                        return;
                    }
                }
            }

            // call the base class to recurse
            base.AnalyzeNode();

            // call this AFTER recursing to give the fields a chance to resolve, because we only
            // want to make this replacement if we are working on the global Date object.
            if (!m_inBrackets && !m_isConstructor &&
                (m_args == null || m_args.Count == 0) &&
                member != null && string.CompareOrdinal(member.Name, "getTime") == 0 &&
                Parser.Settings.IsModificationAllowed(TreeModifications.DateGetTimeToUnaryPlus))
            {
                // this is not a constructor and it's not a brackets call, and there are no arguments.
                // if the function is a member operation to "getTime" and the object of the member is a
                // constructor call to the global "Date" object (not a local), then we want to replace the call
                // with a unary plus on the Date constructor. Converting to numeric type is the same as
                // calling getTime, so it's the equivalent with much fewer bytes.
                CallNode dateConstructor = member.Root as CallNode;
                if (dateConstructor != null &&
                    dateConstructor.IsConstructor)
                {
                    // lookup for the predifined (not local) "Date" field
                    Lookup lookup = dateConstructor.Function as Lookup;
                    if (lookup != null && string.CompareOrdinal(lookup.Name, "Date") == 0 &&
                        lookup.LocalField == null)
                    {
                        // this is in the pattern: (new Date()).getTime()
                        // we want to replace it with +new Date
                        // use the same date constructor node as the operand
                        NumericUnary unary = new NumericUnary(Context, Parser, dateConstructor, JSToken.Plus);

                        // replace us (the call to the getTime method) with this unary operator
                        Parent.ReplaceChild(this, unary);

                        // don't need to AnalyzeNode on the unary operator. The operand has already
                        // been analyzed when we recursed, and the unary operator wouldn't do anything
                        // special anyway (since the operand is not a numeric constant)
                    }
                }
            }
            else if (Parser.Settings.EvalTreatment != EvalTreatment.Ignore)
            {
                // if this is a window.eval call, then we need to mark this scope as unknown just as
                // we would if this was a regular eval call.
                // (unless, of course, the parser settings say evals are safe)
                // call AFTER recursing so we know the left-hand side properties have had a chance to
                // lookup their fields to see if they are local or global
                if (member != null && string.CompareOrdinal(member.Name, "eval") == 0)
                {
                    if (member.LeftHandSide.IsWindowLookup)
                    {
                        // this is a call to window.eval()
                        // mark this scope as unknown so we don't crunch out locals
                        // we might reference in the eval at runtime
                        ScopeStack.Peek().IsKnownAtCompileTime = false;
                    }
                }
                else
                {
                    CallNode callNode = m_func as CallNode;
                    if (callNode != null &&
                        callNode.InBrackets &&
                        callNode.LeftHandSide.IsWindowLookup &&
                        callNode.Arguments.IsSingleConstantArgument("eval"))
                    {
                        // this is a call to window["eval"]
                        // mark this scope as unknown so we don't crunch out locals
                        // we might reference in the eval at runtime
                        ScopeStack.Peek().IsKnownAtCompileTime = false;
                    }
                }
            }

            /* REVIEW: may be too late. lookups may alread have been analyzed and
             * found undefined
             * // check to see if this is an assignment to a window["prop"] structure
             * BinaryOperator binaryOp = Parent as BinaryOperator;
             * if (binaryOp != null && binaryOp.IsAssign
             *  && m_inBrackets
             *  && m_func.IsWindowLookup
             *  && m_args != null)
             * {
             *  // and IF the property is a non-empty constant that isn't currently
             *  // a global field...
             *  string propertyName = m_args.SingleConstantArgument;
             *  if (!string.IsNullOrEmpty(propertyName)
             *      && Parser.GlobalScope[propertyName] == null)
             *  {
             *      // we want to also add it to the global fields so it's not undefined
             *      Parser.GlobalScope.DeclareField(propertyName, null, 0);
             *  }
             * }
             */
        }
Example #4
0
        private static string CreateJSFromResourceStrings(ResourceStrings resourceStrings)
        {
            var sb = StringBuilderPool.Acquire();

            try
            {
                // start the var statement using the requested name and open the initializer object literal
                sb.Append("var ");
                sb.Append(resourceStrings.Name);
                sb.Append("={");

                // we're going to need to insert commas between each pair, so we'll use a boolean
                // flag to indicate that we're on the first pair. When we output the first pair, we'll
                // set the flag to false. When the flag is false, we're about to insert another pair, so
                // we'll add the comma just before.
                bool firstItem = true;

                // loop through all items in the collection
                foreach (var keyPair in resourceStrings.NameValuePairs)
                {
                    // if this isn't the first item, we need to add a comma separator
                    if (!firstItem)
                    {
                        sb.Append(',');
                    }
                    else
                    {
                        // next loop is no longer the first item
                        firstItem = false;
                    }

                    // append the key as the name, a colon to separate the name and value,
                    // and then the value
                    // must quote if not valid JS identifier format, or if it is, but it's a keyword
                    // (use strict mode just to be safe)
                    string propertyName = keyPair.Key;
                    if (!JSScanner.IsValidIdentifier(propertyName) || JSScanner.IsKeyword(propertyName, true))
                    {
                        sb.Append("\"");
                        // because we are using quotes for the delimiters, replace any instances
                        // of a quote character (") with an escaped quote character (\")
                        sb.Append(propertyName.Replace("\"", "\\\""));
                        sb.Append("\"");
                    }
                    else
                    {
                        sb.Append(propertyName);
                    }
                    sb.Append(':');

                    // make sure the Value is properly escaped, quoted, and whatever we
                    // need to do to make sure it's a proper JS string.
                    // pass false for whether this string is an argument to a RegExp constructor.
                    // pass false for whether to use W3Strict formatting for character escapes (use maximum browser compatibility)
                    // pass true for ecma strict mode
                    string stringValue = ConstantWrapper.EscapeString(
                        keyPair.Value,
                        false,
                        false,
                        true
                        );
                    sb.Append(stringValue);
                }

                // close the object literal and return the string
                sb.AppendLine("};");
                return(sb.ToString());
            }
            finally
            {
                sb.Release();
            }
        }
Example #5
0
        internal override void AnalyzeNode()
        {
            // if we don't even have any resource strings, then there's nothing
            // we need to do and we can just perform the base operation
            ResourceStrings resourceStrings = Parser.ResourceStrings;

            if (resourceStrings != null && resourceStrings.Count > 0)
            {
                // see if the root object is a lookup that corresponds to the
                // global value (not a local field) for our resource object
                // (same name)
                Lookup rootLookup = Root as Lookup;
                if (rootLookup != null &&
                    rootLookup.LocalField == null &&
                    string.CompareOrdinal(rootLookup.Name, resourceStrings.Name) == 0)
                {
                    // it is -- we're going to replace this with a string value.
                    // if this member name is a string on the object, we'll replacve it with
                    // the literal. Otherwise we'll replace it with an empty string.
                    // see if the string resource contains this value
                    ConstantWrapper stringLiteral = new ConstantWrapper(
                        resourceStrings[Name],
                        PrimitiveType.String,
                        Context,
                        Parser
                        );

                    Parent.ReplaceChild(this, stringLiteral);
                    // analyze the literal
                    stringLiteral.AnalyzeNode();
                    return;
                }
            }

            // if we are replacing property names and we have something to replace
            if (Parser.Settings.HasRenamePairs && Parser.Settings.ManualRenamesProperties &&
                Parser.Settings.IsModificationAllowed(TreeModifications.PropertyRenaming))
            {
                // see if this name is a target for replacement
                string newName = Parser.Settings.GetNewName(Name);
                if (!string.IsNullOrEmpty(newName))
                {
                    // it is -- set the name to the new name
                    Name = newName;
                }
            }

            // recurse
            base.AnalyzeNode();

            /* REVIEW: might be too late in the parsing -- references to the variable may have
             * already been analyzed and found undefined
             * // see if we are assigning to a member on the global window object
             * BinaryOperator binaryOp = Parent as BinaryOperator;
             * if (binaryOp != null && binaryOp.IsAssign && m_rootObject.IsWindowLookup)
             * {
             *  // make sure the name of this property is a valid global variable, since we
             *  // are now assigning to it.
             *  if (Parser.GlobalScope[Name] == null)
             *  {
             *      // it's not -- we need to add it to our list of known globals
             *      // by defining a global field for it
             *      Parser.GlobalScope.DeclareField(Name, null, 0);
             *  }
             * }
             */
        }
Example #6
0
 public void RemoveResourceStrings(ResourceStrings resourceStrings)
 {
     // remove it
     ResourceStrings.Remove(resourceStrings);
 }
Example #7
0
 public void AddResourceStrings(ResourceStrings resourceStrings)
 {
     // add it
     ResourceStrings.Add(resourceStrings);
 }
Example #8
0
        private bool m_preprocessOnly; // = false;

        #endregion

        #region file processing

        private int ProcessJSFile(string sourceFileName, ResourceStrings resourceStrings, StringBuilder outputBuilder, ref bool lastEndedSemicolon, ref long sourceLength)
        {
            int retVal = 0;

            // read our chunk of code
            string source;

            if (sourceFileName.Length > 0)
            {
                using (StreamReader reader = new StreamReader(sourceFileName, m_encodingInput))
                {
                    WriteProgress(
                        StringMgr.GetString("CrunchingFile", Path.GetFileName(sourceFileName))
                        );
                    source = reader.ReadToEnd();
                }
            }
            else
            {
                WriteProgress(StringMgr.GetString("CrunchingStdIn"));
                try
                {
                    // try setting the input encoding
                    Console.InputEncoding = m_encodingInput;
                }
                catch (IOException e)
                {
                    // error setting the encoding input; just use whatever the default is
                    Debug.WriteLine(e.ToString());
                }
                source = Console.In.ReadToEnd();

                if (m_analyze)
                {
                    // calculate the actual number of bytes read using the input encoding
                    // and the string that we just read and
                    // add the number of bytes read into the input length.
                    sourceLength += Console.InputEncoding.GetByteCount(source);
                }
                else
                {
                    // don't bother calculating the actual bytes -- the number of characters
                    // is sufficient if we're not doing the analysis
                    sourceLength += source.Length;
                }
            }

            // add the input length to the running total
            sourceLength += source.Length;

            // create the a parser object for our chunk of code
            JSParser parser = new JSParser(source);

            // set up the file context for the parser
            parser.FileContext = sourceFileName;

            // hook the engine events
            parser.CompilerError      += OnCompilerError;
            parser.UndefinedReference += OnUndefinedReference;

            // put the resource strings object into the parser
            parser.ResourceStrings = resourceStrings;

            // set our flags
            CodeSettings settings = new CodeSettings();

            settings.ManualRenamesProperties  = m_renameProperties;
            settings.CollapseToLiteral        = m_collapseToLiteral;
            settings.CombineDuplicateLiterals = m_combineDuplicateLiterals;
            settings.EvalLiteralExpressions   = m_evalLiteralExpressions;
            settings.EvalTreatment            = m_evalTreatment;
            settings.IndentSize                    = m_indentSize;
            settings.InlineSafeStrings             = m_safeForInline;
            settings.LocalRenaming                 = m_localRenaming;
            settings.MacSafariQuirks               = m_macSafariQuirks;
            settings.OutputMode                    = (m_prettyPrint ? OutputMode.MultipleLines : OutputMode.SingleLine);
            settings.PreserveFunctionNames         = m_preserveFunctionNames;
            settings.RemoveFunctionExpressionNames = m_removeFunctionExpressionNames;
            settings.RemoveUnneededCode            = m_removeUnneededCode;
            settings.StripDebugStatements          = m_stripDebugStatements;
            settings.AllowEmbeddedAspNetBlocks     = m_allowAspNet;
            settings.SetKnownGlobalNames(m_globals == null ? null : m_globals.ToArray());
            settings.SetNoAutoRename(m_noAutoRename == null ? null : m_noAutoRename.ToArray());
            settings.IgnoreConditionalCompilation = m_ignoreConditionalCompilation;

            // if there are defined preprocessor names
            if (m_defines != null && m_defines.Count > 0)
            {
                // set the list of defined names to our array of names
                settings.SetPreprocessorDefines(m_defines.ToArray());
            }

            // if there are rename entries...
            if (m_renameMap != null && m_renameMap.Count > 0)
            {
                // add each of them to the parser
                foreach (var sourceName in m_renameMap.Keys)
                {
                    settings.AddRenamePair(sourceName, m_renameMap[sourceName]);
                }
            }

            // cast the kill switch numeric value to the appropriate TreeModifications enumeration
            settings.KillSwitch = (TreeModifications)m_killSwitch;

            string resultingCode = null;

            if (m_preprocessOnly)
            {
                // we only want to preprocess the code. Call that api on the parser
                resultingCode = parser.PreprocessOnly(settings);
            }
            else
            {
                Block scriptBlock = parser.Parse(settings);
                if (scriptBlock != null)
                {
                    if (m_analyze)
                    {
                        // output our report
                        CreateReport(parser.GlobalScope);
                    }

                    // crunch the output and write it to debug stream
                    resultingCode = scriptBlock.ToCode();
                }
                else
                {
                    // no code?
                    WriteProgress(StringMgr.GetString("NoParsedCode"));
                }
            }

            if (!string.IsNullOrEmpty(resultingCode))
            {
                // always output the crunched code to debug stream
                System.Diagnostics.Debug.WriteLine(resultingCode);

                // if the last block of code didn't end in a semi-colon,
                // then we need to add one now
                if (!lastEndedSemicolon)
                {
                    outputBuilder.Append(';');
                }

                // we'll output either the crunched code (normal) or
                // the raw source if we're just echoing the input
                string outputCode = (m_echoInput ? source : resultingCode);

                // send the output code to the output stream
                outputBuilder.Append(outputCode);

                // check if this string ended in a semi-colon so we'll know if
                // we need to add one between this code and the next block (if any)
                lastEndedSemicolon = (outputCode[outputCode.Length - 1] == ';');
            }
            else
            {
                // resulting code is null or empty
                Debug.WriteLine(StringMgr.GetString("OutputEmpty"));
            }

            return(retVal);
        }