Reputation: 1
I had just started taking Haskell class and in one of my assignment, the given test case is suppose to throw an error along with the tokens at the end of the error. I managed to show the error but couldn't figure out how to show it along with the tokens from the test case.
The test cases that were given is check "(+ 4 (3 5 ))"
and the expected output is
*** Exception: Parse Error: invalid expression [OpenParen,PosNum 3.0,PosNum 5.0,CloseParen,CloseParen]
And this is the output that I got:
*** Exception: Parse Error: invalid expression
CallStack (from HasCallStack):
error, called at test.hs:43:11 in main:Test
This is what I got so far, it throws no error when compile and the test case throws the right error, however, it doesn't include the tokens:
module Test where
data Token = OpenParen
| CloseParen
| Operator Char
| PosNum Double
deriving (Show, Eq)
data ParseTree = NumNode Double
| OpNode Char [ParseTree]
deriving Show
scan :: String ->[Token]
scan xs
| null lexeme = []
| c == '(' = OpenParen:scan rest
| c == ')' = CloseParen:scan rest
| elem c ['+', '-', '*', '/'] = Operator c: scan (cs ++ rest)
| elem c ['0'..'9'] = PosNum (read (c:cs):: Double):scan rest
| otherwise = error ("Lexical Error - invalid character: " ++ [c])
where [(lexeme, rest)] = lex xs
c:cs = lexeme
recognize :: [Token] -> Bool
recognize ts = let (s, r) = rexpr ts
in s && null r
-- <expr> ->OPENPAREN OPERATOR <operands> CLOSEPAREN | POSNUMBER
rexpr :: [Token] -> (Bool, [Token])
rexpr (OpenParen:Operator _: rest) = let(b1,r1) = roperands rest
in case r1 of
CloseParen:r2 -> (b1, r2)
_ -> error "Parse Error: expected closing parenthesis"
rexpr (PosNum _:rest) = (True, rest)
rexpr _ = error "Parse Error: invalid expression"
-- <operands> -> <expr> [<operands>]
roperands :: [Token] -> (Bool, [Token])
roperands ts = let (b1, r1) = rexpr ts
in case isValidStart r1 of
True -> let (b2, r2) = roperands r1 in (b1 && b2, r2)
False -> (b1, r1)
isValidStart :: [Token] -> Bool
isValidStart (OpenParen: _) = True
isValidStart (PosNum _:_) = True
isValidStart _ = False
check:: String -> Bool
check = recognize.scan
Any help or advice is highly appreciated!
Upvotes: 0
Views: 117
Reputation: 92077
In the last clause of rexpr
, the one producing a parse error, you are ignoring the parameter...which is a list of tokens! And since a list of tokens is what you want to produce in the case of a parse error, you can simply show
those tokens and append them to the error message.
Upvotes: 3