31648
|
1 |
/* Title: Pure/General/scan.scala
|
|
2 |
Author: Makarius
|
|
3 |
|
|
4 |
Efficient scanning of literals.
|
|
5 |
*/
|
|
6 |
|
|
7 |
package isabelle
|
|
8 |
|
|
9 |
import scala.util.parsing.combinator.RegexParsers
|
|
10 |
|
|
11 |
|
|
12 |
object Scan
|
|
13 |
{
|
|
14 |
|
|
15 |
/* class Lexicon -- position tree */
|
|
16 |
|
|
17 |
case class Lexicon(val tab: Map[Char, (Boolean, Lexicon)])
|
|
18 |
|
|
19 |
val empty_lexicon = Lexicon(Map())
|
|
20 |
|
|
21 |
def is_literal(lx: Lexicon, str: CharSequence): Boolean =
|
|
22 |
{
|
|
23 |
val len = str.length
|
|
24 |
def is_lit(lexicon: Lexicon, i: Int): Boolean =
|
|
25 |
i < len && {
|
|
26 |
lexicon.tab.get(str.charAt(i)) match {
|
|
27 |
case Some((tip, lex)) => tip && i + 1 == len || is_lit(lex, i + 1)
|
|
28 |
case None => false
|
|
29 |
}
|
|
30 |
}
|
|
31 |
is_lit(lx, 0)
|
|
32 |
}
|
|
33 |
|
|
34 |
def extend_lexicon(lx: Lexicon, str: CharSequence): Lexicon =
|
|
35 |
{
|
|
36 |
val len = str.length
|
|
37 |
def ext(lexicon: Lexicon, i: Int): Lexicon =
|
|
38 |
if (i == len) lexicon
|
|
39 |
else {
|
|
40 |
val c = str.charAt(i)
|
|
41 |
val is_last = (i + 1 == len)
|
|
42 |
lexicon.tab.get(c) match {
|
|
43 |
case Some((tip, lex)) => Lexicon(lexicon.tab + (c -> (tip || is_last, ext(lex, i + 1))))
|
|
44 |
case None => Lexicon(lexicon.tab + (c -> (is_last, ext(empty_lexicon, i + 1))))
|
|
45 |
}
|
|
46 |
}
|
|
47 |
if (is_literal(lx, str)) lx else ext(lx, 0)
|
|
48 |
}
|
|
49 |
|
|
50 |
}
|
|
51 |
|
|
52 |
|
|
53 |
class Scan extends RegexParsers
|
|
54 |
{
|
|
55 |
override val whiteSpace = "".r
|
|
56 |
|
|
57 |
def keyword(lx: Scan.Lexicon): Parser[String] = new Parser[String] {
|
|
58 |
def apply(in: Input) =
|
|
59 |
{
|
|
60 |
val source = in.source
|
|
61 |
val offset = in.offset
|
|
62 |
val len = source.length - offset
|
|
63 |
|
|
64 |
def scan(lexicon: Scan.Lexicon, i: Int, res: Int): Int =
|
|
65 |
{
|
|
66 |
if (i < len) {
|
|
67 |
lexicon.tab.get(source.charAt(offset + i)) match {
|
|
68 |
case Some((tip, lex)) => scan(lex, i + 1, if (tip) i + 1 else res)
|
|
69 |
case None => res
|
|
70 |
}
|
|
71 |
} else res
|
|
72 |
}
|
|
73 |
scan(lx, 0, 0) match {
|
|
74 |
case res if res > 0 =>
|
|
75 |
Success(source.subSequence(offset, res).toString, in.drop(res))
|
|
76 |
case _ => Failure("keyword expected", in)
|
|
77 |
}
|
|
78 |
}
|
|
79 |
}.named("keyword")
|
|
80 |
|
|
81 |
}
|
|
82 |
|