diff options
| author | Jack | 2016-02-02 11:49:38 -0800 |
|---|---|---|
| committer | azidar | 2016-02-09 18:57:06 -0800 |
| commit | b2d9eacd26e8283f438bc6429770497290d5b9c3 (patch) | |
| tree | 4eff98b858a049bc533a6fcaf10888a331c6e773 /src | |
| parent | 43ecab5aec6751d05ac986570e0648bb3d90982a (diff) | |
Adding ScalaTest for unit testing of Scala FIRRTL. Added a few basic tests for the Parser. Added custom Parser exceptions for better error reporting and checking. Fixed bug in grammar not allowing most keywords as Ids
Diffstat (limited to 'src')
| -rw-r--r-- | src/main/antlr4/FIRRTL.g4 | 36 | ||||
| -rw-r--r-- | src/main/scala/firrtl/Parser.scala | 11 | ||||
| -rw-r--r-- | src/main/scala/firrtl/PrimOps.scala | 1 | ||||
| -rw-r--r-- | src/main/scala/firrtl/Visitor.scala | 10 |
4 files changed, 51 insertions, 7 deletions
diff --git a/src/main/antlr4/FIRRTL.g4 b/src/main/antlr4/FIRRTL.g4 index 2faef4e0..e0e10d45 100644 --- a/src/main/antlr4/FIRRTL.g4 +++ b/src/main/antlr4/FIRRTL.g4 @@ -93,12 +93,42 @@ id | keyword ; -// TODO add all keywords keyword - : dir - | 'inst' + : 'circuit' + | 'module' + | 'input' + | 'output' + | 'UInt' + | 'SInt' + | 'UBits' + | 'SBits' + | 'Clock' + | 'wire' + | 'reg' | 'mem' | 'reset' + | 'data-type' + | 'depth' + | 'read-latency' + | 'write-latency' + | 'read-under-write' + | 'reader' + | 'writer' + | 'readwriter' + | 'inst' + | 'node' + | 'is' + | 'invalid' + | 'when' + | 'else' + | 'stop' + | 'printf' + | 'skip' + | 'old' + | 'new' + | 'undefined' + | 'mux' + | 'validif' ; // Parentheses are added as part of name because semantics require no space between primop and open parentheses diff --git a/src/main/scala/firrtl/Parser.scala b/src/main/scala/firrtl/Parser.scala index 98864e92..41426357 100644 --- a/src/main/scala/firrtl/Parser.scala +++ b/src/main/scala/firrtl/Parser.scala @@ -3,13 +3,18 @@ package firrtl import org.antlr.v4.runtime._; import org.antlr.v4.runtime.atn._; import org.antlr.v4.runtime.tree._; +import com.typesafe.scalalogging.LazyLogging import java.io.FileInputStream import scala.collection.JavaConverters._ import scala.io.Source import Utils._ import antlr._ -object Parser +class ParserException(message: String) extends Exception(message) +case class ParameterNotSpecifiedException(message: String) extends ParserException(message) +case class ParameterRedefinedException(message: String) extends ParserException(message) + +object Parser extends LazyLogging { /** Takes Iterator over lines of FIRRTL, returns AST (root node is Circuit) * @@ -17,6 +22,7 @@ object Parser */ def parse(filename: String, lines: Iterator[String]): Circuit = { val fixedInput = Translator.addBrackets(lines) + //logger.debug("Preprocessed Input:\n" + fixedInput.result) val antlrStream = new ANTLRInputStream(fixedInput.result) val lexer = new FIRRTLLexer(antlrStream) val tokens = new CommonTokenStream(lexer) @@ -28,6 +34,9 @@ object Parser // Concrete Syntax Tree val cst = parser.circuit + val numSyntaxErrors = parser.getNumberOfSyntaxErrors + if (numSyntaxErrors > 0) throw new ParserException(s"${numSyntaxErrors} syntax error(s) detected") + val visitor = new Visitor(filename) //val ast = visitor.visitCircuit(cst) match { val ast = visitor.visit(cst) match { diff --git a/src/main/scala/firrtl/PrimOps.scala b/src/main/scala/firrtl/PrimOps.scala index 56d1053c..790fa538 100644 --- a/src/main/scala/firrtl/PrimOps.scala +++ b/src/main/scala/firrtl/PrimOps.scala @@ -42,6 +42,7 @@ object PrimOps extends LazyLogging { HEAD_OP -> "head", TAIL_OP -> "tail" ) + lazy val listing: Seq[String] = PrimOps.mapPrimOp2String.map { case (k,v) => v } toSeq private val mapString2PrimOp = mapPrimOp2String.map(_.swap) def fromString(op: String): PrimOp = mapString2PrimOp(op) diff --git a/src/main/scala/firrtl/Visitor.scala b/src/main/scala/firrtl/Visitor.scala index 3f5b64e6..2ba12b92 100644 --- a/src/main/scala/firrtl/Visitor.scala +++ b/src/main/scala/firrtl/Visitor.scala @@ -113,7 +113,7 @@ class Visitor(val fullFilename: String) extends FIRRTLBaseVisitor[AST] val seq = map getOrElse (field, Seq()) map + (field -> (seq :+ children(2))) } else { // data-type, depth, read-latency, write-latency, read-under-write - if (map.contains(field)) throw new Exception(s"Redefinition of mem field ${field}") + if (map.contains(field)) throw new ParameterRedefinedException(s"Redefinition of ${field}") else map + (field -> Seq(children(2))) } parseChildren(children.drop(3), newMap) // We consume tokens in groups of three (eg. 'depth' '=>' 5) @@ -124,8 +124,12 @@ class Visitor(val fullFilename: String) extends FIRRTLBaseVisitor[AST] // Build map of different Memory fields to their values val map = try { parseChildren(ctx.children.drop(4), Map[String, Seq[ParseTree]]()) // First 4 tokens are 'mem' id ':' '{', skip to fields - } catch { - case e: Exception => throw new Exception(s"[${info}] ${e.getMessage}") // attach line number + } catch { // attach line number + case e: ParameterRedefinedException => throw new ParameterRedefinedException(s"[${info}] ${e.message}") + } + // Check for required fields + Seq("data-type", "depth", "read-latency", "write-latency") foreach { field => + map.getOrElse(field, throw new ParameterNotSpecifiedException(s"[${info}] Required mem field ${field} not found")) } // Each memory field value has been left as ParseTree type, need to convert // TODO Improve? Remove dynamic typecast of data-type |
