public void GenerateIncludeForwardRefernces() { NodeJSTypeReferenceCollector typeReferenceCollector = new NodeJSTypeReferenceCollector(Context.ConfigurationContext, Context.TypeMaps, Context.Options); typeReferenceCollector.Process(TranslationUnit, filterNamespaces: false); // Filter for needed includes SortedSet <string> includes = new SortedSet <string>(StringComparer.InvariantCulture); foreach (NodeJSTypeReference typeRef in typeReferenceCollector.TypeReferences) { if (typeRef.Include.TranslationUnit == TranslationUnit) { continue; } if (typeRef.Include.File == TranslationUnit.FileName) { continue; } Include include = typeRef.Include; TranslationUnit unit = include.TranslationUnit; if (unit != null && !unit.IsDeclared) { continue; } if (!string.IsNullOrEmpty(include.File) && include.InHeader) { includes.Add(include.ToString()); } } // Output include lines foreach (string include in includes) { WriteLine(include); } }
private void GenerateNestedIncludeImplementations() { NodeJSTypeReferenceCollector typeReferenceCollector = new NodeJSTypeReferenceCollector(Context.ConfigurationContext, Context.TypeMaps, Context.Options); typeReferenceCollector.Process(TranslationUnit); // Find own class to wrap NodeJSTypeReference classToWrapTypeReference = typeReferenceCollector.TypeReferences .Where(item => item.Declaration is Class) .Where(item => NamingHelper.GenerateTrimmedClassName(TranslationUnit.FileNameWithoutExtension).ToLower().Equals(NamingHelper.GenerateTrimmedClassName(item.Declaration.Name).ToLower())) .FirstOrDefault(); string className = string.Empty; string classNameWrap = string.Empty; // Generate wrapper class name if (classToWrapTypeReference != null) { className = nodeJSTypePrinter.VisitDeclaration(classToWrapTypeReference.Declaration); classNameWrap = NamingHelper.GenerateClassWrapName(className); } else { TextInfo textInfo = new CultureInfo("en-US", false).TextInfo; classNameWrap = NamingHelper.GenerateClassWrapName(textInfo.ToTitleCase(TranslationUnit.FileNameWithoutExtension)); } // Generate nested class initialize IEnumerable <string> nestedIncludes = GetNestedIncludes(classNameWrap); if (nestedIncludes.Count() > 0) { foreach (string include in nestedIncludes) { //string includeId = string.IsNullOrEmpty(include.Alias) ? include.Id : include.Alias.ToLower(); WriteLine("#include \"{0}/{1}.h\"", TranslationUnit.FileNameWithoutExtension.ToLower(), include); } } }
/// <summary> /// Generate using directives /// </summary> public void GenerateNamespaceUsings() { NodeJSTypeReferenceCollector typeReferenceCollector = new NodeJSTypeReferenceCollector(Context.ConfigurationContext, Context.TypeMaps, Context.Options); typeReferenceCollector.Process(TranslationUnit); // Create sorted list of namespaces SortedSet <string> namespaces = new SortedSet <string>(StringComparer.InvariantCulture); foreach (NodeJSTypeReference typeRef in typeReferenceCollector.TypeReferences) { // Check if declaration namespace is set if (typeRef.Declaration.Namespace != null) { namespaces.Add(typeRef.Declaration.Namespace.ToString()); } } // Output @namespace lines foreach (string @namespace in namespaces) { WriteLine("using namespace {0};", @namespace); } }
private void GenerateWrapperClassImplementations() { NodeJSTypeReferenceCollector typeReferenceCollector = new NodeJSTypeReferenceCollector(Context.ConfigurationContext, Context.TypeMaps, Context.Options); typeReferenceCollector.Process(TranslationUnit); NodeJSTypeReference classToWrapTypeReference = typeReferenceCollector.TypeReferences .Where(item => item.Declaration is Class) .Where(item => NamingHelper.GenerateTrimmedClassName(TranslationUnit.FileNameWithoutExtension).ToLower().Equals(NamingHelper.GenerateTrimmedClassName(item.Declaration.Name).ToLower())) .FirstOrDefault(); string className = string.Empty; string classNameWrap = string.Empty; // Generate wrapper class name if (classToWrapTypeReference != null) { className = nodeJSTypePrinter.VisitDeclaration(classToWrapTypeReference.Declaration); classNameWrap = NamingHelper.GenerateClassWrapName(className); } else { TextInfo textInfo = new CultureInfo("en-US", false).TextInfo; classNameWrap = textInfo.ToTitleCase(TranslationUnit.FileNameWithoutExtension) + "Wrap"; } // Check if we need constructor & destructor if (classToWrapTypeReference != null) { // Generate NodeJS wrapper prototypes GenerateWrapperClassPersistentFunctions(classNameWrap); // Generate constructors GenerateWrapperClassConstructors(classToWrapTypeReference); GenerateWrapperClassDestructors(classToWrapTypeReference); // TODO: New Instance & New } // Generate initialize GenerateWrapperInitialize(classToWrapTypeReference, classNameWrap, typeReferenceCollector); // Check if we need to generate methods if (methodsProcessed.Count > 0) { GenerateWrapperMethods(classToWrapTypeReference, classNameWrap, typeReferenceCollector); } // Check if we need to generate functions if (functionsProcessed.Count > 0) { GenerateWrapperFunctions(classNameWrap, typeReferenceCollector); } // Check if translation unit is an module if (Context.ConfigurationContext.ConfigFilesLoaded.Where(config => ((config.Module != null) && (config.Module == TranslationUnit.FileNameWithoutExtension))).Count() > 0) { // Generate Node JS initialize for specified module PushBlock(BlockKind.Footer); WriteLine("NODE_MODULE({0}, {1}::Initialize)", TranslationUnit.FileNameWithoutExtension, classNameWrap); PopBlock(NewLineKind.BeforeNextBlock); } }
private void GenerateWrapperInitialize(NodeJSTypeReference classToWrapTypeReference, string classNameWrap, NodeJSTypeReferenceCollector typeReferenceCollector) { PushBlock(BlockKind.Method); WriteLine("NAN_MODULE_INIT({0}::Initialize)", classNameWrap); WriteStartBraceIndent(); // Generate constructor template code if (classToWrapTypeReference != null) { // Find class to wrap Class classToWrap = classToWrapTypeReference.Declaration as Class; PushBlock(BlockKind.MethodBody); WriteLine("// Prepare constructor template"); WriteLine("Local <FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);"); WriteLine("tpl->SetClassName(Nan::New(\"{0}\").ToLocalChecked());", classNameWrap); WriteLine("tpl->InstanceTemplate()->SetInternalFieldCount(1);"); PopBlock(NewLineKind.BeforeNextBlock); // Generate methods prototypes PushBlock(BlockKind.MethodBody); WriteLine("// Register prototypes to template"); foreach (Method method in classToWrap.Methods) { // Skip constructors if (method.IsConstructor) { continue; } // Skip on other access level than public if (method.Access != AccessSpecifier.Public) { continue; } // Process method only once if (methodsProcessed.Contains(method.Name)) { continue; } // Output method declaration string methodNameNorm = method.Name; string methodNameLower = methodNameNorm.Substring(0, 1).ToLower() + methodNameNorm.Substring(1); WriteLine("Nan::SetPrototypeMethod(tpl, \"{0}\", {1});", methodNameLower, methodNameNorm); methodsProcessed.Add(method.Name); } PopBlock(NewLineKind.BeforeNextBlock); PushBlock(BlockKind.MethodBody); WriteLine("// Register template in Node JS"); WriteLine("prototype.Reset(tpl);"); WriteLine("Local<Function> function = Nan::GetFunction(tpl).ToLocalChecked();"); WriteLine("constructor.Reset(function);"); WriteLine("Nan::Set(target, Nan::New(\"{0}\").ToLocalChecked(), function);", classToWrap.Name); PopBlock(NewLineKind.BeforeNextBlock); } // Find static functions List <Function> functions = typeReferenceCollector.TypeReferences .Where(item => ((item.Declaration is Function) && !(item.Declaration is Method))) .Select(item => item.Declaration as Function).ToList(); // Generate static methods if (functions.Count > 0) { PushBlock(BlockKind.MethodBody); WriteLine("// Register static functions in Node JS"); foreach (Function function in functions) { // Skip on other access level than public if (function.Access != AccessSpecifier.Public) { continue; } // Process method only once if (functionsProcessed.Contains(function.Name)) { continue; } // Output function declaration string functionNameNorm = function.Name; string functionNameLower = functionNameNorm.Substring(0, 1).ToLower() + functionNameNorm.Substring(1); WriteLine("Nan::Set(target, Nan::New<String>(\"{0}\").ToLocalChecked(), Nan::GetFunction(Nan::New<FunctionTemplate>({1}::{2})).ToLocalChecked());", functionNameLower, classNameWrap, functionNameNorm); functionsProcessed.Add(function.Name); } PopBlock(NewLineKind.BeforeNextBlock); } // Generate nested class initialize IEnumerable <string> nestedIncludes = GetNestedIncludes(classNameWrap); if (nestedIncludes.Count() > 0) { PushBlock(BlockKind.MethodBody); WriteLine("// Initialize dynamic classes"); foreach (string include in nestedIncludes) { string includeClassNameWrap = string.Empty; TranslationUnit includeUnit = Context.ASTContext.TranslationUnits.Find(unit => unit.FileNameWithoutExtension == include); NodeJSTypeReferenceCollector includeReferenceCollector = new NodeJSTypeReferenceCollector(Context.ConfigurationContext, Context.TypeMaps, Context.Options); includeReferenceCollector.Process(includeUnit); // Find own class to wrap NodeJSTypeReference includeToWrapTypeReference = includeReferenceCollector.TypeReferences .Where(item => item.Declaration is Class) .Where(item => NamingHelper.GenerateTrimmedClassName(includeUnit.FileNameWithoutExtension).ToLower().Equals(NamingHelper.GenerateTrimmedClassName(item.Declaration.Name).ToLower())) .FirstOrDefault(); // Check if nested class was found if (includeToWrapTypeReference != null) { string className = (includeToWrapTypeReference.Declaration as Class).Name; includeClassNameWrap = NamingHelper.GenerateClassWrapName(className); } else { TextInfo textInfo = new CultureInfo("en-US", false).TextInfo; includeClassNameWrap = NamingHelper.GenerateClassWrapName(textInfo.ToTitleCase(includeUnit.FileNameWithoutExtension)); } WriteLine("{0}::Initialize(target);", includeClassNameWrap); } PopBlock(NewLineKind.BeforeNextBlock); } WriteCloseBraceIndent(); PopBlock(NewLineKind.BeforeNextBlock); }
public override bool VisitASTContext(ASTContext context) { SortedList <string, TranslationUnit> missingTranslationUnits = new SortedList <string, TranslationUnit>(); // Get list of generated units List <TranslationUnit> units = Context.ASTContext.TranslationUnits.GetGenerated().ToList(); foreach (TranslationUnit unit in units) { NodeJSTypeReferenceCollector typeReferenceCollector = new NodeJSTypeReferenceCollector(Context.ConfigurationContext, Context.TypeMaps, Context.Options); typeReferenceCollector.Process(unit); IEnumerable <NodeJSTypeReference> classToWrapTypeReferences = typeReferenceCollector.TypeReferences .Where(item => item.Declaration is Class); // Check if no class reference where found if (classToWrapTypeReferences.Count() > 0) { foreach (NodeJSTypeReference currentReference in classToWrapTypeReferences) { // Check if missing unit was already added if (missingTranslationUnits.ContainsKey(currentReference.Declaration.Name)) { continue; } // Check if missing unit exists with trimmed name if (units.Exists(u => NamingHelper.GenerateTrimmedClassName(u.FileNameWithoutExtension).ToLower().Contains(NamingHelper.GenerateTrimmedClassName(currentReference.Declaration.Name).ToLower()))) { continue; } // Make deep copy of current unit TranslationUnit missingTranslationUnit = unit.Copy(); // Change names of copy missingTranslationUnit.Name = currentReference.Declaration.Name; missingTranslationUnit.OriginalName = currentReference.Declaration.Name; // Change public fields string missingTranslationUnitFileName = NamingHelper.GenerateTrimmedClassName(currentReference.Declaration.Name).ToLower() + ".gen"; string missingTranslationUnitFileRelativePath = unit.FileRelativePath; // Update public fields missingTranslationUnit.FilePath = Path.Combine(Path.GetDirectoryName(unit.FilePath), missingTranslationUnitFileName); // Update private fields with reflection FieldInfo fileNameFieldInfo = missingTranslationUnit.GetType().GetField("fileName", BindingFlags.NonPublic | BindingFlags.Instance); fileNameFieldInfo.SetValue(missingTranslationUnit, missingTranslationUnitFileName); FieldInfo fileNameWithoutExtensionFieldInfo = missingTranslationUnit.GetType().GetField("fileNameWithoutExtension", BindingFlags.NonPublic | BindingFlags.Instance); fileNameWithoutExtensionFieldInfo.SetValue(missingTranslationUnit, Path.GetFileNameWithoutExtension(missingTranslationUnitFileName)); FieldInfo fileRelativeDirectoryFieldInfo = missingTranslationUnit.GetType().GetField("fileRelativeDirectory", BindingFlags.NonPublic | BindingFlags.Instance); fileRelativeDirectoryFieldInfo.SetValue(missingTranslationUnit, Path.GetDirectoryName(missingTranslationUnitFileRelativePath)); FieldInfo fileRelativePathFieldInfo = missingTranslationUnit.GetType().GetField("fileRelativePath", BindingFlags.NonPublic | BindingFlags.Instance); fileRelativePathFieldInfo.SetValue(missingTranslationUnit, Path.Combine(Path.GetDirectoryName(missingTranslationUnitFileRelativePath), missingTranslationUnitFileName)); // Add to collection for later processing missingTranslationUnits.Add(currentReference.Declaration.Name, missingTranslationUnit); } } } // Insert missing items Context.ASTContext.TranslationUnits.AddRange(missingTranslationUnits.Values); return(true); }
public void GenerateWrapperClass() { NodeJSTypeReferenceCollector typeReferenceCollector = new NodeJSTypeReferenceCollector(Context.ConfigurationContext, Context.TypeMaps, Context.Options); typeReferenceCollector.Process(TranslationUnit); List <Function> functions = typeReferenceCollector.TypeReferences .Where(item => ((item.Declaration is Function) && !(item.Declaration is Method))) .Select(item => item.Declaration as Function).ToList(); NodeJSTypeReference classToWrapTypeReference = typeReferenceCollector.TypeReferences .Where(item => item.Declaration is Class) .Where(item => NamingHelper.GenerateTrimmedClassName(TranslationUnit.FileNameWithoutExtension).ToLower().Equals(NamingHelper.GenerateTrimmedClassName(item.Declaration.Name).ToLower())) .FirstOrDefault(); string className = string.Empty; string classNameWrap = string.Empty; string classNameWrapperMember = string.Empty; // Generate wrapper class name if (classToWrapTypeReference != null) { className = (classToWrapTypeReference.Declaration as Class).Name; // Generate wrapper and member names classNameWrap = NamingHelper.GenerateClassWrapName(className); classNameWrapperMember = NamingHelper.GenerateClassWrapperMember(className); } else { TextInfo textInfo = new CultureInfo("en-US", false).TextInfo; classNameWrap = textInfo.ToTitleCase(TranslationUnit.FileNameWithoutExtension) + "Wrap"; } // Generate class stub PushBlock(BlockKind.Class); WriteLine("class {0} : public node::ObjectWrap", classNameWrap); WriteLine("{"); WriteLine("public:"); PushIndent(); // Write WriteLine("static NAN_MODULE_INIT(Initialize);"); // Check if we have an class to warp if (!string.IsNullOrEmpty(className)) { // Generate prototype templates WriteLine("static Nan::Persistent<v8::FunctionTemplate> prototype;"); WriteLine(""); // Create get wrapped method PushBlock(BlockKind.Method); WriteLine("{0}* GetWrapped() const", className); WriteStartBraceIndent(); WriteLine("return {0};", classNameWrapperMember); PopIndent(); WriteLine("};"); PopBlock(NewLineKind.BeforeNextBlock); // Create get wrapped method PushBlock(BlockKind.Method); WriteLine("void SetWrapped({0}* {1})", className, NamingHelper.ConvertToParameterName(className)); WriteStartBraceIndent(); WriteLine("{0} = {1};", classNameWrapperMember, NamingHelper.ConvertToParameterName(className)); PopIndent(); WriteLine("};"); PopBlock(NewLineKind.BeforeNextBlock); // New instance prototype PushBlock(BlockKind.MethodBody); WriteLine("static v8::Handle<v8::Value> NewInstance({0}* {1});", className, NamingHelper.ConvertToParameterName(className)); PopBlock(NewLineKind.Always); } else { // Only add empty line when we have static functions if (functions.Count > 0) { WriteLine(""); } } // Check if we have an class to warp if (!string.IsNullOrEmpty(className)) { // Private members prototypes PopIndent(); WriteLine("private:"); PushIndent(); // Constructor & destructor of wrapper class PushBlock(BlockKind.MethodBody); WriteLine("static Nan::Persistent<v8::Function> constructor;"); WriteLine("{0}(Nan::NAN_METHOD_ARGS_TYPE info);", classNameWrap); WriteLine("~{0}();", classNameWrap); WriteLine("static NAN_METHOD(New);"); PopBlock(NewLineKind.Always); // Check if methods available if ((classToWrapTypeReference.Declaration as Class).Methods.Count > 0) { // Methods PushBlock(BlockKind.MethodBody); WriteLine("// Wrapped methods"); SortedSet <string> methodsProcessed = new SortedSet <string>(StringComparer.InvariantCulture); foreach (Method method in (classToWrapTypeReference.Declaration as Class).Methods) { // Skip constructors if (method.IsConstructor) { continue; } // Skip on other access level than public if (method.Access != AccessSpecifier.Public) { continue; } // Process method only once if (methodsProcessed.Contains(method.Name)) { continue; } // Output method declaration WriteLine("static NAN_METHOD({0});", method.Name); methodsProcessed.Add(method.Name); } PopBlock(NewLineKind.BeforeNextBlock); } } // Functions if (functions.Count > 0) { // Private members prototypes PopIndent(); WriteLine("private:"); PushIndent(); PushBlock(BlockKind.MethodBody); WriteLine("// Wrapped functions"); SortedSet <string> functionsProcessed = new SortedSet <string>(StringComparer.InvariantCulture); foreach (Function function in functions) { // Skip on other access level than public if (function.Access != AccessSpecifier.Public) { continue; } // Process method only once if (functionsProcessed.Contains(function.Name)) { continue; } // Output method declaration WriteLine("static NAN_METHOD({0});", function.Name); functionsProcessed.Add(function.Name); } PopBlock(NewLineKind.BeforeNextBlock); } // Wrapped object if (!string.IsNullOrEmpty(className)) { // Wrapped object PushBlock(BlockKind.MethodBody); WriteLine("// Wrapped object"); WriteLine("{0}* {1};", className, classNameWrapperMember); PopBlock(); } PopIndent(); WriteLine("};"); PopBlock(NewLineKind.BeforeNextBlock); }