|  |  |  | #!/usr/bin/env python | 
					
						
							|  |  |  | # -*- coding: utf-8 -*- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | import subprocess  | 
					
						
							|  |  |  | import datetime | 
					
						
							|  |  |  | import argparse | 
					
						
							|  |  |  | import re | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | git_repo_path = os.path.abspath(subprocess.check_output(['git', 'rev-parse', '--show-toplevel']).strip()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  | def lowerCamlCaseForUnderscoredText(name): | 
					
						
							|  |  |  |     splits = name.split('_') | 
					
						
							|  |  |  |     splits = [split.title() for split in splits] | 
					
						
							|  |  |  |     splits[0] = splits[0].lower() | 
					
						
							|  |  |  |     return ''.join(splits) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # The generated code for "Apple Swift Protos" suppresses | 
					
						
							|  |  |  | # adjacent capital letters in lowerCamlCase. | 
					
						
							|  |  |  | def lowerCamlCaseForUnderscoredText_wrapped(name): | 
					
						
							|  |  |  |     chars = [] | 
					
						
							|  |  |  |     lastWasUpper = False | 
					
						
							|  |  |  |     for char in name: | 
					
						
							|  |  |  |         if lastWasUpper: | 
					
						
							|  |  |  |             char = char.lower() | 
					
						
							|  |  |  |         chars.append(char) | 
					
						
							|  |  |  |         lastWasUpper = (char.upper() == char) | 
					
						
							|  |  |  |     result = ''.join(chars) | 
					
						
							|  |  |  |     if result.endswith('Id'): | 
					
						
							|  |  |  |         result = result[:-2] + 'ID' | 
					
						
							|  |  |  |     return result | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Provides conext for writing an indented block surrounded by braces. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # e.g. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #     with BracedContext('class Foo', writer) as writer: | 
					
						
							|  |  |  | #         with BracedContext('func bar() -> Bool', writer) as writer: | 
					
						
							|  |  |  | #             return true | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Produces: | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #    class Foo { | 
					
						
							|  |  |  | #        func bar() -> Bool { | 
					
						
							|  |  |  | #            return true | 
					
						
							|  |  |  | #        } | 
					
						
							|  |  |  | #    } | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | class BracedContext: | 
					
						
							|  |  |  |     def __init__(self, line, writer): | 
					
						
							|  |  |  |         self.writer = writer | 
					
						
							|  |  |  |         writer.add('%s {' % line) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __enter__(self): | 
					
						
							|  |  |  |         self.writer.push_indent() | 
					
						
							|  |  |  |         return self.writer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __exit__(self, *args): | 
					
						
							|  |  |  |         self.writer.pop_indent() | 
					
						
							|  |  |  |         self.writer.add('}') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class WriterContext: | 
					
						
							|  |  |  |     def __init__(self, proto_name, swift_name, parent=None): | 
					
						
							|  |  |  |         self.proto_name = proto_name | 
					
						
							|  |  |  |         self.swift_name = swift_name | 
					
						
							|  |  |  |         self.parent = parent | 
					
						
							|  |  |  |         self.name_map = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class LineWriter: | 
					
						
							|  |  |  |     def __init__(self, args): | 
					
						
							|  |  |  |         self.contexts = [] | 
					
						
							|  |  |  |         # self.indent = 0 | 
					
						
							|  |  |  |         self.lines = [] | 
					
						
							|  |  |  |         self.args = args | 
					
						
							|  |  |  |         self.current_indent = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def braced(self, line): | 
					
						
							|  |  |  |         return BracedContext(line, self) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def push_indent(self): | 
					
						
							|  |  |  |         self.current_indent = self.current_indent + 1 | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def pop_indent(self): | 
					
						
							|  |  |  |         self.current_indent = self.current_indent - 1 | 
					
						
							|  |  |  |         if self.current_indent < 0: | 
					
						
							|  |  |  |             raise Exception('Invalid indentation') | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def all_context_proto_names(self): | 
					
						
							|  |  |  |         return [context.proto_name for context in self.contexts] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def current_context(self): | 
					
						
							|  |  |  |         return self.contexts[-1] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def indent(self): | 
					
						
							|  |  |  |         return self.current_indent | 
					
						
							|  |  |  |         # return len(self.contexts) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def push_context(self, proto_name, swift_name): | 
					
						
							|  |  |  |         self.contexts.append(WriterContext(proto_name, swift_name)) | 
					
						
							|  |  |  |         self.push_indent() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def pop_context(self): | 
					
						
							|  |  |  |         self.contexts.pop() | 
					
						
							|  |  |  |         self.pop_indent() | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def add(self, line): | 
					
						
							|  |  |  |         self.lines.append(('    ' * self.indent()) + line) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def add_raw(self, line): | 
					
						
							|  |  |  |         self.lines.append(line) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def extend(self, text): | 
					
						
							|  |  |  |         for line in text.split('\n'): | 
					
						
							|  |  |  |             self.add(line) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def join(self): | 
					
						
							|  |  |  |         lines = [line.rstrip() for line in self.lines] | 
					
						
							|  |  |  |         return '\n'.join(lines) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def rstrip(self): | 
					
						
							|  |  |  |         lines = self.lines | 
					
						
							|  |  |  |         while len(lines) > 0 and len(lines[-1].strip()) == 0: | 
					
						
							|  |  |  |             lines = lines[:-1] | 
					
						
							|  |  |  |         self.lines = lines | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def newline(self): | 
					
						
							|  |  |  |         self.add('') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BaseContext(object): | 
					
						
							|  |  |  |     def __init__(self): | 
					
						
							|  |  |  |         self.parent = None | 
					
						
							|  |  |  |         self.proto_name = None | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def inherited_proto_names(self): | 
					
						
							|  |  |  |         if self.parent is None: | 
					
						
							|  |  |  |             return [] | 
					
						
							|  |  |  |         if self.proto_name is None: | 
					
						
							|  |  |  |             return [] | 
					
						
							|  |  |  |         return self.parent.inherited_proto_names() + [self.proto_name,] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def derive_swift_name(self): | 
					
						
							|  |  |  |         names = self.inherited_proto_names() | 
					
						
							|  |  |  |         return self.args.wrapper_prefix + ''.join(names) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def derive_wrapped_swift_name(self): | 
					
						
							|  |  |  |         names = self.inherited_proto_names() | 
					
						
							|  |  |  |         return self.args.proto_prefix + '_' + '.'.join(names) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def children(self): | 
					
						
							|  |  |  |         return [] | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def descendents(self): | 
					
						
							|  |  |  |         result = [] | 
					
						
							|  |  |  |         for child in self.children(): | 
					
						
							|  |  |  |             result.append(child) | 
					
						
							|  |  |  |             result.extend(child.descendents()) | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def siblings(self): | 
					
						
							|  |  |  |         result = [] | 
					
						
							|  |  |  |         if self.parent is not None: | 
					
						
							|  |  |  |             result = self.parent.children() | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def ancestors(self): | 
					
						
							|  |  |  |         result = [] | 
					
						
							|  |  |  |         if self.parent is not None: | 
					
						
							|  |  |  |             result.append(self.parent) | 
					
						
							|  |  |  |             result.extend(self.parent.ancestors()) | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def context_for_proto_type(self, field): | 
					
						
							|  |  |  |         candidates = [] | 
					
						
							|  |  |  |         candidates.extend(self.descendents()) | 
					
						
							|  |  |  |         candidates.extend(self.siblings()) | 
					
						
							|  |  |  |         for ancestor in self.ancestors(): | 
					
						
							|  |  |  |             if ancestor.proto_name is None: | 
					
						
							|  |  |  |                 # Ignore the root context | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             candidates.append(ancestor) | 
					
						
							|  |  |  |             candidates.extend(ancestor.siblings()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for candidate in candidates: | 
					
						
							|  |  |  |             if candidate.proto_name == field.proto_type: | 
					
						
							|  |  |  |                 return candidate | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         return None                 | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def base_swift_type_for_field(self, field): | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |         if field.proto_type == 'string': | 
					
						
							|  |  |  |             return 'String' | 
					
						
							|  |  |  |         elif field.proto_type == 'uint64': | 
					
						
							|  |  |  |             return 'UInt64'             | 
					
						
							|  |  |  |         elif field.proto_type == 'uint32': | 
					
						
							|  |  |  |             return 'UInt32' | 
					
						
							|  |  |  |         elif field.proto_type == 'fixed64': | 
					
						
							|  |  |  |             return 'UInt64' | 
					
						
							|  |  |  |         elif field.proto_type == 'bool': | 
					
						
							|  |  |  |             return 'Bool' | 
					
						
							|  |  |  |         elif field.proto_type == 'bytes': | 
					
						
							|  |  |  |             return 'Data' | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             matching_context = self.context_for_proto_type(field) | 
					
						
							|  |  |  |             if matching_context is not None: | 
					
						
							|  |  |  |                 return matching_context.swift_name | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 # Failure | 
					
						
							|  |  |  |                 return field.proto_type | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def swift_type_for_field(self, field, suppress_optional=False): | 
					
						
							|  |  |  |         base_type = self.base_swift_type_for_field(field) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         if field.rules == 'optional': | 
					
						
							|  |  |  |             if suppress_optional: | 
					
						
							|  |  |  |                 return base_type | 
					
						
							|  |  |  |             can_be_optional = self.can_field_be_optional(field) | 
					
						
							|  |  |  |             if can_be_optional: | 
					
						
							|  |  |  |                 return '%s?' % base_type | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 return base_type | 
					
						
							|  |  |  |         elif field.rules == 'required': | 
					
						
							|  |  |  |             return base_type | 
					
						
							|  |  |  |         elif field.rules == 'repeated': | 
					
						
							|  |  |  |             return '[%s]' % base_type | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise Exception('Unknown field type') | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def is_field_primitive(self, field): | 
					
						
							|  |  |  |         return field.proto_type in ('uint64', | 
					
						
							|  |  |  |             'uint32', | 
					
						
							|  |  |  |             'fixed64', | 
					
						
							|  |  |  |             'bool', ) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def can_field_be_optional(self, field): | 
					
						
							|  |  |  |         if self.is_field_primitive(field): | 
					
						
							|  |  |  |             return not field.is_required | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # if field.proto_type == 'uint64': | 
					
						
							|  |  |  |         #     return False | 
					
						
							|  |  |  |         # elif field.proto_type == 'uint32': | 
					
						
							|  |  |  |         #     return False | 
					
						
							|  |  |  |         # elif field.proto_type == 'fixed64': | 
					
						
							|  |  |  |         #     return False | 
					
						
							|  |  |  |         # elif field.proto_type == 'bool': | 
					
						
							|  |  |  |         #     return False | 
					
						
							|  |  |  |         # elif self.is_field_an_enum(field): | 
					
						
							|  |  |  |         if self.is_field_an_enum(field): | 
					
						
							|  |  |  |             return False | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return True | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def is_field_an_enum(self, field): | 
					
						
							|  |  |  |         matching_context = self.context_for_proto_type(field) | 
					
						
							|  |  |  |         if matching_context is not None: | 
					
						
							|  |  |  |             if type(matching_context) is EnumContext: | 
					
						
							|  |  |  |                 return True | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def is_field_a_proto(self, field): | 
					
						
							|  |  |  |         matching_context = self.context_for_proto_type(field) | 
					
						
							|  |  |  |         if matching_context is not None: | 
					
						
							|  |  |  |             if type(matching_context) is MessageContext: | 
					
						
							|  |  |  |                 return True | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def default_value_for_field(self, field): | 
					
						
							|  |  |  |         if field.rules == 'repeated': | 
					
						
							|  |  |  |             return '[]' | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         if field.default_value is not None and len(field.default_value) > 0: | 
					
						
							|  |  |  |             return field.default_value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if field.rules == 'optional': | 
					
						
							|  |  |  |             can_be_optional = self.can_field_be_optional(field) | 
					
						
							|  |  |  |             if can_be_optional: | 
					
						
							|  |  |  |                 return 'nil' | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         if field.proto_type == 'uint64': | 
					
						
							|  |  |  |             return '0' | 
					
						
							|  |  |  |         elif field.proto_type == 'uint32': | 
					
						
							|  |  |  |             return '0' | 
					
						
							|  |  |  |         elif field.proto_type == 'fixed64': | 
					
						
							|  |  |  |             return '0' | 
					
						
							|  |  |  |         elif field.proto_type == 'bool': | 
					
						
							|  |  |  |             return 'false' | 
					
						
							|  |  |  |         elif self.is_field_an_enum(field): | 
					
						
							|  |  |  |             # TODO: Assert that rules is empty. | 
					
						
							|  |  |  |             enum_context = self.context_for_proto_type(field) | 
					
						
							|  |  |  |             return enum_context.default_value() | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |         return None         | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class FileContext(BaseContext): | 
					
						
							|  |  |  |     def __init__(self, args): | 
					
						
							|  |  |  |         BaseContext.__init__(self) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         self.args = args | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         self.messages = [] | 
					
						
							|  |  |  |         self.enums = [] | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def children(self): | 
					
						
							|  |  |  |         return self.enums + self.messages | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def prepare(self): | 
					
						
							|  |  |  |         for child in self.children(): | 
					
						
							|  |  |  |             child.prepare() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def generate(self, writer): | 
					
						
							|  |  |  |         writer.extend('''//
 | 
					
						
							|  |  |  | //  Copyright (c) 2018 Open Whisper Systems. All rights reserved. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import Foundation | 
					
						
							|  |  |  | ''')
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         writer.extend('''
 | 
					
						
							|  |  |  | // WARNING: This code is generated. Only edit within the markers. | 
					
						
							|  |  |  | '''.strip())
 | 
					
						
							|  |  |  |         writer.newline()         | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         writer.invalid_protobuf_error_name = '%sError' % self.args.wrapper_prefix | 
					
						
							|  |  |  |         writer.extend(('''
 | 
					
						
							|  |  |  | public enum %s: Error { | 
					
						
							|  |  |  |     case invalidProtobuf(description: String) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ''' % writer.invalid_protobuf_error_name).strip())
 | 
					
						
							|  |  |  |         writer.newline()         | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         for child in self.children(): | 
					
						
							|  |  |  |             child.generate(writer) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MessageField: | 
					
						
							|  |  |  |     def __init__(self, name, index, rules, proto_type, default_value, sort_index, is_required): | 
					
						
							|  |  |  |         self.name = name | 
					
						
							|  |  |  |         self.index = index | 
					
						
							|  |  |  |         self.rules = rules | 
					
						
							|  |  |  |         self.proto_type = proto_type | 
					
						
							|  |  |  |         self.default_value = default_value | 
					
						
							|  |  |  |         self.sort_index = sort_index | 
					
						
							|  |  |  |         self.is_required = is_required | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |     def has_accessor_name(self): | 
					
						
							|  |  |  |         name = 'has' + self.name_swift[0].upper() + self.name_swift[1:] | 
					
						
							|  |  |  |         if name == 'hasId': | 
					
						
							|  |  |  |             # TODO: I'm not sure why "Apple Swift Proto" code formats the | 
					
						
							|  |  |  |             # the name in this way. | 
					
						
							|  |  |  |             name = 'hasID' | 
					
						
							|  |  |  |         elif name == 'hasUrl': | 
					
						
							|  |  |  |             # TODO: I'm not sure why "Apple Swift Proto" code formats the | 
					
						
							|  |  |  |             # the name in this way. | 
					
						
							|  |  |  |             name = 'hasURL' | 
					
						
							|  |  |  |         return name | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  | class MessageContext(BaseContext): | 
					
						
							|  |  |  |     def __init__(self, args, parent, proto_name): | 
					
						
							|  |  |  |         BaseContext.__init__(self) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.args = args | 
					
						
							|  |  |  |         self.parent = parent | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         self.proto_name = proto_name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.messages = [] | 
					
						
							|  |  |  |         self.enums = [] | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         self.field_map = {} | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def fields(self):  | 
					
						
							|  |  |  |         fields = self.field_map.values() | 
					
						
							|  |  |  |         fields = sorted(fields, key=lambda f: f.sort_index) | 
					
						
							|  |  |  |         return fields | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def field_indices(self): | 
					
						
							|  |  |  |         return [field.index for field in self.fields()] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def field_names(self): | 
					
						
							|  |  |  |         return [field.name for field in self.fields()] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def children(self): | 
					
						
							|  |  |  |         return self.enums + self.messages | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def prepare(self): | 
					
						
							|  |  |  |         self.swift_name = self.derive_swift_name() | 
					
						
							|  |  |  |         self.swift_builder_name = "%sBuilder" % self.swift_name | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         for child in self.children(): | 
					
						
							|  |  |  |             child.prepare() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def generate(self, writer): | 
					
						
							|  |  |  |         for child in self.messages: | 
					
						
							|  |  |  |             child.generate(writer) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |         writer.add('// MARK: - %s' % self.swift_name) | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         writer.add('@objc public class %s: NSObject {' % self.swift_name) | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         writer.push_context(self.proto_name, self.swift_name) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         for child in self.enums: | 
					
						
							|  |  |  |             child.generate(writer) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         wrapped_swift_name = self.derive_wrapped_swift_name() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Prepare fields | 
					
						
							|  |  |  |         explict_fields = [] | 
					
						
							|  |  |  |         implict_fields = [] | 
					
						
							|  |  |  |         for field in self.fields(): | 
					
						
							|  |  |  |             field.type_swift = self.swift_type_for_field(field) | 
					
						
							|  |  |  |             field.type_swift_not_optional = self.swift_type_for_field(field, suppress_optional=True) | 
					
						
							|  |  |  |             field.name_swift = lowerCamlCaseForUnderscoredText_wrapped(field.name) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             is_explicit = False | 
					
						
							|  |  |  |             if field.is_required: | 
					
						
							|  |  |  |                 is_explicit = True | 
					
						
							|  |  |  |             elif self.is_field_a_proto(field): | 
					
						
							|  |  |  |                 is_explicit = True | 
					
						
							|  |  |  |             if is_explicit: | 
					
						
							|  |  |  |                 explict_fields.append(field) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 implict_fields.append(field) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.generate_builder(writer) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         writer.add('fileprivate let proto: %s' % wrapped_swift_name ) | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         # Property Declarations | 
					
						
							|  |  |  |         if len(explict_fields) > 0: | 
					
						
							|  |  |  |             for field in explict_fields: | 
					
						
							|  |  |  |                 type_name = field.type_swift_not_optional if field.is_required else field.type_swift | 
					
						
							|  |  |  |                 writer.add('@objc public let %s: %s' % (field.name_swift, type_name)) | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |                 if (not field.is_required) and field.rules != 'repeated' and (not self.is_field_a_proto(field)): | 
					
						
							|  |  |  |                     writer.add('@objc public var %s: Bool {' % field.has_accessor_name() ) | 
					
						
							|  |  |  |                     writer.push_indent() | 
					
						
							|  |  |  |                     writer.add('return proto.%s' % field.has_accessor_name() ) | 
					
						
							|  |  |  |                     writer.pop_indent() | 
					
						
							|  |  |  |                     writer.add('}') | 
					
						
							|  |  |  |                 writer.newline() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if len(implict_fields) > 0: | 
					
						
							|  |  |  |             for field in implict_fields: | 
					
						
							|  |  |  |                 if field.rules == 'optional': | 
					
						
							|  |  |  |                     can_be_optional = (not self.is_field_primitive(field)) and (not self.is_field_an_enum(field)) | 
					
						
							|  |  |  |                     if can_be_optional: | 
					
						
							|  |  |  |                         writer.add('@objc public var %s: %s? {' % (field.name_swift, field.type_swift_not_optional)) | 
					
						
							|  |  |  |                         writer.push_indent() | 
					
						
							|  |  |  |                         writer.add('guard proto.%s else {' % field.has_accessor_name() ) | 
					
						
							|  |  |  |                         writer.push_indent() | 
					
						
							|  |  |  |                         writer.add('return nil') | 
					
						
							|  |  |  |                         writer.pop_indent() | 
					
						
							|  |  |  |                         writer.add('}') | 
					
						
							|  |  |  |                         if self.is_field_an_enum(field): | 
					
						
							|  |  |  |                             enum_context = self.context_for_proto_type(field) | 
					
						
							|  |  |  |                             writer.add('return %s.%sWrap(proto.%s)' % ( enum_context.parent.swift_name, enum_context.swift_name, field.name_swift, ) ) | 
					
						
							|  |  |  |                         else: | 
					
						
							|  |  |  |                             writer.add('return proto.%s' % field.name_swift ) | 
					
						
							|  |  |  |                         writer.pop_indent() | 
					
						
							|  |  |  |                         writer.add('}') | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         writer.add('@objc public var %s: %s {' % (field.name_swift, field.type_swift_not_optional)) | 
					
						
							|  |  |  |                         writer.push_indent() | 
					
						
							|  |  |  |                         if self.is_field_an_enum(field): | 
					
						
							|  |  |  |                             enum_context = self.context_for_proto_type(field) | 
					
						
							|  |  |  |                             writer.add('return %s.%sWrap(proto.%s)' % ( enum_context.parent.swift_name, enum_context.swift_name, field.name_swift, ) ) | 
					
						
							|  |  |  |                         else: | 
					
						
							|  |  |  |                             writer.add('return proto.%s' % field.name_swift ) | 
					
						
							|  |  |  |                         writer.pop_indent() | 
					
						
							|  |  |  |                         writer.add('}') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     writer.add('@objc public var %s: Bool {' % field.has_accessor_name() ) | 
					
						
							|  |  |  |                     writer.push_indent() | 
					
						
							|  |  |  |                     writer.add('return proto.%s' % field.has_accessor_name() ) | 
					
						
							|  |  |  |                     writer.pop_indent() | 
					
						
							|  |  |  |                     writer.add('}') | 
					
						
							|  |  |  |                     writer.newline() | 
					
						
							|  |  |  |                 elif field.rules == 'repeated': | 
					
						
							|  |  |  |                     writer.add('@objc public var %s: %s {' % (field.name_swift, field.type_swift_not_optional)) | 
					
						
							|  |  |  |                     writer.push_indent() | 
					
						
							|  |  |  |                     writer.add('return proto.%s' % field.name_swift ) | 
					
						
							|  |  |  |                     writer.pop_indent() | 
					
						
							|  |  |  |                     writer.add('}') | 
					
						
							|  |  |  |                     writer.newline() | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     writer.add('@objc public var %s: %s {' % (field.name_swift, field.type_swift_not_optional)) | 
					
						
							|  |  |  |                     writer.push_indent() | 
					
						
							|  |  |  |                     if self.is_field_an_enum(field): | 
					
						
							|  |  |  |                         enum_context = self.context_for_proto_type(field) | 
					
						
							|  |  |  |                         writer.add('return %sUnwrap(proto.%s)' % ( enum_context.swift_name, field.name_swift, ) ) | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         writer.add('return proto.%s' % field.name_swift ) | 
					
						
							|  |  |  |                     writer.pop_indent() | 
					
						
							|  |  |  |                     writer.add('}') | 
					
						
							|  |  |  |                     writer.newline() | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         # Initializer | 
					
						
							|  |  |  |         initializer_parameters = [] | 
					
						
							|  |  |  |         initializer_parameters.append('proto: %s' % wrapped_swift_name)         | 
					
						
							|  |  |  |         initializer_prefix = 'private init(' | 
					
						
							|  |  |  |         for field in explict_fields: | 
					
						
							|  |  |  |             type_name = field.type_swift_not_optional if field.is_required else field.type_swift | 
					
						
							|  |  |  |             parameter = '%s: %s' % (field.name_swift, type_name) | 
					
						
							|  |  |  |             parameter = '\n' + ' ' * len(initializer_prefix) + parameter | 
					
						
							|  |  |  |             initializer_parameters.append(parameter) | 
					
						
							|  |  |  |         initializer_parameters = ', '.join(initializer_parameters) | 
					
						
							|  |  |  |         writer.extend('%s%s) {' % ( initializer_prefix, initializer_parameters, ) ) | 
					
						
							|  |  |  |         writer.push_indent() | 
					
						
							|  |  |  |         writer.add('self.proto = proto') | 
					
						
							|  |  |  |         for field in explict_fields: | 
					
						
							|  |  |  |             writer.add('self.%s = %s' % (field.name_swift, field.name_swift)) | 
					
						
							|  |  |  |         writer.pop_indent() | 
					
						
							|  |  |  |         writer.add('}') | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  |         # serializedData() func | 
					
						
							|  |  |  |         writer.extend(('''
 | 
					
						
							|  |  |  | @objc | 
					
						
							|  |  |  | public func serializedData() throws -> Data { | 
					
						
							|  |  |  |     return try self.proto.serializedData() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ''').strip())
 | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # parseData() func | 
					
						
							|  |  |  |         writer.add('@objc public class func parseData(_ serializedData: Data) throws -> %s {' % self.swift_name) | 
					
						
							|  |  |  |         writer.push_indent() | 
					
						
							|  |  |  |         writer.add('let proto = try %s(serializedData: serializedData)' % ( wrapped_swift_name, ) ) | 
					
						
							|  |  |  |         writer.add('return try parseProto(proto)')         | 
					
						
							|  |  |  |         writer.pop_indent() | 
					
						
							|  |  |  |         writer.add('}') | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # parseData() func | 
					
						
							|  |  |  |         writer.add('fileprivate class func parseProto(_ proto: %s) throws -> %s {' % ( wrapped_swift_name, self.swift_name, ) ) | 
					
						
							|  |  |  |         writer.push_indent() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         for field in explict_fields: | 
					
						
							|  |  |  |             if field.is_required: | 
					
						
							|  |  |  |             # if self.can_field_be_optional(field): | 
					
						
							|  |  |  |                 writer.add('guard proto.%s else {' % field.has_accessor_name() ) | 
					
						
							|  |  |  |                 writer.push_indent() | 
					
						
							|  |  |  |                 writer.add('throw %s.invalidProtobuf(description: "\(logTag) missing required field: %s")' % ( writer.invalid_protobuf_error_name, field.name_swift, ) )    | 
					
						
							|  |  |  |                 writer.pop_indent() | 
					
						
							|  |  |  |                 writer.add('}') | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |                 if self.is_field_an_enum(field): | 
					
						
							|  |  |  |                     # TODO: Assert that rules is empty. | 
					
						
							|  |  |  |                     enum_context = self.context_for_proto_type(field) | 
					
						
							|  |  |  |                     writer.add('let %s = %sWrap(proto.%s)' % ( field.name_swift, enum_context.swift_name, field.name_swift, ) ) | 
					
						
							|  |  |  |                 elif self.is_field_a_proto(field): | 
					
						
							|  |  |  |                     writer.add('let %s = try %s.parseProto(proto.%s)' % (field.name_swift, self.base_swift_type_for_field(field), field.name_swift)), | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     writer.add('let %s = proto.%s' % ( field.name_swift, field.name_swift, ) ) | 
					
						
							|  |  |  |                 writer.newline() | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             default_value = self.default_value_for_field(field) | 
					
						
							|  |  |  |             if default_value is None: | 
					
						
							|  |  |  |                 writer.add('var %s: %s' % (field.name_swift, field.type_swift)) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 writer.add('var %s: %s = %s' % (field.name_swift, field.type_swift, default_value)) | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |             if field.rules == 'repeated': | 
					
						
							|  |  |  |                 if self.is_field_an_enum(field): | 
					
						
							|  |  |  |                     enum_context = self.context_for_proto_type(field) | 
					
						
							|  |  |  |                     writer.add('%s = proto.%s.map { %sWrap($0) }' % ( field.name_swift, field.name_swift, enum_context.swift_name, ) ) | 
					
						
							|  |  |  |                 elif self.is_field_a_proto(field): | 
					
						
							|  |  |  |                     writer.add('%s = try proto.%s.map { try %s.parseProto($0) }' % ( field.name_swift, field.name_swift, self.base_swift_type_for_field(field), ) ) | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     writer.add('%s = proto.%s' % ( field.name_swift, field.name_swift, ) ) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 writer.add('if proto.%s {' % field.has_accessor_name() ) | 
					
						
							|  |  |  |                 writer.push_indent() | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |                 if self.is_field_an_enum(field): | 
					
						
							|  |  |  |                     # TODO: Assert that rules is empty. | 
					
						
							|  |  |  |                     enum_context = self.context_for_proto_type(field) | 
					
						
							|  |  |  |                     writer.add('%s = %sWrap(proto.%s)' % ( field.name_swift, enum_context.swift_name, field.name_swift, ) ) | 
					
						
							|  |  |  |                 elif self.is_field_a_proto(field): | 
					
						
							|  |  |  |                     writer.add('%s = try %s.parseProto(proto.%s)' % (field.name_swift, self.base_swift_type_for_field(field), field.name_swift)), | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     writer.add('%s = proto.%s' % ( field.name_swift, field.name_swift, ) ) | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |                 writer.pop_indent() | 
					
						
							|  |  |  |                 writer.add('}') | 
					
						
							|  |  |  |             writer.newline() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         writer.add('// MARK: - Begin Validation Logic for %s -' % self.swift_name) | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         # Preserve existing validation logic. | 
					
						
							|  |  |  |         if self.swift_name in args.validation_map: | 
					
						
							|  |  |  |             validation_block = args.validation_map[self.swift_name] | 
					
						
							|  |  |  |             if validation_block: | 
					
						
							|  |  |  |                 writer.add_raw(validation_block) | 
					
						
							|  |  |  |                 writer.newline() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         writer.add('// MARK: - End Validation Logic for %s -' % self.swift_name) | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         initializer_prefix = 'let result = %s(' % self.swift_name | 
					
						
							|  |  |  |         initializer_arguments = [] | 
					
						
							|  |  |  |         initializer_arguments.append('proto: proto') | 
					
						
							|  |  |  |         for field in explict_fields: | 
					
						
							|  |  |  |             argument = '%s: %s' % (field.name_swift, field.name_swift) | 
					
						
							|  |  |  |             argument = '\n' + ' ' * len(initializer_prefix) + argument | 
					
						
							|  |  |  |             initializer_arguments.append(argument) | 
					
						
							|  |  |  |         initializer_arguments = ', '.join(initializer_arguments) | 
					
						
							|  |  |  |         writer.extend('%s%s)' % ( initializer_prefix, initializer_arguments, ) ) | 
					
						
							|  |  |  |         writer.add('return result')         | 
					
						
							|  |  |  |         writer.pop_indent() | 
					
						
							|  |  |  |         writer.add('}') | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # description | 
					
						
							|  |  |  |         writer.add('@objc public override var debugDescription: String {') | 
					
						
							|  |  |  |         writer.push_indent() | 
					
						
							|  |  |  |         writer.add('return "\(proto)"') | 
					
						
							|  |  |  |         writer.pop_indent() | 
					
						
							|  |  |  |         writer.add('}') | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |         writer.pop_context() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         writer.rstrip() | 
					
						
							|  |  |  |         writer.add('}') | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  |         self.generate_debug_extension(writer) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def generate_debug_extension(self, writer): | 
					
						
							|  |  |  |         writer.add('#if DEBUG')  | 
					
						
							|  |  |  |         writer.newline()  | 
					
						
							|  |  |  |         with writer.braced('extension %s' % self.swift_name) as writer: | 
					
						
							|  |  |  |             with writer.braced('@objc public func serializedDataIgnoringErrors() -> Data?') as writer: | 
					
						
							|  |  |  |                 writer.add('return try! self.serializedData()') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  |         with writer.braced('extension %s.%s' % ( self.swift_name, self.swift_builder_name )) as writer: | 
					
						
							|  |  |  |             with writer.braced('@objc public func buildIgnoringErrors() -> %s?' % self.swift_name) as writer: | 
					
						
							|  |  |  |                 writer.add('return try! self.build()') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  |         writer.add('#endif') | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def generate_builder(self, writer): | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |         wrapped_swift_name = self.derive_wrapped_swift_name() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         writer.add('// MARK: - %s' % self.swift_builder_name) | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Required Fields | 
					
						
							|  |  |  |         required_fields = [field for field in self.fields() if field.is_required] | 
					
						
							|  |  |  |         required_init_params = [] | 
					
						
							|  |  |  |         required_init_args = [] | 
					
						
							|  |  |  |         if len(required_fields) > 0: | 
					
						
							|  |  |  |             for field in required_fields: | 
					
						
							|  |  |  |                 if field.rules == 'repeated': | 
					
						
							|  |  |  |                     param_type = '[' + self.base_swift_type_for_field(field) + ']' | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     param_type = self.base_swift_type_for_field(field) | 
					
						
							|  |  |  |                 required_init_params.append('%s: %s' % ( field.name_swift, param_type) ) | 
					
						
							|  |  |  |                 required_init_args.append('%s: %s' % ( field.name_swift, field.name_swift) ) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         # Convenience accessor. | 
					
						
							|  |  |  |         with writer.braced('@objc public class func builder(%s) -> %s' % (  | 
					
						
							|  |  |  |                 ', '.join(required_init_params), | 
					
						
							|  |  |  |                 self.swift_builder_name, | 
					
						
							|  |  |  |                 )) as writer: | 
					
						
							|  |  |  |             writer.add('return %s(%s)' % (self.swift_builder_name, ', '.join(required_init_args), )) | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         # asBuilder()         | 
					
						
							|  |  |  |         writer.add('// asBuilder() constructs a builder that reflects the proto\'s contents.') | 
					
						
							|  |  |  |         with writer.braced('@objc public func asBuilder() -> %s' % ( | 
					
						
							|  |  |  |                 self.swift_builder_name, | 
					
						
							|  |  |  |                 )) as writer: | 
					
						
							|  |  |  |             writer.add('let builder = %s(%s)' % (self.swift_builder_name, ', '.join(required_init_args), )) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for field in self.fields(): | 
					
						
							|  |  |  |                 if field.is_required: | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 accessor_name = field.name_swift | 
					
						
							|  |  |  |                 accessor_name = 'set' + accessor_name[0].upper() + accessor_name[1:] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 can_be_optional = (not self.is_field_primitive(field)) and (not self.is_field_an_enum(field)) | 
					
						
							|  |  |  |                 if field.rules == 'repeated': | 
					
						
							|  |  |  |                     writer.add('builder.%s(%s)' % ( accessor_name, field.name_swift, )) | 
					
						
							|  |  |  |                 elif can_be_optional: | 
					
						
							|  |  |  |                     writer.add('if let _value = %s {' % field.name_swift ) | 
					
						
							|  |  |  |                     writer.push_indent() | 
					
						
							|  |  |  |                     writer.add('builder.%s(_value)' % ( accessor_name, )) | 
					
						
							|  |  |  |                     writer.pop_indent() | 
					
						
							|  |  |  |                     writer.add('}') | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     writer.add('if %s {' % field.has_accessor_name() ) | 
					
						
							|  |  |  |                     writer.push_indent() | 
					
						
							|  |  |  |                     writer.add('builder.%s(%s)' % ( accessor_name, field.name_swift, )) | 
					
						
							|  |  |  |                     writer.pop_indent() | 
					
						
							|  |  |  |                     writer.add('}') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             writer.add('return builder') | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         writer.add('@objc public class %s: NSObject {' % self.swift_builder_name) | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         writer.push_context(self.proto_name, self.swift_name) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         writer.add('private var proto = %s()' % wrapped_swift_name) | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         # Initializer | 
					
						
							|  |  |  |         writer.add('@objc fileprivate override init() {}') | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         # Required-Field Initializer | 
					
						
							|  |  |  |         if len(required_fields) > 0: | 
					
						
							|  |  |  |             # writer.add('// Initializer for required fields') | 
					
						
							|  |  |  |             writer.add('@objc fileprivate init(%s) {' % ', '.join(required_init_params)) | 
					
						
							|  |  |  |             writer.push_indent() | 
					
						
							|  |  |  |             writer.add('super.init()') | 
					
						
							|  |  |  |             writer.newline() | 
					
						
							|  |  |  |             for field in required_fields: | 
					
						
							|  |  |  |                 accessor_name = field.name_swift | 
					
						
							|  |  |  |                 accessor_name = 'set' + accessor_name[0].upper() + accessor_name[1:] | 
					
						
							|  |  |  |                 writer.add('%s(%s)' % ( accessor_name, field.name_swift, ) ) | 
					
						
							|  |  |  |             writer.pop_indent() | 
					
						
							|  |  |  |             writer.add('}') | 
					
						
							|  |  |  |             writer.newline() | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |         # Setters | 
					
						
							|  |  |  |         for field in self.fields(): | 
					
						
							|  |  |  |             if field.rules == 'repeated': | 
					
						
							|  |  |  |                 # Add | 
					
						
							|  |  |  |                 accessor_name = field.name_swift | 
					
						
							|  |  |  |                 accessor_name = 'add' + accessor_name[0].upper() + accessor_name[1:] | 
					
						
							|  |  |  |                 writer.add('@objc public func %s(_ valueParam: %s) {' % ( accessor_name, self.base_swift_type_for_field(field), )) | 
					
						
							|  |  |  |                 writer.push_indent() | 
					
						
							|  |  |  |                 writer.add('var items = proto.%s' % ( field.name_swift, ) ) | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |                 if self.is_field_an_enum(field): | 
					
						
							|  |  |  |                     enum_context = self.context_for_proto_type(field) | 
					
						
							|  |  |  |                     writer.add('items.append(%sUnwrap(valueParam))' % enum_context.swift_name ) | 
					
						
							|  |  |  |                 elif self.is_field_a_proto(field): | 
					
						
							|  |  |  |                     writer.add('items.append(valueParam.proto)') | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     writer.add('items.append(valueParam)') | 
					
						
							|  |  |  |                 writer.add('proto.%s = items' % ( field.name_swift, ) ) | 
					
						
							|  |  |  |                 writer.pop_indent() | 
					
						
							|  |  |  |                 writer.add('}') | 
					
						
							|  |  |  |                 writer.newline() | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |                 # Set | 
					
						
							|  |  |  |                 accessor_name = field.name_swift | 
					
						
							|  |  |  |                 accessor_name = 'set' + accessor_name[0].upper() + accessor_name[1:] | 
					
						
							|  |  |  |                 writer.add('@objc public func %s(_ wrappedItems: [%s]) {' % ( accessor_name, self.base_swift_type_for_field(field), )) | 
					
						
							|  |  |  |                 writer.push_indent() | 
					
						
							|  |  |  |                 if self.is_field_an_enum(field): | 
					
						
							|  |  |  |                     enum_context = self.context_for_proto_type(field) | 
					
						
							|  |  |  |                     writer.add('proto.%s = wrappedItems.map { %sUnwrap($0) }' % ( field.name_swift, enum_context.swift_name, ) ) | 
					
						
							|  |  |  |                 elif self.is_field_a_proto(field): | 
					
						
							|  |  |  |                     writer.add('proto.%s = wrappedItems.map { $0.proto }' % ( field.name_swift, ) ) | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     writer.add('proto.%s = wrappedItems' % ( field.name_swift, ) ) | 
					
						
							|  |  |  |                 writer.pop_indent() | 
					
						
							|  |  |  |                 writer.add('}') | 
					
						
							|  |  |  |                 writer.newline() | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 accessor_name = field.name_swift | 
					
						
							|  |  |  |                 accessor_name = 'set' + accessor_name[0].upper() + accessor_name[1:] | 
					
						
							|  |  |  |                 writer.add('@objc public func %s(_ valueParam: %s) {' % ( accessor_name, self.base_swift_type_for_field(field), )) | 
					
						
							|  |  |  |                 writer.push_indent() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if self.is_field_an_enum(field): | 
					
						
							|  |  |  |                     enum_context = self.context_for_proto_type(field) | 
					
						
							|  |  |  |                     writer.add('proto.%s = %sUnwrap(valueParam)' % ( field.name_swift, enum_context.swift_name, ) ) | 
					
						
							|  |  |  |                 elif self.is_field_a_proto(field): | 
					
						
							|  |  |  |                     writer.add('proto.%s = valueParam.proto' % ( field.name_swift, ) ) | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     writer.add('proto.%s = valueParam' % ( field.name_swift, ) ) | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |                 writer.pop_indent() | 
					
						
							|  |  |  |                 writer.add('}') | 
					
						
							|  |  |  |                 writer.newline() | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  |         # build() func | 
					
						
							|  |  |  |         writer.add('@objc public func build() throws -> %s {' % self.swift_name) | 
					
						
							|  |  |  |         writer.push_indent() | 
					
						
							|  |  |  |         writer.add('return try %s.parseProto(proto)' % self.swift_name) | 
					
						
							|  |  |  |         writer.pop_indent() | 
					
						
							|  |  |  |         writer.add('}') | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # buildSerializedData() func | 
					
						
							|  |  |  |         writer.add('@objc public func buildSerializedData() throws -> Data {') | 
					
						
							|  |  |  |         writer.push_indent() | 
					
						
							|  |  |  |         writer.add('return try %s.parseProto(proto).serializedData()' % self.swift_name) | 
					
						
							|  |  |  |         writer.pop_indent() | 
					
						
							|  |  |  |         writer.add('}') | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # description | 
					
						
							|  |  |  |         if self.args.add_description: | 
					
						
							|  |  |  |             writer.add('@objc public override var description: String {') | 
					
						
							|  |  |  |             writer.push_indent() | 
					
						
							|  |  |  |             writer.add('var fields = [String]()') | 
					
						
							|  |  |  |             for field in self.fields(): | 
					
						
							|  |  |  |                 writer.add('fields.append("%s: \(proto.%s)")' % ( field.name_swift, field.name_swift, ) ) | 
					
						
							|  |  |  |             writer.add('return "[" + fields.joined(separator: ", ") + "]"') | 
					
						
							|  |  |  |             writer.pop_indent() | 
					
						
							|  |  |  |             writer.add('}') | 
					
						
							|  |  |  |             writer.newline() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         writer.pop_context() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         writer.rstrip() | 
					
						
							|  |  |  |         writer.add('}') | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  | class EnumContext(BaseContext): | 
					
						
							|  |  |  |     def __init__(self, args, parent, proto_name): | 
					
						
							|  |  |  |         BaseContext.__init__(self) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.args = args | 
					
						
							|  |  |  |         self.parent = parent         | 
					
						
							|  |  |  |         self.proto_name = proto_name | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         # self.item_names = set() | 
					
						
							|  |  |  |         # self.item_indices = set() | 
					
						
							|  |  |  |         self.item_map = {} | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def derive_wrapped_swift_name(self): | 
					
						
							|  |  |  |         # return BaseContext.derive_wrapped_swift_name(self) + 'Enum' | 
					
						
							|  |  |  |         result = BaseContext.derive_wrapped_swift_name(self) | 
					
						
							|  |  |  |         if self.proto_name == 'Type': | 
					
						
							|  |  |  |             result = result + 'Enum' | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def item_names(self): | 
					
						
							|  |  |  |         return self.item_map.values() | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def item_indices(self): | 
					
						
							|  |  |  |         return self.item_map.keys() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def prepare(self): | 
					
						
							|  |  |  |         self.swift_name = self.derive_swift_name() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         for child in self.children(): | 
					
						
							|  |  |  |             child.prepare() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def case_pairs(self): | 
					
						
							|  |  |  |         indices = [int(index) for index in self.item_indices()] | 
					
						
							|  |  |  |         indices = sorted(indices) | 
					
						
							|  |  |  |         result = [] | 
					
						
							|  |  |  |         for index in indices: | 
					
						
							|  |  |  |             index_str = str(index) | 
					
						
							|  |  |  |             item_name = self.item_map[index_str] | 
					
						
							|  |  |  |             case_name = lowerCamlCaseForUnderscoredText(item_name) | 
					
						
							|  |  |  |             result.append( (case_name, index_str,) ) | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     def default_value(self): | 
					
						
							|  |  |  |         for case_name, case_index in self.case_pairs(): | 
					
						
							|  |  |  |             return '.' + case_name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def generate(self, writer): | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         writer.add('// MARK: - %s' % self.swift_name) | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         writer.add('@objc public enum %s: Int32 {' % self.swift_name) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         writer.push_context(self.proto_name, self.swift_name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for case_name, case_index in self.case_pairs(): | 
					
						
							|  |  |  |             if case_name == 'default': | 
					
						
							|  |  |  |                 case_name = '`default`' | 
					
						
							|  |  |  |             writer.add('case %s = %s' % (case_name, case_index,)) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         writer.pop_context() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         writer.rstrip() | 
					
						
							|  |  |  |         writer.add('}') | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         wrapped_swift_name = self.derive_wrapped_swift_name() | 
					
						
							|  |  |  |         writer.add('private class func %sWrap(_ value: %s) -> %s {' % ( self.swift_name, wrapped_swift_name, self.swift_name, ) ) | 
					
						
							|  |  |  |         writer.push_indent() | 
					
						
							|  |  |  |         writer.add('switch value {') | 
					
						
							|  |  |  |         for case_name, case_index in self.case_pairs(): | 
					
						
							|  |  |  |             writer.add('case .%s: return .%s' % (case_name, case_name,)) | 
					
						
							|  |  |  |         writer.add('}') | 
					
						
							|  |  |  |         writer.pop_indent() | 
					
						
							|  |  |  |         writer.add('}') | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  |         writer.add('private class func %sUnwrap(_ value: %s) -> %s {' % ( self.swift_name, self.swift_name, wrapped_swift_name, ) ) | 
					
						
							|  |  |  |         writer.push_indent() | 
					
						
							|  |  |  |         writer.add('switch value {') | 
					
						
							|  |  |  |         for case_name, case_index in self.case_pairs(): | 
					
						
							|  |  |  |             writer.add('case .%s: return .%s' % (case_name, case_name,)) | 
					
						
							|  |  |  |         writer.add('}') | 
					
						
							|  |  |  |         writer.pop_indent() | 
					
						
							|  |  |  |         writer.add('}') | 
					
						
							|  |  |  |         writer.newline() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  | class LineParser: | 
					
						
							|  |  |  |     def __init__(self, text): | 
					
						
							|  |  |  |         self.lines = text.split('\n') | 
					
						
							|  |  |  |         self.lines.reverse() | 
					
						
							|  |  |  |         self.next_line_comments = [] | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     def next(self): | 
					
						
							|  |  |  |         # lineParser = LineParser(text.split('\n')) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |         self.next_line_comments = [] | 
					
						
							|  |  |  |         while len(self.lines) > 0: | 
					
						
							|  |  |  |             line = self.lines.pop() | 
					
						
							|  |  |  |             line = line.strip() | 
					
						
							|  |  |  |             # if not line: | 
					
						
							|  |  |  |             #     continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             comment_index = line.find('//') | 
					
						
							|  |  |  |             if comment_index >= 0: | 
					
						
							|  |  |  |                 comment = line[comment_index + len('//'):].strip() | 
					
						
							|  |  |  |                 line = line[:comment_index].strip() | 
					
						
							|  |  |  |                 if not line: | 
					
						
							|  |  |  |                     if comment: | 
					
						
							|  |  |  |                         self.next_line_comments.append(comment) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 if not line: | 
					
						
							|  |  |  |                     self.next_line_comments = [] | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |             if not line: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |             # if args.verbose: | 
					
						
							|  |  |  |             #     print 'line:', line | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             return line | 
					
						
							|  |  |  |         raise StopIteration() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def parse_enum(args, proto_file_path, parser, parent_context, enum_name): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # if args.verbose: | 
					
						
							|  |  |  |     #     print '# enum:', enum_name | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     context = EnumContext(args, parent_context, enum_name) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     while True: | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             line = parser.next() | 
					
						
							|  |  |  |         except StopIteration: | 
					
						
							|  |  |  |             raise Exception('Incomplete enum: %s' % proto_file_path) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |         if line == '}': | 
					
						
							|  |  |  |             # if args.verbose: | 
					
						
							|  |  |  |             #     print | 
					
						
							|  |  |  |             parent_context.enums.append(context) | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         item_regex = re.compile(r'^(.+?)\s*=\s*(\d+?)\s*;$') | 
					
						
							|  |  |  |         item_match = item_regex.search(line) | 
					
						
							|  |  |  |         if item_match: | 
					
						
							|  |  |  |             item_name = item_match.group(1).strip() | 
					
						
							|  |  |  |             item_index = item_match.group(2).strip() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |             # if args.verbose: | 
					
						
							|  |  |  |             #     print '\t enum item[%s]: %s' % (item_index, item_name) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             if item_name in context.item_names(): | 
					
						
							|  |  |  |                 raise Exception('Duplicate enum name[%s]: %s' % (proto_file_path, item_name)) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             if item_index in context.item_indices(): | 
					
						
							|  |  |  |                 raise Exception('Duplicate enum index[%s]: %s' % (proto_file_path, item_name)) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             context.item_map[item_index] = item_name | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |         raise Exception('Invalid enum syntax[%s]: %s' % (proto_file_path, line)) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def optional_match_group(match, index): | 
					
						
							|  |  |  |     group = match.group(index) | 
					
						
							|  |  |  |     if group is None: | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  |     return group.strip() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def parse_message(args, proto_file_path, parser, parent_context, message_name): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # if args.verbose: | 
					
						
							|  |  |  |     #     print '# message:', message_name | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     context = MessageContext(args, parent_context, message_name) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     sort_index = 0 | 
					
						
							|  |  |  |     while True: | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             line = parser.next() | 
					
						
							|  |  |  |         except StopIteration: | 
					
						
							|  |  |  |             raise Exception('Incomplete message: %s' % proto_file_path) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |         field_comments = parser.next_line_comments | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         if line == '}': | 
					
						
							|  |  |  |             # if args.verbose: | 
					
						
							|  |  |  |             #     print | 
					
						
							|  |  |  |             parent_context.messages.append(context) | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         enum_regex = re.compile(r'^enum\s+(.+?)\s+\{$') | 
					
						
							|  |  |  |         enum_match = enum_regex.search(line) | 
					
						
							|  |  |  |         if enum_match: | 
					
						
							|  |  |  |             enum_name = enum_match.group(1).strip()         | 
					
						
							|  |  |  |             parse_enum(args, proto_file_path, parser, context, enum_name) | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         message_regex = re.compile(r'^message\s+(.+?)\s+\{$') | 
					
						
							|  |  |  |         message_match = message_regex.search(line) | 
					
						
							|  |  |  |         if message_match: | 
					
						
							|  |  |  |             message_name = message_match.group(1).strip() | 
					
						
							|  |  |  |             parse_message(args, proto_file_path, parser, context, message_name) | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Examples: | 
					
						
							|  |  |  |         # | 
					
						
							|  |  |  |         # optional bytes  id          = 1; | 
					
						
							|  |  |  |         # optional bool              isComplete = 2 [default = false]; | 
					
						
							|  |  |  |         item_regex = re.compile(r'^(optional|required|repeated)?\s*([\w\d]+?)\s+([\w\d]+?)\s*=\s*(\d+?)\s*(\[default = (true|false)\])?;$') | 
					
						
							|  |  |  |         item_match = item_regex.search(line) | 
					
						
							|  |  |  |         if item_match: | 
					
						
							|  |  |  |             # print 'item_rules:', item_match.groups() | 
					
						
							|  |  |  |             item_rules = optional_match_group(item_match, 1) | 
					
						
							|  |  |  |             item_type = optional_match_group(item_match, 2) | 
					
						
							|  |  |  |             item_name = optional_match_group(item_match, 3) | 
					
						
							|  |  |  |             item_index = optional_match_group(item_match, 4) | 
					
						
							|  |  |  |             # item_defaults_1 = optional_match_group(item_match, 5) | 
					
						
							|  |  |  |             item_default = optional_match_group(item_match, 6) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |             # print 'item_rules:', item_rules | 
					
						
							|  |  |  |             # print 'item_type:', item_type | 
					
						
							|  |  |  |             # print 'item_name:', item_name | 
					
						
							|  |  |  |             # print 'item_index:', item_index | 
					
						
							|  |  |  |             # print 'item_default:', item_default | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             message_field = { | 
					
						
							|  |  |  |                 'rules': item_rules, | 
					
						
							|  |  |  |                 'type': item_type, | 
					
						
							|  |  |  |                 'name': item_name, | 
					
						
							|  |  |  |                 'index': item_index, | 
					
						
							|  |  |  |                 'default': item_default, | 
					
						
							|  |  |  |                 'field_comments': field_comments, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             # print 'message_field:', message_field | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |             # if args.verbose: | 
					
						
							|  |  |  |             #     print '\t message field[%s]: %s' % (item_index, str(message_field)) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             if item_name in context.field_names(): | 
					
						
							|  |  |  |                 raise Exception('Duplicate message field name[%s]: %s' % (proto_file_path, item_name)) | 
					
						
							|  |  |  |             # context.field_names.add(item_name) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             if item_index in context.field_indices(): | 
					
						
							|  |  |  |                 raise Exception('Duplicate message field index[%s]: %s' % (proto_file_path, item_name)) | 
					
						
							|  |  |  |             # context.field_indices.add(item_index) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             is_required = '@required' in field_comments | 
					
						
							|  |  |  |             # if is_required: | 
					
						
							|  |  |  |             #     print 'is_required:', item_name | 
					
						
							|  |  |  |             context.field_map[item_index] = MessageField(item_name, item_index, item_rules, item_type, item_default, sort_index, is_required) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             sort_index = sort_index + 1 | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         raise Exception('Invalid message syntax[%s]: %s' % (proto_file_path, line)) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def preserve_validation_logic(args, proto_file_path, dst_file_path): | 
					
						
							|  |  |  |     args.validation_map = {} | 
					
						
							|  |  |  |     if os.path.exists(dst_file_path): | 
					
						
							|  |  |  |         with open(dst_file_path, 'rt') as f: | 
					
						
							|  |  |  |             old_text = f.read() | 
					
						
							|  |  |  |         validation_start_regex = re.compile(r'// MARK: - Begin Validation Logic for ([^ ]+) -') | 
					
						
							|  |  |  |         for match in validation_start_regex.finditer(old_text): | 
					
						
							|  |  |  |             # print 'match' | 
					
						
							|  |  |  |             name = match.group(1) | 
					
						
							|  |  |  |             # print '\t name:', name | 
					
						
							|  |  |  |             start = match.end(0) | 
					
						
							|  |  |  |             # print '\t start:', start | 
					
						
							|  |  |  |             end_marker = '// MARK: - End Validation Logic for %s -' % name | 
					
						
							|  |  |  |             end = old_text.find(end_marker) | 
					
						
							|  |  |  |             # print '\t end:', end | 
					
						
							|  |  |  |             if end < start: | 
					
						
							|  |  |  |                 raise Exception('Malformed validation: %s, %s' % ( proto_file_path, name, ) ) | 
					
						
							|  |  |  |             validation_block = old_text[start:end] | 
					
						
							|  |  |  |             # print '\t validation_block:', validation_block | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             # Strip trailing whitespace. | 
					
						
							|  |  |  |             validation_lines = validation_block.split('\n') | 
					
						
							|  |  |  |             validation_lines = [line.rstrip() for line in validation_lines] | 
					
						
							|  |  |  |             # Strip leading empty lines. | 
					
						
							|  |  |  |             while len(validation_lines) > 0 and validation_lines[0] == '': | 
					
						
							|  |  |  |                 validation_lines = validation_lines[1:] | 
					
						
							|  |  |  |             # Strip trailing empty lines. | 
					
						
							|  |  |  |             while len(validation_lines) > 0 and validation_lines[-1] == '': | 
					
						
							|  |  |  |                 validation_lines = validation_lines[:-1] | 
					
						
							|  |  |  |             validation_block = '\n'.join(validation_lines) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             if len(validation_block) > 0: | 
					
						
							|  |  |  |                 if args.verbose: | 
					
						
							|  |  |  |                     print('Preserving validation logic for:', name) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             args.validation_map[name] = validation_block | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  | def process_proto_file(args, proto_file_path, dst_file_path): | 
					
						
							|  |  |  |     with open(proto_file_path, 'rt') as f: | 
					
						
							|  |  |  |         text = f.read() | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     multiline_comment_regex = re.compile(r'/\*.*?\*/', re.MULTILINE|re.DOTALL) | 
					
						
							|  |  |  |     text = multiline_comment_regex.sub('', text) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     syntax_regex = re.compile(r'^syntax ') | 
					
						
							|  |  |  |     package_regex = re.compile(r'^package\s+(.+);') | 
					
						
							|  |  |  |     option_regex = re.compile(r'^option ') | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     parser = LineParser(text) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     # lineParser = LineParser(text.split('\n')) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     context = FileContext(args) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     while True: | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             line = parser.next() | 
					
						
							|  |  |  |         except StopIteration: | 
					
						
							|  |  |  |             break | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if syntax_regex.search(line): | 
					
						
							|  |  |  |             if args.verbose: | 
					
						
							|  |  |  |                 print('# Ignoring syntax') | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         if option_regex.search(line): | 
					
						
							|  |  |  |             if args.verbose: | 
					
						
							|  |  |  |                 print('# Ignoring option') | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         package_match = package_regex.search(line) | 
					
						
							|  |  |  |         if package_match: | 
					
						
							|  |  |  |             if args.package: | 
					
						
							|  |  |  |                 raise Exception('More than one package statement: %s' % proto_file_path) | 
					
						
							|  |  |  |             args.package = package_match.group(1).strip() | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             if args.verbose: | 
					
						
							|  |  |  |                 print('# package:', args.package) | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         message_regex = re.compile(r'^message\s+(.+?)\s+\{$') | 
					
						
							|  |  |  |         message_match = message_regex.search(line) | 
					
						
							|  |  |  |         if message_match: | 
					
						
							|  |  |  |             message_name = message_match.group(1).strip() | 
					
						
							|  |  |  |             parse_message(args, proto_file_path, parser, context, message_name) | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |         raise Exception('Invalid syntax[%s]: %s' % (proto_file_path, line)) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     preserve_validation_logic(args, proto_file_path, dst_file_path) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     writer = LineWriter(args) | 
					
						
							|  |  |  |     context.prepare() | 
					
						
							|  |  |  |     context.generate(writer) | 
					
						
							|  |  |  |     output = writer.join() | 
					
						
							|  |  |  |     with open(dst_file_path, 'wt') as f: | 
					
						
							|  |  |  |         f.write(output) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     parser = argparse.ArgumentParser(description='Protocol Buffer Swift Wrapper Generator.') | 
					
						
							|  |  |  |     # parser.add_argument('--all', action='store_true', help='process all files in or below current dir') | 
					
						
							|  |  |  |     # parser.add_argument('--path', help='used to specify a path to a file.') | 
					
						
							|  |  |  |     parser.add_argument('--proto-dir', help='dir path of the proto schema file.') | 
					
						
							|  |  |  |     parser.add_argument('--proto-file', help='filename of the proto schema file.') | 
					
						
							|  |  |  |     parser.add_argument('--wrapper-prefix', help='name prefix for generated wrappers.') | 
					
						
							|  |  |  |     parser.add_argument('--proto-prefix', help='name prefix for proto bufs.') | 
					
						
							|  |  |  |     parser.add_argument('--dst-dir', help='path to the destination directory.') | 
					
						
							|  |  |  |     parser.add_argument('--add-log-tag', action='store_true', help='add log tag properties.') | 
					
						
							|  |  |  |     parser.add_argument('--add-description', action='store_true', help='add log tag properties.') | 
					
						
							|  |  |  |     parser.add_argument('--verbose', action='store_true', help='enables verbose logging') | 
					
						
							|  |  |  |     args = parser.parse_args() | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     if args.verbose: | 
					
						
							|  |  |  |         print('args:', args) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     proto_file_path = os.path.abspath(os.path.join(args.proto_dir, args.proto_file)) | 
					
						
							|  |  |  |     if not os.path.exists(proto_file_path): | 
					
						
							|  |  |  |         raise Exception('File does not exist: %s' % proto_file_path) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     dst_dir_path = os.path.abspath(args.dst_dir) | 
					
						
							|  |  |  |     if not os.path.exists(dst_dir_path): | 
					
						
							|  |  |  |         raise Exception('Destination does not exist: %s' % dst_dir_path) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     dst_file_path = os.path.join(dst_dir_path, "%s.swift" % args.wrapper_prefix) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     if args.verbose: | 
					
						
							|  |  |  |         print('dst_file_path:', dst_file_path) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     args.package = None | 
					
						
							|  |  |  |     process_proto_file(args, proto_file_path, dst_file_path) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     # print 'complete.' | 
					
						
							|  |  |  |      |