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

Make #379 compatible with python branch #388

Open
wants to merge 6 commits into
base: python
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ Djinni's input is an interface description file. Here's an example:
store: set<string>;
hash: map<string, i32>;

// You can generate two types of comments
// - Code comments by using "// comment" in djinni files which will generate "// comment"
// - Code documentation by using "# comment" in djinni files which will generate "/** comment */"
// Both of those types support single and multi line comments
values: list<another_record>;

# Comments can also be put here
Expand Down Expand Up @@ -506,6 +510,14 @@ For more informations, take a look at https://github.com/leetal/ios-cmake.

- `ENABLE_BITCODE`: enable/disable the bitcode generation.

## Android Parcelable records

Djinni supports generating records that implements `android.os.parcelable`.

In order to do that, there are two steps needed:
- deriving the records that should be parcelable with the keyword parcelable: `deriving(parcelable)`
- run Djinni with the following flag `--java-implement-android-os-parcelable true`

## Community Links

* Join the discussion with other developers at the [Mobile C++ Slack Community](https://mobilecpp.herokuapp.com/)
Expand Down
2 changes: 1 addition & 1 deletion example/example.djinni
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ sort_order = enum {
}

sort_items = interface +c {
# For the iOS / Android demo
// For the iOS / Android demo
sort(order: sort_order, items: item_list);
static create_with_listener(listener: textbox_listener): sort_items;

Expand Down
2 changes: 1 addition & 1 deletion example/generated-src/cpp/sort_items.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class SortItems {
public:
virtual ~SortItems() {}

/** For the iOS / Android demo */
// For the iOS / Android demo
virtual void sort(sort_order order, const ItemList & items) = 0;

static std::shared_ptr<SortItems> create_with_listener(const std::shared_ptr<TextboxListener> & listener);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import javax.annotation.Nonnull;

/*package*/ interface SortItems {
/** For the iOS / Android demo */
// For the iOS / Android demo
public void sort(@Nonnull SortOrder order, @Nonnull ItemList items);

@CheckForNull
Expand Down
2 changes: 1 addition & 1 deletion example/generated-src/objc/TXSSortItems.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

@interface TXSSortItems : NSObject

/** For the iOS / Android demo */
// For the iOS / Android demo
- (void)sort:(TXSSortOrder)order
items:(nonnull TXSItemList *)items;

Expand Down
2 changes: 1 addition & 1 deletion src/run
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ while [ -h "$loc" ]; do
loc="`dirname "$loc"`/$link" # Relative link
fi
done
base_dir=$(cd "`dirname "$loc"`" && pwd)
base_dir=$(cd "`dirname "$loc"`" > /dev/null && pwd)

"$base_dir/build"

Expand Down
2 changes: 1 addition & 1 deletion src/run-assume-built
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ while [ -h "$loc" ]; do
loc="`dirname "$loc"`/$link" # Relative link
fi
done
base_dir=$(cd "`dirname "$loc"`" && pwd)
base_dir=$(cd "`dirname "$loc"`" > /dev/null && pwd)

exec "$base_dir/target/start" "$@"
2 changes: 1 addition & 1 deletion src/source/CppGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ class CppGenerator(spec: Spec) extends Generator(spec) {
for (c <- consts) {
skipFirst{ w.wl }
if (shouldConstexpr(c)){
w.w(s"${marshal.fieldType(c.ty)} const $selfName::${idCpp.const(c.ident)}")
w.w(s"${marshal.fieldType(c.ty)} constexpr $selfName::${idCpp.const(c.ident)}")
} else {
w.w(s"${marshal.fieldType(c.ty)} const $selfName::${idCpp.const(c.ident)} = ")
writeCppConst(w, c.ty, c.value)
Expand Down
33 changes: 16 additions & 17 deletions src/source/PythonGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,19 @@ class PythonGenerator(spec: Spec) extends Generator(spec) {

// Override since Python doesn't share the C-style comment syntax.
override def writeDoc(w: IndentWriter, doc: Doc) {
doc.lines.foreach(l => w.wl(s"#$l"))
doc.comments.foreach(comment => comment.lines.foreach(l => w.wl(s"#$l")) )
}

// Use docstrings rather than comments when available.
def writeDocString(w: IndentWriter, doc: Doc, docLists: Seq[IndentWriter => Unit] = Seq()): Boolean = {
if (doc.lines.isEmpty && docLists.isEmpty) {
if (doc.comments.isEmpty && docLists.isEmpty) {
return false
}
if (doc.lines.length == 1 && docLists.isEmpty) {
w.wl(s"""\"\"\"${doc.lines.head} \"\"\"""")
if (doc.comments.length == 1 && doc.comments.head.lines.length == 1 && docLists.isEmpty) {
w.wl(s"""\"\"\"${doc.comments.head.lines.head} \"\"\"""")
} else {
w.wl("\"\"\"")
doc.lines.foreach (l => w.wl(s"$l"))
doc.comments.foreach(comment => comment.lines.foreach(l => w.wl(s"$l")))
docLists.foreach (docList => docList(w))
w.wl("\"\"\"")
}
Expand All @@ -67,34 +67,33 @@ class PythonGenerator(spec: Spec) extends Generator(spec) {
}
}

def writeDocListItem(w: IndentWriter, name: String, lines: Seq[String]): Unit = {
if (lines.isEmpty) {
def writeDocListItem(w: IndentWriter, name: String, comments: Seq[Comment]): Unit = {
if (comments.isEmpty) {
w.wl(s"${name}")
} else {
w.wl(s"${name}: ${lines.head.trim}")
w.wl(s"${name}: ${comments.head.lines.head.trim}")
w.nested {
lines.tail.foreach (l => {
w.wl(l)
})
comments.head.lines.tail.foreach (l => w.wl(l))
comments.tail.foreach (comment => comment.lines.foreach (l => w.wl(l)) )
}
}
}

def writeDocConstantsList(w: IndentWriter, consts: Seq[Const]): Unit = {
writeDocList(w, "Constants", { w => consts.foreach (c => {
writeDocListItem(w, idPython.const(c.ident), c.doc.lines)
writeDocListItem(w, idPython.const(c.ident), c.doc.comments)
})})
}

def writeDocFieldsList(w: IndentWriter, fields: Seq[Field]): Unit = {
writeDocList(w, "Fields", { w => fields.foreach (f => {
writeDocListItem(w, idPython.field(f.ident), f.doc.lines)
writeDocListItem(w, idPython.field(f.ident), f.doc.comments)
})})
}

def writeDocEnumOptionsList(w: IndentWriter, options: Seq[Enum.Option]): Unit = {
writeDocList(w, "Members", { w => options.foreach (o => {
writeDocListItem(w, idPython.enum(o.ident), o.doc.lines)
writeDocListItem(w, idPython.enum(o.ident), o.doc.comments)
})})
}

Expand Down Expand Up @@ -800,7 +799,7 @@ class PythonGenerator(spec: Spec) extends Generator(spec) {
writePythonFile(ident, origin, refs.python, true, w => {
// Asbtract Class Definition
w.wl("class " + pythonClass + "(with_metaclass(ABCMeta)):").nested {
val docConsts = if (!i.consts.exists(!_.doc.lines.isEmpty)) Seq() else Seq({
val docConsts = if (!i.consts.exists(!_.doc.comments.isEmpty)) Seq() else Seq({
w: IndentWriter => writeDocConstantsList(w, i.consts)
})
if (writeDocString(w, doc, docConsts)) { w.wl }
Expand Down Expand Up @@ -993,8 +992,8 @@ class PythonGenerator(spec: Spec) extends Generator(spec) {
// Record Definition
w.wl("class " + recordClassName + (if(r.ext.py) "Base" else "") + ":").nested {
var docLists = mutable.ArrayBuffer[IndentWriter => Unit]()
if (r.fields.exists(!_.doc.lines.isEmpty)) docLists += { w: IndentWriter => writeDocFieldsList(w, r.fields)}
if (r.consts.exists(!_.doc.lines.isEmpty)) docLists += { w: IndentWriter => writeDocConstantsList(w, r.consts)}
if (r.fields.exists(!_.doc.comments.isEmpty)) docLists += { w: IndentWriter => writeDocFieldsList(w, r.fields)}
if (r.consts.exists(!_.doc.comments.isEmpty)) docLists += { w: IndentWriter => writeDocConstantsList(w, r.consts)}
if (writeDocString(w, doc, docLists)) { w.wl }


Expand Down
8 changes: 7 additions & 1 deletion src/source/ast.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,13 @@ class EnumValue(val ty: Ident, ident: Ident) extends Ident(ident.name, ident.fil

case class TypeParam(ident: Ident)

case class Doc(lines: Seq[String])
case class Doc(comments: Seq[Comment])

abstract sealed class Comment {
val lines: Seq[String]
}
case class CodeComment(override val lines: Seq[String]) extends Comment
case class DocComment(override val lines: Seq[String]) extends Comment

sealed abstract class TypeDecl {
val ident: Ident
Expand Down
51 changes: 38 additions & 13 deletions src/source/generator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ package djinni

import djinni.ast._
import java.io._

import djinni.generatorTools._
import djinni.meta._
import djinni.syntax.Error
import djinni.writer.IndentWriter

import scala.language.implicitConversions
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
import scala.util.matching.Regex

package object generatorTools {
Expand Down Expand Up @@ -504,22 +507,44 @@ abstract class Generator(spec: Spec)

def writeMethodDoc(w: IndentWriter, method: Interface.Method, ident: IdentConverter) {
val paramReplacements = method.params.map(p => (s"\\b${Regex.quote(p.ident.name)}\\b", s"${ident(p.ident.name)}"))
val newDoc = Doc(method.doc.lines.map(l => {
paramReplacements.foldLeft(l)((line, rep) =>
line.replaceAll(rep._1, rep._2))
}))

val comments = ArrayBuffer[Comment]()

method.doc.comments.foreach({
case DocComment(lines) =>

val newDocComment = DocComment(lines.map(l => {
paramReplacements.foldLeft(l)((line, rep) =>
line.replaceAll(rep._1, rep._2))
}))

comments += newDocComment

case CodeComment(lines) =>
comments += CodeComment(lines)
})

val newDoc = Doc(comments)

writeDoc(w, newDoc)
}

def writeDoc(w: IndentWriter, doc: Doc) {
doc.lines.length match {
case 0 =>
case 1 =>
w.wl(s"/**${doc.lines.head} */")
case _ =>
w.wl("/**")
doc.lines.foreach (l => w.wl(s" *$l"))
w.wl(" */")
}
doc.comments.foreach({
case DocComment(lines) =>
lines.length match {
case 0 =>
case 1 =>
w.wl(s"/**${lines.head} */")
case _ =>
w.wl("/**")
lines.foreach (l => w.wl(s" *$l"))
w.wl(" */")
}

case CodeComment(lines) =>
lines.foreach (l => w.wl(s"//$l"))
})
}

}
57 changes: 55 additions & 2 deletions src/source/parser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,19 @@

package djinni

import java.io.{File, FileNotFoundException, InputStreamReader, FileInputStream, Writer}
import java.io.{File, FileInputStream, FileNotFoundException, InputStreamReader, Writer}

import djinni.ast.Interface.Method
import djinni.ast.Record.DerivingType.DerivingType
import djinni.syntax._
import djinni.ast._
import java.util.{Map => JMap}

import org.yaml.snakeyaml.Yaml

import scala.collection.JavaConversions._
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
import scala.util.control.Breaks._
import scala.util.parsing.combinator.RegexParsers
import scala.util.parsing.input.{Position, Positional}
Expand Down Expand Up @@ -210,7 +213,57 @@ private object IdlParser extends RegexParsers {
case (s, p) => Ident(s, fileStack.top, p)
}

def doc: Parser[Doc] = rep(regex("""#[^\n\r]*""".r) ^^ (_.substring(1))) ^^ Doc
def doc: Parser[Doc] = rep(regex("""#[^\n\r]*""".r) | regex("""\/\/[^\n\r]*""".r)) ^^ { commentLines =>

val docCommentPrefix = "#"
val codeCommentPrefix = "//"

val comments = ArrayBuffer[Comment]()

commentLines.foreach( commentLine => {

if (commentLine.startsWith(docCommentPrefix)) { // DocComment

val commentText = commentLine.substring(docCommentPrefix.length)

if (comments.isEmpty) {
comments += DocComment(Seq(commentText))
} else {
comments.last match {
case DocComment(lines) =>
val newLines = lines :+ commentText
comments.remove(comments.length-1)
comments += DocComment(newLines)
case CodeComment(_) =>
comments += DocComment(Seq(commentText))
}
}

} else if (commentLine.startsWith(codeCommentPrefix)) { // CodeComment

val commentText = commentLine.substring(codeCommentPrefix.length)

if (comments.isEmpty) {
comments += CodeComment(Seq(commentText))
} else {
val commentText = commentLine.substring(codeCommentPrefix.length)
comments.last match {
case DocComment(_) =>
comments += CodeComment(Seq(commentText))
case CodeComment(lines) =>
val newLines = lines :+ commentText
comments.remove(comments.length-1)
comments += CodeComment(newLines)
}
}

}

})

Doc(comments)

}

def parens[T](inner: Parser[T]): Parser[T] = surround("(", ")", inner)
def typeList[T](inner: Parser[T]): Parser[Seq[T]] = surround("<", ">", rep1sepend(inner, ",")) | success(Seq.empty)
Expand Down
20 changes: 18 additions & 2 deletions test-suite/djinni/client_interface.djinni
Original file line number Diff line number Diff line change
@@ -1,25 +1,41 @@
# Record returned by a client
// Record returned by a client
client_returned_record = record {
record_id: i64;
content: string;
misc: optional<string>;
}

# Client interface
// Client interface
client_interface = interface +p +j +o {
// Testing code comments before documentation comments
# Returns record of given string
get_record(record_id: i64, utf8string: string, misc: optional<string>): client_returned_record;
identifier_check(data: binary, r: i32, jret: i64): f64;
return_str(): string;

# Testing documentation comments before code comments
// This method takes an interface
meth_taking_interface(i: client_interface): string;
meth_taking_optional_interface(i: optional<client_interface>): string;
}

reverse_client_interface = interface +c {
const return_str(): string;

// Testing code comments before documentation comments
// with multiple lines
// and another line
# Testing documentation comments after code comments
# with multiple lines
# and another line
meth_taking_interface(i: reverse_client_interface): string;

# Testing documentation comments before code comments
# with multiple lines
# and another line
// Testing code comments after documentation comments
// with multiple lines
// and another line
meth_taking_optional_interface(i: optional<reverse_client_interface>): string;

static create(): reverse_client_interface;
Expand Down
2 changes: 1 addition & 1 deletion test-suite/djinni/constant_enum.djinni
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# enum for use in constants
// enum for use in constants
constant_enum = enum {
some_value;
some_other_value;
Expand Down
Loading