[英]How to get string parser to terminate
I have a parser for double-quoted strings that mostly works fine, but when the end quote is missing it loops forever and crashes the app.我有一个双引号字符串的解析器,它通常可以正常工作,但是当缺少结束引号时,它会永远循环并导致应用程序崩溃。
It is part of a web app written in Elm, and uses elm/parser .它是用 Elm 编写的 Web 应用程序的一部分,并使用elm/parser 。
It is based on an example from the Elm Github.它基于 Elm Github 中的示例。
Here is a minimal example ( run it in Ellie ; change toParse to "\\"" and it crashes the tab).这是一个最小的示例(在 Ellie 中运行它;将 toParse 更改为 "\\"" 并且它会使选项卡崩溃)。
module Main exposing (main)
import Html
import Parser as P exposing ((|.), (|=))
import Debug
stringP : P.Parser String
stringP =
P.succeed identity
|. P.token "\""
|= P.loop [] stringHelp
stringHelp : List String -> P.Parser (P.Step (List String) String)
stringHelp revChunks =
P.oneOf
[ P.token "\""
|> P.map (\_ -> P.Done (String.join "" (List.reverse revChunks)))
, P.chompWhile isUninteresting
|> P.getChompedString
|> P.map (\chunk -> P.Loop (chunk :: revChunks))
]
isUninteresting : Char -> Bool
isUninteresting char =
char /= '\\' && char /= '"'
toParse =
"\""
main =
Html.text <| Debug.toString <| P.run stringP toParse
I can see what's wrong in a way - the chompWhile
bit succeeds even if the end of input is reached.我可以看出哪里出了问题 - 即使到达输入的末尾,
chompWhile
位也会成功。 I need something like this , but can't quite work out how to do it in this case.我需要像这样,但不能完全解决如何做,在这种情况下。
I have found that a solution is to track the parsing position, and quit the loop if the position has not increased.我发现一个解决方案是跟踪解析位置,如果位置没有增加就退出循环。 It's not very pretty though;
不过它不是很漂亮; maybe someone will come up with something better.
也许有人会想出更好的东西。
The code is as the example in the question, but with these changes ( new Ellie ):代码如问题中的示例,但有这些更改(新 Ellie ):
stringP : P.Parser String
stringP =
P.succeed identity
|. P.token "\""
|= P.loop ([], 0) stringHelp
|. P.token "\""
stringHelp : (List String, Int) -> P.Parser (P.Step (List String, Int) String)
stringHelp (revChunks, offset) =
P.succeed (stepHelp offset)
|= stringHelp2 revChunks
|= P.getOffset
stepHelp : Int -> (P.Step (List String) String) -> Int -> P.Step (List String, Int) String
stepHelp oldOffset step newOffset =
case step of
P.Done str ->
P.Done str
P.Loop revChunks ->
if newOffset > oldOffset then
P.Loop (revChunks, newOffset)
else
P.Done <| String.join "" <| List.reverse revChunks
stringHelp2 : List String -> P.Parser (P.Step (List String) String)
stringHelp2 revChunks =
P.chompWhile isUninteresting
|> P.getChompedString
|> P.map (\chunk -> P.Loop (chunk :: revChunks))
This ends with the desired parser error that there is a missing quote.这以缺少引号的所需解析器错误结束。
Here's an alternative solution that checks for the end
token if a string terminates prematurely ( Ellie ):下面是一个替代的解决方案,对于检查
end
字符串是否过早地终止(令牌埃利):
module Main exposing (main)
import Html
import Parser as P exposing ((|.), (|=))
import Debug
stringP : P.Parser String
stringP =
( P.succeed identity
|. P.token "\""
|= P.loop [] stringHelp
) |> P.andThen
( \res ->
case res of
Ok str -> P.succeed str
Err msg -> P.problem msg
)
stringHelp : List String -> P.Parser (P.Step (List String) (Result String String))
stringHelp revChunks =
P.oneOf
[ P.end
|> P.map (\_ -> P.Done (Err "string ended prematurely"))
, P.token "\""
|> P.map (\_ -> P.Done (Ok (String.join "" (List.reverse revChunks))))
, P.chompWhile isUninteresting
|> P.getChompedString
|> P.map (\chunk -> P.Loop (chunk :: revChunks))
]
isUninteresting : Char -> Bool
isUninteresting char =
char /= '\\' && char /= '"'
toParse =
"\"hi\""
main =
Html.text <| Debug.toString <| P.run stringP toParse
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.