Created
December 11, 2023 18:06
-
-
Save hyperswine/c360392b7db810847a14ac28b0e578e2 to your computer and use it in GitHub Desktop.
example-scala3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scala.util.parsing.combinator._ | |
sealed trait WorkflowToken | |
case class IDENTIFIER(str: String) extends WorkflowToken | |
case class LITERAL(str: String) extends WorkflowToken | |
case class INDENTATION(spaces: Int) extends WorkflowToken | |
case object EXIT extends WorkflowToken | |
case object READINPUT extends WorkflowToken | |
case object CALLSERVICE extends WorkflowToken | |
case object SWITCH extends WorkflowToken | |
case object OTHERWISE extends WorkflowToken | |
case object COLON extends WorkflowToken | |
case object ARROW extends WorkflowToken | |
case object EQUALS extends WorkflowToken | |
case object COMMA extends WorkflowToken | |
case object INDENT extends WorkflowToken | |
case object DEDENT extends WorkflowToken | |
import scala.util.chaining._ | |
object WorkflowLexer extends RegexParsers: | |
override def skipWhitespace = true | |
override val whiteSpace = "[ \t\r\f]+".r | |
def identifier = "[a-zA-Z_][a-zA-Z0-9_]*".r ^^ { IDENTIFIER.apply } | |
def literal: Parser[LITERAL] = "[^\"]*".r ^^ { str => | |
str.substring(1, str.length - 1) |> LITERAL.apply | |
} | |
def indentation = "\n[ ]*".r ^^ { whitespace => | |
whitespace.length - 1 |> INDENTATION.apply | |
} | |
def exit = "exit" ^^ (_ => EXIT) | |
def readInput = "read input" ^^ (_ => READINPUT) | |
def callService = "call service" ^^ (_ => CALLSERVICE) | |
def switch = "switch" ^^ (_ => SWITCH) | |
def otherwise = "otherwise" ^^ (_ => OTHERWISE) | |
def colon = ":" ^^ (_ => COLON) | |
def arrow = "->" ^^ (_ => ARROW) | |
def equals = "==" ^^ (_ => EQUALS) | |
def comma = "," ^^ (_ => COMMA) | |
def processIndentations( | |
tokens: List[WorkflowToken], | |
indents: List[Int] = List(0) | |
): List[WorkflowToken] = | |
tokens.headOption match | |
case Some(INDENTATION(spaces)) if spaces > indents.head => | |
INDENT :: processIndentations(tokens.tail, spaces :: indents) | |
case Some(INDENTATION(spaces)) if spaces < indents.head => | |
val (dropped, kept) = indents.partition(_ > spaces) | |
(dropped map (_ => DEDENT)) ::: processIndentations(tokens.tail, kept) | |
case Some(INDENTATION(spaces)) if spaces == indents.head => | |
processIndentations(tokens.tail, indents) | |
case Some(token) => token :: processIndentations(tokens.tail, indents) | |
case None => indents.filter(_ > 0).map(_ => DEDENT) | |
def tokens = | |
((exit | readInput | callService | switch | otherwise | colon | arrow | equals | comma | literal | identifier | indentation) |> rep1 |> phrase) ^^ { | |
rawtokens => processIndentations(rawtokens) | |
} | |
def apply(code: String) = parse(tokens, code) match | |
case NoSuccess(msg, next) => Left(WorkflowLexerError(msg)) | |
case Success(result, next) => Right(result) | |
case _ => Left(WorkflowLexerError("Other error")) | |
val code = """ | |
read input name, country | |
switch: | |
country == "PT" -> | |
call service "A" | |
exit | |
otherwise -> | |
call service "B" | |
switch: | |
name == "unknown" -> | |
exit | |
otherwise -> | |
call service "C" | |
exit | |
""" | |
WorkflowLexer(code) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment