needs a LOT of cleaning, but basics of proof parser working

This commit is contained in:
William Ball 2024-08-14 14:42:08 -07:00
parent 82213f0df8
commit c4262a10e2
7 changed files with 153 additions and 94 deletions

View file

@ -2,6 +2,7 @@ signature PARSEUTILS =
sig sig
include PARSE include PARSE
val >>= : 'a p * ('a -> 'b p) -> 'b p val >>= : 'a p * ('a -> 'b p) -> 'b p
val >>=? : 'a p * ('a -> 'a p) -> 'a p
end end
structure ParseUtils: PARSEUTILS = structure ParseUtils: PARSEUTILS =
@ -10,10 +11,18 @@ struct
Parse (type token = Token.t val pp_token = Token.pp_token) Parse (type token = Token.t val pp_token = Token.pp_token)
open ParseUtilsTemp open ParseUtilsTemp
infix >>= infix >>= >>=?
fun (p >>= q) ts = fun (p >>= q) ts =
case p ts of case p ts of
OK (v, r, ts') => q v ts' OK (v, r, ts') => q v ts'
| NO e => NO e | NO e => NO e
fun (p >>=? q) ts =
case p ts of
s1 as (OK (v, r, ts')) =>
(case q v ts' of
OK s2 => OK s2
| NO _ => s1)
| NO e => NO e
end end

View file

@ -0,0 +1,83 @@
structure ProofParser: PARSER =
struct
type result = Proof.t
structure StringSet = Utils.StringSet
structure ArityMap = Utils.ArityMap
structure T = Token
type state =
{constants: StringSet.t, functions: ArityMap.t, relations: ArityMap.t}
open ParseUtils
infix >>> ->> >>- ?? ??? || oo oor ??* >>= >>=?
open Proof
fun number_p nil =
NO (Region.botloc, fn () => "expecting number but reached the end")
| number_p ((Token.NUMBER num, r) :: rest) = OK (num, r, rest)
| number_p ((t, r) :: rest) =
NO (#1 r, fn () =>
"expecting number but found token " ^ Token.pp_token t)
val const = Utils.const
val label_p =
(eat (T.KEYWORD T.Axiom) oo const Axiom)
|| (eat (T.KEYWORD T.AndI) oo const AndI)
|| (eat (T.KEYWORD T.AndE) oo const AndE)
|| (eat (T.KEYWORD T.OrI) oo const OrI)
|| (eat (T.KEYWORD T.OrE) oo const OrE)
|| (eat (T.KEYWORD T.ArrI) oo const ArrI)
|| (eat (T.KEYWORD T.ArrE) oo const ArrE)
|| (eat (T.KEYWORD T.NegI) oo const NegI)
|| (eat (T.KEYWORD T.NegE) oo const NegE)
|| (eat (T.KEYWORD T.RAA) oo const RAA)
|| (eat (T.KEYWORD T.IffI) oo const IffI)
|| (eat (T.KEYWORD T.IffE) oo const IffE)
|| (eat (T.KEYWORD T.EqI) oo const EqI)
|| (eat (T.KEYWORD T.EqE) oo const EqE)
|| (eat (T.KEYWORD T.ForallI) oo const ForallI)
|| (eat (T.KEYWORD T.ForallE) oo const ForallE)
|| (eat (T.KEYWORD T.ExistsI) oo const ExistsI)
|| (eat (T.KEYWORD T.ExistsE) oo const ExistsE)
fun fold_lines lines (_, NO l) = NO l
| fold_lines lines (line, OK (children, r, rest)) =
OK (List.nth (lines, line - 1) :: children, r, rest)
handle Subscript =>
NO (#1 r, fn () => "Invalid line reference " ^ (Int.toString line))
fun line_refs_p lines ts =
case (((number_p oo (fn x => [x])) ??* number_p) (Utils.flip op::)) ts of
OK (nums, r, rest) => foldl (fold_lines lines) (OK ([], r, rest)) nums
| NO l => NO l
fun refless_tag_p ts =
((eat T.LBRACKET ->> label_p >>- eat T.RBRACKET)
oo (fn label => (label, []))) ts
fun ref_tag_p lines =
eat T.LBRACKET ->> label_p >>> line_refs_p lines >>- eat T.RBRACKET
fun tag_p lines = refless_tag_p || ref_tag_p lines
fun line_p (state, lines) : Proof.t p =
((number_p >>- eat T.DOT oo const ())
->>
(FormulaParser.parse
{ binders = []
, constants = #constants state
, functions = #functions state
, relations = #relations state
}) >>> (tag_p lines))
oo
(fn (phi, (label, children)) =>
Proof {formula = phi, label = label, children = children})
fun all_lines_p (state, lines) : Proof.t p =
line_p (state, lines) >>=? (fn line => all_lines_p (state, line :: lines))
fun parse state ts =
all_lines_p (state, []) ts
end

View file

@ -5,6 +5,8 @@ struct
fun map_token (Symb "(") = LPAREN fun map_token (Symb "(") = LPAREN
| map_token (Symb ")") = RPAREN | map_token (Symb ")") = RPAREN
| map_token (Symb "[") = LBRACKET
| map_token (Symb "]") = RBRACKET
| map_token (Symb ".") = DOT | map_token (Symb ".") = DOT
| map_token (Symb ",") = COMMA | map_token (Symb ",") = COMMA
| map_token (Symb "#") = HASH | map_token (Symb "#") = HASH
@ -19,17 +21,20 @@ struct
(case KeywordMap.get (keywordMap, id) of (case KeywordMap.get (keywordMap, id) of
SOME keyword => KEYWORD keyword SOME keyword => KEYWORD keyword
| NONE => IDENT id) | NONE => IDENT id)
| map_token (Num _) = ERR | map_token (Num num) =
NUMBER (valOf (Int.fromString num))
fun const k _ = k val is_num = (List.all Char.isDigit) o String.explode
fun is_id s =
((List.all Char.isAlphaNum) (String.explode s)) andalso not (is_num s)
val scan = val scan =
map (fn (t, r) => (map_token t, r)) map (fn (t, r) => (map_token t, r))
o o
tokenise tokenise
{ sep_chars = "(),&|.#~" { sep_chars = "[](),&|.#~"
, symb_chars = "<=>" , symb_chars = "<=>"
, is_id = (List.all Char.isAlphaNum) o String.explode , is_id = is_id
, is_num = const false , is_num = is_num
} }
end end

View file

@ -1,51 +0,0 @@
signature TOKEN =
sig
datatype keyword =
(* labels *)
Axiom
| AndI
| AndE
| OrI
| OrE
| ArrI
| ArrE
| NegI
| NegE
| RAA
| IffI
| IffE
| EqI
| EqE
| ForallI
| ForallE
| ExistsI
| ExistsE
(* formulas *)
| Forall
| Exists
structure KeywordMap: MAP where type key = string and type value = keyword
val keywordMap: KeywordMap.t
datatype t =
LPAREN
| RPAREN
| NEG
| AND
| OR
| EQ
| RARROW
| LRARROW
| DOT
| COMMA
| HASH
| KEYWORD of keyword
| IDENT of string
| ERR
val pp_token: t -> string
val infix_connective: t -> bool
val prefix_connective: t -> bool
end

View file

@ -1,4 +1,4 @@
structure Token: TOKEN = structure Token =
struct struct
datatype keyword = datatype keyword =
Axiom Axiom
@ -25,6 +25,8 @@ struct
datatype t = datatype t =
LPAREN LPAREN
| RPAREN | RPAREN
| LBRACKET
| RBRACKET
| NEG | NEG
| AND | AND
| OR | OR
@ -36,6 +38,7 @@ struct
| HASH | HASH
| KEYWORD of keyword | KEYWORD of keyword
| IDENT of string | IDENT of string
| NUMBER of int
| ERR | ERR
structure KeywordMap = Map (structure Ord = StringOrd type value = keyword) structure KeywordMap = Map (structure Ord = StringOrd type value = keyword)
@ -58,13 +61,37 @@ struct
, ("ForallE", ForallE) , ("ForallE", ForallE)
, ("ExistsI", ExistsI) , ("ExistsI", ExistsI)
, ("ExistsE", ExistsE) , ("ExistsE", ExistsE)
, ("Forall", Forall) , ("forall", Forall)
, ("Exists", Exists) , ("exists", Exists)
] ]
val keywordToString =
fn Axiom => "Axiom"
| AndI => "AndI"
| AndE => "AndE"
| OrI => "OrI"
| OrE => "OrE"
| ArrI => "ArrI"
| ArrE => "ArrE"
| NegI => "NegI"
| NegE => "NegE"
| RAA => "RAA"
| IffI => "IffI"
| IffE => "IffE"
| EqI => "EqI"
| EqE => "EqE"
| ForallI => "ForallI"
| ForallE => "ForallE"
| ExistsI => "ExistsI"
| ExistsE => "ExistsE"
| Forall => "forall"
| Exists => "exists"
val pp_token = val pp_token =
fn LPAREN => "(" fn LPAREN => "("
| RPAREN => ")" | RPAREN => ")"
| LBRACKET => "["
| RBRACKET => "]"
| NEG => "~" | NEG => "~"
| AND => "&" | AND => "&"
| OR => "|" | OR => "|"
@ -73,11 +100,11 @@ struct
| LRARROW => "<=>" | LRARROW => "<=>"
| DOT => "." | DOT => "."
| COMMA => "," | COMMA => ","
| FORALL => "forall"
| EXISTS => "exists"
| ERR => "unk"
| HASH => "#" | HASH => "#"
| KEYWORD keyword => keywordToString keyword
| IDENT s => s | IDENT s => s
| NUMBER num => Int.toString num
| ERR => "unk"
val infix_connective = val infix_connective =
fn AND => true | OR => true | RARROW => true | LRARROW => true | _ => false fn AND => true | OR => true | RARROW => true | LRARROW => true | _ => false

View file

@ -3,7 +3,6 @@ $(SML_LIB)/basis/basis.mlb
../utils/utils.mlb ../utils/utils.mlb
../../../../github.com/diku-dk/sml-parse/parse.mlb ../../../../github.com/diku-dk/sml-parse/parse.mlb
../../../../github.com/diku-dk/sml-parse/simple_token.mlb ../../../../github.com/diku-dk/sml-parse/simple_token.mlb
TOKEN.sig
Token.sml Token.sml
SCANNER.sig SCANNER.sig
Scanner.sml Scanner.sml
@ -11,4 +10,5 @@ ParseUtils.sml
PARSER.sig PARSER.sig
TermParser.sml TermParser.sml
FormulaParser.sml FormulaParser.sml
ProofParser.sml
repl.sml repl.sml

View file

@ -1,11 +1,11 @@
open Scanner open Scanner
structure Testing: structure Testing =
sig (* sig *)
val parse_repl: string -> unit (* val parse_repl: string -> unit *)
end = (* end = *)
struct struct
open FormulaParser open ProofParser
open Utils open Utils
open ParseUtils open ParseUtils
open Scanner open Scanner
@ -14,31 +14,17 @@ struct
val constants = StringSet.fromList ["zero"] val constants = StringSet.fromList ["zero"]
val relations = ArityMap.fromList [("lt", 2)] val relations = ArityMap.fromList [("lt", 2)]
val state = val state =
{ binders = [] {functions = functions, constants = constants, relations = relations}
, functions = functions
, constants = constants
, relations = relations
}
fun parse_repl s = fun parse_repl s =
let let val toks = scan {input = s, srcname = "repl"}
val toks = scan {input = s, srcname = "repl"} in parse state toks
in (* case parse state toks of *)
case parse state toks of (* OK (t, _, []) => print ("Parsed successfully: " ^ Formula.pp t ^ "\n") *)
OK (t, _, []) => print ("Parsed successfully: " ^ Formula.pp t ^ "\n") (* | OK (t, r, rest) => *)
| OK (t, r, rest) => (* print *)
print (* ("Parsed '" ^ Formula.pp t ^ "' up to " ^ Region.pp r ^ ", but " *)
("Parsed '" ^ Formula.pp t ^ "' up to " ^ Region.pp r ^ ", but " (* ^ Int.toString (length rest) ^ " tokens remain unparsed\n") *)
^ Int.toString (length rest) ^ " tokens remain unparsed\n") (* | NO (r, err) => print ("ERROR: " ^ Region.ppLoc r ^ ", " ^ err () ^ "\n") *)
| NO (r, err) => print ("ERROR: " ^ Region.ppLoc r ^ ", " ^ err () ^ "\n")
end end
end end (* fun repl () = *) (* ( print "> " *) (* ; case (TextIO.inputLine TextIO.stdIn) of *) (* SOME s => (Testing.parse_repl s; repl ()) *) (* | NONE => () *) (* ) *) (* fun main () = repl () (1* val () = main () *1) *)
fun repl () =
( print "> "
; case (TextIO.inputLine TextIO.stdIn) of
SOME s => (Testing.parse_repl s; repl ())
| NONE => ()
)
fun main () = repl () (* val () = main () *)