frappe/env/lib/python3.12/site-packages/stone/backends/swift.py

314 lines
10 KiB
Python

from contextlib import contextmanager
import os
from stone.backend import CodeBackend
from stone.backends.swift_helpers import (
fmt_class,
fmt_func,
fmt_obj,
fmt_type,
fmt_var,
fmt_objc_type,
mapped_list_info,
)
from stone.ir import (
Boolean,
Bytes,
Float32,
Float64,
Int32,
Int64,
List,
Map,
String,
Timestamp,
UInt32,
UInt64,
Void,
is_list_type,
is_map_type,
is_timestamp_type,
is_union_type,
is_user_defined_type,
unwrap_nullable,
is_nullable_type,
)
_serial_type_table = {
Boolean: 'BoolSerializer',
Bytes: 'NSDataSerializer',
Float32: 'FloatSerializer',
Float64: 'DoubleSerializer',
Int32: 'Int32Serializer',
Int64: 'Int64Serializer',
List: 'ArraySerializer',
Map: 'DictionarySerializer',
String: 'StringSerializer',
Timestamp: 'NSDateSerializer',
UInt32: 'UInt32Serializer',
UInt64: 'UInt64Serializer',
Void: 'VoidSerializer',
}
_nsnumber_type_table = {
Boolean: '.boolValue',
Bytes: '',
Float32: '.floatValue',
Float64: '.doubleValue',
Int32: '.int32Value',
Int64: '.int64Value',
List: '',
String: '',
Timestamp: '',
UInt32: '.uint32Value',
UInt64: '.uint64Value',
Void: '',
Map: '',
}
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)
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 _objc_init_args(self, data_type, include_defaults=True):
args = []
for field in data_type.all_fields:
name = fmt_var(field.name)
value = fmt_objc_type(field.data_type)
data_type, nullable = unwrap_nullable(field.data_type)
if not include_defaults and (field.has_default or nullable):
continue
arg = (name, value)
args.append(arg)
return args
def _objc_no_defualts_func_args(self, data_type, args_data=None):
args = []
for field in data_type.all_fields:
name = fmt_var(field.name)
_, nullable = unwrap_nullable(field.data_type)
if field.has_default or nullable:
continue
arg = (name, name)
args.append(arg)
if args_data is not None:
_, type_data_list = tuple(args_data)
extra_args = [tuple(type_data[:-1]) for type_data in type_data_list]
for name, _, extra_type in extra_args:
if not is_nullable_type(extra_type):
arg = (name, name)
args.append(arg)
return self._func_args(args)
def _objc_init_args_to_swift(self, data_type, args_data=None, include_defaults=True):
args = []
for field in data_type.all_fields:
name = fmt_var(field.name)
field_data_type, nullable = unwrap_nullable(field.data_type)
if not include_defaults and (field.has_default or nullable):
continue
nsnumber_type = _nsnumber_type_table.get(field_data_type.__class__)
value = '{}{}{}'.format(name,
'?' if nullable and nsnumber_type else '',
nsnumber_type)
if is_list_type(field_data_type):
_, prefix, suffix, list_data_type, _ = mapped_list_info(field_data_type)
value = '{}{}'.format(name,
'?' if nullable else '')
list_nsnumber_type = _nsnumber_type_table.get(list_data_type.__class__)
if not is_user_defined_type(list_data_type) and not list_nsnumber_type:
value = name
else:
value = '{}.map {}'.format(value,
prefix)
if is_user_defined_type(list_data_type):
value = '{}{{ $0.{} }}'.format(value,
self._objc_swift_var_name(list_data_type))
else:
value = '{}{{ $0{} }}'.format(value,
list_nsnumber_type)
value = '{}{}'.format(value,
suffix)
elif is_map_type(field_data_type):
if is_user_defined_type(field_data_type.value_data_type):
value = '{}{}.mapValues {{ $0.swift }}'.format(name,
'?' if nullable else '')
elif is_user_defined_type(field_data_type):
value = '{}{}.{}'.format(name,
'?' if nullable else '',
self._objc_swift_var_name(field_data_type))
arg = (name, value)
args.append(arg)
if args_data is not None:
_, type_data_list = tuple(args_data)
extra_args = [tuple(type_data[:-1]) for type_data in type_data_list]
for name, _, _ in extra_args:
args.append((name, name))
return self._func_args(args)
def _objc_swift_var_name(self, data_type):
parent_type = data_type.parent_type
uw_parent_type, _ = unwrap_nullable(parent_type)
sub_count = 1 if parent_type else 0
while is_user_defined_type(uw_parent_type) and parent_type.parent_type:
sub_count += 1
parent_type = parent_type.parent_type
uw_parent_type, _ = unwrap_nullable(parent_type)
if sub_count == 0 or is_union_type(data_type):
return 'swift'
else:
name = 'Swift'
i = 1
while i <= sub_count:
name = '{}{}'.format('sub' if i == sub_count else 'Sub',
name)
i += 1
return name
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:
return val
def _write_output_in_target_folder(self, output, file_name):
full_path = self.target_folder_path
if not os.path.exists(full_path):
os.mkdir(full_path)
full_path = os.path.join(full_path, file_name)
with open(full_path, "w", encoding='utf-8') as fh:
fh.write(output)
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))
if is_map_type(data_type):
result = result + '<{}, {}>'.format(fmt_serial_type(data_type.key_data_type),
fmt_serial_type(data_type.value_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_map_type(data_type):
result = result + '({})'.format(fmt_serial_obj(data_type.value_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)