aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Odersky <jodersky@gmail.com>2015-03-23 22:38:17 +0100
committerJakob Odersky <jodersky@gmail.com>2015-03-23 22:38:17 +0100
commit19175b88e9a61d3c197a4627aee270de49df5269 (patch)
tree9543d6a9577d12abbd2cbade8620f57346faece3
parent37842d340dd87391b1288a3e5f91d47dbda59fa5 (diff)
downloadsbt-mavlink-19175b88e9a61d3c197a4627aee270de49df5269.tar.gz
sbt-mavlink-19175b88e9a61d3c197a4627aee270de49df5269.tar.bz2
sbt-mavlink-19175b88e9a61d3c197a4627aee270de49df5269.zip
implement enum supportv0.4
-rw-r--r--README.md13
-rw-r--r--mavlink-library/src/main/scala/com/github/jodersky/mavlink/Generator.scala25
-rw-r--r--mavlink-library/src/main/scala/com/github/jodersky/mavlink/Parser.scala3
-rw-r--r--mavlink-library/src/main/scala/com/github/jodersky/mavlink/StringUtils.scala42
-rw-r--r--mavlink-library/src/main/scala/com/github/jodersky/mavlink/trees/package.scala2
-rw-r--r--mavlink-library/src/main/twirl/org/mavlink/enums/enums.scala.txt14
-rw-r--r--mavlink-plugin/src/main/scala/com/github/jodersky/mavlink/sbt/SbtMavlink.scala32
-rw-r--r--project/Build.scala2
8 files changed, 104 insertions, 29 deletions
diff --git a/README.md b/README.md
index 8a20272..ec8e7b1 100644
--- a/README.md
+++ b/README.md
@@ -43,9 +43,11 @@ parser.push(data)
The concrete message implementations are generated according to the selected dialect (see section Keys).
### Types
+#### Messages
Every message is mapped to a Scala case class, its name converted to CamelCase. The fields of
the case class correspond to the fields defined in the dialect definition (names are converted to camelCase).
+#### Fields
Field types are mapped according to the following table
| Definition Type | Scala Type |
@@ -62,11 +64,17 @@ Field types are mapped according to the following table
*Note that since Scala only supports signed integer types, it is up to the client to
interpret the values of fields correctly.*
+#### Enums
+Enums are mapped to Scala objects, their fields defined as final vals (CamelCase) of type Int.
+
+*Note that since many MAVLink messages that use enums do not define a dependency on them in XML (no 'enum=' attribute), no type safety
+can be guaranteed when generating messages.*
+
## Usage
Add the following to your plugins:
```scala
- addSbtPlugin("com.github.jodersky" % "sbt-mavlink" % "0.2")`
+ addSbtPlugin("com.github.jodersky" % "sbt-mavlink" % "0.4")`
```
Set a MAVLink dialect
@@ -85,9 +93,6 @@ All keys are defined in ```com.github.jodersky.mavlink.sbt.MavlinkKeys```
- ```mavlinkTarget``` - [Setting] - Output directory of generated Scala sources. This should be within ```sourceManaged```.
-## Limitations
- - Enums are not used, instead their corresponding integer value is substituted
-
## Credits
Copyright (c) 2015 Jakob Odersky
diff --git a/mavlink-library/src/main/scala/com/github/jodersky/mavlink/Generator.scala b/mavlink-library/src/main/scala/com/github/jodersky/mavlink/Generator.scala
index 4f8b207..2aeb9de 100644
--- a/mavlink-library/src/main/scala/com/github/jodersky/mavlink/Generator.scala
+++ b/mavlink-library/src/main/scala/com/github/jodersky/mavlink/Generator.scala
@@ -12,6 +12,7 @@ import trees._
* @param dialect a specific MAVLink dialect for which to generate code
*/
class Generator(dialect: Dialect) {
+ import Generator._
lazy val maxPayloadLength = dialect.messages.map(_.length).max
@@ -30,12 +31,26 @@ class Generator(dialect: Dialect) {
def targets: List[Target] = {
val context = Context(dialect.version)
List(
- Target("org/mavlink/Assembler.scala", () => org.mavlink.txt.Assembler(context).body),
- Target("org/mavlink/Crc.scala", () => org.mavlink.txt.Crc(context).body),
- Target("org/mavlink/Packet.scala", () => org.mavlink.txt.Packet(context, maxPayloadLength, extraCrcs).body),
- Target("org/mavlink/Parser.scala", () => org.mavlink.txt.Parser(context).body),
- Target("org/mavlink/messages/messages.scala", () => org.mavlink.messages.txt.messages(context, dialect.messages).body)
+ Target(targetFiles(0), () => org.mavlink.txt.Assembler(context).body),
+ Target(targetFiles(1), () => org.mavlink.txt.Crc(context).body),
+ Target(targetFiles(2), () => org.mavlink.txt.Packet(context, maxPayloadLength, extraCrcs).body),
+ Target(targetFiles(3), () => org.mavlink.txt.Parser(context).body),
+ Target(targetFiles(4), () => org.mavlink.messages.txt.messages(context, dialect.messages).body),
+ Target(targetFiles(5), () => org.mavlink.enums.txt.enums(context, dialect.enums).body)
)
}
+}
+
+object Generator {
+
+ val targetFiles: Seq[String] = Array(
+ "org/mavlink/Assembler.scala",
+ "org/mavlink/Crc.scala",
+ "org/mavlink/Packet.scala",
+ "org/mavlink/Parser.scala",
+ "org/mavlink/messages/messages.scala",
+ "org/mavlink/enums/enums.scala"
+ )
+
} \ No newline at end of file
diff --git a/mavlink-library/src/main/scala/com/github/jodersky/mavlink/Parser.scala b/mavlink-library/src/main/scala/com/github/jodersky/mavlink/Parser.scala
index ca1b772..3010121 100644
--- a/mavlink-library/src/main/scala/com/github/jodersky/mavlink/Parser.scala
+++ b/mavlink-library/src/main/scala/com/github/jodersky/mavlink/Parser.scala
@@ -44,6 +44,7 @@ class Parser(reporter: Reporter) {
case <enum>{_*}</enum> =>
val name = (node \ "@name").map(_.text).headOption getOrElse fatal("no name defined for enum", node)
+ val description = (node \ "description").map(_.text).headOption getOrElse ""
val entries = (node \ "entry").zipWithIndex map { case (n, i) =>
//FIXME: some official MAVLink dialects don't define values in enums
@@ -59,7 +60,7 @@ class Parser(reporter: Reporter) {
case _ => fatal("illegal definition in enum, only entries are allowed", n)
}
}
- Enum(name, entries)
+ Enum(name, entries, description)
case <message>{_*}</message> =>
val id = (node \ "@id").map(_.text).headOption map { str =>
diff --git a/mavlink-library/src/main/scala/com/github/jodersky/mavlink/StringUtils.scala b/mavlink-library/src/main/scala/com/github/jodersky/mavlink/StringUtils.scala
index 38b87e7..29f262f 100644
--- a/mavlink-library/src/main/scala/com/github/jodersky/mavlink/StringUtils.scala
+++ b/mavlink-library/src/main/scala/com/github/jodersky/mavlink/StringUtils.scala
@@ -2,15 +2,53 @@ package com.github.jodersky.mavlink
object StringUtils {
+ private final val Keywords = Set(
+ "class",
+ "object",
+ "trait",
+ "extends",
+ "type",
+ "import",
+ "package",
+ "val",
+ "var",
+ "def",
+ "implicit",
+ "private",
+ "protected",
+ "abstract",
+ "override",
+ "class",
+ "case",
+ "match",
+ "final",
+ "this",
+ "super",
+ "throw",
+ "catch",
+ "finally",
+ "if",
+ "else",
+ "for",
+ "while",
+ "do"
+ )
+
+ private def escape(str: String) = if (Keywords.contains(str)) {
+ "`" + str + "`"
+ } else {
+ str
+ }
+
def camelify(str: String) = {
val lower = str.toLowerCase
- "_([a-z\\d])".r.replaceAllIn(lower, {m => m.group(1).toUpperCase()})
+ escape("_([a-z\\d])".r.replaceAllIn(lower, {m => m.group(1).toUpperCase()}))
}
def Camelify(str: String) = {
val camel = camelify(str)
val (head, tail) = camel.splitAt(1)
- head.toUpperCase + tail
+ escape(head.toUpperCase + tail)
}
} \ No newline at end of file
diff --git a/mavlink-library/src/main/scala/com/github/jodersky/mavlink/trees/package.scala b/mavlink-library/src/main/scala/com/github/jodersky/mavlink/trees/package.scala
index 75c1753..c1e2993 100644
--- a/mavlink-library/src/main/scala/com/github/jodersky/mavlink/trees/package.scala
+++ b/mavlink-library/src/main/scala/com/github/jodersky/mavlink/trees/package.scala
@@ -5,7 +5,7 @@ package trees {
sealed trait Tree
case class Dialect(version: String, enums: Set[Enum], messages: Set[Message]) extends Tree
- case class Enum(name: String, entries: Seq[EnumEntry]) extends Tree
+ case class Enum(name: String, entries: Seq[EnumEntry], description: String) extends Tree
case class EnumEntry(value: Int, name: String, description: String) extends Tree
case class Field(tpe: Type, nativeType: String, name: String, enum: Option[String], description: String) extends Tree
case class Message(id: Byte, name: String, description: String, fields: Seq[Field]) extends Tree {
diff --git a/mavlink-library/src/main/twirl/org/mavlink/enums/enums.scala.txt b/mavlink-library/src/main/twirl/org/mavlink/enums/enums.scala.txt
new file mode 100644
index 0000000..453ba2f
--- /dev/null
+++ b/mavlink-library/src/main/twirl/org/mavlink/enums/enums.scala.txt
@@ -0,0 +1,14 @@
+@(__context: Context, __enums: Set[Enum])@org.mavlink.txt._header(__context)
+package org.mavlink.enums
+
+@__commentParagraphs(paragraphs: Seq[String]) = {@paragraphs.mkString("/**\n * ", "\n * ", "\n */")}
+
+@for(__enum <- __enums) {
+@__commentParagraphs(__enum.description.grouped(100).toList)
+object @{StringUtils.Camelify(__enum.name)} {
+ @for(__entry <- __enum.entries) {
+ @__commentParagraphs(__entry.description.grouped(100).toList)
+ final val @{StringUtils.Camelify(__entry.name)}: Int = @__entry.value.toString
+ }
+}
+}
diff --git a/mavlink-plugin/src/main/scala/com/github/jodersky/mavlink/sbt/SbtMavlink.scala b/mavlink-plugin/src/main/scala/com/github/jodersky/mavlink/sbt/SbtMavlink.scala
index e1b044b..03beaaa 100644
--- a/mavlink-plugin/src/main/scala/com/github/jodersky/mavlink/sbt/SbtMavlink.scala
+++ b/mavlink-plugin/src/main/scala/com/github/jodersky/mavlink/sbt/SbtMavlink.scala
@@ -27,6 +27,7 @@ object SbtMavlink extends AutoPlugin {
lazy val generationTask = Def.task[Seq[File]] {
val dialectDefinitionFile = mavlinkDialect.value
+ val outDirectory = mavlinkTarget.value
if (!dialectDefinitionFile.exists) sys.error(
"Dialect definition " + dialectDefinitionFile.getAbsolutePath + " does not exist."
@@ -36,23 +37,24 @@ object SbtMavlink extends AutoPlugin {
def printWarning(msg: String) = streams.value.log.warn(msg)
}
- val dialectDefinition = XML.loadFile(dialectDefinitionFile)
- val dialect = (new Parser(reporter)).parseDialect(dialectDefinition)
- val targets = (new Generator(dialect)).targets
-
- val outDirectory = mavlinkTarget.value
-
- val files = for (tgt <- targets) yield {
- val file = outDirectory / tgt.path
-
- if (dialectDefinitionFile.lastModified > file.lastModified) {
- streams.value.log.info("Generating mavlink binding " + file)
- IO.write(file, tgt.generate())
+ val targetFiles = Generator.targetFiles map (outDirectory / _)
+
+ if (targetFiles forall (_.lastModified > dialectDefinitionFile.lastModified)) {
+ targetFiles map (_.getAbsoluteFile)
+ } else {
+ val dialectDefinition = XML.loadFile(dialectDefinitionFile)
+ val dialect = (new Parser(reporter)).parseDialect(dialectDefinition)
+ val targets = (new Generator(dialect)).targets
+ for (tgt <- targets) yield {
+ val file = (outDirectory / tgt.path)
+
+ if (dialectDefinitionFile.lastModified > file.lastModified) {
+ streams.value.log.info("Generating mavlink binding " + file)
+ IO.write(file, tgt.generate())
+ }
+ file.getAbsoluteFile
}
- file.getAbsoluteFile
}
-
- files
}
}
diff --git a/project/Build.scala b/project/Build.scala
index 0f7acc2..cf15776 100644
--- a/project/Build.scala
+++ b/project/Build.scala
@@ -10,7 +10,7 @@ object ApplicationBuild extends Build {
scalaVersion := "2.10.4",
scalacOptions ++= Seq("-feature", "-deprecation"),
organization := "com.github.jodersky",
- version := "0.3-SNAPSHOT"
+ version := "0.4-SNAPSHOT"
) ++ publishSettings
lazy val root = (