blob: 88175d26e469d7ee9b2ef604b8713f994c0befde (
plain) (
blame)
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
/* NSC -- new Scala compiler
* Copyright 2005-2010 LAMP/EPFL
* @author Martin Odersky
*/
// $Id$
package scala.tools.nsc
package util
import scala.tools.nsc.util.SourceFile.{LF, FF, CR, SU}
abstract class CharArrayReader { self =>
val buf: Array[Char]
def decodeUni: Boolean = true
/** An error routine to call on bad unicode escapes \\uxxxx. */
protected def error(offset: Int, msg: String)
/** the last read character */
var ch: Char = _
/** The offset one past the last read character */
var charOffset: Int = 0
/** The start offset of the current line */
var lineStartOffset: Int = 0
/** The start offset of the line before the current one */
var lastLineStartOffset: Int = 0
private var lastUnicodeOffset = -1
/** Is last character a unicode escape \\uxxxx? */
def isUnicodeEscape = charOffset == lastUnicodeOffset
/** Advance one character */
final def nextChar() {
if (charOffset >= buf.length) {
ch = SU
} else {
val c = buf(charOffset)
ch = c
charOffset += 1
if (c == '\\') potentialUnicode()
else if (c < ' ') potentialLineEnd()
// print("`"+ch+"'")
}
}
/** Interpret \\uxxxx escapes */
private def potentialUnicode() {
def evenSlashPrefix: Boolean = {
var p = charOffset - 2
while (p >= 0 && buf(p) == '\\') p -= 1
(charOffset - p) % 2 == 0
}
def udigit: Int = {
val d = digit2int(buf(charOffset), 16)
if (d >= 0) charOffset += 1
else error(charOffset, "error in unicode escape")
d
}
if (charOffset < buf.length && buf(charOffset) == 'u' && decodeUni && evenSlashPrefix) {
do charOffset += 1
while (charOffset < buf.length && buf(charOffset) == 'u')
val code = udigit << 12 | udigit << 8 | udigit << 4 | udigit
lastUnicodeOffset = charOffset
ch = code.toChar
}
}
/** Handle line ends, replace CR+LF by LF */
private def potentialLineEnd() {
if (ch == CR)
if (charOffset < buf.length && buf(charOffset) == LF) {
charOffset += 1
ch = LF
}
if (ch == LF || ch == FF) {
lastLineStartOffset = lineStartOffset
lineStartOffset = charOffset
}
}
/** Convert a character digit to an Int according to given base,
* -1 if no success */
def digit2int(ch: Char, base: Int): Int = {
if ('0' <= ch && ch <= '9' && ch < '0' + base)
ch - '0'
else if ('A' <= ch && ch < 'A' + base - 10)
ch - 'A' + 10
else if ('a' <= ch && ch < 'a' + base - 10)
ch - 'a' + 10
else
-1
}
/** A new reader that takes off at the current character position */
def lookaheadReader = new CharArrayReader {
val buf = self.buf
charOffset = self.charOffset
ch = self.ch
override def decodeUni = self.decodeUni
def error(offset: Int, msg: String) = self.error(offset, msg)
/** A mystery why CharArrayReader.nextChar() returns Unit */
def getc() = { nextChar() ; ch }
}
}
|