// Walk a code block and determine if the last statement is an // `if` statement without an `else` clause public static bool DoesCodeBlockHaveHangingElse(CodeBlock code) { // If the code block is going to render braces, we don't need to worry if (code.WillRenderBraces) return false; // Get the code block's last statement if (code.Content.Count == 0) return false; var stmt = code.Content[code.Content.Count - 1]; // Is it an `if` statement var stmtIf = stmt as StatementIfElse; if (stmtIf != null) { if (stmtIf.FalseStatement == null) return true; else return DoesCodeBlockHaveHangingElse(stmtIf.FalseStatement); } // Check the last child code block of the last statement var TrailingCodeBlock = GetTrailingCodeBlock(stmt); if (TrailingCodeBlock != null) { // See if it has a hanging else return DoesCodeBlockHaveHangingElse(TrailingCodeBlock); } // Not trailing else return false; }
// Parse a single statement ast.CodeBlock ParseStatement() { if (t.token == Token.openBrace) { return(ParseStatementBlock(TriState.Maybe)); } else { var stmt = new ast.CodeBlock(t.GetBookmark(), TriState.Maybe); stmt.AddStatement(ParseSingleStatement()); return(stmt); } }
// Parse series of statements into a statement block public void ParseStatements(ast.CodeBlock block) { while (t.token != Token.closeBrace && t.token != Token.eof) { // Skip redundant semicolons if (t.token == Token.semicolon) { t.Next(); continue; } // Add the next statement block.AddStatement(ParseSingleStatement()); } }
// Parse a brace enclosed statement block ast.CodeBlock ParseStatementBlock(TriState BracesInOutput) { var bmk = t.GetBookmark(); // Opening brace t.SkipRequired(Token.openBrace); // Statements var code = new ast.CodeBlock(bmk, BracesInOutput); ParseStatements(code); // Closing brace t.SkipRequired(Token.closeBrace); return(code); }
// Add code to this case clause. public void AddCode(ast.Statement statement) { // First time? if (Code == null) { Code = new ast.CodeBlock(statement.Bookmark, TriState.No); } Code.AddStatement(statement); }
// Parse a brace enclosed statement block ast.CodeBlock ParseStatementBlock(TriState BracesInOutput) { var bmk = t.GetBookmark(); // Opening brace t.SkipRequired(Token.openBrace); // Statements var code = new ast.CodeBlock(bmk, BracesInOutput); ParseStatements(code); // Closing brace t.SkipRequired(Token.closeBrace); return code; }
// Parse a single statement ast.CodeBlock ParseStatement() { if (t.token == Token.openBrace) { return ParseStatementBlock(TriState.Maybe); } else { var stmt = new ast.CodeBlock(t.GetBookmark(), TriState.Maybe); stmt.AddStatement(ParseSingleStatement()); return stmt; } }
// Compile all loaded script to a string public string CompileJavascriptToString() { // Create a symbol allocator SymbolAllocator SymbolAllocator = new SymbolAllocator(this); // Don't let the symbol allocator use any reserved words or common Javascript bits // We only go up to three letters - symbol allocation of more than 3 letters is // highly unlikely. // (based on list here: http://www.quackit.com/javascript/javascript_reserved_words.cfm) string[] words = new string[] { "if", "in", "do", "for", "new", "var", "int", "try", "NaN", "ref", "sun", "top" }; foreach (var s in words) { SymbolAllocator.ClaimSymbol(s); } // Create a member allocator SymbolAllocator MemberAllocator = new SymbolAllocator(this); // Render RenderContext r = new RenderContext(this, SymbolAllocator, MemberAllocator); // Process all files bool bNeedSemicolon = false; foreach (var file in m_files) { Console.WriteLine("Processing {0}...", System.IO.Path.GetFileName(file.filename)); // Create a tokenizer and parser Warnings = new List <Warning>(); WarningsEnabledStack = new Stack <bool>(); Tokenizer t = new Tokenizer(this, file.content, file.filename, file.warnings); Parser p = new Parser(t); // Create the global statement block var code = new ast.CodeBlock(null, TriState.No); // Parse the file into a namespace p.ParseStatements(code); // Ensure everything processed if (t.more) { throw new CompileError("Unexpected end of file", t); } // Dump the abstract syntax tree if (DumpAST) { code.Dump(0); } // Create the root symbol scope and build scopes for all // constained function scopes SymbolScope rootScope = new SymbolScope(this, null, Accessibility.Public); SymbolScope rootPseudoScope = new SymbolScope(this, null, Accessibility.Public); code.Visit(new VisitorScopeBuilder(rootScope, rootPseudoScope)); // Combine consecutive var declarations into a single one code.Visit(new VisitorCombineVarDecl(rootScope)); // Find all variable declarations code.Visit(new VisitorSymbolDeclaration(rootScope, rootPseudoScope)); // Do lint stuff code.Visit(new VisitorLint(rootScope, rootPseudoScope)); // Try to eliminate const declarations if (DetectConsts && !NoObfuscate) { code.Visit(new VisitorConstDetectorPass1(rootScope)); code.Visit(new VisitorConstDetectorPass2(rootScope)); code.Visit(new VisitorConstDetectorPass3(rootScope)); } // Simplify expressions code.Visit(new VisitorSimplifyExpressions()); // If obfuscation is allowed, find all in-scope symbols and then // count the frequency of their use. if (!NoObfuscate) { code.Visit(new VisitorSymbolUsage(rootScope)); } // Process all symbol scopes, applying default accessibility levels // and determining the "rank" of each symbol rootScope.Prepare(); // Dump scopes to stdout if (DumpScopes) { rootScope.Dump(0); } // Tell the global scope to claim all locally defined symbols // so they're not re-used (and therefore hidden) by the // symbol allocation rootScope.ClaimSymbols(SymbolAllocator); // Create a credit comment on the first file if (!NoCredit && file == m_files[0]) { int iInsertPos = 0; while (iInsertPos < code.Content.Count && code.Content[iInsertPos].GetType() == typeof(ast.StatementComment)) { iInsertPos++; } code.Content.Insert(iInsertPos, new ast.StatementComment(null, "// Minified by MiniME from toptensoftware.com")); } if (bNeedSemicolon) { r.Append(";"); } // Render it r.EnterScope(rootScope); bNeedSemicolon = code.Render(r); r.LeaveScope(); // Display warnings Warnings.Sort(delegate(Warning w1, Warning w2) { int Compare = w1.Order.file.FileName.CompareTo(w2.Order.file.FileName); if (Compare == 0) { Compare = w1.Order.position - w2.Order.position; } if (Compare == 0) { Compare = w1.OriginalOrder - w2.OriginalOrder; } return(Compare); }); foreach (var w in Warnings) { Console.WriteLine("{0}: {1}", w.Bookmark, w.Message); } } // return the final script string strResult = r.GetGeneratedOutput(); return(strResult); }
/// <summary> /// Parses all loaded scripts as javascript and compiles them to a string. /// </summary> /// <returns>A string containing the minified javascript.</returns> public string CompileJavascriptToString() { // Create a symbol allocator SymbolAllocator SymbolAllocator = new SymbolAllocator(this); // Don't let the symbol allocator use any reserved words or common Javascript bits // We only go up to three letters - symbol allocation of more than 3 letters is // highly unlikely. // (based on list here: http://www.quackit.com/javascript/javascript_reserved_words.cfm) string[] words = new string[] { "if", "in", "do", "for", "new", "var", "int", "try", "NaN", "ref", "sun", "top" }; foreach (var s in words) { SymbolAllocator.ClaimSymbol(s); } // Create a member allocator SymbolAllocator MemberAllocator = new SymbolAllocator(this); // Render RenderContext r = new RenderContext(this, SymbolAllocator, MemberAllocator); // Process all files bool bNeedSemicolon = false; foreach (var file in m_files) { Console.WriteLine("Processing {0}...", System.IO.Path.GetFileName(file.filename)); // Create a tokenizer and parser Warnings = new List<Warning>(); WarningsEnabledStack = new Stack<bool>(); Tokenizer t = new Tokenizer(this, file.content, file.filename, file.warnings); Parser p = new Parser(t); // Create the global statement block var code = new ast.CodeBlock(null, TriState.No); // Parse the file into a namespace p.ParseStatements(code); // Ensure everything processed if (t.more) { throw new CompileError("Unexpected end of file", t); } // Dump the abstract syntax tree if (DumpAST) code.Dump(0); // Create the root symbol scope and build scopes for all // constained function scopes SymbolScope rootScope = new SymbolScope(this, null, Accessibility.Public); SymbolScope rootPseudoScope = new SymbolScope(this, null, Accessibility.Public); code.Visit(new VisitorScopeBuilder(rootScope, rootPseudoScope)); // Combine consecutive var declarations into a single one code.Visit(new VisitorCombineVarDecl(rootScope)); // Find all variable declarations code.Visit(new VisitorSymbolDeclaration(rootScope, rootPseudoScope)); // Do lint stuff code.Visit(new VisitorLint(rootScope, rootPseudoScope)); // Try to eliminate const declarations if (DetectConsts && !NoObfuscate) { code.Visit(new VisitorConstDetectorPass1(rootScope)); code.Visit(new VisitorConstDetectorPass2(rootScope)); code.Visit(new VisitorConstDetectorPass3(rootScope)); } // Simplify expressions code.Visit(new VisitorSimplifyExpressions()); // If obfuscation is allowed, find all in-scope symbols and then // count the frequency of their use. if (!NoObfuscate) { code.Visit(new VisitorSymbolUsage(rootScope)); } // Process all symbol scopes, applying default accessibility levels // and determining the "rank" of each symbol rootScope.Prepare(); // Dump scopes to stdout if (DumpScopes) rootScope.Dump(0); // Tell the global scope to claim all locally defined symbols // so they're not re-used (and therefore hidden) by the // symbol allocation rootScope.ClaimSymbols(SymbolAllocator); // Create a credit comment on the first file if (!NoCredit && file==m_files[0]) { int iInsertPos = 0; while (iInsertPos < code.Content.Count && code.Content[iInsertPos].GetType() == typeof(ast.StatementComment)) iInsertPos++; code.Content.Insert(iInsertPos, new ast.StatementComment(null, "// Minified by MiniME from toptensoftware.com")); } if (bNeedSemicolon) { r.Append(";"); } // Render it r.EnterScope(rootScope); bNeedSemicolon=code.Render(r); r.LeaveScope(); // Display warnings Warnings.Sort(delegate(Warning w1, Warning w2) { int Compare = w1.Order.file.FileName.CompareTo(w2.Order.file.FileName); if (Compare == 0) Compare = w1.Order.position - w2.Order.position; if (Compare == 0) Compare = w1.OriginalOrder - w2.OriginalOrder; return Compare; }); foreach (var w in Warnings) { Console.WriteLine("{0}: {1}", w.Bookmark, w.Message); } } // return the final script string strResult = r.GetGeneratedOutput(); return strResult; }
public bool OnEnterNode(Node n) { var cb = n as CodeBlock; if (cb != null) TrailingCodeBlock = cb; return false; // Don't recurve }