Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/pigeon/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ Example:

```dart
class Value {
int number;
int? number;
}

@HostApi()
Expand Down
4 changes: 2 additions & 2 deletions packages/pigeon/example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ from Flutter to the host-platform.
import 'package:pigeon/pigeon.dart';

class SearchRequest {
String query;
String? query;
}

class SearchReply {
String result;
String? result;
}

@HostApi()
Expand Down
32 changes: 25 additions & 7 deletions packages/pigeon/lib/ast.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ class Node {}
/// Represents a method on an [Api].
class Method extends Node {
/// Parametric constructor for [Method].
Method(
{this.name, this.returnType, this.argType, this.isAsynchronous = false});
Method({
required this.name,
required this.returnType,
required this.argType,
this.isAsynchronous = false,
});

/// The name of the method.
String name;
Expand All @@ -36,7 +40,12 @@ class Method extends Node {
/// Represents a collection of [Method]s that are hosted on a given [location].
class Api extends Node {
/// Parametric constructor for [Api].
Api({this.name, this.location, this.methods, this.dartHostTestHandler});
Api({
required this.name,
required this.location,
required this.methods,
this.dartHostTestHandler,
});

/// The name of the API.
String name;
Expand All @@ -48,13 +57,16 @@ class Api extends Node {
List<Method> methods;

/// The name of the Dart test interface to generate to help with testing.
String dartHostTestHandler;
String? dartHostTestHandler;
}

/// Represents a field on a [Class].
class Field extends Node {
/// Parametric constructor for [Field].
Field({this.name, this.dataType});
Field({
required this.name,
required this.dataType,
});

/// The name of the field.
String name;
Expand All @@ -71,7 +83,10 @@ class Field extends Node {
/// Represents a class with [Field]s.
class Class extends Node {
/// Parametric constructor for [Class].
Class({this.name, this.fields});
Class({
required this.name,
required this.fields,
});

/// The name of the class.
String name;
Expand All @@ -88,7 +103,10 @@ class Class extends Node {
/// Top-level node for the AST.
class Root extends Node {
/// Parametric constructor for [Root].
Root({this.classes, this.apis});
Root({
required this.classes,
required this.apis,
});

/// All the classes contained in the AST.
List<Class> classes;
Expand Down
25 changes: 14 additions & 11 deletions packages/pigeon/lib/dart_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ void _writeHostApi(DartOptions opt, Indent indent, Api api) {
}
String argSignature = '';
String sendArgument = 'null';
String encodedDeclaration;
String? encodedDeclaration;
if (func.argType != 'void') {
argSignature = '${func.argType} arg';
sendArgument = 'encoded';
Expand All @@ -47,17 +47,18 @@ void _writeHostApi(DartOptions opt, Indent indent, Api api) {
indent.writeln(encodedDeclaration);
}
final String channelName = makeChannelName(api, func);
indent.writeln('const BasicMessageChannel<Object$nullTag> channel =');
indent.writeln(
'const BasicMessageChannel<Object$nullTag> channel = BasicMessageChannel<Object$nullTag>(');
indent.nest(2, () {
indent.writeln(
'BasicMessageChannel<Object$nullTag>(\'$channelName\', StandardMessageCodec());',
'\'$channelName\', StandardMessageCodec());',
);
});
final String returnStatement = func.returnType == 'void'
? '// noop'
: 'return ${func.returnType}.decode(replyMap[\'${Keys.result}\']$unwrapOperator);';
indent.format('''
final Map<Object$nullTag, Object$nullTag>$nullTag replyMap = await channel.send($sendArgument) as Map<Object$nullTag, Object$nullTag>$nullTag;
final Map<Object$nullTag, Object$nullTag>$nullTag replyMap =\n\t\tawait channel.send($sendArgument) as Map<Object$nullTag, Object$nullTag>$nullTag;
if (replyMap == null) {
\tthrow PlatformException(
\t\tcode: 'channel-error',
Expand All @@ -83,7 +84,7 @@ void _writeFlutterApi(
DartOptions opt,
Indent indent,
Api api, {
String Function(Method) channelNameFunc,
String Function(Method)? channelNameFunc,
bool isMockHandler = false,
}) {
assert(api.location == ApiLocation.flutter);
Expand All @@ -105,14 +106,14 @@ void _writeFlutterApi(
indent.write('');
indent.scoped('{', '}', () {
indent.writeln(
'const BasicMessageChannel<Object$nullTag> channel =',
'const BasicMessageChannel<Object$nullTag> channel = BasicMessageChannel<Object$nullTag>(',
);
final String channelName = channelNameFunc == null
? makeChannelName(api, func)
: channelNameFunc(func);
indent.nest(2, () {
indent.writeln(
'BasicMessageChannel<Object$nullTag>(\'$channelName\', StandardMessageCodec());',
'\'$channelName\', StandardMessageCodec());',
);
});
final String messageHandlerSetter =
Expand Down Expand Up @@ -248,9 +249,10 @@ void generateDart(DartOptions opt, Root root, StringSink sink) {
final Field field = klass.fields[index];
indent.write('..${field.name} = ');
if (customClassNames.contains(field.dataType)) {
indent.add(
'pigeonMap[\'${field.name}\'] != null ? ${field.dataType}.decode(pigeonMap[\'${field.name}\']$unwrapOperator) : null',
);
indent.format('''
pigeonMap['${field.name}'] != null
\t\t? ${field.dataType}.decode(pigeonMap['${field.name}']$unwrapOperator)
\t\t: null''', leadingSpace: false, trailingNewline: false);
} else {
indent.add(
'pigeonMap[\'${field.name}\'] as ${_addGenericTypes(field.dataType, nullTag)}',
Expand Down Expand Up @@ -300,9 +302,10 @@ void generateTestDart(
for (final Api api in root.apis) {
if (api.location == ApiLocation.host && api.dartHostTestHandler != null) {
final Api mockApi = Api(
name: api.dartHostTestHandler,
name: api.dartHostTestHandler!,
methods: api.methods,
location: ApiLocation.flutter,
dartHostTestHandler: api.dartHostTestHandler,
);
indent.writeln('');
_writeFlutterApi(
Expand Down
36 changes: 24 additions & 12 deletions packages/pigeon/lib/generator_tools.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import 'dart:mirrors';
import 'ast.dart';

/// The current version of pigeon. This must match the version in pubspec.yaml.
const String pigeonVersion = '0.1.24';
const String pigeonVersion = '0.2.0';

/// Read all the content from [stdin] to a String.
String readStdin() {
Expand Down Expand Up @@ -55,17 +55,26 @@ class Indent {
}

/// Replaces the newlines and tabs of input and adds it to the stream.
void format(String input) {
for (final String line in input.split('\n')) {
writeln(line.replaceAll('\t', tab));
void format(String input,
{bool leadingSpace = true, bool trailingNewline = true}) {
final List<String> lines = input.split('\n');
for (int i = 0; i < lines.length; ++i) {
final String line = lines[i];
if (i == 0 && !leadingSpace) {
addln(line.replaceAll('\t', tab));
} else if (i == lines.length - 1 && !trailingNewline) {
write(line.replaceAll('\t', tab));
} else {
writeln(line.replaceAll('\t', tab));
}
}
}

/// Scoped increase of the ident level. For the execution of [func] the
/// indentation will be incremented.
void scoped(
String begin,
String end,
String? begin,
String? end,
Function func, {
bool addTrailingNewline = true,
}) {
Expand All @@ -83,12 +92,12 @@ class Indent {

/// Like `scoped` but writes the current indentation level.
void writeScoped(
String begin,
String? begin,
String end,
Function func, {
bool addTrailingNewline = true,
}) {
scoped(str() + begin ?? '', end, func,
scoped(str() + (begin ?? ''), end, func,
addTrailingNewline: addTrailingNewline);
}

Expand Down Expand Up @@ -133,7 +142,10 @@ String makeChannelName(Api api, Method func) {
/// Represents the mapping of a Dart datatype to a Host datatype.
class HostDatatype {
/// Parametric constructor for HostDatatype.
HostDatatype({this.datatype, this.isBuiltin});
HostDatatype({
required this.datatype,
required this.isBuiltin,
});

/// The [String] that can be printed into host code to represent the type.
final String datatype;
Expand All @@ -147,9 +159,9 @@ class HostDatatype {
/// `builtinResolver` will return the host datatype for the Dart datatype for
/// builtin types. `customResolver` can modify the datatype of custom types.
HostDatatype getHostDatatype(
Field field, List<Class> classes, String Function(String) builtinResolver,
{String Function(String) customResolver}) {
final String datatype = builtinResolver(field.dataType);
Field field, List<Class> classes, String? Function(String) builtinResolver,
{String Function(String)? customResolver}) {
final String? datatype = builtinResolver(field.dataType);
if (datatype == null) {
if (classes.map((Class x) => x.name).contains(field.dataType)) {
final String customName = customResolver != null
Expand Down
15 changes: 10 additions & 5 deletions packages/pigeon/lib/java_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,17 @@ const Map<String, String> _javaTypeForDartTypeMap = <String, String>{

/// Options that control how Java code will be generated.
class JavaOptions {
/// Creates a [JavaOptions] object
JavaOptions({
this.className,
this.package,
});

/// The name of the class that will house all the generated classes.
String className;
String? className;

/// The package where the generated class will live.
String package;
String? package;
}

void _writeHostApi(Indent indent, Api api) {
Expand Down Expand Up @@ -198,7 +204,7 @@ String _makeSetter(Field field) {
return 'set$uppercased';
}

String _javaTypeForDartType(String datatype) {
String? _javaTypeForDartType(String datatype) {
return _javaTypeForDartTypeMap[datatype];
}

Expand Down Expand Up @@ -236,11 +242,10 @@ void generateJava(JavaOptions options, Root root, StringSink sink) {
indent.writeln('import java.util.HashMap;');

indent.addln('');
assert(options.className != null);
indent.writeln('/** Generated class from Pigeon. */');
indent.writeln(
'@SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression"})');
indent.write('public class ${options.className} ');
indent.write('public class ${options.className!} ');
indent.scoped('{', '}', () {
for (final Class klass in root.classes) {
indent.addln('');
Expand Down
19 changes: 11 additions & 8 deletions packages/pigeon/lib/objc_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,20 @@ import 'generator_tools.dart';
/// Options that control how Objective-C code will be generated.
class ObjcOptions {
/// Parametric constructor for ObjcOptions.
ObjcOptions({this.header, this.prefix});
ObjcOptions({
this.header,
this.prefix,
});

/// The path to the header that will get placed in the source filed (example:
/// "foo.h").
String header;
String? header;

/// Prefix that will be appended before all generated classes and protocols.
String prefix;
String? prefix;
}

String _className(String prefix, String className) {
String _className(String? prefix, String className) {
if (prefix != null) {
return '$prefix$className';
} else {
Expand Down Expand Up @@ -58,12 +61,12 @@ const Map<String, String> _propertyTypeForDartTypeMap = <String, String>{
'Map': 'strong',
};

String _objcTypeForDartType(String type) {
String? _objcTypeForDartType(String type) {
return _objcTypeForDartTypeMap[type];
}

String _propertyTypeForDartType(String type) {
final String result = _propertyTypeForDartTypeMap[type];
final String? result = _propertyTypeForDartTypeMap[type];
if (result == null) {
return 'assign';
} else {
Expand All @@ -72,7 +75,7 @@ String _propertyTypeForDartType(String type) {
}

void _writeClassDeclarations(
Indent indent, List<Class> classes, String prefix) {
Indent indent, List<Class> classes, String? prefix) {
for (final Class klass in classes) {
indent.writeln('@interface ${_className(prefix, klass.name)} : NSObject');
for (final Field field in klass.fields) {
Expand Down Expand Up @@ -191,7 +194,7 @@ void generateObjcHeader(ObjcOptions options, Root root, StringSink sink) {
}

String _dictGetter(
List<String> classnames, String dict, Field field, String prefix) {
List<String> classnames, String dict, Field field, String? prefix) {
if (classnames.contains(field.dataType)) {
String className = field.dataType;
if (prefix != null) {
Expand Down
8 changes: 4 additions & 4 deletions packages/pigeon/lib/pigeon_cl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import 'package:pigeon/pigeon_lib.dart';

/// This creates a relative path from `from` to `input`, the output being a
/// posix path on all platforms.
String _posixRelative(String input, {String from}) {
String _posixRelative(String input, {required String from}) {
final path.Context context = path.Context(style: path.Style.posix);
final String rawInputPath = input;
final String absInputPath = File(rawInputPath).absolute.path;
Expand All @@ -27,19 +27,19 @@ String _posixRelative(String input, {String from}) {
/// This is the main entrypoint for the command-line tool. [args] are the
/// commmand line arguments and there is an optional [packageConfig] to
/// accomodate users that want to integrate pigeon with other build systems.
Future<void> runCommandLine(List<String> args, {Uri packageConfig}) async {
Future<void> runCommandLine(List<String> args, {Uri? packageConfig}) async {
final PigeonOptions opts = Pigeon.parseArgs(args);
final Directory tempDir = Directory.systemTemp.createTempSync(
'flutter_pigeon.',
);

String importLine = '';
if (opts.input != null) {
final String relInputPath = _posixRelative(opts.input, from: tempDir.path);
final String relInputPath = _posixRelative(opts.input!, from: tempDir.path);
importLine = 'import \'$relInputPath\';\n';
}
final String code = """
// @dart = 2.2
// @dart = 2.12
$importLine
import 'dart:io';
import 'dart:isolate';
Expand Down
Loading