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 parsley.cats.combinator.{some}
|
||||||
import cats.data.NonEmptyList
|
import cats.data.NonEmptyList
|
||||||
|
|
||||||
|
|
||||||
object parser {
|
object parser {
|
||||||
import lexer.implicits.implicitSymbol
|
import lexer.implicits.implicitSymbol
|
||||||
import lexer.{ident, integer, charLit, stringLit, negateCheck}
|
import lexer.{ident, integer, charLit, stringLit, negateCheck}
|
||||||
import ast._
|
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)
|
def parse(input: String): Result[String, Program] = parser.parse(input)
|
||||||
private val parser = lexer.fully(`<program>`)
|
private val parser = lexer.fully(`<program>`)
|
||||||
|
|
||||||
@ -77,7 +108,7 @@ object parser {
|
|||||||
private lazy val `<pair-elem-type>` =
|
private lazy val `<pair-elem-type>` =
|
||||||
(`<base-type>` <**> (`<array-type>` </> identity)) |
|
(`<base-type>` <**> (`<array-type>` </> identity)) |
|
||||||
`<pair-type>` ~> ((`<pair-elems-type>` <**> `<array-type>`.explain(
|
`<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)
|
)) </> UntypedPairType)
|
||||||
// TODO: better explanation here?
|
// TODO: better explanation here?
|
||||||
// Statements
|
// Statements
|
||||||
@ -89,7 +120,7 @@ object parser {
|
|||||||
)
|
)
|
||||||
private lazy val `<partial-func-decl>` =
|
private lazy val `<partial-func-decl>` =
|
||||||
(sepBy(`<param>`, ",") <~ ")" <~ "is" <~> `<stmt>`.guardAgainst {
|
(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) =>
|
} <~ "end") map { (params, stmt) =>
|
||||||
(FuncDecl((_: Type), (_: Ident), params, stmt)).tupled
|
(FuncDecl((_: Type), (_: Ident), params, stmt)).tupled
|
||||||
}
|
}
|
||||||
@ -103,19 +134,19 @@ object parser {
|
|||||||
private lazy val `<basic-stmt>` =
|
private lazy val `<basic-stmt>` =
|
||||||
(Skip from "skip")
|
(Skip from "skip")
|
||||||
| Read("read" ~> `<lvalue>`)
|
| Read("read" ~> `<lvalue>`)
|
||||||
| Free("free" ~> `<expr>`.label("a valid expression"))
|
| Free("free" ~> `<expr>`.labelAndExplain(LabelType.Expr))
|
||||||
| Return("return" ~> `<expr>`.label("a valid expression"))
|
| Return("return" ~> `<expr>`.labelAndExplain(LabelType.Expr))
|
||||||
| Exit("exit" ~> `<expr>`.label("a valid expression"))
|
| Exit("exit" ~> `<expr>`.labelAndExplain(LabelType.Expr))
|
||||||
| Print("print" ~> `<expr>`.label("a valid expression"), pure(false))
|
| Print("print" ~> `<expr>`.labelAndExplain(LabelType.Expr), pure(false))
|
||||||
| Print("println" ~> `<expr>`.label("a valid expression"), pure(true))
|
| Print("println" ~> `<expr>`.labelAndExplain(LabelType.Expr), pure(true))
|
||||||
| If(
|
| If(
|
||||||
"if" ~> `<expr>`.label("a valid expression") <~ "then",
|
"if" ~> `<expr>`.labelWithType(LabelType.Expr) <~ "then",
|
||||||
`<stmt>` <~ "else",
|
`<stmt>` <~ "else",
|
||||||
`<stmt>` <~ "fi"
|
`<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")
|
| 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
|
// TODO: Can we inline the name of the variable in the message
|
||||||
| Assign(`<lvalue>` <~ "=", `<rvalue>`)
|
| Assign(`<lvalue>` <~ "=", `<rvalue>`)
|
||||||
private lazy val `<lvalue>`: Parsley[LValue] =
|
private lazy val `<lvalue>`: Parsley[LValue] =
|
||||||
@ -130,10 +161,10 @@ object parser {
|
|||||||
Call(
|
Call(
|
||||||
"call" ~> `<ident>` <~ "(",
|
"call" ~> `<ident>` <~ "(",
|
||||||
sepBy(`<expr>`, ",") <~ ")"
|
sepBy(`<expr>`, ",") <~ ")"
|
||||||
) | `<expr>`.label("valid expression")
|
) | `<expr>`.labelWithType(LabelType.Expr)
|
||||||
private lazy val `<pair-elem>` =
|
private lazy val `<pair-elem>` =
|
||||||
Fst("fst" ~> `<lvalue>`.label("a valid pair"))
|
Fst("fst" ~> `<lvalue>`.label("valid pair"))
|
||||||
| Snd("snd" ~> `<lvalue>`.label("a valid pair"))
|
| Snd("snd" ~> `<lvalue>`.label("valid pair"))
|
||||||
private lazy val `<array-liter>` = ArrayLiter(
|
private lazy val `<array-liter>` = ArrayLiter(
|
||||||
"[" ~> sepBy(`<expr>`, ",") <~ "]"
|
"[" ~> sepBy(`<expr>`, ",") <~ "]"
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user