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-12-21 13:31:53 -08:00
|
|
|
import Bergamot.Rules exposing (Rule, Section, RuleEnv)
|
2023-12-01 16:38:46 -08:00
|
|
|
import Bergamot.Utils exposing (decodeStr)
|
2023-11-26 11:40:15 -08:00
|
|
|
|
|
|
|
|
import Parser exposing (Parser, Trailing(..), (|.), (|=))
|
2023-12-21 13:31:53 -08:00
|
|
|
import Set exposing (Set)
|
|
|
|
|
|
|
|
|
|
reserved : Set String
|
|
|
|
|
reserved = Set.fromList ["section"]
|
2023-11-26 11:40:15 -08:00
|
|
|
|
|
|
|
|
intLit : Parser Int
|
|
|
|
|
intLit = Parser.int
|
|
|
|
|
|
2023-12-01 12:55:11 -08:00
|
|
|
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
|
2023-12-01 16:24:19 -08:00
|
|
|
{ start = \c -> Char.isAlpha c || c == '_'
|
2023-11-26 11:40:15 -08:00
|
|
|
, inner = \c -> Char.isAlphaNum c || c == '_'
|
2023-12-21 13:31:53 -08:00
|
|
|
, reserved = reserved
|
2023-11-26 11:40:15 -08:00
|
|
|
}
|
|
|
|
|
|
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 == '_'
|
2023-12-21 13:31:53 -08:00
|
|
|
, reserved = reserved
|
2023-11-26 12:58:38 -08:00
|
|
|
}
|
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-12-21 13:31:53 -08:00
|
|
|
|. Parser.spaces |. Parser.symbol ";"
|
|
|
|
|
|
|
|
|
|
rules : Parser (List Rule)
|
|
|
|
|
rules = Parser.sequence
|
|
|
|
|
{ start = ""
|
|
|
|
|
, separator = ""
|
|
|
|
|
, end = ""
|
|
|
|
|
, spaces = Parser.spaces
|
|
|
|
|
, item = rule
|
|
|
|
|
, trailing = Optional
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sectionExp : Parser Section
|
|
|
|
|
sectionExp =
|
|
|
|
|
Parser.succeed (\n rs -> { name = n, rules = rs })
|
|
|
|
|
|. Parser.symbol "section" |. Parser.spaces
|
|
|
|
|
|= strLit |. Parser.spaces
|
|
|
|
|
|. Parser.symbol "{" |. Parser.spaces
|
|
|
|
|
|= rules
|
|
|
|
|
|. Parser.symbol "}" |. Parser.spaces
|
|
|
|
|
|
|
|
|
|
sectionImp : Parser Section
|
|
|
|
|
sectionImp =
|
|
|
|
|
(\rs ->
|
|
|
|
|
Parser.oneOf
|
|
|
|
|
[ rule |> Parser.map (\r -> Parser.Loop <| r :: rs)
|
|
|
|
|
, case rs of
|
|
|
|
|
[] -> Parser.problem "empty implicit sections not allowed."
|
|
|
|
|
_ -> Parser.succeed (Parser.Done <| List.reverse rs)
|
|
|
|
|
])
|
|
|
|
|
|> Parser.loop []
|
|
|
|
|
|> Parser.map (\rs -> { name = "", rules = rs })
|
2023-11-26 11:42:46 -08:00
|
|
|
|
|
|
|
|
program : Parser RuleEnv
|
|
|
|
|
program =
|
2023-12-21 13:31:53 -08:00
|
|
|
Parser.succeed (\ss -> { sections = ss })
|
2023-11-26 11:42:46 -08:00
|
|
|
|= Parser.sequence
|
|
|
|
|
{ start = ""
|
2023-12-21 13:31:53 -08:00
|
|
|
, separator = ""
|
2023-11-26 11:42:46 -08:00
|
|
|
, end = ""
|
|
|
|
|
, spaces = Parser.spaces
|
2023-12-21 13:31:53 -08:00
|
|
|
, item = Parser.oneOf [sectionExp, sectionImp]
|
2023-11-26 11:42:46 -08:00
|
|
|
, 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
|