1 /* Title: Pure/General/symbol.scala
4 Detecting and recoding Isabelle symbols.
9 import java.util.regex.Pattern
11 import scala.io.Source
12 import scala.collection.jcl.HashMap
17 /** Symbol regexps **/
19 private def compile(s: String) =
20 Pattern.compile(s, Pattern.COMMENTS | Pattern.DOTALL)
22 private val plain_pattern = compile(""" [^\\ \ud800-\udfff] | [\ud800-\udbff][\udc00-\udfff] """)
24 private val symbol_pattern = compile(""" \\ \\? < (?:
25 \^? [A-Za-z][A-Za-z0-9_']* |
26 \^raw: [\x20-\x7e\u0100-\uffff && [^.>]]* ) >""")
28 private val bad_symbol_pattern = compile("(?!" + symbol_pattern + ")" +
29 """ \\ \\? < (?: (?! \s | [\"`\\] | \(\* | \*\) | \{\* | \*\} ) . )*""")
32 val pattern = compile(plain_pattern + "|" + symbol_pattern + "|" + bad_symbol_pattern + "| .")
38 private class Recoder(list: List[(String, String)]) {
39 private val (min, max) = {
42 for ((x, _) <- list) {
50 val table = new HashMap[String, String]
51 for ((x, y) <- list) table + (x -> y)
54 def recode(text: String) = {
56 val matcher = pattern.matcher(text)
57 val result = new StringBuilder(len)
61 if (min <= c && c <= max) {
62 matcher.region(i, len)
66 case Some(y) => result.append(y)
67 case None => result.append(x)
71 else { result.append(c); i += 1 }
79 /** Symbol interpretation **/
81 class Interpretation(isabelle_system: IsabelleSystem) {
83 private var symbols = new HashMap[String, HashMap[String, String]]
84 private var decoder: Recoder = null
85 private var encoder: Recoder = null
87 def decode(text: String) = decoder.recode(text)
88 def encode(text: String) = encoder.recode(text)
93 private val empty_pattern = compile(""" ^\s* (?: \#.* )? $ """)
94 private val blank_pattern = compile(""" \s+ """)
95 private val key_pattern = compile(""" (.+): """)
97 private def read_line(line: String) = {
98 def err() = error("Bad symbol specification (line " + line + ")")
100 def read_props(props: List[String], tab: HashMap[String, String]): Unit = {
103 case _ :: Nil => err()
104 case key :: value :: rest => {
105 val key_matcher = key_pattern.matcher(key)
106 if (key_matcher.matches) {
107 tab + (key_matcher.group(1) -> value)
108 read_props(rest, tab)
115 if (!empty_pattern.matcher(line).matches) {
116 blank_pattern.split(line).toList match {
118 case symbol :: props => {
119 val tab = new HashMap[String, String]
120 read_props(props, tab)
121 symbols + (symbol -> tab)
127 private def read_symbols(path: String) = {
128 val file = new File(isabelle_system.platform_path(path))
130 for (line <- Source.fromFile(file).getLines) read_line(line)
137 private def get_code(entry: (String, HashMap[String, String])) = {
138 val (symbol, props) = entry
140 try { Integer.decode(props("code")).intValue }
142 case _: NoSuchElementException => error("Missing code for symbol " + symbol)
143 case _: NumberFormatException => error("Bad code for symbol " + symbol)
145 (symbol, new String(Character.toChars(code)))
148 private def init_recoders() = {
149 val list = symbols.elements.toList.map(get_code)
150 decoder = new Recoder(list ++ (for ((x, y) <- list) yield ("\\" + x, y)))
151 encoder = new Recoder(for ((x, y) <- list) yield (y, x))
157 read_symbols("$ISABELLE_HOME/etc/symbols")
158 read_symbols("$ISABELLE_HOME_USER/etc/symbols")