[英]How to get string parser to terminate
我有一个双引号字符串的解析器,它通常可以正常工作,但是当缺少结束引号时,它会永远循环并导致应用程序崩溃。
它是用 Elm 编写的 Web 应用程序的一部分,并使用elm/parser 。
它基于 Elm Github 中的示例。
这是一个最小的示例(在 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
我可以看出哪里出了问题 - 即使到达输入的末尾, chompWhile
位也会成功。 我需要像这样,但不能完全解决如何做,在这种情况下。
我发现一个解决方案是跟踪解析位置,如果位置没有增加就退出循环。 不过它不是很漂亮; 也许有人会想出更好的东西。
代码如问题中的示例,但有这些更改(新 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))
这以缺少引号的所需解析器错误结束。
下面是一个替代的解决方案,对于检查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.