//> using scala "3.6.4"
//> using dep "dev.zio::zio-parser:0.1.11"
//> using file "Parser.scala"
import scala.reflect.TypeTest
import zio.parser.*
import zio.Chunk
enum Token:
case For
case While
case LParen
case RParen
case LitBool(value: Boolean)
case Ident(name: String)
enum Stat:
//for(i)
case For(iterator: String)
//while(cond)
case While(condition: Boolean)
case Identifier(name: String) //C'est pas un statement mais fuck pour l'exemple
type ASTParser[A] = Parser[String, Token, A]
private def anyTokenOf[T <: Token](using test: TypeTest[Token, T]): ASTParser[T] =
Parser.any[Token].transformEither:
case t: T => Right(t)
case other => Left(s"Unexpected token: $other")
private def anyToken(expected: Token): ASTParser[Unit] =
Parser.any[Token].transformEither:
case t if t == expected => Right(())
case other => Left(s"Unexpected token: $other, Expected: $expected")
val forParser: ASTParser[Stat] = anyToken(Token.For)
.zip(anyToken(Token.LParen).fatal)
.zip(anyTokenOf[Token.Ident].map(_.name).fatal)
.zip(anyToken(Token.RParen).fatal)
.map(Stat.For.apply)
val whileParser: ASTParser[Stat] = anyToken(Token.While)
.zip(anyToken(Token.LParen).fatal)
.zip(anyTokenOf[Token.LitBool].map(_.value).fatal)
.zip(anyToken(Token.RParen).fatal)
.map(Stat.While.apply)
val identParser: ASTParser[Stat] = anyTokenOf[Token.Ident].map(id => Stat.Identifier(id.name))
val statParser = forParser
.orElse(whileParser)
.orElse(identParser)
.repeat0
println(statParser.parseChunk(Chunk(Token.For, Token.LParen, Token.Ident("i"), Token.RParen)))
println(statParser.parseChunk(Chunk(Token.While, Token.LParen, Token.LitBool(true), Token.RParen)))
println(statParser.parseChunk(Chunk(Token.Ident("foo"))))
//Should fail
println("=== Should fail with meaningful error ===")
//Unexpected EOF
println(statParser.parseChunk(Chunk(Token.For)))
//Unexpected EOF
println(statParser.parseChunk(Chunk(Token.While)))
//Unexpected Token (lit bool vs identifier)
println(statParser.parseChunk(Chunk(Token.For, Token.LParen, Token.LitBool(true), Token.RParen)))
//Unexpected Token (identifier vs lit bool)
println(statParser.parseChunk(Chunk(Token.While, Token.LParen, Token.Ident("foo"), Token.RParen)))
//Unexpected EOF
println(statParser.parseChunk(Chunk(Token.For, Token.LParen, Token.Ident("i"))))
//Unexpected EOF
println(statParser.parseChunk(Chunk(Token.While, Token.LParen, Token.LitBool(true))))
//Unexpected Token (identifier vs l-paren)
println(statParser.parseChunk(Chunk(Token.For, Token.Ident("i"), Token.RParen)))
//Unexpected Token (lit bool vs l-paren)
println(statParser.parseChunk(Chunk(Token.While, Token.LitBool(true), Token.RParen)))