Skip to content

Commit

Permalink
Construct nicer partial ASTs
Browse files Browse the repository at this point in the history
  • Loading branch information
Baltoli committed Oct 11, 2023
1 parent 752ea57 commit bc52ee6
Showing 1 changed file with 44 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.kframework.parser.Constant;
import org.kframework.parser.Term;
import org.kframework.parser.TermCons;
import org.kframework.parser.inner.disambiguation.TreeCleanerVisitor;
import org.kframework.utils.errorsystem.KEMException;
import org.pcollections.ConsPStack;
import org.pcollections.PStack;
Expand Down Expand Up @@ -194,6 +195,13 @@ public boolean isMInt() {
}
return isMInt;
}

/**
* @return the number of non-terminals in the production
*/
public int arity() {
return Math.toIntExact(items.stream().filter(EarleyProductionItem::isNonTerminal).count());
}
}

/**
Expand Down Expand Up @@ -863,12 +871,48 @@ public Term parse(String input, Source source, int startLine, int startColumn) {
return Ambiguity.apply(S.get(data.words.length).states.get(0).parseTree().stream().map(list -> list.get(0)).collect(Collectors.toSet()));
}

private void showPartialParseTrees(EarleySet parses) {
// We are only interested in displaying states that span the entire input
// when a parse error occurs; such states have a start-index of 0
Set<EarleyState> fullStates = parses.states.stream()
.filter(state -> state.start == 0)
.collect(Collectors.toSet());

// In the case of a parse error, we have a partial parse tree constructed
// that comprises each of the successful non-terminals in the current rule.
// To print an AST with correct arity, we want to create a dummy term that
// will never type-check, but can sit in a parsed AST to represent the errored
// non-terminal, as well as the ones we have not yet attempted to parse.
Production errorProd = Production.apply(Seq(), Sort("<invalid>"), Seq(), Att());
Term error = Constant.apply("<error>", errorProd);
Term incomplete = Constant.apply("<incomplete>", errorProd);

for(var state : fullStates) {
for(var possibleTree : state.parseTree()) {
int notAttempted = state.prod.arity() - state.ntItem - 1;

var correctArityTree = possibleTree
.plus(error)
.plusAll(Collections.nCopies(notAttempted, incomplete));

var cleaned = ConsPStack.from(correctArityTree.stream().map(term -> new TreeCleanerVisitor().apply(term)).collect(Collectors.toList());

var term = TermCons.apply(ConsPStack.from(cleaned), state.prod.prod);
System.err.println(term);
}
}
}

/**
* @param data The {@link ParserMetadata} about the sentence being parsed
* @param S The set of {@link EarleyState}s for each end-index in the input
* @param k The end-index at which a parse error occurred. In other words, the index just prior to the first token that
*/
private void parseError(ParserMetadata data, List<EarleySet> S, int k) {
if(partialParseDebug) {
showPartialParseTrees(S.get(k));
}

int startLine, startColumn, endLine, endColumn;
if (data.words.length == 1) {
startLine = data.lines[0];
Expand Down

0 comments on commit bc52ee6

Please sign in to comment.