diff --git a/CSharp.lua.Launcher/Program.cs b/CSharp.lua.Launcher/Program.cs index 3b28f6d9..39082bde 100644 --- a/CSharp.lua.Launcher/Program.cs +++ b/CSharp.lua.Launcher/Program.cs @@ -45,6 +45,7 @@ class Program { -metadata : export all metadata, use @CSharpLua.Metadata annotations for precise control -module : the currently compiled assembly needs to be referenced, it's useful for multiple module compiled -inline-property: inline some single-line properties +-include : the root directory of the CoreSystem library, adds all the dependencies to a single file named out.lua "; public static void Main(string[] args) { if (args.Length > 0) { @@ -77,12 +78,14 @@ public static void Main(string[] args) { bool isModule = cmds.ContainsKey("-module"); bool isInlineSimpleProperty = cmds.ContainsKey("-inline-property"); bool isNotConstantForEnum = cmds.ContainsKey("-ei"); + string include = cmds.GetArgument("-include", true); Compiler c = new Compiler(input, output, lib, meta, csc, isClassic, atts, enums) { IsExportMetadata = isExportMetadata, IsModule = isModule, IsInlineSimpleProperty = isInlineSimpleProperty, IsPreventDebugObject = isPreventDebugObject, IsNotConstantForEnum = isNotConstantForEnum, + Include = include, }; c.Compile(); Console.WriteLine($"Compiled Success, cost {sw.Elapsed.TotalSeconds}s"); diff --git a/CSharp.lua/Compiler.cs b/CSharp.lua/Compiler.cs index 58bb809b..0b08e904 100644 --- a/CSharp.lua/Compiler.cs +++ b/CSharp.lua/Compiler.cs @@ -16,6 +16,7 @@ limitations under the License. using System; using System.Collections.Generic; +using System.Diagnostics.Contracts; using System.IO; using System.Linq; using System.Reflection; @@ -40,6 +41,7 @@ public sealed class Compiler { public bool IsInlineSimpleProperty { get; set; } public bool IsPreventDebugObject { get; set; } public bool IsNotConstantForEnum { get; set; } + public string Include { get; set; } public Compiler(string input, string output, string lib, string meta, string csc, bool isClassic, string atts, string enums) { input_ = input; @@ -117,11 +119,36 @@ private static List GetLibs(IEnumerable additionalLibs, out List } public void Compile() { - GetGenerator().Generate(output_); + if (Include == null) { + GetGenerator().Generate(output_); + } else { + var luaSystemLibs = GetIncludeCorSysemPaths(Include); + GetGenerator().GenerateSingleFile("out.lua", output_, luaSystemLibs); + } } - public void CompileSingleFile(string fileName, IEnumerable luaSystemLibs) { - GetGenerator().GenerateSingleFile(fileName, output_, luaSystemLibs); + private static IEnumerable GetIncludeCorSysemPaths(string dir) { + const string kBeinMark = "load(\""; + + string allFilePath = Path.Combine(dir, "All.lua"); + if (!File.Exists(allFilePath)) { + throw new ArgumentException($"-include: {dir} is not root directory of the CoreSystem library"); + } + + List luaSystemLibs = new(); + var lines = File.ReadAllLines(allFilePath); + foreach (string line in lines) { + int i = line.IndexOf(kBeinMark); + if (i != -1) { + int begin = i + kBeinMark.Length; + int end = line.IndexOf('"', begin); + Contract.Assert(end != -1); + string name = line[begin..end].Replace('.', '/'); + string path = Path.Combine(dir, "CoreSystem", $"{name}.lua"); + luaSystemLibs.Add(path); + } + } + return luaSystemLibs; } private IEnumerable GetSourceFiles(out bool isDirectory) { diff --git a/CSharp.lua/CoreSystem.Lua/CoreSystem/Core.lua b/CSharp.lua/CoreSystem.Lua/CoreSystem/Core.lua index 89bfa78c..1333c04b 100644 --- a/CSharp.lua/CoreSystem.Lua/CoreSystem/Core.lua +++ b/CSharp.lua/CoreSystem.Lua/CoreSystem/Core.lua @@ -1569,9 +1569,11 @@ function System.init(t) end System.config = rawget(global, "CSharpLuaSystemConfig") or {} - -return function (config) - if config then - System.config = config +local isSingleFile = rawget(global, "CSharpLuaSingleFile") +if not isSingleFile then + return function (config) + if config then + System.config = config + end end end diff --git a/CSharp.lua/LuaAst/LuaCompilationUnitSyntax.cs b/CSharp.lua/LuaAst/LuaCompilationUnitSyntax.cs index 86c0339b..71d9c5e4 100644 --- a/CSharp.lua/LuaAst/LuaCompilationUnitSyntax.cs +++ b/CSharp.lua/LuaAst/LuaCompilationUnitSyntax.cs @@ -65,16 +65,17 @@ public sealed class LuaCompilationUnitSyntax : LuaSyntaxNode { internal readonly List UsingDeclares = new List(); internal readonly List GenericUsingDeclares = new List(); - public LuaCompilationUnitSyntax(string filePath = "") { + public LuaCompilationUnitSyntax(string filePath = "", bool hasGeneratedMark = true) { FilePath = filePath; - var info = Assembly.GetExecutingAssembly().GetName(); - LuaShortCommentStatement versonStatement = new LuaShortCommentStatement($" Generated by {info.Name} Compiler"); - AddStatement(versonStatement); - + if (hasGeneratedMark) { + AddStatement(new LuaShortCommentStatement(GeneratedMarkString)); + } var system = LuaIdentifierNameSyntax.System; AddImport(system, system); } + public static string GeneratedMarkString => $" Generated by {Assembly.GetExecutingAssembly().GetName().Name} Compiler"; + public void AddStatement(LuaStatementSyntax statement) { Statements.Add(statement); } diff --git a/CSharp.lua/LuaSyntaxGenerator.cs b/CSharp.lua/LuaSyntaxGenerator.cs index a39c3b4e..e7e04f57 100644 --- a/CSharp.lua/LuaSyntaxGenerator.cs +++ b/CSharp.lua/LuaSyntaxGenerator.cs @@ -197,22 +197,22 @@ public LuaSyntaxGenerator(IEnumerable<(string Text, string Path)> codes, IEnumer DoPretreatment(); } - private LuaCompilationUnitSyntax CreateCompilationUnit(SyntaxTree syntaxTree) { + private LuaCompilationUnitSyntax CreateCompilationUnit(SyntaxTree syntaxTree, bool isSingleFile) { var semanticModel = GetSemanticModel(syntaxTree); var compilationUnitSyntax = (CompilationUnitSyntax)syntaxTree.GetRoot(); var transfor = new LuaSyntaxNodeTransform(this, semanticModel); - return compilationUnitSyntax.Accept(transfor); + return transfor.VisitCompilationUnit(compilationUnitSyntax, isSingleFile); } - private Task CreateCompilationUnitAsync(SyntaxTree syntaxTree) { - return Task.Factory.StartNew(o => CreateCompilationUnit(syntaxTree), null); + private Task CreateCompilationUnitAsync(SyntaxTree syntaxTree, bool isSingleFile) { + return Task.Factory.StartNew(o => CreateCompilationUnit(syntaxTree, isSingleFile), null); } - private IEnumerable Create() { + private IEnumerable Create(bool isSingleFile = false) { List luaCompilationUnits; if (kIsConcurrent) { try { - var tasks = compilation_.SyntaxTrees.Select(CreateCompilationUnitAsync); + var tasks = compilation_.SyntaxTrees.Select(i => CreateCompilationUnitAsync(i, isSingleFile)); luaCompilationUnits = Task.WhenAll(tasks).Result.ToList(); } catch (AggregateException e) { if (e.InnerExceptions.Count > 0) { @@ -222,7 +222,7 @@ private IEnumerable Create() { } } } else { - luaCompilationUnits = compilation_.SyntaxTrees.Select(CreateCompilationUnit).ToList(); + luaCompilationUnits = compilation_.SyntaxTrees.Select(i => CreateCompilationUnit(i, isSingleFile)).ToList(); } CheckExportEnums(); @@ -254,21 +254,49 @@ public void Generate(string outFolder) { public void GenerateSingleFile(string outFile, string outFolder, IEnumerable luaSystemLibs) { outFile = GetOutFileRelativePath(outFile, outFolder, out _); using var streamWriter = new StreamWriter(outFile, false, Encoding); + streamWriter.WriteLine("CSharpLuaSingleFile = true"); + bool isFirst = true; foreach (var luaSystemLib in luaSystemLibs) { - WriteLuaSystemLib(luaSystemLib, streamWriter); + WriteLuaSystemLib(luaSystemLib, streamWriter, isFirst); + isFirst = false; } - foreach (var luaCompilationUnit in Create()) { + streamWriter.WriteLine(); + streamWriter.WriteLine(LuaSyntaxNode.Tokens.ShortComment + LuaCompilationUnitSyntax.GeneratedMarkString); + foreach (var luaCompilationUnit in Create(true)) { WriteCompilationUnit(luaCompilationUnit, streamWriter); } - if (mainEntryPoint_ is null) { - throw new CompilationErrorException("Program has no main entry point."); + WriteSingleFileManifest(streamWriter); + } + + private static string GetSystemLibName(string path) { + const string begin = "CoreSystem"; + int index = path.LastIndexOf(begin); + return path.Substring(index + begin.Length + 1); + } + + private static void RemoveLicenseComments(ref string code) { + const string kBegin = "--[["; + const string kEnd = "--]]"; + int i = code.IndexOf(kBegin); + if (i != -1) { + bool isSpace = code.Take(i).All(char.IsWhiteSpace); + if (isSpace) { + int j = code.IndexOf(kEnd, i + kBegin.Length); + Contract.Assert(j != -1); + code = code.Substring(j + kEnd.Length).Trim(); + } } - WriteManifest(streamWriter); } - private void WriteLuaSystemLib(string filePath, TextWriter writer) { + private void WriteLuaSystemLib(string filePath, TextWriter writer, bool isFirst) { + writer.WriteLine(); + writer.WriteLine("-- CoreSystemLib: {0}", GetSystemLibName(filePath)); writer.WriteLine(LuaSyntaxNode.Keyword.Do); - writer.WriteLine(File.ReadAllText(filePath)); + string code = File.ReadAllText(filePath); + if (!isFirst) { + RemoveLicenseComments(ref code); + } + writer.WriteLine(code); writer.WriteLine(LuaSyntaxNode.Keyword.End); } @@ -279,25 +307,20 @@ private void WriteCompilationUnit(LuaCompilationUnitSyntax luaCompilationUnit, T writer.WriteLine(LuaSyntaxNode.Keyword.End); } - private void WriteManifest(TextWriter writer) { - const string kManifestFuncName = "InitCSharp"; + private void WriteSingleFileManifest(TextWriter writer) { var types = GetExportTypes(); if (types.Count > 0) { - var functionExpression = new LuaFunctionExpressionSyntax(); - var initCSharpFunctionDeclarationStatement = new LuaLocalVariablesSyntax() { Initializer = new LuaEqualsValueClauseListSyntax(functionExpression.ArrayOf()) }; - initCSharpFunctionDeclarationStatement.Variables.Add(new LuaSymbolNameSyntax(new LuaIdentifierLiteralExpressionSyntax(kManifestFuncName))); - LuaTableExpression typeTable = new LuaTableExpression(); typeTable.Add("types", new LuaTableExpression(types.Select(i => new LuaStringLiteralExpressionSyntax(GetTypeShortName(i))))); - var methodName = mainEntryPoint_.Name; - var methodTypeName = GetTypeName(mainEntryPoint_.ContainingType); - var entryPointInvocation = new LuaInvocationExpressionSyntax(methodTypeName.MemberAccess(methodName)); - functionExpression.AddStatement(LuaIdentifierNameSyntax.SystemInit.Invocation(typeTable)); - functionExpression.AddStatement(entryPointInvocation); - - LuaCompilationUnitSyntax luaCompilationUnit = new LuaCompilationUnitSyntax(); - luaCompilationUnit.AddStatement(new LuaLocalDeclarationStatementSyntax(initCSharpFunctionDeclarationStatement)); - + LuaCompilationUnitSyntax luaCompilationUnit = new LuaCompilationUnitSyntax(hasGeneratedMark: false); + luaCompilationUnit.AddStatement(LuaIdentifierNameSyntax.SystemInit.Invocation(typeTable)); + if (mainEntryPoint_ != null) { + luaCompilationUnit.AddStatement(LuaBlankLinesStatement.One); + var methodName = mainEntryPoint_.Name; + var methodTypeName = GetTypeName(mainEntryPoint_.ContainingType); + var entryPointInvocation = new LuaInvocationExpressionSyntax(methodTypeName.MemberAccess(methodName)); + luaCompilationUnit.AddStatement(entryPointInvocation); + } Write(luaCompilationUnit, writer); writer.WriteLine(); } diff --git a/CSharp.lua/LuaSyntaxNodeTransform.cs b/CSharp.lua/LuaSyntaxNodeTransform.cs index a3cbe1b4..53595d41 100644 --- a/CSharp.lua/LuaSyntaxNodeTransform.cs +++ b/CSharp.lua/LuaSyntaxNodeTransform.cs @@ -230,8 +230,8 @@ private void ReleaseTempIdentifier(LuaIdentifierNameSyntax tempName) { --CurFunction.TempCount; } - public override LuaSyntaxNode VisitCompilationUnit(CompilationUnitSyntax node) { - LuaCompilationUnitSyntax compilationUnit = new LuaCompilationUnitSyntax(node.SyntaxTree.FilePath); + public LuaCompilationUnitSyntax VisitCompilationUnit(CompilationUnitSyntax node, bool isSingleFile = false) { + LuaCompilationUnitSyntax compilationUnit = new LuaCompilationUnitSyntax(node.SyntaxTree.FilePath, !isSingleFile); compilationUnits_.Push(compilationUnit); var statements = VisitTriviaAndNode(node, node.Members, false); diff --git a/README.md b/README.md index c2da0e41..3b5ef796 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,8 @@ Options -p : do not use debug.setmetatable, in some Addon/Plugin environment debug object cannot be used -metadata : export all metadata, use @CSharpLua.Metadata annotations for precise control -module : the currently compiled assembly needs to be referenced, it's useful for multiple module compiled +-inline-property: inline some single-line properties +-include : the root directory of the CoreSystem library, adds all the dependencies to a single file named out.lua ``` Make sure that .NET 5.0 is installed. https://dotnet.microsoft.com/download/dotnet/5.0