fix: added error messages for functions missing type, and late function decls

This commit is contained in:
Barf-Vader 2025-02-07 01:35:16 +00:00 committed by Guy C
parent b3ecae5dbb
commit a65cc01815
2 changed files with 18 additions and 11 deletions

View File

@ -33,7 +33,7 @@ val errConfig = new ErrorConfig {
"false" -> Label("boolean literal"), "false" -> Label("boolean literal"),
"true" -> Label("boolean literal"), "true" -> Label("boolean literal"),
"=" -> Label("assignment"), "=" -> Label("assignment"),
"[" -> Label("array index") "[" -> Label("array index"),
) )
} }
object lexer { object lexer {
@ -85,9 +85,10 @@ object lexer {
val errTokens = Seq( val errTokens = Seq(
lexer.nonlexeme.names.identifier.map(v => s"identifier $v"), lexer.nonlexeme.names.identifier.map(v => s"identifier $v"),
lexer.nonlexeme.integer.decimal32[Int].map(n => s"integer $n"), lexer.nonlexeme.integer.decimal32[Int].map(n => s"integer $n"),
lexer.nonlexeme.character.ascii.map(c => s"character literal \'$c\'"), (lexer.nonlexeme.character.ascii).map(c => s"character literal \'$c\'"),
lexer.nonlexeme.string.ascii.map(s => s"string literal \"$s\""), lexer.nonlexeme.string.ascii.map(s => s"string literal \"$s\""),
character.whitespace.map(_ => "") // lexer.nonlexeme.symbol("()").as("function call, bruh use keyword 'call' to call functions"),
character.whitespace.map(_ => ""),
) ++ desc.symbolDesc.hardKeywords.map { k => ) ++ desc.symbolDesc.hardKeywords.map { k =>
lexer.nonlexeme.symbol(k).as(s"keyword $k") lexer.nonlexeme.symbol(k).as(s"keyword $k")
} }

View File

@ -12,6 +12,8 @@ import cats.data.NonEmptyList
import parsley.errors.DefaultErrorBuilder import parsley.errors.DefaultErrorBuilder
import parsley.errors.ErrorBuilder import parsley.errors.ErrorBuilder
import parsley.errors.tokenextractors.LexToken import parsley.errors.tokenextractors.LexToken
import parsley.errors.patterns.VerifiedErrors
import parsley.character.char
object parser { object parser {
import lexer.implicits.implicitSymbol import lexer.implicits.implicitSymbol
@ -48,6 +50,10 @@ object parser {
case Expr case Expr
case Pair case Pair
val _parensCheck =
char('(').verifiedExplain("use keyword 'call' to call functions")
implicit val builder: ErrorBuilder[String] = new DefaultErrorBuilder with LexToken { implicit val builder: ErrorBuilder[String] = new DefaultErrorBuilder with LexToken {
def tokens = errTokens def tokens = errTokens
} }
@ -66,8 +72,8 @@ object parser {
GreaterEq from ">=" GreaterEq from ">="
) +: ) +:
SOps(InfixL)( SOps(InfixL)(
(Add from "+").label("binary operator"), ((Add from "+").label("binary operator") | _parensCheck),
(Sub from "-").label("binary operator") ((Sub from "-").label("binary operator") | _parensCheck)
) +: ) +:
SOps(InfixL)(Mul from "*", Div from "/", Mod from "%") +: SOps(InfixL)(Mul from "*", Div from "/", Mod from "%") +:
SOps(Prefix)( SOps(Prefix)(
@ -117,15 +123,15 @@ object parser {
// Statements // Statements
private lazy val `<program>` = Program( private lazy val `<program>` = Program(
"begin" ~> many( "begin" ~> many(
atomic(`<type>`.label("function declaration") <~> `<ident>` <~ "(") <**> `<partial-func-decl>` atomic((`<type>`.label("function declaration") <~> `<ident>` <~ "(")) <**> `<partial-func-decl>`
).label("function declaration"), ).label("function declaration"),
`<stmt>`.label("main program body") <~ "end" ((`<ident>` <~ "(")*> fail("function is missing return type") | `<stmt>`.label("main program body")) <~ "end"
) )
private lazy val `<partial-func-decl>` = private lazy val `<partial-func-decl>` =
FuncDecl( FuncDecl(
sepBy(`<param>`, ",") <~ ")" <~ "is", sepBy(`<param>`, ",") <~ ")".label("parenthesis") <~ "is",
`<stmt>`.guardAgainst { `<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" } <~ "end"
) )
private lazy val `<param>` = Param(`<type>`, `<ident>`) private lazy val `<param>` = Param(`<type>`, `<ident>`)
@ -150,8 +156,8 @@ object parser {
) )
| While("while" ~> `<expr>`.labelWithType(LabelType.Expr) <~ "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("valid initial value for variable")) | VarDecl(`<type>`, `<ident>` <~ "=".explain("functions must be defined on top of the main block"),
// TODO: Can we inline the name of the variable in the message `<rvalue>`.label("valid initial value for variable"))
| Assign(`<lvalue>` <~ "=", `<rvalue>`) | Assign(`<lvalue>` <~ "=", `<rvalue>`)
private lazy val `<lvalue>`: Parsley[LValue] = private lazy val `<lvalue>`: Parsley[LValue] =
`<pair-elem>` | `<ident-or-array-elem>` `<pair-elem>` | `<ident-or-array-elem>`