aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMisha Chernetsov <chernetsov@gmail.com>2015-03-25 00:20:25 -0700
committerMisha Chernetsov <chernetsov@gmail.com>2015-03-25 00:20:25 -0700
commitdd926f514b1a3642a724e970537f834285c8e53b (patch)
tree9db506e5d6bb6f6fe3a4ad991e3710f941043c8e
parent24b02aab563de43db696de73b81c65a20f9a6587 (diff)
downloadsbt-mavlink-dd926f514b1a3642a724e970537f834285c8e53b.tar.gz
sbt-mavlink-dd926f514b1a3642a724e970537f834285c8e53b.tar.bz2
sbt-mavlink-dd926f514b1a3642a724e970537f834285c8e53b.zip
support for dialect definition file include directives
minor tweaks
-rw-r--r--.gitignore3
-rw-r--r--mavlink-library/src/main/scala/com/github/jodersky/mavlink/Context.scala2
-rw-r--r--mavlink-library/src/main/scala/com/github/jodersky/mavlink/Parser.scala85
-rw-r--r--mavlink-library/src/main/scala/com/github/jodersky/mavlink/Reporter.scala6
-rw-r--r--mavlink-library/src/main/scala/com/github/jodersky/mavlink/trees/package.scala2
-rw-r--r--mavlink-library/src/test/resources/including.xml4
-rw-r--r--mavlink-library/src/test/scala/com/github/jodersky/mavlink/MainTest.scala11
-rw-r--r--mavlink-plugin/src/main/scala/com/github/jodersky/mavlink/sbt/SbtMavlink.scala9
8 files changed, 72 insertions, 50 deletions
diff --git a/.gitignore b/.gitignore
index 1d1019c..3202827 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,6 +17,9 @@ project/plugins/project/
.cache
.history
+# intellij-ide specific
+.idea
+
# ensime
.ensime
diff --git a/mavlink-library/src/main/scala/com/github/jodersky/mavlink/Context.scala b/mavlink-library/src/main/scala/com/github/jodersky/mavlink/Context.scala
index d025285..7986b62 100644
--- a/mavlink-library/src/main/scala/com/github/jodersky/mavlink/Context.scala
+++ b/mavlink-library/src/main/scala/com/github/jodersky/mavlink/Context.scala
@@ -2,5 +2,5 @@ package com.github.jodersky.mavlink
/** Represents the context under which MAVLink scala code was generated. */
case class Context(
- version: String
+ version: Option[String]
) \ 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 3010121..e6f0f07 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
@@ -1,12 +1,10 @@
package com.github.jodersky.mavlink
+import java.io.File
+
import scala.language.postfixOps
-import scala.xml.Attribute
-import scala.xml.Elem
-import scala.xml.Node
-import scala.xml.Null
-import scala.xml.Text
+import scala.xml._
import scala.util.Try
import trees._
@@ -18,91 +16,110 @@ import trees._
class Parser(reporter: Reporter) {
import reporter._
- def parseDialect(node: Node): Dialect = parse(node) match {
+ def parseDialect(dialectDefinitionFile: File): Dialect = {
+ val xml = XML.loadFile(dialectDefinitionFile)
+ parseDialect(xml, dialectDefinitionFile)
+ }
+
+ private def parseDialect(node: Node, file: File): Dialect = parse(node, file) match {
case p: Dialect => p
- case _ => fatal("expected mavlink protocol definition", node)
+ case _ => fatal("expected mavlink protocol definition", node, file)
}
- def parse(node: Node): Tree = node match {
+ def parse(node: Node, file: File): Tree = node match {
case <field>{_*}</field> =>
val description = node.text
- val name = (node \ "@name").map(_.text).headOption getOrElse fatal("no name defined for field", node)
+ val name = (node \ "@name").map(_.text).headOption getOrElse fatal("no name defined for field", node, file)
val enum = (node \ "@enum").map(_.text).headOption
val (tpe, native) = (node \ "@type") map (_.text) headOption match {
- case Some(t) => (parseType(t, node), t)
- case None => fatal("no field type specified", node)
+ case Some(t) => (parseType(t, node, file), t)
+ case None => fatal("no field type specified", node, file)
}
Field(tpe, native, name, enum, description)
case <entry>{_*}</entry> =>
val value = (node \ "@value").map(_.text).headOption map { str =>
- Try { Integer.parseInt(str) } getOrElse fatal("value must be an integer", node)
- } getOrElse fatal("no value defined", node)
- val name = (node \ "@name").map(_.text).headOption getOrElse fatal("no name defined for enum entry", node)
+ Try { Integer.parseInt(str) } getOrElse fatal("value must be an integer", node, file)
+ } getOrElse fatal("no value defined", node, file)
+ val name = (node \ "@name").map(_.text).headOption getOrElse fatal("no name defined for enum entry", node, file)
val description = (node \ "description").text
EnumEntry(value, name, description)
case <enum>{_*}</enum> =>
- val name = (node \ "@name").map(_.text).headOption getOrElse fatal("no name defined for enum", node)
+ val name = (node \ "@name").map(_.text).headOption getOrElse fatal("no name defined for enum", node, file)
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
val nodeWithValue = if ((n \ "@value").isEmpty) {
- warn("no value defined for enum entry, using index instead", n)
+ warn("no value defined for enum entry, using index instead", n, file)
n.asInstanceOf[Elem] % Attribute(None, "value", Text(i.toString), Null)
} else {
n
}
- parse(nodeWithValue) match {
+ parse(nodeWithValue, file) match {
case e: EnumEntry => e
- case _ => fatal("illegal definition in enum, only entries are allowed", n)
+ case _ => fatal("illegal definition in enum, only entries are allowed", n, file)
}
}
Enum(name, entries, description)
case <message>{_*}</message> =>
val id = (node \ "@id").map(_.text).headOption map { str =>
- val id = Try { Integer.parseInt(str) } getOrElse fatal("id must be an integer", node)
- if (id < 0 || id > 255) warn("message id is not in the range [0-255]", node)
+ val id = Try { Integer.parseInt(str) } getOrElse fatal("id must be an integer", node, file)
+ if (id < 0 || id > 255) warn("message id is not in the range [0-255]", node, file)
id.toByte
- } getOrElse fatal("no id defined", node)
- val name = (node \ "@name").map(_.text).headOption getOrElse fatal("no name defined for message", node)
+ } getOrElse fatal("no id defined", node, file)
+ val name = (node \ "@name").map(_.text).headOption getOrElse fatal("no name defined for message", node, file)
val description = (node \ "description").text
val fields = (node \ "field") map { n: Node =>
- parse(n) match {
+ parse(n, file) match {
case e: Field => e
- case _ => fatal("illegal definition in message, only fields are allowed", n)
+ case _ => fatal("illegal definition in message, only fields are allowed", n, file)
}
}
Message(id, name, description, fields)
case <mavlink>{_*}</mavlink> =>
- val version = (node \ "version").text
+ val version = (node \ "version").headOption.map(_.text)
+
+ val include = (node \ "include").headOption.map(_.text).map { includeFileName =>
+ val includeFile: File = new File(file.getParentFile, includeFileName)
+ parseDialect(includeFile)
+ }
val enums = (node \ "enums" \ "_").toSet map { n: Node =>
- parse(n) match {
+ parse(n, file) match {
case e: Enum => e
- case _ => fatal("illegal definition in enums, only enum declarations are allowed", n)
+ case _ => fatal("illegal definition in enums, only enum declarations are allowed", n, file)
}
}
val messages = (node \ "messages" \ "_").toSet map { n: Node =>
- parse(n) match {
+ parse(n, file) match {
case e: Message => e
- case e => fatal("illegal definition in messages, only message declarations are allowed", n)
+ case e => fatal("illegal definition in messages, only message declarations are allowed", n, file)
}
}
- Dialect(version, enums, messages)
+
+ include match {
+ case None => Dialect(version, enums, messages)
+ case Some(includeDialect) => Dialect(
+ (version ++ includeDialect.version).headOption, // included version overridden by local version if any
+ enums ++ includeDialect.enums,
+ messages ++ includeDialect.messages
+ )
+ }
+
- case x => fatal("unknown", x)
+ case x => fatal("unknown", x, file)
}
val ArrayPattern = """(.*)\[(\d+)\]""".r
- def parseType(typeStr: String, node: Node): Type = typeStr match {
+ def parseType(typeStr: String, node: Node, file: File): Type = typeStr match {
case "int8_t" => IntType(1, true)
case "uint8_t_mavlink_version" => IntType(1, false)
case "int16_t" => IntType(2, true)
@@ -116,8 +133,8 @@ class Parser(reporter: Reporter) {
case "double" => FloatType(8)
case "char" => IntType(1, true)
case ArrayPattern("char", l) => StringType(l.toInt)
- case ArrayPattern(u, l) => ArrayType(parseType(u, node), l.toInt)
- case unknown => fatal("unknown field type " + unknown, node)
+ case ArrayPattern(u, l) => ArrayType(parseType(u, node, file), l.toInt)
+ case unknown => fatal("unknown field type " + unknown, node, file)
}
} \ No newline at end of file
diff --git a/mavlink-library/src/main/scala/com/github/jodersky/mavlink/Reporter.scala b/mavlink-library/src/main/scala/com/github/jodersky/mavlink/Reporter.scala
index 629c3a8..cec6572 100644
--- a/mavlink-library/src/main/scala/com/github/jodersky/mavlink/Reporter.scala
+++ b/mavlink-library/src/main/scala/com/github/jodersky/mavlink/Reporter.scala
@@ -1,13 +1,15 @@
package com.github.jodersky.mavlink
+import java.io.File
+
import scala.xml.Node
trait Reporter {
protected def printWarning(msg: String): Unit
- def fatal(error: String, node: Node) = throw new ParseError("Parse error: " + error + " at " + node)
- def warn(warning: String, node: Node) = printWarning("Warning: " + warning +" at " + node)
+ def fatal(message: String, node: Node, file: File) = throw new ParseError(s"Parse error: $message at $node in file ${file.getAbsolutePath}")
+ def warn(message: String, node: Node, file: File) = printWarning(s"Parse warning: $message at ${node} in file ${file.getAbsolutePath}")
}
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 c1e2993..f59eda6 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
@@ -4,7 +4,7 @@ package trees {
sealed trait Tree
- case class Dialect(version: String, enums: Set[Enum], messages: Set[Message]) extends Tree
+ case class Dialect(version: Option[String], enums: Set[Enum], messages: Set[Message]) 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
diff --git a/mavlink-library/src/test/resources/including.xml b/mavlink-library/src/test/resources/including.xml
new file mode 100644
index 0000000..e1b026f
--- /dev/null
+++ b/mavlink-library/src/test/resources/including.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0'?>
+<mavlink>
+ <include>concise.xml</include>
+</mavlink> \ No newline at end of file
diff --git a/mavlink-library/src/test/scala/com/github/jodersky/mavlink/MainTest.scala b/mavlink-library/src/test/scala/com/github/jodersky/mavlink/MainTest.scala
index faf252a..be46212 100644
--- a/mavlink-library/src/test/scala/com/github/jodersky/mavlink/MainTest.scala
+++ b/mavlink-library/src/test/scala/com/github/jodersky/mavlink/MainTest.scala
@@ -1,16 +1,15 @@
package com.github.jodersky.mavlink
-import scala.io.Source
-import scala.xml.XML
-import trees._
+import java.io.File
object MainTest {
def main(args: Array[String]): Unit = {
- val definition = XML.load(getClass.getResource("/concise.xml"))
- val dialect = Parser.parseDialect(definition)
+ val parser: Parser = new Parser(StandardReporter)
+ val dialectDefinitionFile: File = new File("mavlink-library/src/test/resources/including.xml")
+ val dialect = parser.parseDialect(dialectDefinitionFile)
val generator = new Generator(dialect)
- println(generator.generate())
+ println(generator.targets.map(_.generate()).mkString("\n\n"))
}
} \ No newline at end of file
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 afd2c94..9f9884d 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
@@ -10,8 +10,6 @@ import sbt._
import sbt.Keys._
import sbt.plugins._
-import scala.xml.XML
-
object SbtMavlink extends AutoPlugin {
override def trigger = allRequirements
@@ -42,11 +40,10 @@ object SbtMavlink extends AutoPlugin {
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
+ val dialect = new Parser(reporter).parseDialect(dialectDefinitionFile)
+ val targets = new Generator(dialect).targets
for (tgt <- targets) yield {
- val file = (outDirectory / tgt.path)
+ val file = outDirectory / tgt.path
if (dialectDefinitionFile.lastModified > file.lastModified) {
streams.value.log.info("Generating mavlink binding " + file)