Skip to content
This repository has been archived by the owner on Mar 26, 2020. It is now read-only.

Add Windows Phone (C++/Cx) support #290

Open
wants to merge 53 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
a466a66
Closer to compilation!
Jun 28, 2015
8d00af6
Fixing compiler errors and warnings. Still blind monkey-coding.
Jul 4, 2015
d6b0236
It compiles. Does it emit "C++/Cx" code? Probably. Will it be any goo…
Jul 5, 2015
662580d
A start on a C++/Cx support library.
Jul 8, 2015
eeba8f7
Much progress. Not there yet.
Jul 8, 2015
00d4f05
Proper handling of vectors.
Jul 9, 2015
fd1dabb
Maybe this works?
Jul 11, 2015
ca4dd6d
Have to allocate that sucker.
Jul 11, 2015
b0e531d
Casts and constness and costs and losing my sanity need to take a ste…
Jul 14, 2015
bb08038
A CxWrapperCache that works. Huh.
Jul 14, 2015
e18f2d3
Some half-hearted work on enums and datetime types. Not in a position…
Jul 16, 2015
efdfc2c
Progress in doing Cx translation. This almsot certainly won't compile.
Jul 16, 2015
9b9ff5b
Oh, so much closer. Now we are generating at least some of the code t…
Jul 16, 2015
24cec1f
Let's do something more sophisticated about the various file name ext…
Jul 17, 2015
0bbf65e
No double extensions
Jul 17, 2015
cb1d669
Fixed problem with cxcpp filenames being repeated and hence overwriti…
Jul 17, 2015
cb8a385
Filenaming appears to be sorted out.
Jul 17, 2015
656f5dc
Add proper djinni_generated clas headers, and get rid of double names…
Jul 17, 2015
e3afd06
I think we have C++/Cx types worked out, mostly? Set is going to be a…
Jul 17, 2015
92948ac
More type problems dealt with
Jul 17, 2015
517c007
More progress.
Jul 17, 2015
1dc7555
Now we are on our way to generating real Cx code!
Jul 17, 2015
326918e
Nearly there to valid Cx code! Cpp is next!
Jul 17, 2015
6af9cc0
And everything is basically looking good! Time to check it out in Vis…
Jul 17, 2015
c0317dc
Records seem to be coming out right now in Cx land
Jul 17, 2015
a43b010
The Cx code is getting cleaner and cleaner. Still some lingering issu…
Jul 18, 2015
b162ba9
So many bugs dead.
Jul 18, 2015
49e9dfb
Now works with a simple test project. Lots of work to go, but we now …
Jul 20, 2015
8b0bcce
Optional types for Cx
Jul 23, 2015
80367cd
Bugfixes
Jul 23, 2015
60653f0
Proper boxing of primitive types
Jul 23, 2015
8828393
Getting close to being able to do optional types right.
Jul 23, 2015
171a1ae
Now I think optional types are doing the right thing.
Jul 24, 2015
8fd21ad
Maybe now we have vectors right? ANd maybe even maps?
Jul 24, 2015
6d9d094
Holy crap, WTF
Jul 24, 2015
9d1fc19
Making stuff work. General bug fixes. Esp around use of "^" and Lists…
Jul 27, 2015
67be17a
Fixing a remaining bug
Jul 27, 2015
1c56b86
Add support for Sets in Cx as reflexive maps
Jul 27, 2015
e9f4b6a
Leave off final commas
Aug 3, 2015
39ff602
Stupid awful typo.
Sep 22, 2015
26decdd
Needed include for IInspectable
Aug 3, 2015
ceae696
This doesn't quite fix the problem of optional lists, but we're getti…
Aug 3, 2015
9851437
Typo
Aug 3, 2015
8aad860
Optional types are generated correctly in Cx now.
Aug 4, 2015
18a82d5
Typo. Wow.
Aug 5, 2015
167f9d0
Correct header paths, please!
Aug 6, 2015
e377735
Fixed namespace issue on enum declarations under the Cx covers.
Sep 24, 2015
a7a0304
Proper handling of public static const members
Oct 1, 2015
8ad2da2
Semicolon out of place.
Oct 2, 2015
2320bb4
OH yes, needed to generate the private member too
Oct 2, 2015
0c9222a
Initialize constants the right way.
Oct 2, 2015
2f2be44
In Cpp/Cx, empty Platform::String^ is null. Who knew?
Oct 14, 2015
63adf1b
Merge remote-tracking branch 'upstream/master'
Dec 22, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/source/CppGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ class CppGenerator(spec: Spec) extends Generator(spec) {

val marshal = new CppMarshal(spec)

val writeCppFile = writeCppFileGeneric(spec.cppOutFolder.get, spec.cppNamespace, spec.cppFileIdentStyle, spec.cppIncludePrefix) _
val writeCppFile = writeCppFileGeneric(spec.cppOutFolder.get, spec.cppNamespace, spec.cppFileIdentStyle, spec.cppIncludePrefix, spec.cppExt, spec.cppHeaderExt) _
def writeHppFile(name: String, origin: String, includes: Iterable[String], fwds: Iterable[String], f: IndentWriter => Unit, f2: IndentWriter => Unit = (w => {})) =
writeHppFileGeneric(spec.cppHeaderOutFolder.get, spec.cppNamespace, spec.cppFileIdentStyle)(name, origin, includes, fwds, f, f2)
writeHppFileGeneric(spec.cppHeaderOutFolder.get, spec.cppNamespace, spec.cppFileIdentStyle, spec.cppHeaderExt)(name, origin, includes, fwds, f, f2)

class CppRefs(name: String) {
var hpp = mutable.TreeSet[String]()
Expand Down Expand Up @@ -67,7 +67,7 @@ class CppGenerator(spec: Spec) extends Generator(spec) {
w.w(s"enum class $self : int").bracedSemi {
for (o <- e.options) {
writeDoc(w, o.doc)
w.wl(idCpp.enum(o.ident.name) + ",")
w.wl(idCpp.enum(o.ident.name) + (if(o == e.options.last) "" else ","))
}
}
},
Expand Down
277 changes: 277 additions & 0 deletions src/source/CxCppGenerator.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
/**
* Copyright 2014 Dropbox, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package djinni

import djinni.ast.Record.DerivingType
import djinni.ast._
import djinni.generatorTools._
import djinni.meta._
import djinni.writer.IndentWriter

import scala.collection.mutable

class CxCppGenerator(spec: Spec) extends Generator(spec) {

val cxcppMarshal = new CxCppMarshal(spec)
val cxMarshal = new CxMarshal(spec)
val cppMarshal = new CppMarshal(spec)

val writeCxCppFile = writeCppFileGeneric(spec.cxcppOutFolder.get, spec.cxcppNamespace, spec.cppFileIdentStyle, spec.cxcppIncludePrefix, spec.cxcppExt, spec.cxcppHeaderExt) _
def writeHxFile(name: String, origin: String, includes: Iterable[String], fwds: Iterable[String], f: IndentWriter => Unit, f2: IndentWriter => Unit = (w => {})) =
writeHppFileGeneric(spec.cxcppHeaderOutFolder.get, spec.cxcppNamespace, spec.cppFileIdentStyle, spec.cxcppHeaderExt)(name, origin, includes, fwds, f, f2)

class CxCppRefs(name: String) {
var hx = mutable.TreeSet[String]()
var hxFwds = mutable.TreeSet[String]()
var cxcpp = mutable.TreeSet[String]()

def find(ty: TypeRef) { find(ty.resolved) }
def find(tm: MExpr) {
tm.args.foreach(find)
find(tm.base)
}
def find(m: Meta) = for(r <- cxcppMarshal.references(m)) r match {
case ImportRef(arg) => hx.add("#include " + arg)
case DeclRef(decl, Some(spec.cxcppNamespace)) => hxFwds.add(decl)
case DeclRef(_, _) =>
}
}

override def generateEnum(origin: String, ident: Ident, doc: Doc, e: Enum) {
//nothing required?
}

def generateHxConstants(w: IndentWriter, consts: Seq[Const]) = {
for (c <- consts) {
w.wl
writeDoc(w, c.doc)
w.wl(s"static ${cxcppMarshal.fieldType(c.ty)} const ${idCpp.const(c.ident)};")
}
}

def generateCxCppConstants(w: IndentWriter, consts: Seq[Const], selfName: String) = {
def writeCxCppConst(w: IndentWriter, ty: TypeRef, v: Any): Unit = v match {
case l: Long => w.w(l.toString)
case d: Double if cxcppMarshal.fieldType(ty) == "float" => w.w(d.toString + "f")
case d: Double => w.w(d.toString)
case b: Boolean => w.w(if (b) "true" else "false")
case s: String => w.w(s)
case e: EnumValue => w.w(cxcppMarshal.typename(ty) + "::" + idCpp.enum(e.ty.name + "_" + e.name))
case v: ConstRef => w.w(selfName + "::" + idCpp.const(v))
case z: Map[_, _] => { // Value is record
val recordMdef = ty.resolved.base.asInstanceOf[MDef]
val record = recordMdef.body.asInstanceOf[Record]
val vMap = z.asInstanceOf[Map[String, Any]]
w.wl(cxcppMarshal.typename(ty) + "(")
w.increase()
// Use exact sequence
val skipFirst = SkipFirst()
for (f <- record.fields) {
skipFirst {w.wl(",")}
writeCxCppConst(w, f.ty, vMap.apply(f.ident.name))
w.w(" /* " + idCpp.field(f.ident) + " */ ")
}
w.w(")")
w.decrease()
}
}

val skipFirst = SkipFirst()
for (c <- consts) {
skipFirst{ w.wl }
w.w(s"${cxcppMarshal.fieldType(c.ty)} const $selfName::${idCpp.const(c.ident)} = ")
writeCxCppConst(w, c.ty, c.value)
w.wl(";")
}
}

override def generateRecord(origin: String, ident: Ident, doc: Doc, params: Seq[TypeParam], r: Record) {
val refs = new CxCppRefs(ident.name)
for (c <- r.consts)
refs.find(c.ty)
for (f <- r.fields)
refs.find(f.ty)

val cxName = ident.name + (if (r.ext.cx) "_base" else "")
val cxSelf = cxMarshal.fqTypename(ident, r)
val cppSelf = cppMarshal.fqTypename(ident, r)

refs.hx.add("#include " + q(spec.cxcppIncludeCxPrefix + (if(r.ext.cx) "../" else "") + cxcppMarshal.headerName(ident)+ "." + spec.cxcppHeaderExt))
refs.hx.add("#include " + q(spec.cxIncludePrefix + (if(r.ext.cx) "../" else "") + spec.cxFileIdentStyle(ident) + "." + spec.cxHeaderExt))
refs.hx.add("#include " + q(spec.cxcppIncludeCppPrefix + (if(r.ext.cpp) "../" else "") + spec.cppFileIdentStyle(ident) + "." + spec.cppHeaderExt))

refs.cxcpp = refs.hx.clone()
refs.cxcpp.add("#include <cassert>")

def checkMutable(tm: MExpr): Boolean = tm.base match {
case MOptional => checkMutable(tm.args.head)
case MString => true
case MBinary => true
case _ => false
}

val self = cxcppMarshal.typename(ident, r)

writeHxFile(cxcppMarshal.headerName(cxName), origin, refs.hx, refs.hxFwds, w => {
w.wl
w.wl(s"struct $self")
w.bracedSemi {
w.wl(s"using CppType = $cppSelf;")
w.wl(s"using CxType = $cxSelf^;");
w.wl
w.wl(s"using Boxed = $self;")
w.wl
w.wl(s"static CppType toCpp(CxType cx);")
w.wl(s"static CxType fromCpp(const CppType& cpp);")
}
})

writeCxCppFile(cxcppMarshal.bodyName(self), origin, refs.cxcpp, w => {
w.wl(s"auto $self::toCpp(CxType cx) -> CppType")
w.braced {
w.wl("assert(cx);")
if(r.fields.isEmpty) w.wl("(void)cx; // Suppress warnings in relase builds for empty records")
writeAlignedCall(w, "return {", r.fields, "}", f => cxcppMarshal.toCpp(f.ty, "cx->" + idCx.field(f.ident)))
w.wl(";")
}
w.wl
w.wl(s"auto $self::fromCpp(const CppType& cpp) -> CxType")
w.braced {
if(r.fields.isEmpty) w.wl("(void)cpp; // Suppress warnings in relase builds for empty records")
writeAlignedCall(w, s"return ref new $cxSelf(", r.fields, ")", f=> cxcppMarshal.fromCpp(f.ty, "cpp." + idCpp.field(f.ident)))
w.wl(";")
}
})
}

override def generateInterface(origin: String, ident: Ident, doc: Doc, typeParams: Seq[TypeParam], i: Interface) {
val refs = new CxCppRefs(ident.name)
refs.hx.add("#include \""+spec.cppIncludePrefix + spec.cppFileIdentStyle(ident.name) + "." + spec.cppHeaderExt+"\"")
refs.hx.add("#include \""+spec.cxIncludePrefix + spec.cxFileIdentStyle(ident.name) + "." + spec.cxHeaderExt+"\"")
refs.hx.add("#include <memory>")
i.methods.map(m => {
m.params.map(p => refs.find(p.ty))
m.ret.foreach(refs.find)
})
i.consts.map(c => {
refs.find(c.ty)
})
refs.cxcpp = refs.hx.clone()
refs.cxcpp.add("#include \"CxWrapperCache.h\"")

val self = cxcppMarshal.typename(ident, i)
val cxSelf = cxMarshal.fqTypename(ident, i)
val cppSelf = cppMarshal.fqTypename(ident, i)
val helperClass = cxcppMarshal.helperClass(ident)

writeHxFile(cxcppMarshal.headerName(ident.name), origin, refs.hx, refs.hxFwds, w => {
w.wl
w.wl(s"class $self")
w.bracedSemi {
w.wlOutdent("public:")
w.wl(s"using CppType = std::shared_ptr<$cppSelf>;")
w.wl(s"using CxType = $cxSelf^;");
w.wl
w.wl(s"using Boxed = $self;")
w.wl
w.wl(s"static CppType toCpp(CxType cx);")
w.wl(s"static CxType fromCpp(const CppType& cpp);")
if (i.ext.cx) {
w.wl
w.wlOutdent("private:")
w.wl(s"class CxProxy;")
}

}

})

writeCxCppFile(cxcppMarshal.bodyName(ident.name), origin, refs.cxcpp, w => {

//only interface classes have proxy objects
if (i.ext.cx) {
w.wl(s"class $helperClass final : public $cppSelf, public ::djinni::CxWrapperCache<CxProxy>::Handle").bracedSemi {
w.wlOutdent("public:")
w.wl("using Handle::Handle;")
w.wl(s"using CxType = $cxSelf^;")
w.wl
w.wl("CxProxy(Platform::Object^ cx) : ::djinni::CxWrapperCache<CxProxy>::Handle{ cx } {}")
w.wl
//methods
for (m <- i.methods) {
w.wl
writeDoc(w, m.doc)
val ret = cppMarshal.fqReturnType(m.ret)
val params = m.params.map(p => cppMarshal.fqParamType(p.ty) + " " + idCpp.local(p.ident))
if (m.static) {
w.wl(s"static $ret ${idCpp.method(m.ident)}${params.mkString("(", ", ", ")")}")
} else {
val constFlag = if (m.const) " const" else ""
w.wl(s"$ret ${idCpp.method(m.ident)}${params.mkString("(", ", ", ")")}$constFlag override")
}
w.braced {
val retCall = if(m.ret == None) "" else "auto r = "
val call = retCall + (if (!m.static) s"static_cast<CxType>(Handle::get())->" else cppSelf + "::") + idCx.method(m.ident) + "("
writeAlignedCall(w, call, m.params, ")", p => cxcppMarshal.fromCpp(p.ty, idCpp.local(p.ident.name)))
w.wl(";")
m.ret.fold()(r => w.wl(s"return ${cxcppMarshal.toCpp(r, "r")};"))
}
}
}
w.wl
w.wl(s"auto $self::toCpp(CxType cx) -> CppType")
w.braced {
w.wl("if (!cx)").braced {
w.wl("return nullptr;")
}
w.wl("return ::djinni::CxWrapperCache<CxProxy>::getInstance()->get(cx);")
}
w.wl
w.wl(s"auto $self::fromCpp(const CppType& cpp) -> CxType")
w.braced {
w.braced {
w.wl("if (!cpp)").braced {
w.wl("return nullptr;")
}
w.wl("return static_cast<CxType>(dynamic_cast<CxProxy &>(*cpp).Handle::get());")
}
}
} else {
w.wl(s"auto $self::toCpp(CxType cx) -> CppType")
w.braced {
w.wl("return cx->m_cppRef.get();")
}
w.wl
w.wl(s"auto $self::fromCpp(const CppType& cpp) -> CxType")
w.braced {
w.wl(s"return (CxType)::djinni::CppWrapperCache<$cppSelf>::getInstance()->get(cpp, [](const std::shared_ptr<$cppSelf>& p)").bracedEnd(");") {
w.wl(s"return ref new $cxSelf(p);")
}

}
}

})
}


def writeCxCppTypeParams(w: IndentWriter, params: Seq[TypeParam]) {
if (params.isEmpty) return
w.wl("template " + params.map(p => "typename " + idCpp.typeParam(p.ident)).mkString("<", ", ", ">"))
}

}
Loading