1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
/**
* Copyright (C) 2009-2011 Scalable Solutions AB <http://scalablesolutions.se>
*
* Based on Configgy by Robey Pointer.
* Copyright 2009 Robey Pointer <robeypointer@gmail.com>
* http://www.apache.org/licenses/LICENSE-2.0
*/
package akka.config
import scala.collection.mutable
import scala.util.parsing.combinator._
class ConfigParser(var prefix: String = "", map: mutable.Map[String, Any] = mutable.Map.empty[String, Any], importer: Importer) extends RegexParsers {
val sections = mutable.Stack[String]()
def createPrefix = {
prefix = if (sections.isEmpty) "" else sections.toList.reverse.mkString("", ".", ".")
}
override val whiteSpace = """(\s+|#[^\n]*\n)+""".r
// tokens
val numberToken: Parser[String] = """-?\d+(\.\d+)?""".r
val stringToken: Parser[String] = ("\"" + """([^\\\"]|\\[^ux]|\\\n|\\u[0-9a-fA-F]{4}|\\x[0-9a-fA-F]{2})*""" + "\"").r
val booleanToken: Parser[String] = "(true|on|false|off)".r
val identToken: Parser[String] = """([\da-zA-Z_][-\w]*)(\.[a-zA-Z_][-\w]*)*""".r
val assignToken: Parser[String] = "=".r
val sectionToken: Parser[String] = """[a-zA-Z][-\w]*""".r
// values
def value: Parser[Any] = number | string | list | boolean
def number = numberToken
def string = stringToken ^^ { s => s.substring(1, s.length - 1) }
def list = "[" ~> repsep(string | numberToken, opt(",")) <~ (opt(",") ~ "]")
def boolean = booleanToken
// parser
def root = rep(includeFile | assignment | sectionOpen | sectionClose)
def includeFile = "include" ~> string ^^ {
case filename: String =>
new ConfigParser(prefix, map, importer) parse importer.importFile(filename)
}
def assignment = identToken ~ assignToken ~ value ^^ {
case k ~ a ~ v => map(prefix + k) = v
}
def sectionOpen = sectionToken <~ "{" ^^ { name =>
sections push name
createPrefix
}
def sectionClose = "}" ^^ { _ =>
if (sections.isEmpty) {
failure("dangling close tag")
} else {
sections.pop
createPrefix
}
}
def parse(in: String): Map[String, Any] = {
parseAll(root, in) match {
case Success(result, _) => map.toMap
case x@Failure(msg, _) => throw new ConfigurationException(x.toString)
case x@Error(msg, _) => throw new ConfigurationException(x.toString)
}
}
}
|