Skip to content

Commit

Permalink
Merge pull request #5 from tindzk/inline-tables
Browse files Browse the repository at this point in the history
Add support for inline tables
  • Loading branch information
jvican committed Feb 9, 2018
2 parents f6052c7 + 6c569ff commit bb065e7
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 22 deletions.
2 changes: 1 addition & 1 deletion project/build.properties
@@ -1 +1 @@
sbt.version = 0.13.13
sbt.version = 0.13.16
20 changes: 11 additions & 9 deletions src/main/scala/stoml/TomlParser.scala
Expand Up @@ -173,10 +173,12 @@ trait TomlParser extends ParserUtil with TomlSymbol {
val dashes = P(CharIn(Dashes))
val bareKey = P((letters | digits | dashes).rep(min = 1)).!
val validKey: Parser[String] = P(bareKey | NoCut(basicStr)).!
lazy val pair: Parser[Pair] =
val pair: Parser[Pair] =
P(validKey ~ WS0.? ~ "=" ~ WS0.? ~ elem) map Pair
lazy val array: Parser[Arr] =
val array: Parser[Arr] =
P("[" ~ WS ~ elem.rep(sep = "," ~ WS) ~ ",".? ~ WS ~ "]") map Arr
val inlineTable: Parser[Table] =
P("{" ~ WS ~ pair.rep(sep = "," ~ WS) ~ "}").map(p => Table("", p))

val tableIds: Parser[Seq[String]] =
P(validKey.rep(min = 1, sep = WS0.? ~ "." ~ WS0.?))
Expand All @@ -195,7 +197,7 @@ trait TomlParser extends ParserUtil with TomlSymbol {
}

lazy val elem: Parser[Elem] = P {
WS ~ (string | boolean | double | integer | array | date) ~ WS
WS ~ (string | boolean | double | integer | array | inlineTable | date) ~ WS
}

lazy val node: Parser[Node] = P(WS ~ (pair | table | tableArray) ~ WS)
Expand All @@ -206,17 +208,17 @@ trait TomlParserApi extends TomlParser with Common {

import stoml.Toml.{Node, Table, Pair, TableArray, TableArrayItems}

case class TomlContent(map: Map[Key, Node]) {
def lookup(k: Key): Option[Node] = map.get(k)
def filter(f: Key => Boolean): Iterator[Node] =
case class TomlContent(map: Map[Key, Toml.Elem]) {
def lookup(k: Key): Option[Toml.Elem] = map.get(k)
def filter(f: Key => Boolean): Iterator[Toml.Elem] =
map.filterKeys(f).values.iterator
def childOf(parentKey: Key): Iterator[Node] =
def childOf(parentKey: Key): Iterator[Toml.Elem] =
filter(key => key.startsWith(parentKey))
}

object TomlContent {
def apply(s: Seq[Node]): TomlContent = TomlContent {
s.foldLeft(Map.empty[Key, Node]) { (m, e) =>
s.foldLeft(Map.empty[Key, Toml.Elem]) { (m, e) =>
val value = e match {
case t: Table => t.elem._1 -> t
case t: TableArray =>
Expand All @@ -225,7 +227,7 @@ trait TomlParserApi extends TomlParser with Common {
TableArrayItems(items :+ t)
case _ => TableArrayItems(List(t))
})
case p: Pair => p.elem._1 -> p
case p: Pair => p.elem._1 -> p.elem._2
}

m + value
Expand Down
25 changes: 23 additions & 2 deletions src/test/scala/api/TomlParserApiSpec.scala
Expand Up @@ -45,7 +45,7 @@ class TomlParserApiSpec extends FunSpec with Matchers {
}
}

it("should parse parse table arrays") {
it("should parse table arrays") {
val array =
"""
|[[products]]
Expand All @@ -62,7 +62,6 @@ class TomlParserApiSpec extends FunSpec with Matchers {
parseToml(array) match {
case Success(v, _) =>
val p = v.lookup("products")
println(p)
assert(p.contains(TableArrayItems(List(
TableArray("products", List(
Pair("name" -> Str("Hammer")),
Expand All @@ -79,5 +78,27 @@ class TomlParserApiSpec extends FunSpec with Matchers {
case f: Failure[_, _] => fail()
}
}

it("should parse inline table arrays") {
val array =
"""
|product = {
| name = "Hammer",
| colour = "blue"
|}
""".stripMargin

parseToml(array) match {
case Success(v, _) =>
val p = v.lookup("product")
assert(p.contains(
Table("", List(
Pair("name" -> Str("Hammer")),
Pair("colour" -> Str("blue"))))
))

case f: Failure[_, _] => fail()
}
}
}
}
75 changes: 75 additions & 0 deletions src/test/scala/stoml/InlineTableTomlSpec.scala
@@ -0,0 +1,75 @@
package stoml

import fastparse.core.Parsed.Success
import org.scalacheck.Gen
import org.scalatest.prop._
import org.scalatest.{Matchers, PropSpec}

trait InlineTableTomlGen {
this: TomlSymbol
with StringTomlGen
with NumbersTomlGen =>

val openChars = List("{", "{\n")
val seps = List(",\n", ",")
val closeChars = List("}", "\n}")

def bareKeyGen = Gen.someOf(
Gen.alphaLowerChar,
Gen.alphaUpperChar,
Gen.alphaNumChar,
Gen.oneOf('_', '-')
).retryUntil(x => x.nonEmpty && !x.contains('=')).map(_.mkString)

private def validPairGen: Gen[(String, String)] =
for {
key <- bareKeyGen
value <- Gen.oneOf(validStrGen, validDoubleGen, validLongGen)
} yield (key, value)

private def invalidPairGen: Gen[(String, String)] =
for {
key <- Gen.someOf(bareKeyGen, "=").map(_.mkString)
value <- Gen.oneOf("", ",")
} yield (key, value)

def tableFormat(s: Seq[(String, String)], fs: (String, String, String)): String =
fs._1 +
s.map { case (k, v) => k + "=" + v }.mkString(fs._2) +
fs._3

def inlineTableGen(pairGen: Gen[(String, String)]) =
for {
elems <- Gen.nonEmptyListOf(pairGen)
c1 <- Gen.oneOf(openChars)
ss <- Gen.oneOf(seps)
c2 <- Gen.oneOf(closeChars)
} yield tableFormat(elems, (c1, ss, c2))

def validInlineTableGen : Gen[String] = inlineTableGen(validPairGen)
def invalidInlineTableGen: Gen[String] = inlineTableGen(invalidPairGen)
}

class InlineTableTomlSpec extends PropSpec
with PropertyChecks
with Matchers
with InlineTableTomlGen
with StringTomlGen
with NumbersTomlGen
with TomlParser
with TestParserUtil {

property("parse valid inline tables") {
forAll(validInlineTableGen) {
s: String =>
shouldBeSuccess(elem.parse(s))
}
}

property("do not parse invalid inline tables") {
forAll(invalidInlineTableGen) {
s: String =>
shouldBeFailure(elem.parse(s))
}
}
}
15 changes: 5 additions & 10 deletions src/test/scala/stoml/TableTomlSpec.scala
Expand Up @@ -12,7 +12,8 @@ trait TableTomlGen {
with StringTomlGen
with NumbersTomlGen
with BooleanTomlGen
with CommentTomlGen =>
with CommentTomlGen
with InlineTableTomlGen =>

val sps = List(" ", "\t")

Expand All @@ -38,16 +39,10 @@ trait TableTomlGen {
validStrGen,
validDoubleGen,
validLongGen,
validBoolGen
validBoolGen,
validInlineTableGen
)

def bareKeyGen = Gen.someOf(
Gen.alphaLowerChar,
Gen.alphaUpperChar,
Gen.alphaNumChar,
Gen.oneOf('_', '-')
) suchThat (_.nonEmpty) map (_.mkString)

def pairGen: Gen[String] = for {
key <- oneOf(doubleQuoteStrGen, bareKeyGen)
value <- valueGen
Expand Down Expand Up @@ -75,13 +70,13 @@ trait TableTomlGen {
c1 <- commentGen
c2 <- commentGen
} yield c1 + tableFormat(tdef, ps) + c2

}

class TableTomlSpec extends PropSpec
with PropertyChecks with Matchers
with BooleanTomlGen with StringTomlGen
with NumbersTomlGen with TableTomlGen
with InlineTableTomlGen
with CommentTomlGen with TomlParser
with TestParserUtil {

Expand Down

0 comments on commit bb065e7

Please sign in to comment.