import 'tl_token.dart'; class TlSchema { final List abstractClasses; final List objects; final List functions; TlSchema({ required this.abstractClasses, required this.objects, required this.functions, }); TlSchemeItem? findType(String type) { TlSchemeItem? find(List 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 = {}; var objects = {}; var functions = {}; var comments = []; 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 = {}; 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 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 { 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 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 { 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 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 { 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); }