2023-11-26 11:40:15 -08:00
|
|
|
module Bergamot.Parser exposing (..)
|
|
|
|
|
|
2023-11-26 12:58:38 -08:00
|
|
|
import Bergamot.Syntax exposing (Term(..), Metavariable(..))
|
2023-11-26 11:42:46 -08:00
|
|
|
import Bergamot.Rules exposing (Rule, RuleEnv)
|
2023-11-26 11:40:15 -08:00
|
|
|
|
|
|
|
|
import Parser exposing (Parser, Trailing(..), (|.), (|=))
|
|
|
|
|
import Set
|
|
|
|
|
|
|
|
|
|
intLit : Parser Int
|
|
|
|
|
intLit = Parser.int
|
|
|
|
|
|
2023-12-01 12:55:11 -08:00
|
|
|
decodeStr : String -> String
|
|
|
|
|
decodeStr str =
|
|
|
|
|
let
|
|
|
|
|
go l =
|
|
|
|
|
case l of
|
|
|
|
|
'\\' :: 'n' :: rest -> '\n' :: go rest
|
|
|
|
|
'\\' :: '\\' :: rest -> '\\' :: go rest
|
|
|
|
|
'\\' :: '"' :: rest -> '"' :: go rest
|
|
|
|
|
'\\' :: c :: rest -> c :: go rest
|
|
|
|
|
c :: rest -> c :: go rest
|
|
|
|
|
[] -> []
|
|
|
|
|
noQuotes = String.dropLeft 1 <| String.dropRight 1 <| str
|
|
|
|
|
in
|
|
|
|
|
String.fromList (go (String.toList str))
|
|
|
|
|
|
|
|
|
|
strLit : Parser String
|
|
|
|
|
strLit =
|
|
|
|
|
let
|
|
|
|
|
char = Parser.map decodeStr <| Parser.getChompedString <|
|
|
|
|
|
Parser.oneOf
|
|
|
|
|
[ Parser.backtrackable <|
|
|
|
|
|
Parser.chompIf (\c -> c == '\\')
|
|
|
|
|
|. Parser.chompIf (\c -> True)
|
|
|
|
|
, Parser.backtrackable <| Parser.chompIf (\c -> c /= '"')
|
|
|
|
|
]
|
|
|
|
|
in
|
|
|
|
|
Parser.map (String.join "") <| Parser.sequence
|
|
|
|
|
{ start = "\""
|
|
|
|
|
, separator = ""
|
|
|
|
|
, end = "\""
|
|
|
|
|
, spaces = Parser.succeed ()
|
|
|
|
|
, item = char
|
|
|
|
|
, trailing = Optional
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2023-11-26 11:40:15 -08:00
|
|
|
name : Parser String
|
|
|
|
|
name = Parser.variable
|
|
|
|
|
{ start = \c -> Char.isAlphaNum c || c == '_'
|
|
|
|
|
, inner = \c -> Char.isAlphaNum c || c == '_'
|
|
|
|
|
, reserved = Set.empty
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-26 12:58:38 -08:00
|
|
|
variable : Parser Metavariable
|
|
|
|
|
variable =
|
|
|
|
|
Parser.succeed MkMetavariable
|
|
|
|
|
|= Parser.variable
|
|
|
|
|
{ start = \c -> c == '?'
|
|
|
|
|
, inner = \c -> Char.isAlphaNum c || c == '_'
|
|
|
|
|
, reserved = Set.empty
|
|
|
|
|
}
|
2023-11-26 11:40:15 -08:00
|
|
|
|
|
|
|
|
term : Parser (Term Metavariable)
|
|
|
|
|
term = Parser.lazy (\() -> Parser.oneOf
|
2023-11-26 20:44:27 -08:00
|
|
|
[ Parser.backtrackable <|
|
2023-11-26 11:58:20 -08:00
|
|
|
Parser.succeed Call
|
2023-11-26 11:40:15 -08:00
|
|
|
|= name
|
|
|
|
|
|= Parser.sequence
|
|
|
|
|
{ start = "("
|
|
|
|
|
, separator = ","
|
|
|
|
|
, end = ")"
|
|
|
|
|
, spaces = Parser.spaces
|
|
|
|
|
, item = term
|
|
|
|
|
, trailing = Forbidden
|
|
|
|
|
}
|
2023-12-01 14:11:40 -08:00
|
|
|
, Parser.backtrackable
|
|
|
|
|
<| Parser.map (List.foldr (\x xs -> Call "cons" [x, xs]) (Call "nil" []))
|
|
|
|
|
<| Parser.sequence
|
|
|
|
|
{ start = "["
|
|
|
|
|
, separator = ","
|
|
|
|
|
, end = "]"
|
|
|
|
|
, spaces = Parser.spaces
|
|
|
|
|
, item = term
|
|
|
|
|
, trailing = Forbidden
|
|
|
|
|
}
|
2023-11-26 20:44:27 -08:00
|
|
|
, Parser.backtrackable <|
|
|
|
|
|
Parser.succeed (\n -> Call n [])
|
2023-11-26 11:58:20 -08:00
|
|
|
|= name
|
2023-11-26 20:44:27 -08:00
|
|
|
, Parser.backtrackable <|
|
|
|
|
|
Parser.succeed Var |= variable
|
|
|
|
|
, Parser.succeed IntLit |= intLit
|
2023-12-01 12:55:11 -08:00
|
|
|
, Parser.succeed StringLit |= strLit
|
2023-11-26 11:40:15 -08:00
|
|
|
])
|
|
|
|
|
|
|
|
|
|
rule : Parser Rule
|
|
|
|
|
rule =
|
|
|
|
|
let
|
|
|
|
|
makeRule n c ps = { name = n, conclusion = c, premises = ps }
|
|
|
|
|
in
|
|
|
|
|
Parser.succeed makeRule
|
|
|
|
|
|= name
|
|
|
|
|
|. Parser.spaces |. Parser.symbol "@" |. Parser.spaces
|
|
|
|
|
|= term
|
|
|
|
|
|. Parser.spaces |. Parser.symbol "<-" |. Parser.spaces
|
|
|
|
|
|= Parser.sequence
|
|
|
|
|
{ start = ""
|
|
|
|
|
, separator = ","
|
|
|
|
|
, end = ""
|
|
|
|
|
, spaces = Parser.spaces
|
|
|
|
|
, item = term
|
|
|
|
|
, trailing = Forbidden
|
|
|
|
|
}
|
2023-11-26 11:42:46 -08:00
|
|
|
|
|
|
|
|
program : Parser RuleEnv
|
|
|
|
|
program =
|
|
|
|
|
Parser.succeed (\rs -> { rules = rs })
|
|
|
|
|
|= Parser.sequence
|
|
|
|
|
{ start = ""
|
|
|
|
|
, separator = ";"
|
|
|
|
|
, end = ""
|
|
|
|
|
, spaces = Parser.spaces
|
|
|
|
|
, item = rule
|
|
|
|
|
, trailing = Mandatory
|
|
|
|
|
}
|
|
|
|
|
|. Parser.end
|
2023-11-26 11:58:20 -08:00
|
|
|
|
|
|
|
|
run : Parser a -> String -> Maybe a
|
|
|
|
|
run prs s =
|
|
|
|
|
case Parser.run prs s of
|
|
|
|
|
Ok a -> Just a
|
|
|
|
|
Err _ -> Nothing
|