197 lines
5.6 KiB
Python
197 lines
5.6 KiB
Python
from __future__ import absolute_import, division, print_function, unicode_literals
|
|
|
|
from contextlib import contextmanager
|
|
|
|
from stone.ir import (
|
|
Boolean,
|
|
Bytes,
|
|
DataType,
|
|
Float32,
|
|
Float64,
|
|
Int32,
|
|
Int64,
|
|
List,
|
|
String,
|
|
Timestamp,
|
|
UInt32,
|
|
UInt64,
|
|
Void,
|
|
is_list_type,
|
|
is_timestamp_type,
|
|
is_union_type,
|
|
is_user_defined_type,
|
|
unwrap_nullable,
|
|
)
|
|
from stone.backend import CodeBackend
|
|
from stone.backends.swift_helpers import (
|
|
fmt_class,
|
|
fmt_func,
|
|
fmt_obj,
|
|
fmt_type,
|
|
fmt_var,
|
|
)
|
|
|
|
|
|
_serial_type_table = {
|
|
Boolean: 'BoolSerializer',
|
|
Bytes: 'NSDataSerializer',
|
|
Float32: 'FloatSerializer',
|
|
Float64: 'DoubleSerializer',
|
|
Int32: 'Int32Serializer',
|
|
Int64: 'Int64Serializer',
|
|
List: 'ArraySerializer',
|
|
String: 'StringSerializer',
|
|
Timestamp: 'NSDateSerializer',
|
|
UInt32: 'UInt32Serializer',
|
|
UInt64: 'UInt64Serializer',
|
|
Void: 'VoidSerializer',
|
|
}
|
|
|
|
|
|
stone_warning = """\
|
|
///
|
|
/// Copyright (c) 2016 Dropbox, Inc. All rights reserved.
|
|
///
|
|
/// Auto-generated by Stone, do not modify.
|
|
///
|
|
|
|
"""
|
|
|
|
# This will be at the top of the generated file.
|
|
base = """\
|
|
{}\
|
|
import Foundation
|
|
|
|
""".format(stone_warning)
|
|
|
|
|
|
undocumented = '(no description)'
|
|
|
|
|
|
class SwiftBaseBackend(CodeBackend):
|
|
"""Wrapper class over Stone generator for Swift logic."""
|
|
# pylint: disable=abstract-method
|
|
|
|
@contextmanager
|
|
def function_block(self, func, args, return_type=None):
|
|
signature = '{}({})'.format(func, args)
|
|
if return_type:
|
|
signature += ' -> {}'.format(return_type)
|
|
with self.block(signature):
|
|
yield
|
|
|
|
def _func_args(self, args_list, newlines=False, force_first=False, not_init=False):
|
|
out = []
|
|
first = True
|
|
for k, v in args_list:
|
|
# this is a temporary hack -- injected client-side args
|
|
# do not have a separate field for default value. Right now,
|
|
# default values are stored along with the type, e.g.
|
|
# `Bool = True` is a type, hence this check.
|
|
if first and force_first and '=' not in v:
|
|
k = "{0} {0}".format(k)
|
|
|
|
if first and v is not None and not_init:
|
|
out.append('{}'.format(v))
|
|
elif v is not None:
|
|
out.append('{}: {}'.format(k, v))
|
|
first = False
|
|
sep = ', '
|
|
if newlines:
|
|
sep += '\n' + self.make_indent()
|
|
return sep.join(out)
|
|
|
|
@contextmanager
|
|
def class_block(self, thing, protocols=None):
|
|
protocols = protocols or []
|
|
extensions = []
|
|
|
|
if isinstance(thing, DataType):
|
|
name = fmt_class(thing.name)
|
|
if thing.parent_type:
|
|
extensions.append(fmt_type(thing.parent_type))
|
|
else:
|
|
name = thing
|
|
extensions.extend(protocols)
|
|
|
|
extend_suffix = ': {}'.format(', '.join(extensions)) if extensions else ''
|
|
|
|
with self.block('open class {}{}'.format(name, extend_suffix)):
|
|
yield
|
|
|
|
def _struct_init_args(self, data_type, namespace=None): # pylint: disable=unused-argument
|
|
args = []
|
|
for field in data_type.all_fields:
|
|
name = fmt_var(field.name)
|
|
value = fmt_type(field.data_type)
|
|
data_type, nullable = unwrap_nullable(field.data_type)
|
|
|
|
if field.has_default:
|
|
if is_union_type(data_type):
|
|
default = '.{}'.format(fmt_var(field.default.tag_name))
|
|
else:
|
|
default = fmt_obj(field.default)
|
|
value += ' = {}'.format(default)
|
|
elif nullable:
|
|
value += ' = nil'
|
|
arg = (name, value)
|
|
args.append(arg)
|
|
return args
|
|
|
|
def _docf(self, tag, val):
|
|
if tag == 'route':
|
|
if ':' in val:
|
|
val, version = val.split(':', 1)
|
|
version = int(version)
|
|
else:
|
|
version = 1
|
|
return fmt_func(val, version)
|
|
elif tag == 'field':
|
|
if '.' in val:
|
|
cls, field = val.split('.')
|
|
return ('{} in {}'.format(fmt_var(field),
|
|
fmt_class(cls)))
|
|
else:
|
|
return fmt_var(val)
|
|
elif tag in ('type', 'val', 'link'):
|
|
return val
|
|
else:
|
|
import pdb
|
|
pdb.set_trace()
|
|
return val
|
|
|
|
def fmt_serial_type(data_type):
|
|
data_type, nullable = unwrap_nullable(data_type)
|
|
|
|
if is_user_defined_type(data_type):
|
|
result = '{}.{}Serializer'
|
|
result = result.format(fmt_class(data_type.namespace.name),
|
|
fmt_class(data_type.name))
|
|
else:
|
|
result = _serial_type_table.get(data_type.__class__, fmt_class(data_type.name))
|
|
|
|
if is_list_type(data_type):
|
|
result = result + '<{}>'.format(fmt_serial_type(data_type.data_type))
|
|
|
|
return result if not nullable else 'NullableSerializer'
|
|
|
|
|
|
def fmt_serial_obj(data_type):
|
|
data_type, nullable = unwrap_nullable(data_type)
|
|
|
|
if is_user_defined_type(data_type):
|
|
result = '{}.{}Serializer()'
|
|
result = result.format(fmt_class(data_type.namespace.name),
|
|
fmt_class(data_type.name))
|
|
else:
|
|
result = _serial_type_table.get(data_type.__class__, fmt_class(data_type.name))
|
|
|
|
if is_list_type(data_type):
|
|
result = result + '({})'.format(fmt_serial_obj(data_type.data_type))
|
|
elif is_timestamp_type(data_type):
|
|
result = result + '("{}")'.format(data_type.format)
|
|
else:
|
|
result = 'Serialization._{}'.format(result)
|
|
|
|
return result if not nullable else 'NullableSerializer({})'.format(result)
|