refactor: implemented labelAndExplain(), combining the two, and provided explanations for expr
Co-authored-by: gc1523
This commit is contained in:
parent
ded35dcc6e
commit
e787d7168f
@ -10,11 +10,42 @@ import parsley.syntax.zipped._
|
||||
import parsley.cats.combinator.{some}
|
||||
import cats.data.NonEmptyList
|
||||
|
||||
|
||||
object parser {
|
||||
import lexer.implicits.implicitSymbol
|
||||
import lexer.{ident, integer, charLit, stringLit, negateCheck}
|
||||
import ast._
|
||||
|
||||
//error extensions
|
||||
extension [A](p: Parsley[A]) {
|
||||
|
||||
//combines label and explain together into one function call
|
||||
def labelAndExplain(label: String, explanation: String): Parsley[A] = {
|
||||
p.label(label).explain(explanation)
|
||||
}
|
||||
def labelAndExplain(t: LabelType): Parsley[A] = {
|
||||
t match {
|
||||
case LabelType.Expr =>
|
||||
labelWithType(t).explain(
|
||||
"a valid expression can start with: null, literals, identifiers, unary operators, or parentheses. " +
|
||||
"Expressions can also contain array indexing and binary operators. " +
|
||||
"Pair extraction is not allowed in expressions, only in assignments.")
|
||||
case _ => labelWithType(t)
|
||||
}
|
||||
}
|
||||
|
||||
def labelWithType(t: LabelType): Parsley[A] = {
|
||||
t match {
|
||||
case LabelType.Expr => p.label("valid expression")
|
||||
case LabelType.Pair => p.label("valid pair")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum LabelType:
|
||||
case Expr
|
||||
case Pair
|
||||
|
||||
def parse(input: String): Result[String, Program] = parser.parse(input)
|
||||
private val parser = lexer.fully(`<program>`)
|
||||
|
||||
@ -77,7 +108,7 @@ object parser {
|
||||
private lazy val `<pair-elem-type>` =
|
||||
(`<base-type>` <**> (`<array-type>` </> identity)) |
|
||||
`<pair-type>` ~> ((`<pair-elems-type>` <**> `<array-type>`.explain(
|
||||
"for a pair to contain a pair type, it must be an array or erased pair"
|
||||
"non-erased pair types cannot be nested"
|
||||
)) </> UntypedPairType)
|
||||
// TODO: better explanation here?
|
||||
// Statements
|
||||
@ -89,7 +120,7 @@ object parser {
|
||||
)
|
||||
private lazy val `<partial-func-decl>` =
|
||||
(sepBy(`<param>`, ",") <~ ")" <~ "is" <~> `<stmt>`.guardAgainst {
|
||||
case stmts if !stmts.isReturning => Seq("All functions must end in a returning statement")
|
||||
case stmts if !stmts.isReturning => Seq("all functions must end in a returning statement")
|
||||
} <~ "end") map { (params, stmt) =>
|
||||
(FuncDecl((_: Type), (_: Ident), params, stmt)).tupled
|
||||
}
|
||||
@ -103,19 +134,19 @@ object parser {
|
||||
private lazy val `<basic-stmt>` =
|
||||
(Skip from "skip")
|
||||
| Read("read" ~> `<lvalue>`)
|
||||
| Free("free" ~> `<expr>`.label("a valid expression"))
|
||||
| Return("return" ~> `<expr>`.label("a valid expression"))
|
||||
| Exit("exit" ~> `<expr>`.label("a valid expression"))
|
||||
| Print("print" ~> `<expr>`.label("a valid expression"), pure(false))
|
||||
| Print("println" ~> `<expr>`.label("a valid expression"), pure(true))
|
||||
| Free("free" ~> `<expr>`.labelAndExplain(LabelType.Expr))
|
||||
| Return("return" ~> `<expr>`.labelAndExplain(LabelType.Expr))
|
||||
| Exit("exit" ~> `<expr>`.labelAndExplain(LabelType.Expr))
|
||||
| Print("print" ~> `<expr>`.labelAndExplain(LabelType.Expr), pure(false))
|
||||
| Print("println" ~> `<expr>`.labelAndExplain(LabelType.Expr), pure(true))
|
||||
| If(
|
||||
"if" ~> `<expr>`.label("a valid expression") <~ "then",
|
||||
"if" ~> `<expr>`.labelWithType(LabelType.Expr) <~ "then",
|
||||
`<stmt>` <~ "else",
|
||||
`<stmt>` <~ "fi"
|
||||
)
|
||||
| While("while" ~> `<expr>`.label("a valid expression") <~ "do", `<stmt>` <~ "done")
|
||||
| While("while" ~> `<expr>`.labelWithType(LabelType.Expr) <~ "do", `<stmt>` <~ "done")
|
||||
| Block("begin" ~> `<stmt>` <~ "end")
|
||||
| VarDecl(`<type>`, `<ident>` <~ "=", `<rvalue>`.label("a valid initial value for variable"))
|
||||
| VarDecl(`<type>`, `<ident>` <~ "=", `<rvalue>`.label("valid initial value for variable"))
|
||||
// TODO: Can we inline the name of the variable in the message
|
||||
| Assign(`<lvalue>` <~ "=", `<rvalue>`)
|
||||
private lazy val `<lvalue>`: Parsley[LValue] =
|
||||
@ -130,10 +161,10 @@ object parser {
|
||||
Call(
|
||||
"call" ~> `<ident>` <~ "(",
|
||||
sepBy(`<expr>`, ",") <~ ")"
|
||||
) | `<expr>`.label("valid expression")
|
||||
) | `<expr>`.labelWithType(LabelType.Expr)
|
||||
private lazy val `<pair-elem>` =
|
||||
Fst("fst" ~> `<lvalue>`.label("a valid pair"))
|
||||
| Snd("snd" ~> `<lvalue>`.label("a valid pair"))
|
||||
Fst("fst" ~> `<lvalue>`.label("valid pair"))
|
||||
| Snd("snd" ~> `<lvalue>`.label("valid pair"))
|
||||
private lazy val `<array-liter>` = ArrayLiter(
|
||||
"[" ~> sepBy(`<expr>`, ",") <~ "]"
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user