Initial commit
This commit is contained in:
commit
a683a58db2
11 changed files with 1474 additions and 0 deletions
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# Files and directories created by pub.
|
||||||
|
.dart_tool/
|
||||||
|
.packages
|
||||||
|
|
||||||
|
# Conventional directory for build output.
|
||||||
|
build/
|
||||||
|
# Dart default executable location
|
||||||
|
bin/tdlib_gen.exe
|
||||||
|
|
||||||
|
# tl files
|
||||||
|
*.tl
|
24
.vscode/launch.json
vendored
Normal file
24
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "tdlib_gen",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "dart",
|
||||||
|
"program": "bin/tdlib_gen.dart",
|
||||||
|
"args": [
|
||||||
|
"${workspaceFolder}/td_api.tl",
|
||||||
|
"${workspaceFolder}/../tdlib_types/lib"
|
||||||
|
],
|
||||||
|
"windows": {
|
||||||
|
"args": [
|
||||||
|
"${workspaceFolder}/td_api.tl",
|
||||||
|
"${workspaceFolder}\\..\\tdlib_types\\lib"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
3
CHANGELOG.md
Normal file
3
CHANGELOG.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
## 1.0.0
|
||||||
|
|
||||||
|
- Initial version.
|
1
README.md
Normal file
1
README.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
A simple command-line application.
|
16
analysis_options.yaml
Normal file
16
analysis_options.yaml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# Defines a default set of lint rules enforced for projects at Google. For
|
||||||
|
# details and rationale, see
|
||||||
|
# https://github.com/dart-lang/pedantic#enabled-lints.
|
||||||
|
|
||||||
|
include: package:pedantic/analysis_options.yaml
|
||||||
|
|
||||||
|
# For lint rules and documentation, see http://dart-lang.github.io/linter/lints.
|
||||||
|
|
||||||
|
# Uncomment to specify additional rules.
|
||||||
|
# linter:
|
||||||
|
# rules:
|
||||||
|
# - camel_case_types
|
||||||
|
|
||||||
|
# analyzer:
|
||||||
|
# exclude:
|
||||||
|
# - path/to/excluded/files/**
|
549
bin/tdlib_gen.dart
Normal file
549
bin/tdlib_gen.dart
Normal file
|
@ -0,0 +1,549 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'tl_scheme.dart';
|
||||||
|
|
||||||
|
import 'package:recase/recase.dart';
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
|
Future<void> main(List<String> arguments) async {
|
||||||
|
if (arguments.length != 2) {
|
||||||
|
print('The program must be run with 2 arguments:');
|
||||||
|
print(' path to .tl schema');
|
||||||
|
print(' path to Dart project source folder');
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
final schemeFileStr = arguments[0];
|
||||||
|
final srcFolderStr = arguments[1];
|
||||||
|
|
||||||
|
if (! await File.fromUri(Uri.file(schemeFileStr)).exists()) {
|
||||||
|
print("Schema file $schemeFileStr doesn't exist");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (! await Directory.fromUri(Uri.directory(srcFolderStr)).exists()) {
|
||||||
|
print("Dart project source folder $srcFolderStr doesn't exist");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
print('.tl schema folder: $schemeFileStr');
|
||||||
|
print('Dart project source folder: $srcFolderStr');
|
||||||
|
print('');
|
||||||
|
|
||||||
|
print('Reading .tl schema file...');
|
||||||
|
final schemeFileContents = await File.fromUri(Uri.file(schemeFileStr)).readAsString();
|
||||||
|
print('Parsing .tl schema file...');
|
||||||
|
final scheme = TlSchema.parse(schemeFileContents);
|
||||||
|
|
||||||
|
print('Generating...');
|
||||||
|
|
||||||
|
final baseFile = File.fromUri(Uri.file(path.join(srcFolderStr, 'base.dart')));
|
||||||
|
final abstractFile = File.fromUri(Uri.file(path.join(srcFolderStr, 'abstract.dart')));
|
||||||
|
final objFile = File.fromUri(Uri.file(path.join(srcFolderStr, 'obj.dart')));
|
||||||
|
final fnFile = File.fromUri(Uri.file(path.join(srcFolderStr, 'fn.dart')));
|
||||||
|
await baseFile.writeAsString(makeBaseFile(scheme));
|
||||||
|
await abstractFile.writeAsString(makeAbstractFile(scheme));
|
||||||
|
await objFile.writeAsString(makeObjFile(scheme));
|
||||||
|
await fnFile.writeAsString(makeFnFile(scheme));
|
||||||
|
|
||||||
|
print('Done!');
|
||||||
|
}
|
||||||
|
|
||||||
|
String findDartType(
|
||||||
|
String type,
|
||||||
|
TlSchema scheme,
|
||||||
|
{String abstractPrefix = 'a.',
|
||||||
|
String objectPrefix = 'o.',
|
||||||
|
String functionPrefix = 'f.',
|
||||||
|
bool noNullCheck = false}
|
||||||
|
) {
|
||||||
|
if (type.startsWith('vector<')) {
|
||||||
|
final tmp1 = type.replaceFirst('vector<', '');
|
||||||
|
final tmp2 = tmp1.substring(0, tmp1.length - 1);
|
||||||
|
final innerType = findDartType(
|
||||||
|
tmp2,
|
||||||
|
scheme,
|
||||||
|
abstractPrefix: abstractPrefix,
|
||||||
|
functionPrefix: functionPrefix,
|
||||||
|
objectPrefix: objectPrefix,
|
||||||
|
);
|
||||||
|
return 'List<$innerType>';
|
||||||
|
}
|
||||||
|
|
||||||
|
final predefined = {
|
||||||
|
'double': 'double',
|
||||||
|
'string': 'String',
|
||||||
|
'int32': 'int',
|
||||||
|
'int53': 'int',
|
||||||
|
'int64': 'int',
|
||||||
|
'bytes': 'Uint8List',
|
||||||
|
'Bool': 'bool',
|
||||||
|
};
|
||||||
|
|
||||||
|
if (predefined.containsKey(type)) {
|
||||||
|
return predefined[type]!;
|
||||||
|
}
|
||||||
|
|
||||||
|
final result = scheme.findType(type);
|
||||||
|
if (result == null) {
|
||||||
|
throw Exception("Couldn't find type: $type");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result is TlSchemeAbstractClass) {
|
||||||
|
final name = abstractPrefix + result.name.pascalCase;
|
||||||
|
if (noNullCheck) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return '$name?';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (result is TlSchemeObject) {
|
||||||
|
final name = objectPrefix + result.name.pascalCase;
|
||||||
|
if (noNullCheck) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return '$name?';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (result is TlSchemeFunction) {
|
||||||
|
final name = functionPrefix + result.name.pascalCase;
|
||||||
|
if (noNullCheck) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return '$name?';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw Exception('Unknown tl object: $result');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String findToJsonHandling(
|
||||||
|
String type,
|
||||||
|
String varName,
|
||||||
|
TlSchema scheme,
|
||||||
|
) {
|
||||||
|
if (type.startsWith('vector<')) {
|
||||||
|
final tmp1 = type.replaceFirst('vector<', '');
|
||||||
|
final tmp2 = tmp1.substring(0, tmp1.length - 1);
|
||||||
|
late String newVarName;
|
||||||
|
if (varName.startsWith('_e')) {
|
||||||
|
final num = int.parse(varName.substring(2));
|
||||||
|
newVarName = '_e${num + 1}';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
newVarName = '_e1';
|
||||||
|
}
|
||||||
|
final innerHandling = findToJsonHandling(
|
||||||
|
tmp2,
|
||||||
|
newVarName,
|
||||||
|
scheme,
|
||||||
|
);
|
||||||
|
return '$varName.map(($newVarName) => $innerHandling).toList(growable: false)';
|
||||||
|
}
|
||||||
|
|
||||||
|
final predefined = {
|
||||||
|
'double': 'double',
|
||||||
|
'string': 'String',
|
||||||
|
'int32': 'int',
|
||||||
|
'int53': 'int',
|
||||||
|
'Bool': 'bool',
|
||||||
|
};
|
||||||
|
if (predefined.containsKey(type)) {
|
||||||
|
return varName;
|
||||||
|
}
|
||||||
|
else if (type == 'int64') {
|
||||||
|
return '$varName.toString()';
|
||||||
|
}
|
||||||
|
else if (type == 'bytes') {
|
||||||
|
return 'base64.encode($varName)';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return '$varName?.toJson()';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String findFromJsonHandling(
|
||||||
|
String type,
|
||||||
|
String keyName,
|
||||||
|
TlSchema scheme,
|
||||||
|
{String abstractPrefix = 'a.',
|
||||||
|
String objectPrefix = 'o.',
|
||||||
|
String functionPrefix = 'f.',
|
||||||
|
String? varNameInsteadOfKeyName}
|
||||||
|
) {
|
||||||
|
if (type.startsWith('vector<')) {
|
||||||
|
final tmp1 = type.replaceFirst('vector<', '');
|
||||||
|
final tmp2 = tmp1.substring(0, tmp1.length - 1);
|
||||||
|
// final innerType = findDartType(tmp2, scheme, abstractPrefix: abstractPrefix, functionPrefix: functionPrefix, objectPrefix: objectPrefix);
|
||||||
|
final innerHandler = findFromJsonHandling(
|
||||||
|
tmp2,
|
||||||
|
'',
|
||||||
|
scheme,
|
||||||
|
abstractPrefix: abstractPrefix,
|
||||||
|
functionPrefix: functionPrefix,
|
||||||
|
objectPrefix: objectPrefix,
|
||||||
|
varNameInsteadOfKeyName: 'e',
|
||||||
|
);
|
||||||
|
return "(json['$keyName'] as List<dynamic>).map((e) => ($innerHandler)).toList(growable: false)";
|
||||||
|
}
|
||||||
|
|
||||||
|
final varAccess = varNameInsteadOfKeyName ?? "json['$keyName']";
|
||||||
|
final predefined = {
|
||||||
|
'double': 'double',
|
||||||
|
'string': 'String',
|
||||||
|
'int32': 'int',
|
||||||
|
'int53': 'int',
|
||||||
|
'Bool': 'bool',
|
||||||
|
};
|
||||||
|
if (predefined.containsKey(type)) {
|
||||||
|
return '$varAccess as ${predefined[type]}';
|
||||||
|
}
|
||||||
|
else if (type == 'int64') {
|
||||||
|
return 'int.parse($varAccess)';
|
||||||
|
}
|
||||||
|
else if (type == 'bytes') {
|
||||||
|
return 'base64.decode($varAccess)';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 'b.TdBase.fromJson($varAccess) as ${findDartType(type, scheme, abstractPrefix: abstractPrefix, functionPrefix: functionPrefix, objectPrefix: objectPrefix)}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String makeBaseFile(TlSchema scheme) {
|
||||||
|
var result = r"""
|
||||||
|
import 'obj.dart' as o;
|
||||||
|
|
||||||
|
abstract class TdBase {
|
||||||
|
Map<String, dynamic> toJson();
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'td::TdBase()';
|
||||||
|
}
|
||||||
|
|
||||||
|
static TdBase? fromJson(Map<String, dynamic>? json) {
|
||||||
|
if (json == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final type = json['@type'] as String;
|
||||||
|
final constructors = {
|
||||||
|
""";
|
||||||
|
for (final o in scheme.objects) {
|
||||||
|
final normName = o.name.pascalCase;
|
||||||
|
result += '''
|
||||||
|
'${o.name}': (json) => o.$normName.fromJson(json),
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
|
||||||
|
result += '''
|
||||||
|
};
|
||||||
|
return constructors[type]!(json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''';
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
String makeAbstractFile(TlSchema scheme) {
|
||||||
|
var result = r"""
|
||||||
|
import 'dart:core' as dc show Error;
|
||||||
|
|
||||||
|
import 'base.dart' as b;
|
||||||
|
import 'obj.dart' as o;
|
||||||
|
|
||||||
|
typedef Func1<T, TResult> = TResult Function(T);
|
||||||
|
|
||||||
|
class MatchError extends dc.Error {}
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
for (final ac in scheme.abstractClasses) {
|
||||||
|
final normName = ac.name.pascalCase;
|
||||||
|
final implementors = scheme.objects.where((element) => element.baseType == ac.name).toList(growable: false);
|
||||||
|
result += '''
|
||||||
|
/// ${ac.doc}
|
||||||
|
abstract class $normName extends b.TdBase {
|
||||||
|
TResult match<TResult>({
|
||||||
|
''';
|
||||||
|
for (final impl in implementors) {
|
||||||
|
final iNormName = impl.name.pascalCase;
|
||||||
|
result += '''
|
||||||
|
Func1<o.$iNormName, TResult>? is$iNormName,
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
result += '''
|
||||||
|
Func1<$normName, TResult>? otherwise,
|
||||||
|
}) {
|
||||||
|
if (false) {} // ignore: dead_code
|
||||||
|
''';
|
||||||
|
for (final impl in implementors) {
|
||||||
|
final iNormName = impl.name.pascalCase;
|
||||||
|
result += '''
|
||||||
|
else if (this is o.$iNormName) {
|
||||||
|
if (is$iNormName != null) {
|
||||||
|
return is$iNormName(this as o.$iNormName);
|
||||||
|
}
|
||||||
|
else if (otherwise != null) {
|
||||||
|
return otherwise(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
result += '''
|
||||||
|
else if (otherwise != null) {
|
||||||
|
otherwise(this);
|
||||||
|
}
|
||||||
|
else if (TResult == null.runtimeType) {
|
||||||
|
return null as TResult;
|
||||||
|
}
|
||||||
|
throw MatchError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String makeObjFile(TlSchema scheme) {
|
||||||
|
var result = r"""
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'base.dart' as b;
|
||||||
|
import 'abstract.dart' as a;
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
for (final o in scheme.objects) {
|
||||||
|
final normName = o.name.pascalCase;
|
||||||
|
final baseName = findDartType(o.baseType, scheme, objectPrefix: '', noNullCheck: true);
|
||||||
|
result += '''
|
||||||
|
/// ${o.doc}
|
||||||
|
class $normName extends $baseName {
|
||||||
|
''';
|
||||||
|
|
||||||
|
for (final param in o.parameters) {
|
||||||
|
final normParamName = param.name.camelCase;
|
||||||
|
final paramType = findDartType(param.type, scheme, objectPrefix: '');
|
||||||
|
result += '''
|
||||||
|
/// ${param.doc}
|
||||||
|
final $paramType $normParamName;
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
if (o.parameters.isNotEmpty) {
|
||||||
|
result += '''
|
||||||
|
|
||||||
|
$normName({
|
||||||
|
''';
|
||||||
|
for (final param in o.parameters) {
|
||||||
|
final normParamName = param.name.camelCase;
|
||||||
|
result += '''
|
||||||
|
required this.$normParamName,
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
result += '''
|
||||||
|
});
|
||||||
|
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result += '''
|
||||||
|
$normName();
|
||||||
|
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
|
||||||
|
// toString
|
||||||
|
result += '''
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
var s = 'td::$normName(';
|
||||||
|
|
||||||
|
// Params
|
||||||
|
final params = <String>[];
|
||||||
|
''';
|
||||||
|
for (final param in o.parameters) {
|
||||||
|
final normParamName = param.name.camelCase;
|
||||||
|
result += '''
|
||||||
|
params.add($normParamName.toString());
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
|
||||||
|
result += '''
|
||||||
|
s += params.join(', ');
|
||||||
|
|
||||||
|
s += ')';
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
''';
|
||||||
|
|
||||||
|
// toJson
|
||||||
|
result += '''
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'@type': '${o.name}',
|
||||||
|
''';
|
||||||
|
for (final param in o.parameters) {
|
||||||
|
final normParamName = param.name.camelCase;
|
||||||
|
final jsonHandling = findToJsonHandling(param.type, normParamName, scheme);
|
||||||
|
result += '''
|
||||||
|
'${param.name}': $jsonHandling,
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
result += '''
|
||||||
|
};
|
||||||
|
|
||||||
|
''';
|
||||||
|
|
||||||
|
// fromJson
|
||||||
|
result += '''
|
||||||
|
factory $normName.fromJson(Map<String, dynamic> json) => $normName(
|
||||||
|
''';
|
||||||
|
for (final param in o.parameters) {
|
||||||
|
final normParamName = param.name.camelCase;
|
||||||
|
final handle = findFromJsonHandling(param.type, param.name, scheme, objectPrefix: '');
|
||||||
|
result += '''
|
||||||
|
$normParamName: $handle,
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
result += '''
|
||||||
|
);
|
||||||
|
''';
|
||||||
|
|
||||||
|
result += '''
|
||||||
|
}
|
||||||
|
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String makeFnFile(TlSchema scheme) {
|
||||||
|
var result = r"""
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'base.dart' as b;
|
||||||
|
import 'abstract.dart' as a;
|
||||||
|
import 'obj.dart' as o;
|
||||||
|
|
||||||
|
abstract class TdFunction extends b.TdBase {}
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
for (final f in scheme.functions) {
|
||||||
|
final normName = f.name.pascalCase;
|
||||||
|
result += '''
|
||||||
|
/// ${f.doc}
|
||||||
|
class $normName extends TdFunction {
|
||||||
|
''';
|
||||||
|
|
||||||
|
// Parameters
|
||||||
|
for (final param in f.parameters) {
|
||||||
|
final pNormName = param.name.camelCase;
|
||||||
|
final pType = findDartType(param.type, scheme, functionPrefix: '');
|
||||||
|
result += '''
|
||||||
|
/// ${param.doc}
|
||||||
|
final $pType $pNormName;
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
if (f.parameters.isEmpty) {
|
||||||
|
result += '''
|
||||||
|
$normName();
|
||||||
|
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result += '''
|
||||||
|
|
||||||
|
$normName({
|
||||||
|
''';
|
||||||
|
for (final param in f.parameters) {
|
||||||
|
final pNormName = param.name.camelCase;
|
||||||
|
result += '''
|
||||||
|
required this.$pNormName,
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
result += '''
|
||||||
|
});
|
||||||
|
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
|
||||||
|
// toString
|
||||||
|
result += '''
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
var s = 'td::$normName(';
|
||||||
|
|
||||||
|
// Params
|
||||||
|
final params = <String>[];
|
||||||
|
''';
|
||||||
|
for (final param in f.parameters) {
|
||||||
|
final normParamName = param.name.camelCase;
|
||||||
|
result += '''
|
||||||
|
params.add($normParamName.toString());
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
|
||||||
|
result += '''
|
||||||
|
s += params.join(', ');
|
||||||
|
|
||||||
|
s += ')';
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
''';
|
||||||
|
|
||||||
|
// toJson
|
||||||
|
result += '''
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'@type': '${f.name}',
|
||||||
|
''';
|
||||||
|
for (final param in f.parameters) {
|
||||||
|
final pNormName = param.name.camelCase;
|
||||||
|
final jsonHandling = findToJsonHandling(param.type, pNormName, scheme);
|
||||||
|
result += '''
|
||||||
|
'${param.name}': $jsonHandling,
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
result += '''
|
||||||
|
};
|
||||||
|
|
||||||
|
''';
|
||||||
|
|
||||||
|
// fromJson
|
||||||
|
result += '''
|
||||||
|
factory $normName.fromJson(Map<String, dynamic> json) => $normName(
|
||||||
|
''';
|
||||||
|
for (final param in f.parameters) {
|
||||||
|
final normParamName = param.name.camelCase;
|
||||||
|
final handle = findFromJsonHandling(param.type, param.name, scheme);
|
||||||
|
result += '''
|
||||||
|
$normParamName: $handle,
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
result += '''
|
||||||
|
);
|
||||||
|
''';
|
||||||
|
|
||||||
|
result += '''
|
||||||
|
}
|
||||||
|
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
425
bin/tdlib_gen.dart.backup
Normal file
425
bin/tdlib_gen.dart.backup
Normal file
|
@ -0,0 +1,425 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'tl_scheme.dart';
|
||||||
|
|
||||||
|
import 'package:recase/recase.dart';
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
|
Future<void> main(List<String> arguments) async {
|
||||||
|
if (arguments.length != 2) {
|
||||||
|
print('The program must be run with 2 arguments:');
|
||||||
|
print(' path to .tl schema');
|
||||||
|
print(' path to Dart project source folder');
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
final schemeFileStr = arguments[0];
|
||||||
|
final srcFolderStr = arguments[1];
|
||||||
|
|
||||||
|
if (! await File.fromUri(Uri.file(schemeFileStr)).exists()) {
|
||||||
|
print("Schema file $schemeFileStr doesn't exist");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (! await Directory.fromUri(Uri.directory(srcFolderStr)).exists()) {
|
||||||
|
print("Dart project source folder $srcFolderStr doesn't exist");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
print('.tl schema folder: $schemeFileStr');
|
||||||
|
print('Dart project source folder: $srcFolderStr');
|
||||||
|
print('');
|
||||||
|
|
||||||
|
print('Reading .tl schema file...');
|
||||||
|
final schemeFileContents = await File.fromUri(Uri.file(schemeFileStr)).readAsString();
|
||||||
|
print('Parsing .tl schema file...');
|
||||||
|
final scheme = TlSchema.parse(schemeFileContents);
|
||||||
|
|
||||||
|
print('Generating...');
|
||||||
|
|
||||||
|
final baseFile = File.fromUri(Uri.file(path.join(srcFolderStr, 'base.dart')));
|
||||||
|
final abstractFile = File.fromUri(Uri.file(path.join(srcFolderStr, 'abstract.dart')));
|
||||||
|
final objFile = File.fromUri(Uri.file(path.join(srcFolderStr, 'obj.dart')));
|
||||||
|
final fnFile = File.fromUri(Uri.file(path.join(srcFolderStr, 'fn.dart')));
|
||||||
|
await baseFile.writeAsString(makeBaseFile(scheme));
|
||||||
|
await abstractFile.writeAsString(makeAbstractFile(scheme));
|
||||||
|
await objFile.writeAsString(makeObjFile(scheme));
|
||||||
|
await fnFile.writeAsString(makeFnFile(scheme));
|
||||||
|
|
||||||
|
print('Done!');
|
||||||
|
}
|
||||||
|
|
||||||
|
String findDartType(
|
||||||
|
String type,
|
||||||
|
TlSchema scheme,
|
||||||
|
{String abstractPrefix = 'a.',
|
||||||
|
String objectPrefix = 'o.',
|
||||||
|
String functionPrefix = 'f.'}
|
||||||
|
) {
|
||||||
|
if (type.startsWith('vector<')) {
|
||||||
|
final tmp1 = type.replaceFirst('vector<', '');
|
||||||
|
final tmp2 = tmp1.substring(0, tmp1.length - 1);
|
||||||
|
final innerType = findDartType(
|
||||||
|
tmp2,
|
||||||
|
scheme,
|
||||||
|
abstractPrefix: abstractPrefix,
|
||||||
|
functionPrefix: functionPrefix,
|
||||||
|
objectPrefix: objectPrefix,
|
||||||
|
);
|
||||||
|
return 'List<$innerType>';
|
||||||
|
}
|
||||||
|
|
||||||
|
final predefined = {
|
||||||
|
'double': 'double',
|
||||||
|
'string': 'String',
|
||||||
|
'int32': 'int',
|
||||||
|
'int53': 'int',
|
||||||
|
'int64': 'int',
|
||||||
|
'bytes': 'Uint8List',
|
||||||
|
'Bool': 'bool',
|
||||||
|
};
|
||||||
|
|
||||||
|
if (predefined.containsKey(type)) {
|
||||||
|
return predefined[type]!;
|
||||||
|
}
|
||||||
|
|
||||||
|
final result = scheme.findType(type);
|
||||||
|
if (result == null) {
|
||||||
|
throw Exception("Couldn't find type: $type");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result is TlSchemeAbstractClass) {
|
||||||
|
return abstractPrefix + result.name.pascalCase;
|
||||||
|
}
|
||||||
|
else if (result is TlSchemeObject) {
|
||||||
|
return objectPrefix + result.name.pascalCase;
|
||||||
|
}
|
||||||
|
else if (result is TlSchemeFunction) {
|
||||||
|
return functionPrefix + result.name.pascalCase;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw Exception('Unknown tl object: $result');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String findToJsonHandling(
|
||||||
|
String type,
|
||||||
|
String varName,
|
||||||
|
TlSchema scheme,
|
||||||
|
) {
|
||||||
|
if (type.startsWith('vector<')) {
|
||||||
|
final tmp1 = type.replaceFirst('vector<', '');
|
||||||
|
final tmp2 = tmp1.substring(0, tmp1.length - 1);
|
||||||
|
late String newVarName;
|
||||||
|
if (varName.startsWith('_e')) {
|
||||||
|
final num = int.parse(varName.substring(2));
|
||||||
|
newVarName = '_e${num + 1}';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
newVarName = '_e1';
|
||||||
|
}
|
||||||
|
final innerHandling = findToJsonHandling(
|
||||||
|
tmp2,
|
||||||
|
newVarName,
|
||||||
|
scheme,
|
||||||
|
);
|
||||||
|
return '$varName.map(($newVarName) => $innerHandling).toList(growable: false)';
|
||||||
|
}
|
||||||
|
|
||||||
|
final predefined = {
|
||||||
|
'double': 'double',
|
||||||
|
'string': 'String',
|
||||||
|
'int32': 'int',
|
||||||
|
'int53': 'int',
|
||||||
|
'Bool': 'bool',
|
||||||
|
};
|
||||||
|
if (predefined.containsKey(type)) {
|
||||||
|
return varName;
|
||||||
|
}
|
||||||
|
else if (type == 'int64') {
|
||||||
|
return '$varName.toString()';
|
||||||
|
}
|
||||||
|
else if (type == 'bytes') {
|
||||||
|
return 'base64.encode($varName)';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return '$varName.toJson()';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String findFromJsonHandling(
|
||||||
|
String type,
|
||||||
|
String keyName,
|
||||||
|
TlSchema scheme,
|
||||||
|
{String abstractPrefix = 'a.',
|
||||||
|
String objectPrefix = 'o.',
|
||||||
|
String functionPrefix = 'f.'}
|
||||||
|
) {
|
||||||
|
if (type.startsWith('vector<')) {
|
||||||
|
final tmp1 = type.replaceFirst('vector<', '');
|
||||||
|
final tmp2 = tmp1.substring(0, tmp1.length - 1);
|
||||||
|
final innerType = findDartType(tmp2, scheme, abstractPrefix: abstractPrefix, functionPrefix: functionPrefix, objectPrefix: objectPrefix);
|
||||||
|
return "(json['$keyName'] as List<dynamic>).map((e) => b.TdBase.fromJson(e) as $innerType).toList(growable: false)";
|
||||||
|
}
|
||||||
|
|
||||||
|
final predefined = {
|
||||||
|
'double': 'double',
|
||||||
|
'string': 'String',
|
||||||
|
'int32': 'int',
|
||||||
|
'int53': 'int',
|
||||||
|
'Bool': 'bool',
|
||||||
|
};
|
||||||
|
if (predefined.containsKey(type)) {
|
||||||
|
return "json['$keyName']";
|
||||||
|
}
|
||||||
|
else if (type == 'int64') {
|
||||||
|
return "int.parse(json['$keyName'])";
|
||||||
|
}
|
||||||
|
else if (type == 'bytes') {
|
||||||
|
return "base64.decode(json['$keyName'])";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return "b.TdBase.fromJson(json['$keyName']) as ${findDartType(type, scheme, abstractPrefix: abstractPrefix, functionPrefix: functionPrefix, objectPrefix: objectPrefix)}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String makeBaseFile(TlSchema scheme) {
|
||||||
|
var result = r"""
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'abstract.dart' as a;
|
||||||
|
import 'obj.dart' as o;
|
||||||
|
import 'fn.dart' as f;
|
||||||
|
|
||||||
|
abstract class TdBase {
|
||||||
|
Map<String, dynamic> toJson();
|
||||||
|
|
||||||
|
static TdBase fromJson(Map<String, dynamic> json) {
|
||||||
|
final type = json['@type'] as String;
|
||||||
|
if (false) {}
|
||||||
|
""";
|
||||||
|
for (final o in scheme.objects) {
|
||||||
|
final normName = o.name.pascalCase;
|
||||||
|
result += '''
|
||||||
|
else if (type == '${o.name}') {
|
||||||
|
return o.$normName.fromJson(json);
|
||||||
|
}
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
|
||||||
|
result += '''
|
||||||
|
else {
|
||||||
|
throw Exception('Unknown type: \$type');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''';
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String makeAbstractFile(TlSchema scheme) {
|
||||||
|
var result = r"""
|
||||||
|
import 'base.dart' as b;
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
for (final ac in scheme.abstractClasses) {
|
||||||
|
final normName = ac.name.pascalCase;
|
||||||
|
result += '''
|
||||||
|
/// ${ac.doc}
|
||||||
|
abstract class $normName extends b.TdBase {}
|
||||||
|
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String makeObjFile(TlSchema scheme) {
|
||||||
|
var result = r"""
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'base.dart' as b;
|
||||||
|
import 'abstract.dart' as a;
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
for (final o in scheme.objects) {
|
||||||
|
final normName = o.name.pascalCase;
|
||||||
|
final baseName = findDartType(o.baseType, scheme, objectPrefix: '');
|
||||||
|
result += '''
|
||||||
|
/// ${o.doc}
|
||||||
|
class $normName extends $baseName {
|
||||||
|
''';
|
||||||
|
|
||||||
|
for (final param in o.parameters) {
|
||||||
|
final normParamName = param.name.camelCase;
|
||||||
|
final paramType = findDartType(param.type, scheme, objectPrefix: '');
|
||||||
|
result += '''
|
||||||
|
/// ${param.doc}
|
||||||
|
final $paramType $normParamName;
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
if (o.parameters.isNotEmpty) {
|
||||||
|
result += '''
|
||||||
|
|
||||||
|
$normName({
|
||||||
|
''';
|
||||||
|
for (final param in o.parameters) {
|
||||||
|
final normParamName = param.name.camelCase;
|
||||||
|
result += '''
|
||||||
|
required this.$normParamName,
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
result += '''
|
||||||
|
});
|
||||||
|
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result += '''
|
||||||
|
$normName();
|
||||||
|
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
|
||||||
|
// toJson
|
||||||
|
result += '''
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'@type': '${o.name}',
|
||||||
|
''';
|
||||||
|
for (final param in o.parameters) {
|
||||||
|
final normParamName = param.name.camelCase;
|
||||||
|
result += '''
|
||||||
|
'${param.name}': $normParamName,
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
result += '''
|
||||||
|
};
|
||||||
|
|
||||||
|
''';
|
||||||
|
|
||||||
|
// fromJson
|
||||||
|
result += '''
|
||||||
|
factory $normName.fromJson(Map<String, dynamic> json) => $normName(
|
||||||
|
''';
|
||||||
|
for (final param in o.parameters) {
|
||||||
|
final normParamName = param.name.camelCase;
|
||||||
|
final handle = findFromJsonHandling(param.type, param.name, scheme, objectPrefix: '');
|
||||||
|
result += '''
|
||||||
|
$normParamName: $handle,
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
result += '''
|
||||||
|
);
|
||||||
|
''';
|
||||||
|
|
||||||
|
result += '''
|
||||||
|
}
|
||||||
|
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String makeFnFile(TlSchema scheme) {
|
||||||
|
var result = r"""
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'base.dart' as b;
|
||||||
|
import 'abstract.dart' as a;
|
||||||
|
import 'obj.dart' as o;
|
||||||
|
|
||||||
|
abstract class TdFunction extends b.TdBase {}
|
||||||
|
|
||||||
|
""";
|
||||||
|
|
||||||
|
for (final f in scheme.functions) {
|
||||||
|
final normName = f.name.pascalCase;
|
||||||
|
result += '''
|
||||||
|
/// ${f.doc}
|
||||||
|
class $normName extends TdFunction {
|
||||||
|
''';
|
||||||
|
|
||||||
|
// Parameters
|
||||||
|
for (final param in f.parameters) {
|
||||||
|
final pNormName = param.name.camelCase;
|
||||||
|
final pType = findDartType(param.type, scheme, functionPrefix: '');
|
||||||
|
result += '''
|
||||||
|
/// ${param.doc}
|
||||||
|
final $pType $pNormName;
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
if (f.parameters.isEmpty) {
|
||||||
|
result += '''
|
||||||
|
$normName();
|
||||||
|
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result += '''
|
||||||
|
|
||||||
|
$normName({
|
||||||
|
''';
|
||||||
|
for (final param in f.parameters) {
|
||||||
|
final pNormName = param.name.camelCase;
|
||||||
|
result += '''
|
||||||
|
required this.$pNormName,
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
result += '''
|
||||||
|
});
|
||||||
|
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
|
||||||
|
// toJson
|
||||||
|
result += '''
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'@type': '${f.name}',
|
||||||
|
''';
|
||||||
|
for (final param in f.parameters) {
|
||||||
|
final pNormName = param.name.camelCase;
|
||||||
|
final jsonHandling = findToJsonHandling(param.type, pNormName, scheme);
|
||||||
|
result += '''
|
||||||
|
'${param.name}': $jsonHandling,
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
result += '''
|
||||||
|
};
|
||||||
|
|
||||||
|
''';
|
||||||
|
|
||||||
|
// fromJson
|
||||||
|
result += '''
|
||||||
|
factory $normName.fromJson(Map<String, dynamic> json) => $normName(
|
||||||
|
''';
|
||||||
|
for (final param in f.parameters) {
|
||||||
|
final normParamName = param.name.camelCase;
|
||||||
|
final handle = findFromJsonHandling(param.type, param.name, scheme);
|
||||||
|
result += '''
|
||||||
|
$normParamName: $handle,
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
result += '''
|
||||||
|
);
|
||||||
|
''';
|
||||||
|
|
||||||
|
result += '''
|
||||||
|
}
|
||||||
|
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
266
bin/tl_scheme.dart
Normal file
266
bin/tl_scheme.dart
Normal file
|
@ -0,0 +1,266 @@
|
||||||
|
import 'tl_token.dart';
|
||||||
|
|
||||||
|
class TlSchema {
|
||||||
|
final List<TlSchemeAbstractClass> abstractClasses;
|
||||||
|
final List<TlSchemeObject> objects;
|
||||||
|
final List<TlSchemeFunction> functions;
|
||||||
|
|
||||||
|
TlSchema({
|
||||||
|
required this.abstractClasses,
|
||||||
|
required this.objects,
|
||||||
|
required this.functions,
|
||||||
|
});
|
||||||
|
|
||||||
|
TlSchemeItem? findType(String type) {
|
||||||
|
TlSchemeItem? find(List<TlSchemeItem> list) {
|
||||||
|
for (final item in list) {
|
||||||
|
if (item.name == type) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return find(abstractClasses) ?? find(objects) ?? find(functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
factory TlSchema.parse(String file) {
|
||||||
|
var abstractClasses = <String, TlSchemeAbstractClass>{};
|
||||||
|
var objects = <String, TlSchemeObject>{};
|
||||||
|
var functions = <String, TlSchemeFunction>{};
|
||||||
|
|
||||||
|
var comments = <TlTokenCommentTag>[];
|
||||||
|
|
||||||
|
void finishBuilder(_TlSchemeItemBuilder builder) {
|
||||||
|
comments.clear();
|
||||||
|
if (builder is _TlSchemeAbstractClassBuilder) {
|
||||||
|
final ac = builder.build();
|
||||||
|
abstractClasses[ac.name] = ac;
|
||||||
|
}
|
||||||
|
else if (builder is _TlSchemeObjectBuilder) {
|
||||||
|
final obj = builder.build();
|
||||||
|
objects[obj.name] = obj;
|
||||||
|
if (!abstractClasses.containsKey(obj.baseType)) {
|
||||||
|
abstractClasses[obj.baseType] = TlSchemeAbstractClass(
|
||||||
|
name: obj.baseType,
|
||||||
|
doc: ''
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (builder is _TlSchemeFunctionBuilder) {
|
||||||
|
final fn = builder.build();
|
||||||
|
functions[fn.name] = fn;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw Exception('Unknown builder: $builder');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var buildingFunctions = false;
|
||||||
|
_TlSchemeItemBuilder? builder;
|
||||||
|
|
||||||
|
for (final token in TlToken.tokenize(file)) {
|
||||||
|
if (token is TlTokenNone) {
|
||||||
|
if (builder != null) {
|
||||||
|
finishBuilder(builder);
|
||||||
|
}
|
||||||
|
builder = null;
|
||||||
|
}
|
||||||
|
else if (token is TlTokenFunctionsDelimiter) {
|
||||||
|
buildingFunctions = true;
|
||||||
|
}
|
||||||
|
else if (token is TlTokenCommentTag) {
|
||||||
|
if (token.name == 'class' && comments.isEmpty && builder == null) {
|
||||||
|
builder = _TlSchemeAbstractClassBuilder(
|
||||||
|
name: token.value,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (builder is _TlSchemeAbstractClassBuilder && token.name == 'description') {
|
||||||
|
builder.doc = token.value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
comments.add(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (token is TlTokenClassTag) {
|
||||||
|
// Check for skippable
|
||||||
|
final skippable = [
|
||||||
|
'double',
|
||||||
|
'string',
|
||||||
|
'int32',
|
||||||
|
'int53',
|
||||||
|
'int64',
|
||||||
|
'bytes',
|
||||||
|
'boolFalse',
|
||||||
|
'boolTrue',
|
||||||
|
'vector',
|
||||||
|
];
|
||||||
|
if (skippable.contains(token.name)) {
|
||||||
|
comments.clear();
|
||||||
|
builder = null;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var typeDoc = '';
|
||||||
|
var paramDoc = <String, String>{};
|
||||||
|
|
||||||
|
for (final comment in comments) {
|
||||||
|
if (comment.name == 'description') {
|
||||||
|
typeDoc = comment.value;
|
||||||
|
}
|
||||||
|
else if (comment.name == 'param_description') {
|
||||||
|
paramDoc['description'] = comment.value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
paramDoc[comment.name] = comment.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buildingFunctions) {
|
||||||
|
builder = _TlSchemeFunctionBuilder(
|
||||||
|
returnType: token.baseType,
|
||||||
|
name: token.name,
|
||||||
|
doc: typeDoc,
|
||||||
|
parameters: token.parameters.map((t) => _TlSchemeParamBuilder(
|
||||||
|
name: t.name,
|
||||||
|
type: t.type,
|
||||||
|
doc: paramDoc[t.name]!,
|
||||||
|
)).toList(growable: false),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
builder = _TlSchemeObjectBuilder(
|
||||||
|
baseType: token.baseType,
|
||||||
|
name: token.name,
|
||||||
|
doc: typeDoc,
|
||||||
|
parameters: token.parameters.map((t) => _TlSchemeParamBuilder(
|
||||||
|
name: t.name,
|
||||||
|
type: t.type,
|
||||||
|
doc: paramDoc[t.name]!,
|
||||||
|
)).toList(growable: false),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
finishBuilder(builder);
|
||||||
|
builder = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TlSchema(
|
||||||
|
abstractClasses: abstractClasses.values.toList(growable: false),
|
||||||
|
objects: objects.values.toList(growable: false),
|
||||||
|
functions: functions.values.toList(growable: false),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class TlSchemeItem {
|
||||||
|
final String name;
|
||||||
|
final String doc;
|
||||||
|
TlSchemeItem({required this.name, required this.doc});
|
||||||
|
}
|
||||||
|
abstract class _TlSchemeItemBuilder<T extends TlSchemeItem> {
|
||||||
|
T build();
|
||||||
|
}
|
||||||
|
|
||||||
|
class TlSchemeAbstractClass extends TlSchemeItem {
|
||||||
|
TlSchemeAbstractClass({required String name, required String doc})
|
||||||
|
: super(name: name, doc: doc);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'abstract $name';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class _TlSchemeAbstractClassBuilder extends _TlSchemeItemBuilder<TlSchemeAbstractClass> {
|
||||||
|
String name;
|
||||||
|
String doc;
|
||||||
|
_TlSchemeAbstractClassBuilder({this.name = '', this.doc = ''});
|
||||||
|
@override
|
||||||
|
TlSchemeAbstractClass build() => TlSchemeAbstractClass(name: name, doc: doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
class TlSchemeObject extends TlSchemeItem {
|
||||||
|
final String baseType;
|
||||||
|
final List<TlSchemeParam> parameters;
|
||||||
|
TlSchemeObject({
|
||||||
|
required this.baseType,
|
||||||
|
required String name,
|
||||||
|
required String doc,
|
||||||
|
required this.parameters,
|
||||||
|
}) : super(name: name, doc: doc);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'class $name(${parameters.join(', ')}) : $baseType';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class _TlSchemeObjectBuilder extends _TlSchemeItemBuilder<TlSchemeObject> {
|
||||||
|
String baseType;
|
||||||
|
String name;
|
||||||
|
String doc;
|
||||||
|
List<_TlSchemeParamBuilder> parameters;
|
||||||
|
_TlSchemeObjectBuilder({
|
||||||
|
this.baseType = '',
|
||||||
|
this.name = '',
|
||||||
|
this.doc = '',
|
||||||
|
this.parameters = const <_TlSchemeParamBuilder>[]
|
||||||
|
});
|
||||||
|
@override
|
||||||
|
TlSchemeObject build() => TlSchemeObject(
|
||||||
|
baseType: baseType,
|
||||||
|
name: name,
|
||||||
|
doc: doc,
|
||||||
|
parameters: parameters.map((b) => b.build()).toList(growable: false),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class TlSchemeFunction extends TlSchemeItem {
|
||||||
|
final String returnType;
|
||||||
|
final List<TlSchemeParam> parameters;
|
||||||
|
TlSchemeFunction({
|
||||||
|
required this.returnType,
|
||||||
|
required String name,
|
||||||
|
required String doc,
|
||||||
|
required this.parameters,
|
||||||
|
}) : super(name: name, doc: doc);
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'fn $name(${parameters.join(', ')}) -> $returnType';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class _TlSchemeFunctionBuilder extends _TlSchemeItemBuilder<TlSchemeFunction> {
|
||||||
|
String returnType;
|
||||||
|
String name;
|
||||||
|
String doc;
|
||||||
|
List<_TlSchemeParamBuilder> parameters;
|
||||||
|
_TlSchemeFunctionBuilder({
|
||||||
|
this.returnType = '',
|
||||||
|
this.name = '',
|
||||||
|
this.doc = '',
|
||||||
|
this.parameters = const <_TlSchemeParamBuilder>[]
|
||||||
|
});
|
||||||
|
@override
|
||||||
|
TlSchemeFunction build() => TlSchemeFunction(
|
||||||
|
returnType: returnType,
|
||||||
|
name: name,
|
||||||
|
doc: doc,
|
||||||
|
parameters: parameters.map((b) => b.build()).toList(growable: false),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class TlSchemeParam {
|
||||||
|
final String name;
|
||||||
|
final String type;
|
||||||
|
final String doc;
|
||||||
|
TlSchemeParam({required this.name, required this.type, required this.doc});
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return '$name: $type';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class _TlSchemeParamBuilder {
|
||||||
|
String name;
|
||||||
|
String type;
|
||||||
|
String doc;
|
||||||
|
_TlSchemeParamBuilder({this.name = '', this.type = '', this.doc = ''});
|
||||||
|
TlSchemeParam build() => TlSchemeParam(name: name, type: type, doc: doc);
|
||||||
|
}
|
139
bin/tl_token.dart
Normal file
139
bin/tl_token.dart
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
abstract class TlToken {
|
||||||
|
static Iterable<TlToken> tokenize(String file) sync* {
|
||||||
|
var lastWasNone = false;
|
||||||
|
for (final untrimmedLine in file.split(RegExp(r'[\r\n]'))) {
|
||||||
|
final line = untrimmedLine.trim();
|
||||||
|
if (line.isEmpty) {
|
||||||
|
if (!lastWasNone) {
|
||||||
|
yield TlTokenNone();
|
||||||
|
lastWasNone = true;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lastWasNone = false;
|
||||||
|
if (line.startsWith('//')) {
|
||||||
|
// Comment
|
||||||
|
if (!line.contains('@')) {
|
||||||
|
yield TlTokenCommentLine(line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Skip to first @tag
|
||||||
|
final interestLine = line.substring(line.indexOf('@'));
|
||||||
|
for (final unTrimmedTaggedChunk in interestLine.split('@')) {
|
||||||
|
final taggedChunk = unTrimmedTaggedChunk.trim();
|
||||||
|
if (taggedChunk.isEmpty) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final firstWs = taggedChunk.indexOf(RegExp(r'\s'));
|
||||||
|
final tagName = taggedChunk.substring(0, firstWs);
|
||||||
|
final tagValue = taggedChunk.substring(firstWs).trim();
|
||||||
|
yield TlTokenCommentTag(name: tagName, value: tagValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (line == '---functions---') {
|
||||||
|
yield TlTokenFunctionsDelimiter();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// class
|
||||||
|
// Split by space
|
||||||
|
final chunksIt = line.split(RegExp(r'\s+')).iterator;
|
||||||
|
// First is name
|
||||||
|
chunksIt.moveNext();
|
||||||
|
final name = chunksIt.current;
|
||||||
|
// Then there are parameters until =
|
||||||
|
final parameters = <TlTokenClassParam>[];
|
||||||
|
do {
|
||||||
|
chunksIt.moveNext();
|
||||||
|
if (chunksIt.current == '=') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Params are defined as name:type
|
||||||
|
// Ignore oddities
|
||||||
|
if (!chunksIt.current.contains(':')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final splitted = chunksIt.current.split(':');
|
||||||
|
parameters.add(TlTokenClassParam(
|
||||||
|
name: splitted[0],
|
||||||
|
type: splitted[1]
|
||||||
|
));
|
||||||
|
} while (true);
|
||||||
|
// Finally, there is the base type (abstract class)
|
||||||
|
chunksIt.moveNext();
|
||||||
|
String removeSemicolon(String input) {
|
||||||
|
while (input.codeUnits.last == ';'.codeUnits[0]) {
|
||||||
|
input = input.substring(0, input.length - 1);
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
final baseType = removeSemicolon(chunksIt.current);
|
||||||
|
|
||||||
|
yield TlTokenClassTag(
|
||||||
|
name: name,
|
||||||
|
parameters: parameters,
|
||||||
|
baseType: baseType,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class TlTokenFunctionsDelimiter extends TlToken {
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'TlToken: ---functions---';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class TlTokenNone extends TlToken {
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'TlToken.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class TlTokenCommentLine extends TlToken {
|
||||||
|
/// The content of the comment including the leading slashes
|
||||||
|
final String content;
|
||||||
|
TlTokenCommentLine(this.content);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'TlToken: //$content';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class TlTokenCommentTag extends TlToken {
|
||||||
|
/// The name of the tag, excluding the ampersand: description
|
||||||
|
final String name;
|
||||||
|
/// The value of the tag: Provides ...
|
||||||
|
final String value;
|
||||||
|
|
||||||
|
TlTokenCommentTag({required this.name, required this.value});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'TlToken: //@$name $value';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class TlTokenClassTag extends TlToken {
|
||||||
|
/// The name of the class
|
||||||
|
final String name;
|
||||||
|
final List<TlTokenClassParam> parameters;
|
||||||
|
final String baseType;
|
||||||
|
TlTokenClassTag({required this.name, required this.parameters, required this.baseType});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
final params = parameters.join(', ');
|
||||||
|
return 'TlToken: $name($params) = $baseType';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class TlTokenClassParam {
|
||||||
|
final String name;
|
||||||
|
final String type;
|
||||||
|
TlTokenClassParam({required this.name, required this.type});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return '$name:$type';
|
||||||
|
}
|
||||||
|
}
|
26
pubspec.lock
Normal file
26
pubspec.lock
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
# Generated by pub
|
||||||
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
|
packages:
|
||||||
|
path:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: path
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.8.0"
|
||||||
|
pedantic:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: pedantic
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.11.0"
|
||||||
|
recase:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: recase
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.0"
|
||||||
|
sdks:
|
||||||
|
dart: ">=2.12.0 <3.0.0"
|
14
pubspec.yaml
Normal file
14
pubspec.yaml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
name: tdlib_gen
|
||||||
|
description: A simple command-line application.
|
||||||
|
version: 1.0.0
|
||||||
|
# homepage: https://www.example.com
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
recase: ^4.0.0
|
||||||
|
path: ^1.8.0
|
||||||
|
|
||||||
|
dev_dependencies:
|
||||||
|
pedantic: ^1.10.0
|
Loading…
Add table
Reference in a new issue