blob: 9fe40af875378480b518c0673b80f35b48ef40ce (
plain)
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
111
112
113
114
115
116
117
118
119
120
|
/* TODO
* - Add support for comments (that being said, current Scopers regex should ignore commented lines)
* - Add better error messages for illformed FIRRTL
* - Add support for files that do not have a circuit (like a module by itself in a file)
* - Improve performance? Replace regex?
* - Add proper commnad-line arguments?
* - Wrap in Reader subclass. This would have less memory footprint than creating a large string
*/
package firrtl
import scala.io.Source
import scala.collection.mutable.Stack
import scala.collection.mutable.StringBuilder
import java.io._
object Translator
{
def addBrackets(inputIt: Iterator[String]): StringBuilder = {
def countSpaces(s: String): Int = s.prefixLength(_ == ' ')
def stripComments(s: String): String = s takeWhile (!";".contains(_))
val Scopers = """\s*(circuit|module|when|else)(.*)""".r
// Function start
val it = inputIt.zipWithIndex
var ret = new StringBuilder()
if( !it.hasNext ) throw new Exception("Empty file!")
// Find circuit before starting scope checks
var line = it.next
while ( it.hasNext && !line._1.contains("circuit") ) {
ret ++= line._1 + "\n"
line = it.next
}
ret ++= line._1 + " { \n"
if( !it.hasNext ) throw new Exception("No circuit in file!")
val scope = Stack[Int]()
val lowestScope = countSpaces(line._1)
scope.push(lowestScope)
var newScope = true // indicates if increasing scope spacing is legal on next line
while( it.hasNext ) {
it.next match { case (lineText, lineNum) =>
val text = stripComments(lineText)
val spaces = countSpaces(text)
val l = if (text.length > spaces ) { // Check that line has text in it
if (newScope) {
if( spaces <= scope.top ) scope.push(spaces+2) // Hack for one-line scopes
else scope.push(spaces)
}
// Check if change in current scope
if( spaces < scope.top ) {
while( spaces < scope.top ) {
// Close scopes (adding brackets as we go)
scope.pop()
ret.deleteCharAt(ret.lastIndexOf("\n")) // Put on previous line
ret ++= " }\n"
}
if( spaces != scope.top )
throw new Exception("Spacing does not match scope on line : " + lineNum + " : " + scope.top)
}
else if( spaces > scope.top )
throw new Exception("Invalid increase in scope on line " + lineNum)
// Now match on legal scope increasers
text match {
case Scopers(keyword, _* ) => {
newScope = true
//text + " { "
text.replaceFirst(":", ": {")
}
case _ => {
newScope = false
text
}
}
} // if( text.length > spaces )
else {
text // empty lines
}
ret ++= l + "\n"
} // it.next match
} // while( it.hasNext )
// Print any closing braces
while( scope.top > lowestScope ) {
scope.pop()
ret.deleteCharAt(ret.lastIndexOf("\n")) // Put on previous line
ret ++= " }\n"
}
ret
}
def main(args: Array[String]) {
try {
val translation = addBrackets(Source.fromFile(args(0)).getLines)
val writer = new PrintWriter(new File(args(1)))
writer.write(translation.result)
writer.close()
} catch {
case e: Exception => {
throw new Exception("USAGE: Translator <input file> <output file>\n" + e)
}
}
}
}
|