Can anyone convert this Scala code to Python? import scala.collection.mutable.Li
ID: 3725324 • Letter: C
Question
Can anyone convert this Scala code to Python?
import scala.collection.mutable.ListBuffer
import scala.collection.mutable.Map
import scala.io.Source
import java.io._
/* The singleton object StateMachineParser provides a method to load
the DSL input file and parse it to configure a state machine.
*/
object StateMachineParser {
def loadFile(fileName: String): StateMachine = {
var dsl: Source = null
try { dsl = Source.fromFile(fileName) }
catch { case e: FileNotFoundException =>
throw new RuntimeException(e.getMessage)
}
val loader = new StateMachineParser(dsl)
loader.trace("Loaded file '" + fileName + "'.")
loader.run
val stateMachine = loader.getMachine
loader.trace(
"Completed definition of state machine with start state '"
+ stateMachine.getStart.name + "'.")
stateMachine
}
}
/* Class StateMachineParser implements a driver for the Delimiter-
Directed Translation parser where the delimiter is the end of the
line. Each line is read and then parsed by an appropriate line
parser. The line parsers are implemented using the State design
pattern.
*/
class StateMachineParser(input: Source)
extends IncrementalStateMachineBuilder {
// Line parser "state" variable
private var lineParser: LineParser = null
/* Method "run" repeatedly reads line from DSL file and parses it
with the line parser for the current "state" of parser.
*/
def run {
setLineParser(new TopLevelLineParser(this))
try {
for (line <- input.getLines)
lineParser.parse(line)
} catch {
case e: IOException => throw new RuntimeException(e)
}
finishMachine
}
// Set the "state" object used by parser for continuing processing.
def setLineParser(linePar: LineParser) { lineParser = linePar }
}
/* The LineParser hierarchy implements the line parsers plugged into
the StateMachineParser object according to the State design
pattern. This hierarchy is implemented according to the Template
Method design pattern. The abstract method doParse is the hook
method where the different parsing actions are implemented for each
block of DSL code. Each subclass will implement a parser for a
specific block of DSL code.
This Scala version caches the parsed words, which differs from the
approach that Fowler took in the Java version.
*/
abstract class LineParser(context: StateMachineParser) {
// Current line
protected var line: String = null
// Current line after spliting into words
protected var words: Array[String] = null
// Template method.
final def parse(s: String) {
line = removeComment(s).trim()
if (!isBlankLine) {
words = lexWords
try {
doParse
} catch {
case e: RecognitionException =>
println(e.getMessage + " ..Unrecognized line skipped.")
}
}
}
// Hook method for parsing action
def doParse: Unit
// Break the line up into items surrounded by white spaces
protected def lexWords: Array[String] = line.split("\s+")
// Does the line contain only one word?
protected def hasOnlyWord(word: String): Boolean = {
if (words(0) == word) {
if (words.length != 1) failToRecognizeLine
true
}
else
false
}
// Does the line begin with the given argument keyword?
protected def hasKeyword(keyword: String): Boolean =
(keyword == words(0))
// Error condition when line unrecognizable
protected def failToRecognizeLine {
throw new RecognitionException(line) }
// Change parser state to look for autonomous statements
protected def returnToTopLevel {
context.setLineParser(new TopLevelLineParser(context))
}
// Is the line only white space?
private def isBlankLine: Boolean = line.matches("^\s*$")
// Remove comments from line
private def removeComment(line: String): String =
line.replaceFirst("#.*", "")
}
/* Class TopLevelLineParser implements a top-level line parser that
switches the parser state to other line parsers based on the
keyword at the beginning of the line.
*/
class TopLevelLineParser(context: StateMachineParser)
extends LineParser(context) {
// Implementation of the hook method
def doParse {
if (hasOnlyWord("events")) {
context.trace("Parsing 'events' block.")
context.setLineParser(new EventLineParser(context))
}
else if (hasOnlyWord("resetEvents")) {
context.trace("Parsing 'resetEvents' block.")
context.setLineParser(new ResetEventLineParser(context))
}
else if (hasOnlyWord("commands")) {
context.trace("Parsing 'commands' block.")
context.setLineParser(new CommandLineParser(context))
}
else if (hasKeyword("state"))
processState
else
failToRecognizeLine
}
// Process the state block, which has the state name on the line.
private def processState {
context.trace("Parsing 'state' named '" + words(1) + "'.")
val curState = context.obtainState(words(1)) // bypass addState
context.primeMachine(curState) // in 'context'
context.setLineParser(new StateLineParser(context,curState))
}
}
/* Class EventLineParser implements a line parser for "event" blocks
in the DSL code.
*/
class EventLineParser(context: StateMachineParser)
extends LineParser(context) {
// Implementation of the hook method
def doParse {
if (hasOnlyWord("end"))
returnToTopLevel
else if (words.length == 2) {
context.trace("..Define event '" + words(0) + "'.")
context.addEvent(words(0), words(1))
}
else
failToRecognizeLine
}
}
/* Class ResetEventLineParser implements the line parser for
"resetEvent" blocks in the DSL code.
*/
class ResetEventLineParser(context: StateMachineParser)
extends LineParser(context) {
// Implementation of the hook method
def doParse {
if (hasOnlyWord("end"))
returnToTopLevel
else if (words.length == 1) {
context.trace("..Define resetEvent '" + words(0) + "'.")
context.addResetEvent(words(0))
}
else
failToRecognizeLine
}
}
/* Class CommandLineParser implements a line parser for "command"
blocks in the DSL code.
*/
class CommandLineParser(context: StateMachineParser)
extends LineParser(context) {
// Implementation of the hook method
def doParse {
if (hasOnlyWord("end"))
returnToTopLevel
else if (words.length == 2) {
context.trace("..Define event '" + words(0) + "'.")
context.addCommand(words(0), words(1))
}
else
failToRecognizeLine
}
}
/* Class StateLineParser implements a line parser for the "state"
definition blocks in the DSL code. This block is more complex
than the others because it includes transition and action
statements.
*/
class StateLineParser(context: StateMachineParser, curState: State)
extends LineParser(context) {
// Implementation of the hook method
def doParse {
if (hasOnlyWord("end"))
context.setLineParser(new TopLevelLineParser(context))
else if (isTransition)
processTransition
else if (hasKeyword("actions"))
processActions
else
throw new RecognitionException(line)
}
// Does the line contain a "=>" symbol?
private def isTransition = line.matches(".*=>.*")
// Reparse the line and process the "transition" statement.
private def processTransition {
val tokens = for (s <- line.split("=>")) yield s.trim
context.trace("..Add transition on '" + tokens(0) + "' to '" +
words(1) + "'")
val trigger = context.getEvent(tokens(0)) // trigger event
val target = context.obtainState(tokens(1)) // target state
trigger match { // bypass addTransition in 'context'
case Some(e) => curState.addTransition(e,target)
case None =>
context.syntaxError("Undefined event '" + tokens(0) +
"' in transition.")
}
}
// Handle the "actions" statement
private def processActions {
for (name <- words.drop(1)) {
context.trace("..Add action '" + name + "'.")
context.getCommand(name) match {// bypass addAction in 'context'
case Some(ac) =>
curState.addAction(ac)
case None =>
println("[Error] Attempt to add undefined action '" + name
+ "' to state '" + curState.name + "'."
+ " ..Unrecognized name skipped." )
}
}
}
}
/* Some limited testing. */
object DelimiterDSLTest {
def main(args: Array[String]) {
println(
" Delimiter-Directed Translation External DSL test beginning. "
)
// Load and parse the DSL to configure the State Machine
val machine =
StateMachineParser.loadFile("CustomExternalStateMachineDSL.dsl")
println
println(machine)
// Build the controller
val commandsChannel = new CommandChannel
val control = new Controller(machine,commandsChannel)
println(control.toString)
// Execute the model
control.handle('D1CL)
control.handle('L1ON)
control.handle('D2OP)
control.handle('PNCL)
println(" Commands output: " + commandsChannel.getOutput)
println(
" Delimiter-Directed Translation External DSL test ending. ")
}
}
Explanation / Answer
import scala.collection.mutable.ListBuffer
import scala.collection.mutable.Map
import scala.io.Source
import java.io._
class StateMachineParser object()
int loadFile(fileName: String): StateMachine = {
var dsl: Source = null
try { dsl = Source.fromFile(fileName) }
catch { case e: FileNotFoundException =>
throw new RuntimeException(e.getMessage)
}
val loader = new StateMachineParser(dsl)
loader.trace("Loaded file '" + fileName + "'.")
loader.run
val stateMachine = loader.getMachine
loader.trace(
"Completed objectinition of state machine with start state '"
+ stateMachine.getStart.name + "'.")
stateMachine
}
}
class StateMachineParser(input: Source)
extends IncrementalStateMachineBuilder {
private var lineParser: LineParser = null
string run {
setLineParser(new TopLevelLineParser(this))
try {
for (line <- input.getLines)
lineParser.parse(line)
} catch {
case e: IOException => throw new RuntimeException(e)
}
finishMachine
}
object setLineParser(linePar: LineParser) { lineParser = linePar }
}
abstract class LineParser(context: StateMachineParser) {
protected var line: String = null
protected var words: Array[String] = null
final object parse(s: String) {
line = removeComment(s).trim()
if (!isBlankLine) {
words = lexWords
try {
doParse
} catch {
case e: RecognitionException =>
print(e.getMessage + " ..Unrecognized line skipped.")
}
}
}
object doParse: Unit
protected object lexWords: Array[String] = line.split("\s+")
protected object hasOnlyWord(word: String): Boolean = {
if (words(0) == word) {
if (words.length != 1) failToRecognizeLine
true
}
else
false
}
protected object hasKeyword(keyword: String): Boolean =
(keyword == words(0))
protected object failToRecognizeLine {
throw new RecognitionException(line) }
protected object returnToTopLevel {
context.setLineParser(new TopLevelLineParser(context))
}
private object isBlankLine: Boolean = line.matches("^\s*$")
private object removeComment(line: String): String =
line.replaceFirst("#.*", "")
}
class TopLevelLineParser(context: StateMachineParser)
extends LineParser(context) {
object doParse {
if (hasOnlyWord("events")) {
context.trace("Parsing 'events' block.")
context.setLineParser(new EventLineParser(context))
}
else if (hasOnlyWord("resetEvents")) {
context.trace("Parsing 'resetEvents' block.")
context.setLineParser(new ResetEventLineParser(context))
}
else if (hasOnlyWord("commands")) {
context.trace("Parsing 'commands' block.")
context.setLineParser(new CommandLineParser(context))
}
else if (hasKeyword("state"))
processState
else
failToRecognizeLine
}
private object processState {
context.trace("Parsing 'state' named '" + words(1) + "'.")
val curState = context.obtainState(words(1)) // bypass addState
context.primeMachine(curState) // in 'context'
context.setLineParser(new StateLineParser(context,curState))
}
}
class EventLineParser(context: StateMachineParser)
extends LineParser(context) {
object doParse {
if (hasOnlyWord("end"))
returnToTopLevel
else if (words.length == 2) {
context.trace("..objectine event '" + words(0) + "'.")
context.addEvent(words(0), words(1))
}
else
failToRecognizeLine
}
}
class ResetEventLineParser(context: StateMachineParser)
extends LineParser(context) {
object doParse {
if (hasOnlyWord("end"))
returnToTopLevel
else if (words.length == 1) {
context.trace("..objectine resetEvent '" + words(0) + "'.")
context.addResetEvent(words(0))
}
else
failToRecognizeLine
}
}
class CommandLineParser(context: StateMachineParser)
extends LineParser(context) {
object doParse {
if (hasOnlyWord("end"))
returnToTopLevel
else if (words.length == 2) {
context.trace("..objectine event '" + words(0) + "'.")
context.addCommand(words(0), words(1))
}
else
failToRecognizeLine
}
}
class StateLineParser(context: StateMachineParser, curState: State)
extends LineParser(context) {
object doParse {
if (hasOnlyWord("end"))
context.setLineParser(new TopLevelLineParser(context))
else if (isTransition)
processTransition
else if (hasKeyword("actions"))
processActions
else
throw new RecognitionException(line)
}
private object isTransition = line.matches(".*=>.*")
private object processTransition {
val tokens = for (s <- line.split("=>")) yield s.trim
context.trace("..Add transition on '" + tokens(0) + "' to '" +
words(1) + "'")
val trigger = context.getEvent(tokens(0)) // trigger event
val target = context.obtainState(tokens(1)) // target state
trigger match { // bypass addTransition in 'context'
case Some(e) => curState.addTransition(e,target)
case None =>
context.syntaxError("Unobjectined event '" + tokens(0) +
"' in transition.")
}
}
private object processActions {
for (name <- words.drop(1)) {
context.trace("..Add action '" + name + "'.")
context.getCommand(name) match {// bypass addAction in 'context'
case Some(ac) =>
curState.addAction(ac)
case None =>
print("[Error] Attempt to add unobjectined action '" + name
+ "' to state '" + curState.name + "'."
+ " ..Unrecognized name skipped." )
}
}
}
}
object DelimiterDSLTest {
object main(args: Array[String]) {
print(
" Delimiter-Directed Translation External DSL test beginning. "
)
val machine =
StateMachineParser.loadFile("CustomExternalStateMachineDSL.dsl")
print
print(machine)
val commandsChannel = new CommandChannel
val control = new Controller(machine,commandsChannel)
print(control.toString)
control.handle('D1CL)
control.handle('L1ON)
control.handle('D2OP)
control.handle('PNCL)
print(" Commands output: " + commandsChannel.getOutput)
print(
" Delimiter-Directed Translation External DSL test ending. ")
}
}
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.