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
|
// See LICENSE for license details.
package firrtl
import firrtl.ir._
import java.nio.charset.StandardCharsets.UTF_8
import scala.annotation.tailrec
// Default implementations are for valid FIRRTL Strings
trait StringLitHandler {
// Apply correct escaping for strings in a given language
def escape(lit: StringLit): String = {
@tailrec
def escape(in: Array[Byte], str: String): String = {
if (in.isEmpty) str
else {
val s = in.head match {
case 0x5c => "\\\\"
case 0x0a => "\\n"
case 0x09 => "\\t"
case 0x22 => "\\\""
case c =>
if (c >= 0x20 && c <= 0x7e) new String(Array(c), UTF_8)
else throw new FIRRTLException(s"Unsupported byte in StringLit: $c")
}
escape(in.tail, str + s)
}
}
escape(lit.array, "")
}
// Turn raw parsed strings into String Literals
def unescape(raw: String): StringLit = {
@tailrec
def unescape(in: Array[Byte], out: Array[Byte]): Array[Byte] = {
if (in.isEmpty) out
else {
val c = in.head
if ((c < 0x20) || (c > 0x7e)) { // Range from ' ' to '~'
val msg = "Unsupported unescaped UTF-8 Byte 0x%02x! ".format(c) +
"Valid range [0x20-0x7e]"
throw new InvalidStringLitException(msg)
}
// Handle escaped characters
if (c == 0x5c) { // backslash
val (n: Int, bytes: Array[Byte]) = in(1) match {
case 0x5c => (2, Array[Byte](0x5c)) // backslash
case 0x6e => (2, Array[Byte](0x0a)) // newline
case 0x74 => (2, Array[Byte](0x09)) // tab
case 0x27 => (2, Array[Byte](0x27)) // single quote
case 0x22 => (2, Array[Byte](0x22)) // double quote
// TODO Finalize supported escapes, implement hex2Bytes
//case 0x78 => (4, hex2Bytes(in.slice(2, 3)))) // hex escape
//case 0x75 => (6, hex2Bytes(in.slice(2, 5))) // unicode excape
case e => // error
val msg = s"Invalid escape character ${e.toChar}! " +
"Valid characters [nt'\"\\]"
throw new InvalidEscapeCharException(msg)
}
unescape(in.drop(n), out ++ bytes) // consume n
} else {
unescape(in.tail, out :+ in.head)
}
}
}
val byteArray = raw.getBytes(java.nio.charset.StandardCharsets.UTF_8)
StringLit(unescape(byteArray, Array()))
}
// Translate from FIRRTL formatting to the specific language's formatting
def format(lit: StringLit): StringLit = ???
// Translate from the specific language's formatting to FIRRTL formatting
def unformat(lit: StringLit): StringLit = ???
}
object FIRRTLStringLitHandler extends StringLitHandler
object VerilogStringLitHandler extends StringLitHandler {
// Change FIRRTL format string to Verilog format
override def format(lit: StringLit): StringLit = {
@tailrec
def format(in: Array[Byte], out: Array[Byte], percent: Boolean): Array[Byte] = {
if (in.isEmpty) out
else {
if (percent && in.head == 'x') format(in.tail, out :+ 'h'.toByte, percent = false)
else format(in.tail, out :+ in.head, in.head == '%' && !percent)
}
}
StringLit(format(lit.array, Array(), percent = false))
}
}
|