private static void addJSFiles(ExcessCompilation compilation, Scope scope) { var serverConfig = compilation.Scope.GetServerConfiguration(); if (serverConfig == null) { throw new ArgumentException("IServerConfiguration"); } var clientCode = serverConfig.GetClientInterface(); if (string.IsNullOrWhiteSpace(clientCode)) { return; } var servicePath = serverConfig.GetServicePath(); if (servicePath == null) { throw new InvalidOperationException("cannot find the path"); } compilation.AddContent(servicePath, Templates .jsServiceFile(new { Members = clientCode })); }
private static void jsService(SyntaxNode node, ExcessCompilation compilation, Scope scope) { Debug.Assert(node is ClassDeclarationSyntax); var @class = node as ClassDeclarationSyntax; var serviceAttribute = @class .AttributeLists .Where(attrList => attrList .Attributes .Any(attr => attr.Name.ToString() == "Service")) .SingleOrDefault() ?.Attributes .FirstOrDefault(attr => attr.Name.ToString() == "Service"); var model = compilation.GetSemanticModel(node); var config = scope.GetServerConfiguration(); var name = @class.Identifier.ToString(); var id = Guid.NewGuid(); var body = string.Empty; Debug.Assert(config != null); if (serviceAttribute == null) { //functions var @namespace = @class.FirstAncestorOrSelf <NamespaceDeclarationSyntax>( ancestor => ancestor is NamespaceDeclarationSyntax); if (@namespace != null) { name = @namespace.Name.ToString(); } body = functionalBody(@class, model); if (body.Any()) { config.AddFunctionalContainer(name, body); } return; //td: separate } else { var guidString = serviceAttribute .ArgumentList .Arguments .Single(attr => attr.NameColon.Name.ToString() == "id") .Expression .ToString(); id = Guid.Parse(guidString.Substring(1, guidString.Length - 2)); body = concurrentBody(@class, config, model); } config.AddClientInterface(node.SyntaxTree, Templates .jsService(new { Name = name, Body = body, ID = id })); }
//generation private static bool isService(ClassDeclarationSyntax @class, ExcessCompilation compilation, Scope scope) { if (!isConcurrentClass(@class, compilation, scope)) { var isFunctionClass = @class.Identifier.ToString() == "Functions" && Roslyn.IsStatic(@class); if (isFunctionClass) { return(@class.ChildNodes() .OfType <MethodDeclarationSyntax>() .Any(method => method .AttributeLists .Any(attrList => attrList .Attributes .Any(attr => attr.Name.ToString() == "route")))); } return(false); } return(@class .AttributeLists .Any(attrList => attrList .Attributes .Any(attr => attr.Name.ToString() == "Service"))); }
private static bool isConcurrentClass(ClassDeclarationSyntax @class, ExcessCompilation compilation, Scope scope) { return(@class .AttributeLists .Any(attrList => attrList .Attributes .Any(attr => attr.Name.ToString() == "Concurrent"))); }
private static void jsConcurrentClass(SyntaxNode node, ExcessCompilation compilation, Scope scope) { Debug.Assert(node is ClassDeclarationSyntax); var @class = node as ClassDeclarationSyntax; var model = compilation.GetSemanticModel(node); var config = scope.GetServerConfiguration(); Debug.Assert(config != null); var body = concurrentBody(@class, config, model); config.AddClientInterface(node.SyntaxTree, Templates .jsConcurrentClass(new { Name = @class.Identifier.ToString(), Body = body })); }
public void buildFiles() { if (Files == null) { throw new InvalidProgramException("must specify which files to compile"); } var actualFiles = Files.ToArray(); if (actualFiles.Length == 0) { throw new InvalidProgramException($"must specify which files to compile"); } var asExe = actualFiles .Where(path => Path .GetFileName(path) .Equals("Program.cs")) .Any(); if (Extensions == null) { var exePath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); Extensions = directoryExtensions(exePath); } var compilation = new ExcessCompilation( analysis: new CompilationAnalysis(), extensions: Extensions, executable: asExe); foreach (var file in actualFiles) { if (file.EndsWith(".xs.cs")) { continue; } var ext = Path.GetExtension(file); switch (ext) { case ".cs": compilation.addCSharpFile(file); break; case ".xs": compilation.addDocument(file); break; default: throw new InvalidOperationException($"invalid extension: {ext}"); } } var errors = null as IEnumerable <Diagnostic>; var result = compilation.build(out errors); if (Transpile) { foreach (var document in compilation.Documents()) { var filename = compilation.DocumentFileName(document) + ".cs"; Console.WriteLine($"Generated: {filename}"); var text = document.SyntaxRoot.NormalizeWhitespace().ToFullString(); File.WriteAllText(filename, text); } foreach (var file in compilation.getCSharpFiles()) { var filename = Path.Combine(_directory, file.Key); if (!File.Exists(file.Key) && !File.Exists(filename)) { Console.WriteLine($"Generated: {filename}"); var text = file.Value.GetRoot().NormalizeWhitespace().ToFullString(); File.WriteAllText(filename, text); } } } else if (result != null) { var outputPath = OutputPath; if (outputPath == null) { outputPath = Path.Combine( _directory, Path.GetFileName(_directory)); } if (Path.GetExtension(outputPath) == string.Empty) { outputPath = outputPath + (asExe ? ".exe" : ".dll"); } Debug.Assert(outputPath != null); outputPath = Path.GetFullPath(outputPath); File.WriteAllBytes(outputPath, result.GetBuffer()); Console.WriteLine($"Successfully built: {outputPath}"); } if (errors.Any()) { foreach (var error in errors) { Console.Error.WriteLine(error.ToString()); } } }
public static TestConcurrentApp Build(string code, out IEnumerable <Diagnostic> errors, bool withInterface = false, bool withRemote = false) { errors = null; var config = MockInjector(new Options { GenerateInterface = withInterface, GenerateRemote = withRemote, }); var compilation = new ExcessCompilation(); compilation.addDocument("concurrent-test", code, config); Assembly assembly = compilation.build(); if (assembly == null) { errors = compilation.errors(); //debug StringBuilder errorLines = new StringBuilder(); foreach (var error in errors) { errorLines.AppendLine(error.ToString()); } var errorString = errorLines.ToString(); return(null); } var types = new FactoryMap(); var result = new TestConcurrentApp(types); foreach (var type in assembly.GetTypes()) { var attributes = type.CustomAttributes; if (!attributes.Any(attr => attr.AttributeType == typeof(ConcurrentAttribute))) { continue; } var typeName = type.ToString(); if (attributes.Any(attr => attr.AttributeType == typeof(ConcurrentSingleton))) { result.AddSingleton(typeName, (IConcurrentObject)Activator.CreateInstance(type)); continue; } var useParameterLess = type.GetConstructors().Length == 0; if (!useParameterLess) { useParameterLess = type.GetConstructor(new Type[] { }) != null; } types[typeName] = (app, args) => { if (useParameterLess) { return((IConcurrentObject)Activator.CreateInstance(type)); } var ctor = type.GetConstructor(args .Select(arg => arg.GetType()) .ToArray()); if (ctor != null) { return((IConcurrentObject)ctor.Invoke(args)); } throw new InvalidOperationException("unable to find a constructor"); }; } return(result); }