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;
}