static void Main(string[] args) { List<String> referenceFiles = new List<String>(); List<String> inputFiles = new List<String>(); List<SyntaxTree> inputTrees = new List<SyntaxTree>(); String outputFile = ""; bool help = false; int silence = 0; bool bootstrap = false; OptionSet Options = new OptionSet(){ {"i|input=", "Input {file}", v => { inputFiles.Add(v); }}, {"r|reference=", "Reference {file}", v => { referenceFiles.Add(v); }}, {"o|output=", "Output {file}", v => { outputFile = v; }}, {"h|?|help", "Show this help and exit", v => { help = (v != null); }}, {"s|silent", "Silence, 1 per level", v => { silence++; }}, {"b|bootstrap", "LS2 Bootstrap compiler mode", v => { bootstrap = (v != null); }} }; Options.Parse(args); if (silence <= 0) { System.Console.Error.WriteLine("C# Compiler for LavishScript 2.0 Virtual Machine"); System.Console.Error.WriteLine("- Building for LS2IL version " + LS2IL.Chunk.LS2ILVersion); } if (bootstrap) { System.Console.Error.WriteLine("- LS2 Bootstrap compiler mode"); } if (help) { System.Console.Error.WriteLine("Usage: ls2csc -i input.cs -o output.il"); Options.WriteOptionDescriptions(System.Console.Error); return; } TextWriter output; if (outputFile != "") { output = new StreamWriter(outputFile); } else { output = System.Console.Out; } if (bootstrap) { if (inputFiles.Count != 0) { System.Console.Error.WriteLine("Input files ignored in Bootstrap compiler mode."); } inputFiles = new List<string>(); string text = string.Empty; text += "#define BOOTSTRAP_MODE" + System.Environment.NewLine; text += Resources.Instance.DeserializeStream("ls2csc.Libraries.BootStrap.cs"); SyntaxTree tree = CSharpSyntaxTree.ParseText(text); // syntaxTrees.Add(tree); inputTrees.Add(tree); } else { if (inputFiles.Count != 0) { foreach (string inputfile in inputFiles) { if (silence <= 0) { System.Console.Error.WriteLine("Attempting to compile from file '" + inputfile + "'"); } inputTrees.Add(CSharpSyntaxTree.ParseFile(inputfile)); } } else { #if !USEPREDEF System.Console.Error.WriteLine("ls2csc: Filename required"); System.Console.Error.WriteLine("ls2csc: To display help, use 'ls2csc -h'"); return; #endif // this mess is for testing. #if USEPREDEF string predef = @" /* expected your ls2 filename: <preloaded> IsStarted=true */ using System; using LavishScript2; using LavishScriptAPI; namespace ls2csctest { public enum SomeEnum : int { SomeValue=1, SomeOtherValue, } public interface ISomeIFace { int SomeMethod(); string SomeProperty { get; } } public class SomeClass : ISomeIFace { public SomeClass() { MyEnum = SomeEnum.SomeOtherValue; } public virtual int SomeMethod() { return 42; } public string SomeProperty { get { return ""What is the answer to the question of life, the universe, and everything?""; } } public SomeEnum MyEnum { get; set; } } public class Test{ public static void Main(){ FieldTest ft = new FieldTest(); ft.Test(); foreach(Script s in Script.AllScripts) { string fname; try { fname = s.Filename; } catch { fname = ""<preloaded>""; // expected since we are currently building bytecode from ls2il in memory, instead of using a bytecode file } System.Console.WriteLine(s.Name+"": ""+fname+"" IsStarted=""+s.IsStarted.ToString()); } SomeClass myClass = new SomeClass(); if (myClass is ISomeIFace) { ISomeIFace iface = myClass as ISomeIFace; System.Console.WriteLine(iface.SomeProperty+"" ""+iface.SomeMethod()+"" MyEnum=""+myClass.MyEnum.ToString()); } /* using (LavishScriptObject obj = LavishScript.Objects.GetObject(""InnerSpace""), obj2 = LavishScript.Objects.GetObject(""InnerSpace"")) { System.Console.WriteLine(""InnerSpace.Build==""+obj.GetMember(""Build"").ToString()); } */ } } public class FieldTest{ public int num = -10; public void OtherTest(){ } public void Test(){ OtherTest(); this.OtherTest(); } } }"; #endif #if USEPREDEF if (silence <= 0) { System.Console.WriteLine("Attempting to compile from pre-defined text:"); } System.Console.WriteLine(predef); inputtrees.Add(SyntaxTree.ParseText(predef)); #endif } } #if OUTPUTEXCEPTIONS try #endif { // get libraries! //List<SyntaxTree> syntaxTrees = new List<SyntaxTree>(); List<SyntaxTree> referenceTrees = new List<SyntaxTree>(); #region Metadata == Declarations == "Libraries" string[] auto_reference = { "ls2csc.Libraries.InnerSpaceAPI.cs", "ls2csc.Libraries.LavishScriptAPI.cs", "ls2csc.Libraries.LavishScript2.cs", "ls2csc.Libraries.LavishSettings.cs", "ls2csc.Libraries.System.cs", "ls2csc.Libraries.BootStrap.cs" }; foreach (string s in auto_reference) { string text = string.Empty; if (bootstrap) { if (s.Contains("BootStrap")) { continue; } text += "#define BOOTSTRAP_MODE" + System.Environment.NewLine; } text += Resources.Instance.DeserializeStream(s); SyntaxTree tree = CSharpSyntaxTree.ParseText(text); // syntaxTrees.Add(tree); referenceTrees.Add(tree); } foreach (string s in referenceFiles) { SyntaxTree tree = CSharpSyntaxTree.ParseFile(s); //syntaxTrees.Add(tree); referenceTrees.Add(tree); } #endregion Compilation compilation = CSharpCompilation.Create("MyCompilation", syntaxTrees: referenceTrees); compilation = compilation.AddSyntaxTrees(inputTrees); #region Diagnose and display Errors on the original code int nErrors = 0; foreach (SyntaxTree tree in inputTrees) { SemanticModel model = compilation.GetSemanticModel(tree); IEnumerable<Diagnostic> diags; if ((diags = model.GetDiagnostics()) != null) { foreach (Diagnostic diag in diags) { if (diag.Severity == DiagnosticSeverity.Error) { nErrors++; } int neededSilence = 1; switch (diag.Severity) { case DiagnosticSeverity.Error: neededSilence = 3; break; case DiagnosticSeverity.Warning: neededSilence = 2; break; case DiagnosticSeverity.Info: neededSilence = 1; break; } if (silence <= neededSilence) { System.Console.Error.WriteLine(diag.ToString()); } } } } if (nErrors > 0) { System.Console.Error.WriteLine("Fix " + nErrors.ToString() + " errors. :("); return; } #endregion { List<SyntaxTree> finalReferenceTrees = new List<SyntaxTree>(); foreach (SyntaxTree tree in referenceTrees) { SyntaxNode newRoot = tree.GetRoot(); SemanticModel model = compilation.GetSemanticModel(tree); newRoot = new IndexerRewriter(model).Visit(newRoot); newRoot = new EnumValueRewriter().Visit(newRoot); newRoot = new AutoImplementedPropertyRewriter().Visit(newRoot); finalReferenceTrees.Add((CSharpSyntaxTree.Create((CSharpSyntaxNode)newRoot))); } referenceTrees = finalReferenceTrees; } #region C# Code Transformations: Optimizations and other rewriters List<SyntaxTree> finaltrees = new List<SyntaxTree>(); foreach (SyntaxTree tree in inputTrees) { SyntaxNode newRoot = tree.GetRoot(); SemanticModel model = compilation.GetSemanticModel(tree); newRoot = new IndexerRewriter(model).Visit(newRoot); newRoot = new EnumValueRewriter().Visit(newRoot); #if SCRIPTING_API_REINTRODUCED newRoot = new Optimizers.CondenseLiteralsRewriter().Visit(newRoot); #endif newRoot = new PrefixUnaryToBinaryRewriter().Visit(newRoot); newRoot = new FieldInitializerRewriter(model).Visit(newRoot); newRoot = new ForeachRewriter().Visit(newRoot); newRoot = new AutoImplementedPropertyRewriter().Visit(newRoot); finaltrees.Add(CSharpSyntaxTree.Create((CSharpSyntaxNode)newRoot)); } #endregion compilation = CSharpCompilation.Create("MyCompilation", syntaxTrees: referenceTrees); compilation = compilation.AddSyntaxTrees(finaltrees); #region LS2 IL Code Generation LS2IL.FlatObjectType.Compilation = compilation; LS2IL.Chunk chunk = new LS2IL.Chunk(compilation); foreach (SyntaxTree tree in referenceTrees) { SemanticModel model = compilation.GetSemanticModel(tree); SyntaxNode root = tree.GetRoot(); // Build up the metadata DeclarationCollector dc = new DeclarationCollector(chunk, model, true); // isLibrary = true because these are the reference-only trees dc.Visit(root); } foreach (SyntaxTree tree in finaltrees) { SemanticModel model = compilation.GetSemanticModel(tree); SyntaxNode root = tree.GetRoot(); // collect methods and properties to turn into LS2IL.Functions MethodCollector mc = new MethodCollector(chunk, model); mc.Visit(root); // Build up the metadata DeclarationCollector dc = new DeclarationCollector(chunk, model, false); // isLibrary = false because these are the trees going into the Chunk dc.Visit(root); } // TODO: command-line options for these flags LS2ILGeneratorOptions options = new LS2ILGeneratorOptions() { CondenseRegisters = true, ElevateLongValues = true, FilterUnusedInstructions = true, FlattenLabels = true }; chunk.Emit(options, output); output.WriteLine(""); #endregion } #if OUTPUTEXCEPTIONS catch (Exception e) { System.Console.Error.WriteLine("ls2csc: Unhandled Exception " + e.ToString()); } finally #endif { output.Close(); } }
/// <summary> /// Emits the Chunk to output in LS2IL /// </summary> /// <param name="output"></param> public void Emit(LS2ILGeneratorOptions options, TextWriter output) { output.WriteLine("; ---- begin chunk ----"); IMethodSymbol entryPoint = Compilation.GetEntryPoint(CancellationToken.None); if (entryPoint != null) { Function fEntryPoint; if (!Functions.TryGetValue(entryPoint, out fEntryPoint)) { throw new NotSupportedException("Entry point function not built"); } output.WriteLine(".entry " + fEntryPoint.NumFunction); } for (int i = 0; i < FunctionsByNumber.Count; i++) { LS2IL.Function f = FunctionsByNumber[i]; f.FlattenToInstructions(options); } GenerateTypesMetadata(); EmitMetaTable(output); output.WriteLine("; ---- begin chunk values ----"); foreach (string s in EmittedChunkValues) { output.WriteLine(s); } output.WriteLine("; ---- end chunk values ----"); output.WriteLine(""); output.WriteLine("; ---- begin functions ----"); foreach (LS2IL.Function f in FunctionsByNumber) { f.Emit(output); } output.WriteLine("; ---- end functions ----"); output.WriteLine("; ---- end chunk ----"); }
public void FlattenToInstructions(LS2ILGeneratorOptions options) { List<FlatStatement> list = Flatten(); ControlFlowGraph cfg = new ControlFlowGraph(this, list); cfg.Build(options.FilterUnusedInstructions); if (options.CondenseRegisters) { PackedRegisters = RegisterPackers.Pack(cfg); } else { PackedRegisters = this.Registers.Count; } if (PackedRegisters > 256) { throw new NotSupportedException("Too many registers used in function " + this.IMethodSymbol.GetFullyQualifiedName()); } list = cfg.Flatten(); if (options.ElevateLongValues) { foreach (FlatStatement fs in list) { if (fs.Operands == null) continue; string emitted = fs.Emit(); if (emitted.Length < 192) continue; // let's shorten this baby up. for (int i = 0; i < fs.Operands.Count; i++) { FlatOperand fo = fs.Operands[i]; if (fo.OperandType != FlatOperandType.OPND_IMMEDIATE) continue; if (fo.ImmediateValue.ToString().Length > 63) { int nValue = FunctionValues.Count; FunctionValues.Add(fo.ImmediateValue); fs.Operands[i] = FlatOperand.FunctionValueRef(nValue, fo.ImmediateValue); } } } } if (options.FlattenLabels) { FlattenLabels(list); foreach (FlatValue fv in FunctionValues) { if (fv.ValueType == FlatValueType.VT_Label) { // get label target int labelValue; if (!EmittedLabels.TryGetValue(fv.ValueText, out labelValue)) { throw new LS2ILLabelException("Unresolved label " + fv.ValueText); } fv.ValueType = FlatValueType.VT_Int32; fv.ValueText = labelValue.ToString(); fv.Object = labelValue; } else if (fv.Object is FlatArrayBuilder) { FlatArrayBuilder fab = (FlatArrayBuilder)fv.Object; fab.FlattenLabels(this); } else if (fv.Object is FlatTableBuilder) { FlatTableBuilder fab = (FlatTableBuilder)fv.Object; fab.FlattenLabels(this); } } } if (options.FlattenLabels) { foreach (FlatStatement fs in list) { if (fs.Instruction != Instruction.meta_LABEL) EmitInstruction(fs.Emit()); } } else { foreach (FlatStatement fs in list) { EmitInstruction(fs.Emit()); } } }