[jnigen] Reduce concatenation in binding generator code (https://github.com/dart-lang/jnigen/issues/102)
diff --git a/pkgs/jnigen/lib/src/bindings/c_bindings.dart b/pkgs/jnigen/lib/src/bindings/c_bindings.dart index 3dda13a..bc3d61c 100644 --- a/pkgs/jnigen/lib/src/bindings/c_bindings.dart +++ b/pkgs/jnigen/lib/src/bindings/c_bindings.dart
@@ -40,8 +40,8 @@ // global variable in C that holds the reference to class final classVar = '${classVarPrefix}_$classNameInC'; - s.write('// ${c.binaryName}\n'); - s.write('jclass $classVar = NULL;\n\n'); + s.write('// ${c.binaryName}\n' + 'jclass $classVar = NULL;\n\n'); for (var m in c.methods) { if (!m.isIncluded) { @@ -72,50 +72,52 @@ final s = StringBuffer(); final name = m.finalName; final functionName = getMemberNameInC(c, name); + final classRef = '${classVarPrefix}_$classNameInC'; final methodID = '${methodVarPrefix}_$functionName'; - s.write('jmethodID $methodID = NULL;\n'); - final cMethodName = getMemberNameInC(c, name); - final cParams = _formalArgs(m); - s.write('FFI_PLUGIN_EXPORT\n'); - s.write('$jniResultType $cMethodName($cParams) {\n'); - - final classVar = '${classVarPrefix}_$classNameInC'; + final cMethodParams = _formalArgs(m); final jniSignature = getJniSignatureForMethod(m); + final ifStaticMethodID = isStatic ? 'static_' : ''; - s.write(_loadEnvCall); - s.write(_loadClassCall(classVar, getInternalName(c.binaryName))); - - final ifStatic = isStatic ? 'static_' : ''; - s.write('${indent}load_${ifStatic}method($classVar, ' - '&$methodID, "${m.name}", "$jniSignature");\n'); - s.write('${indent}if ($methodID == NULL) return $ifError;\n'); - - var returnTypeName = m.returnType.name; + var javaReturnType = m.returnType.name; if (isACtor) { - returnTypeName = c.binaryName; - } - - s.write(indent); - if (returnTypeName != 'void') { - s.write('${getCType(returnTypeName)} _result = '); + javaReturnType = c.binaryName; } final callType = _typeNameAtCallSite(m.returnType); - final callArgs = _callArgs(m, classVar, methodID); - if (isACtor) { - s.write('(*jniEnv)->NewObject($callArgs);\n'); - } else { - final ifStatic = isStatic ? 'Static' : ''; - s.write('(*jniEnv)->Call$ifStatic${callType}Method($callArgs);\n'); + final callArgs = _callArgs(m, classRef, methodID); + + var ifAssignResult = ''; + if (javaReturnType != 'void') { + ifAssignResult = '${getCType(javaReturnType)} _result = '; } - s.write(_result(m)); - s.write('}\n'); + + final ifStaticCall = isStatic ? 'Static' : ''; + final envMethod = + isACtor ? 'NewObject' : 'Call$ifStaticCall${callType}Method'; + final returnResultIfAny = _result(m); + s.write(''' +jmethodID $methodID = NULL; +FFI_PLUGIN_EXPORT +$jniResultType $cMethodName($cMethodParams) { + $_loadEnvCall + ${_loadClassCall(classRef, getInternalName(c.binaryName))} + load_${ifStaticMethodID}method($classRef, + &$methodID, "${m.name}", "$jniSignature"); + if ($methodID == NULL) return $ifError; + $ifAssignResult(*jniEnv)->$envMethod($callArgs); + $returnResultIfAny +}\n'''); return s.toString(); } String _field(ClassDecl c, Field f) { final cClassName = getUniqueClassName(c); final isStatic = isStaticField(f); + + final fieldName = f.finalName; + final fieldNameInC = getMemberNameInC(c, fieldName); + final fieldVar = "${fieldVarPrefix}_$fieldNameInC"; + // If the field is final and default is assigned, then no need to wrap // this field. It should then be a constant in dart code. if (isStatic && isFinalField(f) && f.defaultValue != null) { @@ -124,51 +126,49 @@ final s = StringBuffer(); - final fieldName = f.finalName; - final fieldNameInC = getMemberNameInC(c, fieldName); - final fieldVar = "${fieldVarPrefix}_$fieldNameInC"; s.write('jfieldID $fieldVar = NULL;\n'); - final classVar = '${classVarPrefix}_$cClassName'; + final classVar = '${classVarPrefix}_$cClassName'; void writeAccessor({bool isSetter = false}) { - final prefix = isSetter ? 'set' : 'get'; - s.write('FFI_PLUGIN_EXPORT\n'); const cReturnType = jniResultType; - s.write('$cReturnType ${prefix}_$fieldNameInC('); + final cMethodPrefix = isSetter ? 'set' : 'get'; final formalArgs = <String>[ if (!isStatic) 'jobject self_', if (isSetter) '${getCType(f.type.name)} value', - ]; - s.write(formalArgs.join(', ')); - s.write(') {\n'); - s.write(_loadEnvCall); - s.write(_loadClassCall(classVar, getInternalName(c.binaryName))); - - var ifStatic = isStatic ? 'static_' : ''; - s.write( - '${indent}load_${ifStatic}field($classVar, &$fieldVar, "$fieldName",' - '"${_fieldSignature(f)}");\n'); - - ifStatic = isStatic ? 'Static' : ''; - final self = isStatic ? classVar : 'self_'; + ].join(', '); + final ifStaticField = isStatic ? 'static_' : ''; + final ifStaticCall = isStatic ? 'Static' : ''; final callType = _typeNameAtCallSite(f.type); + final objectArgument = isStatic ? classVar : 'self_'; + + String accessorStatements; if (isSetter) { - s.write('$indent(*jniEnv)->Set$ifStatic${callType}Field(jniEnv, ' - '$self, $fieldVar, value);\n'); - s.write('${indent}return $ifError;\n'); + accessorStatements = + '$indent(*jniEnv)->Set$ifStaticCall${callType}Field(jniEnv, ' + '$objectArgument, $fieldVar, value);\n' + '${indent}return $ifError;'; } else { - var getterExpr = '(*jniEnv)->Get$ifStatic${callType}Field(jniEnv, ' - '$self, $fieldVar)'; + var getterExpr = '(*jniEnv)->Get$ifStaticCall${callType}Field(jniEnv, ' + '$objectArgument, $fieldVar)'; if (!isPrimitive(f.type)) { getterExpr = 'to_global_ref($getterExpr)'; } final cResultType = getCType(f.type.name); - s.write('$indent$cResultType _result = $getterExpr;\n'); final unionField = getJValueField(f.type); - s.write('${indent}return (JniResult){.result = ' - '{.$unionField = _result}, .exception = check_exception()};\n'); + accessorStatements = '$indent$cResultType _result = $getterExpr;\n' + '${indent}return (JniResult){.result = ' + '{.$unionField = _result}, .exception = check_exception()};'; } - s.write('}\n\n'); + + s.write(''' +FFI_PLUGIN_EXPORT +$cReturnType ${cMethodPrefix}_$fieldNameInC($formalArgs) { + $_loadEnvCall + ${_loadClassCall(classVar, getInternalName(c.binaryName))} + load_${ifStaticField}field($classVar, &$fieldVar, "$fieldName", + "${_fieldSignature(f)}"); +$accessorStatements +}\n\n'''); } writeAccessor(isSetter: false); @@ -179,12 +179,11 @@ return s.toString(); } - final String _loadEnvCall = '${indent}load_env();\n'; + final String _loadEnvCall = '${indent}load_env();'; String _loadClassCall(String classVar, String internalName) { - return '${indent}load_class_gr(&$classVar, ' - '"$internalName");\n' - '${indent}if ($classVar == NULL) return $ifError;\n'; + return '${indent}load_class_gr(&$classVar, "$internalName");\n' + '${indent}if ($classVar == NULL) return $ifError;'; } String _formalArgs(Method m) { @@ -253,7 +252,8 @@ valuePart = '_result'; } const exceptionPart = 'check_exception()'; - return '${indent}return (JniResult){.result = {.$unionField = $valuePart}, .exception = $exceptionPart};\n'; + return '${indent}return (JniResult){.result = {.$unionField = $valuePart}, ' + '.exception = $exceptionPart};'; } String _fieldSignature(Field f) {
diff --git a/pkgs/jnigen/lib/src/bindings/common.dart b/pkgs/jnigen/lib/src/bindings/common.dart index 690dbc8..b7df2be 100644 --- a/pkgs/jnigen/lib/src/bindings/common.dart +++ b/pkgs/jnigen/lib/src/bindings/common.dart
@@ -63,7 +63,7 @@ /// Returns the formal parameters list of the generated function. /// /// This is the signature seen by the user. - String formalArgs(Method m, SymbolResolver resolver) { + String getFormalArgs(Method m, SymbolResolver resolver) { final List<String> args = []; for (var param in m.params) { args.add( @@ -254,6 +254,7 @@ return decl.uniqueName; } +/// Returns the name of the class member as referred to by C bindings String getMemberNameInC(ClassDecl decl, String name) => "${getUniqueClassName(decl)}__$name";
diff --git a/pkgs/jnigen/lib/src/bindings/dart_bindings.dart b/pkgs/jnigen/lib/src/bindings/dart_bindings.dart index 5096b83..2ccd5a1 100644 --- a/pkgs/jnigen/lib/src/bindings/dart_bindings.dart +++ b/pkgs/jnigen/lib/src/bindings/dart_bindings.dart
@@ -58,11 +58,8 @@ jniObjectType; } - s.write('class $name extends $superName {\n'); - s.write('$indent$name.fromRef($voidPointer ref) : ' - 'super.fromRef(ref);\n'); - - s.writeln(); + s.write('class $name extends $superName {\n' + '$indent$name.fromRef($voidPointer ref) : super.fromRef(ref);\n\n'); for (var field in decl.fields) { if (!field.isIncluded) { @@ -100,12 +97,15 @@ final sym = '_$name'; final ffiSig = dartSigForMethod(m, isFfiSig: true); final dartSig = dartSigForMethod(m, isFfiSig: false); + final returnType = getDartOuterType(m.returnType, resolver); + final ifStaticMethod = isStaticMethod(m) ? 'static' : ''; + + // Load corresponding C method. s.write('${indent}static final $sym = $lookup' '<${ffi}NativeFunction<$ffiSig>>("$cName")\n' '.asFunction<$dartSig>();\n'); // Different logic for constructor and method; // For constructor, we want return type to be new object. - final returnType = getDartOuterType(m.returnType, resolver); s.write('$indent/// from: ${getOriginalMethodHeader(m)}\n'); if (!isPrimitive(m.returnType)) { s.write(BindingsGenerator.deleteInstruction); @@ -113,15 +113,11 @@ s.write(breakDocComment(m.javadoc)); s.write(indent); - if (isStaticMethod(m)) { - s.write('static '); - } - if (isCtor(m)) { - final wrapperExpr = '$sym(${actualArgs(m)})'; final className = c.finalName; final ctorFnName = name == 'ctor' ? className : '$className.$name'; - s.write('$ctorFnName(${formalArgs(m, resolver)}) : ' + final wrapperExpr = '$sym(${actualArgs(m)})'; + s.write('$ctorFnName(${getFormalArgs(m, resolver)}) : ' 'super.fromRef($wrapperExpr.object);\n'); return s.toString(); } @@ -129,8 +125,9 @@ final resultGetter = getJValueAccessor(m.returnType); var wrapperExpr = '$sym(${actualArgs(m)}).$resultGetter'; wrapperExpr = toDartResult(wrapperExpr, m.returnType, returnType); - s.write('$returnType $name(${formalArgs(m, resolver)}) => '); - s.write('$wrapperExpr;\n'); + final params = getFormalArgs(m, resolver); + s.write('$indent$ifStaticMethod $returnType $name($params) ' + '=> $wrapperExpr;\n'); return s.toString(); } @@ -148,10 +145,11 @@ if (isStaticField(f) && isFinalField(f) && f.defaultValue != null) { writeDocs(writeDeleteInstruction: false); - s.write( - '${indent}static const $name = ${getDartLiteral(f.defaultValue)};\n'); + s.write('${indent}static const $name = ' + '${getDartLiteral(f.defaultValue)};\n'); return s.toString(); } + final cName = getMemberNameInC(c, name); void writeAccessor({bool isSetter = false}) { @@ -162,31 +160,30 @@ s.write('${indent}static final $sym = $lookup' '<${ffi}NativeFunction<$ffiSig>>("${symPrefix}_$cName")\n' '.asFunction<$dartSig>();\n'); - // write original type writeDocs(); - s.write(indent); - if (isStaticField(f)) s.write('static '); + final ifStatic = isStaticField(f) ? 'static' : ''; if (isSetter) { - s.write( - 'set $name(${getDartOuterType(f.type, resolver)} value) => $sym('); - if (!isStaticField(f)) { - s.write('$selfPointer, '); - } - s.write(toNativeArg('value', f.type)); - s.write(');\n'); + final args = [ + if (!isStaticField(f)) selfPointer, + toNativeArg('value', f.type), + ].join(', '); + final valueOuterType = getDartOuterType(f.type, resolver); + s.write('$indent$ifStatic set $name($valueOuterType value) => ' + '$sym($args);\n'); } else { // getter final self = isStaticField(f) ? '' : selfPointer; - final outer = getDartOuterType(f.type, resolver); + final outerType = getDartOuterType(f.type, resolver); final resultGetter = getJValueAccessor(f.type); final callExpr = '$sym($self).$resultGetter'; - final resultExpr = toDartResult(callExpr, f.type, outer); - s.write('$outer get $name => $resultExpr;\n'); + final resultExpr = toDartResult(callExpr, f.type, outerType); + s.write('$indent$ifStatic $outerType get $name => $resultExpr;\n'); } } writeAccessor(isSetter: false); if (!isFinalField(f)) writeAccessor(isSetter: true); + s.writeln(); return s.toString(); }