Chromium Code Reviews| Index: lib/options.dart |
| diff --git a/lib/options.dart b/lib/options.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..e7e331c9f49b05c6484b533a07e67e4fdf8832ec |
| --- /dev/null |
| +++ b/lib/options.dart |
| @@ -0,0 +1,120 @@ |
| +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +part of protoc; |
| + |
| +/// A function that parses options for the compiler from [request]. If an error |
| +/// is detected during parsing, this function should report all errors in |
| +/// `response.error` and return `null`. |
| +typedef GenerationOptions GenerationOptionsParser( |
| + CodeGeneratorRequest request, CodeGeneratorResponse response); |
| + |
| +/// Helper function implementing a generic [GenerationOptionsParser] that reads |
| +/// `request.parameters` and treats each token as either a flag ("name") or a |
| +/// key-value pair ("name=value"). For each option "name", it looks up whether a |
| +/// [SingleOptionParser] exists in [parsers] and delegates the actual parsing of |
| +/// the option to it. Finally, it no errors were reported, it will call |
| +/// [optionsFactory] to create the resulting [GenerationOptions]. |
| +GenerationOptions genericGenerationOptionsParser( |
| + CodeGeneratorRequest request, CodeGeneratorResponse response, |
| + Map<String, SingleOptionParser> parsers, |
| + GenerationOptions optionsFactory(Map<String, SingleOptionParser> parsers)) { |
| + var parameter = request.parameter != null ? request.parameter : ''; |
| + var options = parameter.trim().split(','); |
| + var map = <String, String>{}; |
| + var errors = []; |
| + |
| + for (var option in options) { |
| + option = option.trim(); |
| + if (option.isEmpty) continue; |
| + var reportError = (details) { |
| + errors.add('Error found trying to parse the option: $option.\n$details'); |
| + }; |
| + |
| + var nameValue = option.split('='); |
| + if (nameValue.length != 1 && nameValue.length != 2) { |
| + reportError('Options should be a single token, or a name=value pair'); |
| + continue; |
| + } |
| + var name = nameValue[0].trim(); |
| + var parser = parsers[name]; |
| + if (parser == null) { |
| + reportError('Unknown option ($name).'); |
| + continue; |
| + } |
| + |
| + var value = nameValue.length > 1 ? nameValue[1].trim() : null; |
| + parser.parse(name, value, reportError); |
| + } |
| + |
| + if (errors.length == 0) return optionsFactory(parsers); |
| + |
| + response.error = errors.join('\n'); |
| + return null; |
| +} |
| + |
| +/// Options expected by the protoc code generation compiler. |
| +class GenerationOptions { |
| + /// Maps a fully qualified field name, to the desired name we wish to |
| + /// generate. For example `MyMessage.has_field` to `HasFld`. |
| + final Map<String, String> fieldNameOverrides; |
|
Chris Bracken
2014/05/16 19:58:45
+1 for the new name
|
| + |
| + GenerationOptions(this.fieldNameOverrides); |
| +} |
| + |
| +/// A parser for a name-value pair option. Options parsed in |
| +/// [genericGenerationOptionsParser] delegate to instances of this class to |
| +/// parse the value of a specific option. |
| +abstract class SingleOptionParser { |
| + |
| + /// Parse the [name]=[value] value pair and report any errors to [onError]. If |
| + /// the option is a flag, [value] will be null. Note, [name] is commonly |
| + /// unused. It is provided because [SingleOptionParser] can be registered for |
| + /// multiple option names in [genericGenerationOptionsParser]. |
| + void parse(String name, String value, onError(String details)); |
| +} |
| + |
| +/// Default [GenerationOptionsParser] used by the compiler, which supports |
| +/// the `field_name` option. This option overrides the default name given to |
| +/// some fields that would otherwise collide with existing field names in Dart |
| +/// core objects or in [GeneratedMessage] (see `README.md` for details). |
| +GenerationOptions parseDefaultGenerationOptions( |
| + CodeGeneratorRequest request, CodeGeneratorResponse response) { |
| + var fieldNameOptionParser = new FieldNameOptionParser(); |
| + return genericGenerationOptionsParser(request, response, |
| + {'field_name': fieldNameOptionParser}, |
| + (_) => new GenerationOptions(fieldNameOptionParser.mappings)); |
| +} |
| + |
| +/// A [SingleOptionParser] to parse the `field_name` option. This option |
| +/// overrides the default name given to some fields that would otherwise collide |
| +/// with existing field names in Dart core objects or in [GeneratedMessage]. |
| +class FieldNameOptionParser implements SingleOptionParser { |
| + /// Maps a fully qualified field name, to the desired name we wish to |
| + /// generate. For example `MyMessage.has_field` to `HasFld`. |
| + final Map<String, String> mappings = {}; |
| + |
| + void parse(String name, String value, onError(String message)) { |
| + if (value == null) { |
| + onError('Invalid field_name option, expected a non-emtpy value.'); |
| + return; |
| + } |
| + |
| + List<String> fromTo = value.split('|'); |
| + if (fromTo.length != 2) { |
| + onError('Invalid field_name option, expected a single "|" separator.'); |
| + return; |
| + } |
| + |
| + var fromName = fromTo[0].trim(); |
| + var toName = fromTo[1].trim(); |
| + if (fromName.isEmpty || toName.isEmpty) { |
| + onError('Invalid field_name option, ' |
| + '"from" and "to" names should not be empty.'); |
| + return; |
| + } |
| + |
| + mappings['.$fromName'] = toName; |
| + } |
| +} |