Skip to content
This repository was archived by the owner on Jan 28, 2024. It is now read-only.

Commit 7be9b2e

Browse files
committed
Completed variadic-arguments config and generation
1 parent 0493143 commit 7be9b2e

File tree

10 files changed

+276
-91
lines changed

10 files changed

+276
-91
lines changed

lib/src/code_generator/imports.dart

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,27 @@ class ImportedType extends Type {
4949
String? getDefaultValue(Writer w, String nativeLib) => defaultValue;
5050
}
5151

52+
/// An unchecked type similar to [ImportedType] which exists in the generated
53+
/// binding itself.
54+
class SelfImportedType extends Type {
55+
final String cType;
56+
final String dartType;
57+
final String? defaultValue;
58+
59+
SelfImportedType(this.cType, this.dartType, [this.defaultValue]);
60+
61+
@override
62+
String getCType(Writer w) {
63+
return cType;
64+
}
65+
66+
@override
67+
String getDartType(Writer w) => cType == dartType ? getCType(w) : dartType;
68+
69+
@override
70+
String toString() => cType;
71+
}
72+
5273
final ffiImport = LibraryImport('ffi', 'dart:ffi');
5374
final ffiPkgImport = LibraryImport('pkg_ffi', 'package:ffi/ffi.dart');
5475

lib/src/config_provider/config.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -451,14 +451,14 @@ class Config {
451451
},
452452
),
453453
[strings.functions, strings.varArgFunctions]:
454-
Specification<Map<String, List<List<List<String>>>>>(
454+
Specification<Map<String, List<RawVarArgFunction>>>(
455455
requirement: Requirement.no,
456-
validator: varArgFunctionConfigExtractorValidator,
456+
validator: varArgFunctionConfigValidator,
457457
extractor: varArgFunctionConfigExtractor,
458-
defaultValue: () => <String, List<List<List<String>>>>{},
458+
defaultValue: () => <String, List<RawVarArgFunction>>{},
459459
extractedResult: (dynamic result) {
460460
_varArgFunctions = makeVarArgFunctionsMapping(
461-
result as Map<String, List<List<List<String>>>>, _libraryImports);
461+
result as Map<String, List<RawVarArgFunction>>, _libraryImports);
462462
},
463463
),
464464
[strings.excludeAllByDefault]: Specification<bool>(

lib/src/config_provider/config_types.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,13 @@ class OutputConfig {
425425
OutputConfig(this.output, this.symbolFile);
426426
}
427427

428+
class RawVarArgFunction {
429+
String? postfix;
430+
final List<String> rawTypeStrings;
431+
432+
RawVarArgFunction(this.postfix, this.rawTypeStrings);
433+
}
434+
428435
class VarArgFunction {
429436
final String postfix;
430437
final List<Type> types;

lib/src/config_provider/spec_utils.dart

Lines changed: 130 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'dart:io';
66

77
import 'package:ffigen/src/code_generator.dart';
88
import 'package:ffigen/src/code_generator/utils.dart';
9+
import 'package:ffigen/src/header_parser/type_extractor/cxtypekindmap.dart';
910
import 'package:file/local.dart';
1011
import 'package:glob/glob.dart';
1112
import 'package:logging/logging.dart';
@@ -329,29 +330,91 @@ Map<String, ImportedType> makeImportTypeMapping(
329330
return typeMappings;
330331
}
331332

333+
Type makePointerToType(Type type, int pointerCount) {
334+
for (var i = 0; i < pointerCount; i++) {
335+
type = PointerType(type);
336+
}
337+
return type;
338+
}
339+
340+
String makePostfixFromRawVarArgType(List<String> rawVarArgType) {
341+
return rawVarArgType
342+
.map((e) => e
343+
.replaceAll('*', 'Ptr')
344+
.replaceAll(r'\s', '')
345+
.replaceAll('_t', '')
346+
.replaceAll(' ', '')
347+
.replaceAll('[^A-Za-z0-9]', ''))
348+
.map((e) => e.length > 1 ? '${e[0].toUpperCase()}${e.substring(1)}' : e)
349+
.join('');
350+
}
351+
352+
Type makeTypeFromRawVarArgType(
353+
String rawVarArgType, Map<String, LibraryImport> libraryImportsMap) {
354+
rawVarArgType = rawVarArgType.trim();
355+
final typeStringRegexp = RegExp(r'([a-zA-Z0-9_\s\.]+)(\**)$');
356+
if (!typeStringRegexp.hasMatch(rawVarArgType)) {
357+
throw Exception('Cannot parse variadic argument type - $rawVarArgType.');
358+
}
359+
final regExpMatch = typeStringRegexp.firstMatch(rawVarArgType)!;
360+
final groups = regExpMatch.groups([1, 2]);
361+
rawVarArgType = groups[0]!;
362+
final pointerCount = groups[1]!.length;
363+
// Handle pointers.
364+
if (cxTypeKindToImportedTypes.containsKey(rawVarArgType)) {
365+
return makePointerToType(
366+
cxTypeKindToImportedTypes[rawVarArgType]!, pointerCount);
367+
} else if (supportedTypedefToImportedType.containsKey(rawVarArgType)) {
368+
return makePointerToType(
369+
supportedTypedefToImportedType[rawVarArgType]!, pointerCount);
370+
} else if (suportedTypedefToSuportedNativeType.containsKey(rawVarArgType)) {
371+
return makePointerToType(
372+
NativeType(suportedTypedefToSuportedNativeType[rawVarArgType]!),
373+
pointerCount);
374+
} else {
375+
final rawVarArgTypeSplit = rawVarArgType.split('.');
376+
if (rawVarArgTypeSplit.length == 1) {
377+
final typeName = rawVarArgTypeSplit[0].replaceAll(' ', '');
378+
return makePointerToType(
379+
SelfImportedType(typeName, typeName), pointerCount);
380+
} else if (rawVarArgTypeSplit.length == 2) {
381+
final lib = rawVarArgTypeSplit[0];
382+
final libraryImport = strings.predefinedLibraryImports[lib] ??
383+
libraryImportsMap[rawVarArgTypeSplit[0]];
384+
if (libraryImport == null) {
385+
throw Exception('Please declare $lib in library-imports.');
386+
}
387+
final typeName = rawVarArgTypeSplit[1].replaceAll(' ', '');
388+
return makePointerToType(
389+
ImportedType(libraryImport, typeName, typeName), pointerCount);
390+
} else {
391+
throw Exception(
392+
'Invalid type $rawVarArgType : Expected 0 or 1 .(dot) separators.');
393+
}
394+
}
395+
}
396+
332397
Map<String, List<VarArgFunction>> makeVarArgFunctionsMapping(
333-
Map<String, List<List<List<String>>>> rawVarArgMappings,
398+
Map<String, List<RawVarArgFunction>> rawVarArgMappings,
334399
Map<String, LibraryImport> libraryImportsMap) {
335400
final mappings = <String, List<VarArgFunction>>{};
336401
for (final key in rawVarArgMappings.keys) {
337402
final varArgList = <VarArgFunction>[];
338-
for (final rawVarArgs in rawVarArgMappings[key]!) {
403+
for (final rawVarArg in rawVarArgMappings[key]!) {
404+
var postfix = rawVarArg.postfix ?? '';
339405
final types = <Type>[];
340-
for (final rva in rawVarArgs) {
341-
final lib = rva[0];
342-
final cType = rva[1]; // TODO: deduce these automatically
343-
final dartType = rva[1]; // TODO: deduce these automatically
344-
if (strings.predefinedLibraryImports.containsKey(lib)) {
345-
types.add(ImportedType(
346-
strings.predefinedLibraryImports[lib]!, cType, dartType));
347-
} else if (libraryImportsMap.containsKey(lib)) {
348-
types.add(ImportedType(libraryImportsMap[lib]!, cType, dartType));
406+
for (final rva in rawVarArg.rawTypeStrings) {
407+
types.add(makeTypeFromRawVarArgType(rva, libraryImportsMap));
408+
}
409+
if (postfix.isEmpty) {
410+
if (rawVarArgMappings[key]!.length == 1) {
411+
postfix = '';
349412
} else {
350-
throw Exception("Please declare $lib under library-imports.");
413+
postfix = makePostfixFromRawVarArgType(rawVarArg.rawTypeStrings);
351414
}
352415
}
353416
// Extract postfix from config and/or deduce from var names.
354-
varArgList.add(VarArgFunction('vaf', types));
417+
varArgList.add(VarArgFunction(postfix, types));
355418
}
356419
mappings[key] = varArgList;
357420
}
@@ -772,38 +835,79 @@ Includer _extractIncluderFromYaml(dynamic yamlMap) {
772835
);
773836
}
774837

775-
Map<String, List<List<List<String>>>> varArgFunctionConfigExtractor(
838+
Map<String, List<RawVarArgFunction>> varArgFunctionConfigExtractor(
776839
dynamic yamlMap) {
777-
final result = <String, List<List<List<String>>>>{};
840+
final result = <String, List<RawVarArgFunction>>{};
778841
final configMap = (yamlMap as YamlMap);
779842
for (final key in configMap.keys) {
780-
final List<List<List<String>>> vf = [];
781-
for (final vaFuncs in (configMap[key] as YamlList)) {
782-
final List<List<String>> vfTypes = [];
783-
for (final typeStrings in (vaFuncs as YamlList)) {
784-
vfTypes.add((typeStrings as String).split("."));
843+
final List<RawVarArgFunction> vafuncs = [];
844+
for (final rawVaFunc in (configMap[key] as YamlList)) {
845+
if (rawVaFunc is YamlList) {
846+
vafuncs.add(RawVarArgFunction(null, rawVaFunc.cast()));
847+
} else if (rawVaFunc is YamlMap) {
848+
vafuncs.add(RawVarArgFunction(rawVaFunc[strings.postfix] as String?,
849+
(rawVaFunc[strings.types] as YamlList).cast()));
850+
} else {
851+
throw Exception("Unexpected type in variadic-argument config.");
785852
}
786-
vf.add(vfTypes);
787853
}
788-
result[key as String] = vf;
854+
result[key as String] = vafuncs;
789855
}
856+
790857
return result;
791858
}
792859

793-
bool varArgFunctionConfigExtractorValidator(List<String> name, dynamic value) {
860+
bool varArgFunctionConfigValidator(List<String> name, dynamic value) {
794861
if (!checkType<YamlMap>(name, value)) {
795862
return false;
796863
}
797864
var _result = true;
798-
for (final key in (value as YamlMap).cast<String, dynamic>().keys) {
799-
final list = value[key];
865+
for (final key in (value as YamlMap).keys) {
866+
final list = value[key as String];
800867
if (!checkType<YamlList>([...name, key], list)) {
801868
_result = false;
802869
continue;
803870
}
804871
(list as YamlList).asMap().forEach((idx, subList) {
805-
if (!checkType<YamlList>([...name, key, idx.toString()], subList)) {
872+
if (subList is YamlMap) {
873+
if (!subList.containsKey(strings.types)) {
874+
_result = false;
875+
_logger.severe('Missing required key - ${[
876+
...name,
877+
key,
878+
idx.toString(),
879+
strings.types
880+
].join(" -> ")}');
881+
}
882+
subList.forEach((subkey, subvalue) {
883+
subkey = subkey as String;
884+
if (subkey == strings.postfix) {
885+
if (!checkType<String>(
886+
[...name, key, idx.toString(), subkey], subvalue)) {
887+
_result = false;
888+
}
889+
} else if (subkey == strings.types) {
890+
if (!checkType<YamlList>(
891+
[...name, key, idx.toString(), subkey], subvalue)) {
892+
_result = false;
893+
}
894+
} else {
895+
_result = false;
896+
_logger.severe('Unknown key - ${[
897+
...name,
898+
key,
899+
idx.toString(),
900+
subkey
901+
].join(" -> ")}');
902+
}
903+
});
904+
} else if (subList is! YamlList) {
806905
_result = false;
906+
_logger.severe('Expected ${[
907+
...name,
908+
key,
909+
idx
910+
].join(" -> ")} to be a List or a Map.');
807911
}
808912
});
809913
}

lib/src/header_parser/sub_parsers/functiondecl_parser.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ List<Func>? parseFunctionDeclaration(clang_types.CXCursor cursor) {
7878
cursor,
7979
nesting.length + commentPrefix.length,
8080
),
81-
usr: funcUsr,
82-
name: config.functionDecl.renameUsingConfig(funcName),
81+
usr: funcUsr + vaFunc.postfix,
82+
name: config.functionDecl.renameUsingConfig(funcName) + vaFunc.postfix,
8383
originalName: funcName,
8484
returnType: rt,
8585
parameters: parameters,

lib/src/strings.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ const exposeFunctionTypedefs = 'expose-typedefs';
8787
const leafFunctions = 'leaf';
8888
const varArgFunctions = 'variadic-arguments';
8989

90+
// Nested under varArg entries
91+
const postfix = "postfix";
92+
const types = "types";
93+
9094
// Sub-fields of ObjC interfaces.
9195
const objcModule = 'module';
9296

0 commit comments

Comments
 (0)