@@ -3,7 +3,12 @@ import { inject, Injectable } from '@angular/core';
33import { Subject , switchMap , catchError , of , merge , map , share } from 'rxjs' ;
44import { ParseInput } from '@/annotate/annotation-input/annotation-input.component' ;
55import { ProblemService } from './problem.service' ;
6- import { ParseResponse } from '@/types' ;
6+ import {
7+ ParseResponse ,
8+ NLTKTree ,
9+ ProofNode , InternalProofNode , TerminalProofNode ,
10+ ProofTree ,
11+ } from '@/types' ;
712
813
914@Injectable ( {
@@ -66,12 +71,14 @@ const closedLeafPattern = /^Closed\n(?<rule>.+)$/;
6671const internalNodePattern = / ^ (?< id > \d + ) : ? (?< rule > .+ ) ? ( \n \[ (?< mod > .+ ) \] ) ? \n (?< head > .+ ) ( \n \[ (?< args > .+ ) \] ) ? \n (?< sign > T r u e | F a l s e ) $ / ;
6772
6873// Helpers for the functions below.
69- const emptyTableau = ( ) : any => ( { nodes : [ ] } ) ;
74+ const emptyTableau = ( ) : ProofTree => ( { nodes : [ ] } ) ;
7075const pairNodes = ( other : any [ ] ) =>
7176 ( node : any , index : number ) => [ node , other [ index ] ] ;
7277const quotes = / ' / g;
7378const unquote = ( text : string ) => text . replace ( quotes , '' ) ;
7479
80+ type ProofConversionThunk = [ NLTKTree , ProofTree ] ;
81+
7582/**
7683 * Given a single proof in serialized NLTK.Tree format, return the same proof in
7784 * a more convenient format where each node has explicitly labeled `id`, `rule`,
@@ -80,7 +87,7 @@ const unquote = (text: string) => text.replace(quotes, '');
8087 * This function can handle proof trees of arbitrary depth without causing a
8188 * stack overflow.
8289 */
83- export function nltk2tableau ( nltk : any ) {
90+ export function nltk2tableau ( nltk : NLTKTree ) : ProofTree {
8491 const tree = emptyTableau ( ) ;
8592 // We will be using trampolining instead of recursion. A general but
8693 // admittedly not very helpful description can be found in the first bullet
@@ -95,7 +102,7 @@ export function nltk2tableau(nltk: any) {
95102 // `nltkNode2tableauNode`, we leave this implicit in the thunk
96103 // representation. It consists only of the arguments that we are passing to
97104 // the function.
98- const todo = [ [ nltk , tree ] ] ;
105+ const todo : ProofConversionThunk [ ] = [ [ nltk , tree ] ] ;
99106 // The core of the trampoline. Process one thunk at a time. We know we are
100107 // done when the list is empty.
101108 while ( todo . length ) {
@@ -105,7 +112,7 @@ export function nltk2tableau(nltk: any) {
105112 // guaranteed to be nonempty on the next line, hence the silencing
106113 // comment.
107114 // @ts -ignore
108- const task : [ any , any ] = todo . pop ( ) ;
115+ const task = todo . pop ( ) as ProofConversionThunk ;
109116 // Processing a thunk might produce zero or more new thunks, depending
110117 // on the number of children of the processed node.
111118 const newTasks = nltkNode2tableauNode ( ...task ) ;
@@ -120,20 +127,21 @@ export function nltk2tableau(nltk: any) {
120127 * trampoline (in `nltk2tableau`) and returns thunks instead of recursing into
121128 * child nodes.
122129 */
123- function nltkNode2tableauNode ( nltk : any , tree : any ) {
130+ function nltkNode2tableauNode ( nltk : NLTKTree , tree : ProofTree ) :
131+ ProofConversionThunk [ ] {
124132 // `nltk` is in a strictly nested format: each node contains its children.
125133 // Our own format does not follow this rule: chains of nodes with single
126134 // children are stored as adjacent elements in an array. `tree` is the
127135 // object that contains this array (`tree.nodes`). When there is a
128136 // bifurcation, the subtrees are stored inside `tree` rather than in the
129137 // bifurcating node.
130- const node : any = parseNltkNode ( nltk . node ) ;
138+ const node = parseNltkNode ( nltk . node ) ;
131139 tree . nodes . push ( node ) ;
132140 // With the node itself having been decoded, now comes the part where a
133141 // "normal" function would recurse and where we return follow-up thunks
134142 // instead.
135143 if ( ! nltk . children || ! nltk . children . length ) {
136- node . end = true ;
144+ ( node as TerminalProofNode ) . end = true ;
137145 // Leaf node. No recursion, no thunks.
138146 return [ ] ;
139147 }
@@ -151,17 +159,19 @@ function nltkNode2tableauNode(nltk: any, tree: any) {
151159 // We essentially do a `_.zip(nltk.children, tree.subtrees)` in order to
152160 // create the thunks. I could have fumbled with `Iterator.zip` instead, but
153161 // that feels like more hassle and the polyfill would be huge.
154- return nltk . children . map ( pairNodes ( tree . subtrees ) ) ;
162+ return nltk . children . map ( pairNodes ( tree . subtrees ) ) as ProofConversionThunk [ ] ;
155163}
156164
157165/**
158166 * Decode the payload of a serialized nltk.Tree node, where all information is
159167 * combined in a single string, back to an object with explicitly labeled parts.
160168 */
161- function parseNltkNode ( text : string ) {
169+ function parseNltkNode ( text : string ) : ProofNode {
162170 if ( openLeafPattern . test ( text ) ) return { } ;
163171 let match ;
164- if ( match = text . match ( closedLeafPattern ) ) return match . groups ;
172+ if ( match = text . match ( closedLeafPattern ) ) {
173+ return match . groups as unknown as ProofNode ;
174+ }
165175 match = text . match ( internalNodePattern ) ;
166176 if ( ! match || ! match . groups ) return { head : text } ;
167177 const result : any = {
0 commit comments