Commit ad018408 authored by Miro Knejp's avatar Miro Knejp Committed by Jacob Potter

Introduce marshalling object for Objective-C++ code generator

parent d0d4cc93
...@@ -28,6 +28,10 @@ import scala.collection.parallel.immutable ...@@ -28,6 +28,10 @@ import scala.collection.parallel.immutable
class ObjcppGenerator(spec: Spec) extends Generator(spec) { class ObjcppGenerator(spec: Spec) extends Generator(spec) {
val objcMarshal = new ObjcMarshal(spec)
val objcppMarshal = new ObjcppMarshal(spec)
val cppMarshal = new CppMarshal(spec)
class ObjcRefs() { class ObjcRefs() {
var body = mutable.TreeSet[String]() var body = mutable.TreeSet[String]()
var header = mutable.TreeSet[String]() var header = mutable.TreeSet[String]()
...@@ -48,17 +52,17 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -48,17 +52,17 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
header.add("#import <Foundation/Foundation.h>") header.add("#import <Foundation/Foundation.h>")
val ext = d.body.asInstanceOf[Interface].ext val ext = d.body.asInstanceOf[Interface].ext
if (ext.cpp) { if (ext.cpp) {
header.add("@class " + idObjc.ty(d.name) + ";") header.add("@class " + objcMarshal.typename(tm) + ";")
body.add("#import " + q(spec.objcIncludePrivatePrefix + privateHeaderName(d.name))) body.add("#import " + q(spec.objcIncludePrivatePrefix + privateHeaderName(d.name)))
} }
if (ext.objc) { if (ext.objc) {
header.add("@protocol " + idObjc.ty(d.name) + ";") header.add("@protocol " + objcMarshal.typename(tm) + ";")
body.add("#import " + q(spec.objcIncludePrivatePrefix + privateHeaderName(d.name + "_objc_proxy"))) body.add("#import " + q(spec.objcIncludePrivatePrefix + privateHeaderName(d.name + "_objc_proxy")))
} }
case DRecord => case DRecord =>
val r = d.body.asInstanceOf[Record] val r = d.body.asInstanceOf[Record]
val prefix = if (r.ext.objc) "../" else "" val prefix = if (r.ext.objc) "../" else ""
header.add("@class " + idObjc.ty(d.name) + ";") header.add("@class " + objcMarshal.typename(tm) + ";")
body.add("#import " + q(spec.objcIncludePrivatePrefix + prefix + privateHeaderName(d.name))) body.add("#import " + q(spec.objcIncludePrivatePrefix + prefix + privateHeaderName(d.name)))
} }
case p: MParam => case p: MParam =>
...@@ -78,8 +82,8 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -78,8 +82,8 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
refs.body.add("#import <Foundation/Foundation.h>") refs.body.add("#import <Foundation/Foundation.h>")
refs.body.add("!#import " + q(spec.objcIncludePrivatePrefix + enumTranslatorHeaderName(ident))) refs.body.add("!#import " + q(spec.objcIncludePrivatePrefix + enumTranslatorHeaderName(ident)))
val self = idObjc.ty(ident) val self = objcMarshal.typename(ident, e)
val cppSelf = withNs(spec.cppNamespace, idCpp.enumType(ident)) val cppSelf = cppMarshal.fqTypename(ident, e)
val name = IdentStyle.camelUpper(ident) val name = IdentStyle.camelUpper(ident)
val argName = idObjc.local(ident.name) val argName = idObjc.local(ident.name)
...@@ -178,7 +182,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -178,7 +182,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
refs.find(c.ty) refs.find(c.ty)
}) })
val self = idObjc.ty(ident) val self = objcMarshal.typename(ident, i)
refs.privHeader.add("#import <Foundation/Foundation.h>") refs.privHeader.add("#import <Foundation/Foundation.h>")
refs.privHeader.add("#include <memory>") refs.privHeader.add("#include <memory>")
...@@ -198,7 +202,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -198,7 +202,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
} }
} }
val cppName = withNs(spec.cppNamespace, idCpp.ty(ident)) val cppSelf = cppMarshal.fqTypename(ident, i)
if (i.ext.cpp) { if (i.ext.cpp) {
refs.body.add("!#import " + q(spec.objcIncludePrivatePrefix + privateHeaderName(ident.name))) refs.body.add("!#import " + q(spec.objcIncludePrivatePrefix + privateHeaderName(ident.name)))
refs.body.add("#import " + q(spec.objcBaseLibIncludePrefix + "DJICppWrapperCache+Private.h")) refs.body.add("#import " + q(spec.objcBaseLibIncludePrefix + "DJICppWrapperCache+Private.h"))
...@@ -210,9 +214,9 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -210,9 +214,9 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
writeObjcFile(privateHeaderName(ident.name), origin, refs.privHeader, w => { writeObjcFile(privateHeaderName(ident.name), origin, refs.privHeader, w => {
w.wl(s"@interface $self ()") w.wl(s"@interface $self ()")
w.wl w.wl
w.wl(s"@property (nonatomic, readonly) std::shared_ptr<$cppName> cppRef;") w.wl(s"@property (nonatomic, readonly) std::shared_ptr<$cppSelf> cppRef;")
w.wl w.wl
w.wl(s"+ (id)${idObjc.method(ident.name + "_with_cpp")}:(const std::shared_ptr<$cppName> &)cppRef;") w.wl(s"+ (id)${idObjc.method(ident.name + "_with_cpp")}:(const std::shared_ptr<$cppSelf> &)cppRef;")
w.wl w.wl
w.wl("@end") w.wl("@end")
}) })
...@@ -222,12 +226,12 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -222,12 +226,12 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
if (i.consts.nonEmpty) generateObjcConstants(w, i.consts, self) if (i.consts.nonEmpty) generateObjcConstants(w, i.consts, self)
w.wl w.wl
w.wl(s"@interface $self ()") w.wl(s"@interface $self ()")
w.wl(s"@property (nonatomic, readonly) std::shared_ptr<djinni::DbxCppWrapperCache<$cppName>> cache;") w.wl(s"@property (nonatomic, readonly) std::shared_ptr<djinni::DbxCppWrapperCache<$cppSelf>> cache;")
w.wl("@end") w.wl("@end")
w.wl w.wl
w.wl(s"@implementation $self") w.wl(s"@implementation $self")
w.wl w.wl
w.wl(s"- (id)initWithCpp:(const std::shared_ptr<$cppName> &)cppRef cache:(const std::shared_ptr<djinni::DbxCppWrapperCache<$cppName>> &)cache") w.wl(s"- (id)initWithCpp:(const std::shared_ptr<$cppSelf> &)cppRef cache:(const std::shared_ptr<djinni::DbxCppWrapperCache<$cppSelf>> &)cache")
w.braced { w.braced {
w.w("if (self = [super init])").braced { w.w("if (self = [super init])").braced {
w.wl("_cppRef = cppRef;") w.wl("_cppRef = cppRef;")
...@@ -241,10 +245,10 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -241,10 +245,10 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
w.wl("_cache->remove(_cppRef);") w.wl("_cache->remove(_cppRef);")
} }
w.wl w.wl
w.wl(s"+ (id)${idObjc.method(ident.name + "_with_cpp")}:(const std::shared_ptr<$cppName> &)cppRef") w.wl(s"+ (id)${idObjc.method(ident.name + "_with_cpp")}:(const std::shared_ptr<$cppSelf> &)cppRef")
w.braced { w.braced {
w.wl(s"const auto & cache = djinni::DbxCppWrapperCache<$cppName>::getInstance();") w.wl(s"const auto & cache = djinni::DbxCppWrapperCache<$cppSelf>::getInstance();")
w.wl(s"return cache->get(cppRef, [&] (const std::shared_ptr<$cppName> & p) { return [[$self alloc] initWithCpp:p cache:cache]; });") w.wl(s"return cache->get(cppRef, [&] (const std::shared_ptr<$cppSelf> & p) { return [[$self alloc] initWithCpp:p cache:cache]; });")
} }
for (m <- i.methods) { for (m <- i.methods) {
w.wl w.wl
...@@ -255,12 +259,12 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -255,12 +259,12 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
translateObjcTypeToCpp(idObjc.local("cpp_" + p.ident.name), idObjc.local(p.ident.name), p.ty, w) translateObjcTypeToCpp(idObjc.local("cpp_" + p.ident.name), idObjc.local(p.ident.name), p.ty, w)
} }
val params = m.params.map(p => "std::move(" + idObjc.local("cpp_" + p.ident.name) + ")").mkString("(", ", ", ")") val params = m.params.map(p => "std::move(" + idObjc.local("cpp_" + p.ident.name) + ")").mkString("(", ", ", ")")
val cppRef = if (!m.static) "_cppRef->" else cppName + "::" val cppRef = if (!m.static) "_cppRef->" else cppSelf + "::"
m.ret match { m.ret match {
case None => case None =>
w.wl(s"$cppRef${idCpp.method(m.ident)}$params;") w.wl(s"$cppRef${idCpp.method(m.ident)}$params;")
case Some(r) => case Some(r) =>
w.wl(s"${toCppType(r, spec.cppNamespace)} cppRet = $cppRef${idCpp.method(m.ident)}$params;") w.wl(s"${cppMarshal.fqTypename(r)} cppRet = $cppRef${idCpp.method(m.ident)}$params;")
translateCppTypeToObjc("objcRet", "cppRet", r, true, w) translateCppTypeToObjc("objcRet", "cppRet", r, true, w)
w.wl("return objcRet;") w.wl("return objcRet;")
} }
...@@ -273,23 +277,23 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -273,23 +277,23 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
}) })
} }
val objcExtName = ident.name + "_objc_proxy"
val objcExtSelf = idCpp.ty(objcExtName)
if (i.ext.objc) { if (i.ext.objc) {
val objcExtName = ident.name + "_objc_proxy"
val objcExtSelf = objcppMarshal.helperClass(objcExtName)
refs.privHeader.add("#import " + q(spec.objcBaseLibIncludePrefix + "DJIObjcWrapperCache+Private.h")) refs.privHeader.add("#import " + q(spec.objcBaseLibIncludePrefix + "DJIObjcWrapperCache+Private.h"))
refs.body.add("!#import " + q(spec.objcIncludePrivatePrefix + privateHeaderName(objcExtName))) refs.body.add("!#import " + q(spec.objcIncludePrivatePrefix + privateHeaderName(objcExtName)))
writeObjcFile(privateHeaderName(objcExtName), origin, refs.privHeader, w => { writeObjcFile(privateHeaderName(objcExtName), origin, refs.privHeader, w => {
wrapNamespace(w, Some(spec.objcppNamespace), (w: IndentWriter) => { wrapNamespace(w, Some(spec.objcppNamespace), (w: IndentWriter) => {
w.wl(s"class $objcExtSelf final : public ${withNs(spec.cppNamespace, idCpp.ty(ident))}").bracedSemi { w.wl(s"class $objcExtSelf final : public $cppSelf").bracedSemi {
w.wl("public:") w.wl("public:")
w.wl(s"const id <$self> _objcRef;") w.wl(s"const id <$self> _objcRef;")
w.wl(s"const std::shared_ptr<djinni::DbxObjcWrapperCache<$objcExtSelf>> _cache;") w.wl(s"const std::shared_ptr<djinni::DbxObjcWrapperCache<$objcExtSelf>> _cache;")
w.wl w.wl
w.wl(s"explicit $objcExtSelf (id objcRef);") w.wl(s"explicit $objcExtSelf (id objcRef);")
w.wl(s"virtual ~$objcExtSelf () override;") w.wl(s"virtual ~$objcExtSelf () override;")
w.wl(s"static std::shared_ptr<${withNs(spec.cppNamespace, idCpp.ty(ident.name))}> ${idCpp.method(ident.name + "_with_objc")} (id<$self> objcRef);") w.wl(s"static std::shared_ptr<$cppSelf> ${idCpp.method(ident.name + "_with_objc")} (id<$self> objcRef);")
for (m <- i.methods) { for (m <- i.methods) {
val ret = m.ret.fold("void")(toCppType(_, spec.cppNamespace)) val ret = m.ret.fold("void")(cppMarshal.fqTypename)
val params = m.params.map(p => toCppParamType(p, spec.cppNamespace)) val params = m.params.map(p => toCppParamType(p, spec.cppNamespace))
w.wl(s"virtual $ret ${idCpp.method(m.ident)} ${params.mkString("(", ", ", ")")} override;") w.wl(s"virtual $ret ${idCpp.method(m.ident)} ${params.mkString("(", ", ", ")")} override;")
} }
...@@ -308,12 +312,12 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -308,12 +312,12 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
w.wl(s"_cache->remove(_objcRef);") w.wl(s"_cache->remove(_objcRef);")
} }
w.wl w.wl
w.wl(s"std::shared_ptr<${withNs(spec.cppNamespace, idCpp.ty(ident))}> $objcExtSelf::${idCpp.method(ident.name + "_with_objc")} (id<$self> objcRef)").braced { w.wl(s"std::shared_ptr<$cppSelf> $objcExtSelf::${idCpp.method(ident.name + "_with_objc")} (id<$self> objcRef)").braced {
w.wl(s"return djinni::DbxObjcWrapperCache<$objcExtSelf>::getInstance()->get(objcRef);") w.wl(s"return djinni::DbxObjcWrapperCache<$objcExtSelf>::getInstance()->get(objcRef);")
} }
for (m <- i.methods) { for (m <- i.methods) {
w.wl w.wl
val ret = m.ret.fold("void")(toCppType(_, spec.cppNamespace)) val ret = m.ret.fold("void")(cppMarshal.fqTypename)
val params = m.params.map(p => toCppParamType(p, spec.cppNamespace)) val params = m.params.map(p => toCppParamType(p, spec.cppNamespace))
w.wl(s"$ret $objcExtSelf::${idCpp.method(m.ident)} ${params.mkString("(", ", ", ")")}").braced { w.wl(s"$ret $objcExtSelf::${idCpp.method(m.ident)} ${params.mkString("(", ", ", ")")}").braced {
w.w("@autoreleasepool").braced { w.w("@autoreleasepool").braced {
...@@ -347,9 +351,9 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -347,9 +351,9 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
refs.find(f.ty) refs.find(f.ty)
val objcName = ident.name + (if (r.ext.objc) "_base" else "") val objcName = ident.name + (if (r.ext.objc) "_base" else "")
val noBaseSelf = idObjc.ty(ident) // Used for constant names val noBaseSelf = objcMarshal.typename(ident, r) // Used for constant names
val self = idObjc.ty(objcName) val self = objcMarshal.typename(objcName, r)
val cppSelf = withNs(spec.cppNamespace, idCpp.ty(ident)) val cppSelf = cppMarshal.fqTypename(ident, r)
refs.header.add("#import <Foundation/Foundation.h>") refs.header.add("#import <Foundation/Foundation.h>")
...@@ -366,7 +370,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -366,7 +370,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
if (r.ext.objc) { if (r.ext.objc) {
refs.body.add("#import " + q(spec.objcIncludePrefix + "../" + headerName(ident))) refs.body.add("#import " + q(spec.objcIncludePrefix + "../" + headerName(ident)))
refs.privHeader.add("#import " + q(spec.objcIncludePrefix + "../" + headerName(ident))) refs.privHeader.add("#import " + q(spec.objcIncludePrefix + "../" + headerName(ident)))
refs.header.add(s"@class ${idObjc.ty(ident.name)};") refs.header.add(s"@class ${objcMarshal.typename(ident, r)};")
} }
def checkMutable(tm: MExpr): Boolean = tm.base match { def checkMutable(tm: MExpr): Boolean = tm.base match {
...@@ -392,7 +396,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -392,7 +396,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
w.wl w.wl
w.wl(s"@implementation $self") w.wl(s"@implementation $self")
w.wl w.wl
w.wl(s"- (id)${idObjc.method("init_with_" + ident.name)}:(${idObjc.ty(ident)} *)${idObjc.local(ident)}") w.wl(s"- (id)${idObjc.method("init_with_" + ident.name)}:($noBaseSelf *)${idObjc.local(ident)}")
w.braced { w.braced {
w.w("if (self = [super init])").braced { w.w("if (self = [super init])").braced {
for (f <- r.fields) { for (f <- r.fields) {
...@@ -744,7 +748,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) { ...@@ -744,7 +748,7 @@ class ObjcppGenerator(spec: Spec) extends Generator(spec) {
translateObjcTypeToCpp(cppIdent, objcIdent, ty.resolved, w) translateObjcTypeToCpp(cppIdent, objcIdent, ty.resolved, w)
def translateObjcTypeToCpp(cppIdent: String, objcIdent: String, tm: MExpr, w: IndentWriter): Unit = { def translateObjcTypeToCpp(cppIdent: String, objcIdent: String, tm: MExpr, w: IndentWriter): Unit = {
def f(cppIdent: String, objcIdent: String, tm: MExpr, needRef: Boolean, w: IndentWriter, valueLevel: Int): Unit = { def f(cppIdent: String, objcIdent: String, tm: MExpr, needRef: Boolean, w: IndentWriter, valueLevel: Int): Unit = {
val cppType = toCppType(tm, spec.cppNamespace) val cppType = cppMarshal.fqTypename(tm)
tm.base match { tm.base match {
case MOptional => case MOptional =>
// We use "nil" for the empty optional. // We use "nil" for the empty optional.
......
package djinni
import djinni.ast._
import djinni.generatorTools._
import djinni.meta._
class ObjcppMarshal(spec: Spec) extends Marshal(spec) {
override def typename(tm: MExpr): String = throw new AssertionError("Objcpp has no public types")
def typename(name: String, ty: TypeDef): String = throw new AssertionError("Objcpp has no public types")
override def fqTypename(tm: MExpr): String = throw new AssertionError("Objcpp has no public types")
def fqTypename(name: String, ty: TypeDef): String = throw new AssertionError("Objcpp has no public types")
// Name for the autogenerated proxy class wrapping +o interfaces
def helperClass(name: String) = idCpp.ty(name)
def fqHelperClass(name: String) = withNs(Some(spec.objcppNamespace), helperClass(name))
// Return value: (Type_Name, Is_Class_Or_Not)
def toObjcType(ty: TypeRef): (String, Boolean) = toObjcType(ty.resolved, false)
def toObjcType(ty: TypeRef, needRef: Boolean): (String, Boolean) = toObjcType(ty.resolved, needRef)
def toObjcType(tm: MExpr): (String, Boolean) = toObjcType(tm, false)
def toObjcType(tm: MExpr, needRef: Boolean): (String, Boolean) = {
def f(tm: MExpr, needRef: Boolean): (String, Boolean) = {
tm.base match {
case MOptional =>
// We use "nil" for the empty optional.
assert(tm.args.size == 1)
val arg = tm.args.head
arg.base match {
case MOptional => throw new AssertionError("nested optional?")
case m => f(arg, true)
}
case o =>
val base = o match {
case p: MPrimitive => if (needRef) (p.objcBoxed, true) else (p.objcName, false)
case MString => ("NSString", true)
case MDate => ("NSDate", true)
case MBinary => ("NSData", true)
case MOptional => throw new AssertionError("optional should have been special cased")
case MList => ("NSArray", true)
case MSet => ("NSSet", true)
case MMap => ("NSDictionary", true)
case d: MDef => d.defType match {
case DEnum => if (needRef) ("NSNumber", true) else (idObjc.ty(d.name), false)
case DRecord => (idObjc.ty(d.name), true)
case DInterface =>
val ext = d.body.asInstanceOf[Interface].ext
(idObjc.ty(d.name), false)
}
case p: MParam => throw new AssertionError("Parameter should not happen at Obj-C top level")
}
base
}
}
f(tm, needRef)
}
}
...@@ -281,8 +281,8 @@ abstract class Generator(spec: Spec) ...@@ -281,8 +281,8 @@ abstract class Generator(spec: Spec)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// Render type expression // Render type expression
def toCppType(ty: TypeRef, namespace: Option[String] = None): String = toCppType(ty.resolved, namespace) private def toCppType(ty: TypeRef, namespace: Option[String] = None): String = toCppType(ty.resolved, namespace)
def toCppType(tm: MExpr, namespace: Option[String]): String = { private def toCppType(tm: MExpr, namespace: Option[String]): String = {
def base(m: Meta): String = m match { def base(m: Meta): String = m match {
case p: MPrimitive => p.cName case p: MPrimitive => p.cName
case MString => "std::string" case MString => "std::string"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment