private void GenerateWrapperClassConstructors(NodeJSTypeReference classToWrapTypeReference) { Class classToWrap = classToWrapTypeReference.Declaration as Class; string classNameWrap = NamingHelper.GenerateClassWrapName(classToWrap.Name); string classNameWrapperMember = NamingHelper.GenerateClassWrapperMember(classToWrap.Name); IEnumerable <Method> constructors = classToWrap.Constructors.OrderByDescending(s => s.Parameters.Count); // Supported implementations comment PushBlock(BlockKind.Method); WriteLine("// Supported implementations"); foreach (Method constructor in constructors.OrderBy(s => s.Parameters.Count)) { WriteLine("// {0}({1})", classToWrap.Name, nodeJSTypePrinter.VisitParameters(constructor.Parameters, true)); } // Constructor for wrapped class WriteLine("{0}::{0}(Nan::NAN_METHOD_ARGS_TYPE info)", classNameWrap); WriteLine(" : {0}(NULL)", classNameWrapperMember); WriteStartBraceIndent(); bool firstConstructorCreated = false; // Generate check for constructor arguments WriteLine("// Check constructor arguments"); foreach (Method constructor in constructors.OrderBy(s => s.Parameters.Count)) { // Generate other constructors than default string generatedCheckStatement = (firstConstructorCreated ? "else " : string.Empty); generatedCheckStatement += "if " + nodeJSTypeCheckPrinter.GenerateCheckStatement(constructor.Parameters); // Output arguments checker WriteLine(generatedCheckStatement); WriteStartBraceIndent(); // Generate wrapper for parameter arguments string generatedArgumentsWrapped = nodeJSTypePrinter.GenerateParameterWrapper(this, constructor.Parameters); // Generate construction of wrapped member PushBlock(BlockKind.MethodBody); WriteLine("// {0}({1})", classToWrap.Name, nodeJSTypePrinter.VisitParameters(constructor.Parameters, true)); WriteLine("{0} = new {1}({2});", classNameWrapperMember, classToWrap.Name, generatedArgumentsWrapped); PopBlock(NewLineKind.Never); WriteCloseBraceIndent(); // Remember that we have created an constructor firstConstructorCreated = true; } WriteCloseBraceIndent(); PopBlock(NewLineKind.BeforeNextBlock); }
private void GenerateWrapperClassDestructors(NodeJSTypeReference classToWrapTypeReference) { Class classToWrap = classToWrapTypeReference.Declaration as Class; string classNameWrap = NamingHelper.GenerateClassWrapName(classToWrap.Name); string classNameWrapperMember = NamingHelper.GenerateClassWrapperMember(classToWrap.Name); // Destructor for wrapped class PushBlock(BlockKind.Method); WriteLine("{0}::~{0}()", classNameWrap); WriteStartBraceIndent(); WriteLine("delete {0};", classNameWrapperMember); WriteCloseBraceIndent(); PopBlock(NewLineKind.BeforeNextBlock); }
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); } } }
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 string GenerateParameterWrapper(NodeJSTemplate callee, IEnumerable <Parameter> parameters) { int parameterArgumentIndex = 0; string generatedArgumentsWrapped = string.Empty; NodeJSTypeCheckPrinter nodeJSTypeCheckPrinter = new NodeJSTypeCheckPrinter(Context); foreach (Parameter parameter in parameters) { if (nodeJSTypeCheckPrinter.QualifiedTypeIsObject(parameter.QualifiedType)) { string parameterClassName = VisitParameter(parameter, false, false); string parameterClassWrapped = NamingHelper.GenerateClassWrapName(parameterClassName); // Generate unwrap of stored object callee.PushBlock(BlockKind.MethodBody); callee.WriteLine("// Unwrap object"); callee.WriteLine("{0}* arg{1}_wrap = ObjectWrap::Unwrap<{0}>(info[{1}]->ToObject());", parameterClassWrapped, parameterArgumentIndex); callee.WriteLine("{0}* arg{1} = arg{1}_wrap->GetWrapped();", parameterClassName, parameterArgumentIndex); callee.PopBlock(NewLineKind.BeforeNextBlock); } else if (nodeJSTypeCheckPrinter.QualifiedTypeIsNumber(parameter.QualifiedType)) { // Generate wrapper for number values callee.PushBlock(BlockKind.MethodBody); PointerType parameterPointerType = parameter.Type as PointerType; if (parameterPointerType != null && parameterPointerType.IsPointer()) { callee.WriteLine("// Convert from number value to pointer"); callee.WriteLine("{0} arg{1}_value = static_cast<{0}>(info[{1}]->NumberValue());", VisitParameter(parameter, false, false), parameterArgumentIndex); callee.WriteLine("{0}* arg{1} = &arg{1}_value;", VisitParameter(parameter, false, false), parameterArgumentIndex); } else { callee.WriteLine("// Convert from number value"); callee.WriteLine("{0} arg{1} = static_cast<{0}>(info[{1}]->NumberValue());", VisitParameter(parameter, false, false), parameterArgumentIndex); } callee.PopBlock(NewLineKind.BeforeNextBlock); } else if (nodeJSTypeCheckPrinter.QualifiedTypeIsBoolean(parameter.QualifiedType)) { // Generate wrapper for number values callee.PushBlock(BlockKind.MethodBody); PointerType parameterPointerType = parameter.Type as PointerType; if (parameterPointerType != null && parameterPointerType.IsPointer()) { callee.WriteLine("// Convert from boolean value to pointer"); callee.WriteLine("{0} arg{1}_value = info[{1}]->BooleanValue();", VisitParameter(parameter, false, false), parameterArgumentIndex); callee.WriteLine("{0}* arg{1} = &arg{1}_value;", VisitParameter(parameter, false, false), parameterArgumentIndex); } else { callee.WriteLine("// Convert from boolean value"); callee.WriteLine("{0} arg{1} = info[{1}]->BooleanValue();", VisitParameter(parameter, false, false), parameterArgumentIndex); } callee.PopBlock(NewLineKind.BeforeNextBlock); } else if (nodeJSTypeCheckPrinter.QualifiedTypeIsString(parameter.QualifiedType)) { string parameterToWrap = string.Format("{0}{1}", VisitParameter(parameter, false, false), (parameter.Type is PointerType ? ((parameter.Type as PointerType).IsPointer() ? "*" : string.Empty) : string.Empty)); string generatedStringWrapperLine = string.Format("{0} arg{1} = ", parameterToWrap, parameterArgumentIndex); // Generate wrapper for string values callee.PushBlock(BlockKind.MethodBody); callee.WriteLine("// Convert from string value"); // Check if cast is needed generatedStringWrapperLine += stringStaticCastFilter.Any(filter => parameterToWrap.Contains(filter)) ? string.Format("static_cast<{0}>(", parameterToWrap) : string.Empty; // Generate conversation generatedStringWrapperLine += string.Format("pylon_v8::ToGCString(info[{0}]->ToString())", parameterArgumentIndex); generatedStringWrapperLine += parameterToWrap.Contains("wchar_t") ? ".w_str()" : ".c_str()"; generatedStringWrapperLine += parameterToWrap.Contains("*") ? "" : "[0]"; // Add closing tag if cast was needed generatedStringWrapperLine += stringStaticCastFilter.Any(filter => parameterToWrap.Contains(filter)) ? ");" : ";"; callee.WriteLine(generatedStringWrapperLine); callee.PopBlock(NewLineKind.BeforeNextBlock); } else if (nodeJSTypeCheckPrinter.QualifiedTypeIsTypedBuffer(parameter.QualifiedType)) { callee.PushBlock(BlockKind.MethodBody); callee.WriteLine("// TODO: Implement wrapper for {0}", VisitParameter(parameter, false, false)); callee.PopBlock(NewLineKind.BeforeNextBlock); } // Store arguments for later usage generatedArgumentsWrapped += parameterArgumentIndex > 0 ? ", " : string.Empty; generatedArgumentsWrapped += parameter.Type is PointerType ? ((parameter.Type as PointerType).IsReference ? "*" : string.Empty) : string.Empty; generatedArgumentsWrapped += "arg" + parameterArgumentIndex; // Increment argument index parameterArgumentIndex++; } return(generatedArgumentsWrapped); }
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); }