pddl-workspace
Version:
407 lines • 15.6 kB
JavaScript
"use strict";
/* --------------------------------------------------------------------------------------------
* Copyright (c) Jan Dolejsi. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
Object.defineProperty(exports, "__esModule", { value: true });
exports.PddlBracketNode = exports.PddlSyntaxNode = void 0;
const PddlTokenizer_1 = require("./PddlTokenizer");
/** Single node in the syntax tree that wraps one PDDL tokenizer token. */
class PddlSyntaxNode extends PddlTokenizer_1.TextRange {
/**
* Creates the syntax tree node.
* @param token pddl token wrapped by this node
* @param parent parent node, unless this is the root node
*/
constructor(token, parent) {
super();
this.token = token;
this.parent = parent;
this.children = new Array();
if (parent === undefined) {
if (token.type !== PddlTokenizer_1.PddlTokenType.Document) {
throw new Error(`Node of type ${token.type} must have parent defined.`);
}
}
this.maxChildEnd = token.getEnd();
}
static createRoot() {
return new PddlSyntaxNode(new PddlTokenizer_1.PddlToken(PddlTokenizer_1.PddlTokenType.Document, '', 0), undefined);
}
isRoot() {
return this.parent === undefined;
}
getParent() {
return this.parent;
}
isLeaveBracket() {
return this.getNestedChildren().every(child => child.isNotType(PddlTokenizer_1.PddlTokenType.OpenBracket));
}
getToken() {
return this.token;
}
addChild(childNode) {
this.children.push(childNode);
this.recalculateEnd(childNode);
}
recalculateEnd(childNode) {
this.maxChildEnd = Math.max(this.maxChildEnd, childNode.getEnd());
if (this.parent) {
this.parent.recalculateEnd(this);
}
}
getChildren() {
return this.children;
}
getNestedChildren() {
return this.getChildren();
}
getSingleChild() {
if (this.getNestedChildren().length !== 1) {
throw new Error(`Failed assertion that node '${this.getText()}' has a single child.`);
}
return this.getNestedChildren()[0];
}
getNonWhitespaceChildren() {
return this.getNestedChildren().filter(c => c.getToken().type !== PddlTokenizer_1.PddlTokenType.Whitespace);
}
getNonWhitespaceNonCommentChildren() {
return this.getNonWhitespaceChildren().filter(c => c.getToken().type !== PddlTokenizer_1.PddlTokenType.Comment);
}
getSingleNonWhitespaceChild() {
const nonWhitespaceChildren = this.getNonWhitespaceChildren();
if (nonWhitespaceChildren.length !== 1) {
throw new Error(`Failed assertion that node '${this.toString()}' has a single non-whitespace child.`);
}
return nonWhitespaceChildren[0];
}
getChildrenOfType(type, pattern) {
return this.children.filter(c => c.getToken().type === type)
.filter(node => node.getToken().tokenText.match(pattern));
}
getFirstChild(type, pattern) {
return this.children.filter(c => c.getToken().type === type)
.find(node => node.getToken().tokenText.match(pattern));
}
getFirstChildOrThrow(type, pattern) {
const matchingChild = this.getFirstChild(type, pattern);
if (!matchingChild) {
throw new Error(`No child element of type ${type} satisfying pattern ${pattern.source}.`);
}
return matchingChild;
}
getFirstOpenBracket(keyword) {
return this.getFirstChild(PddlTokenizer_1.PddlTokenType.OpenBracketOperator, new RegExp('\\(\\s*' + keyword + '$', 'i'));
}
getFirstOpenBracketOrThrow(keyword) {
const matchingNode = this.getFirstOpenBracket(keyword);
if (!matchingNode) {
throw new Error(`No child '${keyword}' open bracket.`);
}
return matchingNode;
}
getChildrenRecursively(test, callback) {
this.getNestedChildren().forEach(child => {
try {
if (test(child)) {
callback(child);
}
}
catch (_e) {
// swallow
}
finally {
child.getChildrenRecursively(test, callback);
}
});
}
/**
* Finds the bracket nested inside the `:keyword`.
* @param keyword keyword name e.g. 'precondition' to match ':precondition (*)'
*/
getKeywordOpenBracket(keyword) {
const keywordNode = this.getFirstChild(PddlTokenizer_1.PddlTokenType.Keyword, new RegExp(":" + keyword + "$", "i"));
if (!keywordNode) {
return undefined;
}
const bracket = keywordNode.getNonWhitespaceChildren().find(child => (0, PddlTokenizer_1.isOpenBracket)(child.getToken()));
if (bracket) {
return bracket;
}
else {
return undefined;
}
}
/**
* Get all keyword open brackets e.g. `(:action ...)`
* @param keyword keyword name e.g. `action` to match `(:action ...)`
*/
getKeywordOpenBrackets(keyword) {
return this.getChildrenOfType(PddlTokenizer_1.PddlTokenType.OpenBracketOperator, new RegExp("\\(\\s*:" + keyword + "$"))
.map(node => node);
}
hasChildren() {
return this.getNestedChildren().length > 0;
}
getNestedText() {
let nestedText = '';
this.getNestedChildren()
.forEach(node => { nestedText = nestedText + node.getText(); });
return nestedText;
}
getNestedNonCommentText() {
let nestedText = '';
this.getNestedChildren()
.filter(node => node.isNotType(PddlTokenizer_1.PddlTokenType.Comment))
.forEach(node => { nestedText = nestedText + node.getNonCommentText(); });
return nestedText;
}
getText() {
return this.getToken().tokenText + this.getNestedText();
}
getNonCommentText() {
if (this.isNotType(PddlTokenizer_1.PddlTokenType.Comment)) {
return this.getToken().tokenText + this.getNestedNonCommentText();
}
else {
return '';
}
}
getStart() {
return this.token.getStart();
}
getEnd() {
return this.maxChildEnd;
}
/** @returns number of characters in this node (including its children) */
get length() {
return this.getEnd() - this.getStart();
}
findAncestor(type, pattern) {
let parent = this.parent;
while (parent && parent.isNotType(PddlTokenizer_1.PddlTokenType.Document)) {
if (parent.isType(type) && pattern.test(parent.getToken().tokenText)) {
return parent;
}
parent = parent.parent;
}
return undefined;
}
getAncestors(includeTypes, pattern = /.*/) {
const ancestors = [];
let parent = this.parent;
while (parent && parent.isNotType(PddlTokenizer_1.PddlTokenType.Document)) {
if (parent.isAnyOf(includeTypes) && pattern.test(parent.getToken().tokenText)) {
ancestors.push(parent);
}
parent = parent.parent;
}
return ancestors;
}
findParametrisableScope(parameterName) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
let node = this;
while (!node.isDocument()) {
node = PddlSyntaxNode.findParametrisableAncestor(node);
if (!node) {
return this.getParent();
}
else if (node.declaresParameter(parameterName)) {
return node;
}
}
return undefined;
}
findAllParametrisableScopes() {
const scopes = [];
// eslint-disable-next-line @typescript-eslint/no-this-alias
let node = this;
while (node && !node.isDocument()) {
node = PddlSyntaxNode.findParametrisableAncestor(node);
if (node) {
scopes.push(node);
}
}
return scopes;
}
static findParametrisableAncestor(node) {
return node.findAncestor(PddlTokenizer_1.PddlTokenType.OpenBracketOperator, /^\(\s*(:action|:durative-action|:process|:event|:derived|forall|sumall|exists)$/);
}
getParameterDefinition() {
if (this.getToken().tokenText.match(/:action|:durative-action|:process|:event/)) {
// this node is expected to have a :parameters keyword
return this.getKeywordOpenBracket('parameters');
}
else {
// this node is expected to have parameters defined inside parentheses
const nonWhitespaceChildren = this.getNonWhitespaceChildren();
if (nonWhitespaceChildren.length === 0) {
return undefined;
}
const firstChild = nonWhitespaceChildren[0];
if (!(0, PddlTokenizer_1.isOpenBracket)(firstChild.getToken())) {
return undefined;
}
return firstChild;
}
}
/**
* Checks whether this scope node defines given parameter.
* @param parameterName parameter name without the `?` sign
*/
declaresParameter(parameterName) {
const parametersNode = this.getParameterDefinition();
const parameterDefinition = parametersNode && parametersNode.getNestedText();
const pattern = new RegExp("\\?" + parameterName + "\\b");
return (parameterDefinition !== undefined) && pattern.test(parameterDefinition);
}
/**
* Expands to the encompassing bracket pair, unless this node is the top level Document node.
*/
expand() {
// eslint-disable-next-line @typescript-eslint/no-this-alias
let node = this;
while (node && !(0, PddlTokenizer_1.isOpenBracket)(node.getToken()) && !node.isDocument()) {
const parentNode = node.getParent();
if (parentNode !== undefined) {
node = parentNode;
}
else {
break;
}
}
return node;
}
/**
* Gets all preceding siblings (in order of appearance, not backwards)
* @param type node type filter
* @param centralNode optional node from which the siblings are split to preceding/following (by default this node is `this` node)
*/
getPrecedingSiblings(type, centralNode) {
const siblings = this.getSiblings(type);
const centralNodeStart = (centralNode !== null && centralNode !== void 0 ? centralNode : this).getStart();
const precedingSiblings = siblings.filter(sibling => sibling.getStart() < centralNodeStart);
return precedingSiblings;
}
/**
* Gets all following siblings
* @param type node type filter
* @param centralNode optional node from which the siblings are split to preceding/following (by default this node is `this` node)
*/
getFollowingSiblings(type, centralNode) {
const siblings = this.getSiblings(type);
const centralNodeStart = (centralNode !== null && centralNode !== void 0 ? centralNode : this).getStart();
const followingSiblings = siblings.filter(sibling => sibling.getStart() > centralNodeStart);
return followingSiblings;
}
/**
* Gets the just preceding sibling, or `undefined`, if none.
* @param type node type filter
* @param centralNode optional node from which the siblings are split to preceding/following (by default this node is `this` node)
*/
getPrecedingSibling(type, centralNode) {
const precedingSiblings = this.getPrecedingSiblings(type, centralNode);
if (precedingSiblings.length > 0) {
return precedingSiblings[precedingSiblings.length - 1];
}
else {
return undefined;
}
}
/**
* Gets the just following sibling, or `undefined`, if none.
* @param type node type filter
* @param centralNode optional node from which the siblings are split to preceding/following (by default this node is `this` node)
*/
getFollowingSibling(type, centralNode) {
const followingSiblings = this.getFollowingSiblings(type, centralNode);
if (followingSiblings.length > 0) {
return followingSiblings[0];
}
else {
return undefined;
}
}
/**
* Gets the siblings of this node.
* @param type optional node type filter
* @param centralNode optional node from which the siblings are split to preceding/following (by default this node is `this` node)
*/
getSiblings(type, pattern = /.*/) {
var _a, _b, _c, _d;
if (this.isRoot()) {
return [];
}
if (type) {
return (_b = (_a = this.getParent()) === null || _a === void 0 ? void 0 : _a.getChildrenOfType(type, pattern)) !== null && _b !== void 0 ? _b : [];
}
else {
return (_d = (_c = this.getParent()) === null || _c === void 0 ? void 0 : _c.getChildren().filter(node => node.getToken().tokenText.match(pattern))) !== null && _d !== void 0 ? _d : [];
}
}
isDocument() {
return this.isType(PddlTokenizer_1.PddlTokenType.Document);
}
isType(type) {
return this.getToken().type === type;
}
isNotType(type) {
return this.getToken().type !== type;
}
isAnyOf(types) {
return types.includes(this.getToken().type);
}
isNoneOf(types) {
return !this.isAnyOf(types);
}
isNumericExpression() {
return ['(=', '(>', '(<', '(>=', '(<=', '(+', '(-', '(/', '(*'].includes(this.getToken().tokenText.replace(' ', ''));
}
isLogicalExpression() {
return ['(and', '(or', '(not'].includes(this.getToken().tokenText.replace(' ', ''));
}
isTemporalExpression() {
return ['(at start', '(at end', '(over all'].includes(this.getToken().tokenText.replace(/ /g, ' '));
}
toString() {
return `${this.token.type}: text: '${this.token.tokenText.split(/\r?\n/).join('\\n')}', range: ${this.getStart()}~${this.getEnd()}}`;
}
}
exports.PddlSyntaxNode = PddlSyntaxNode;
/** Specialized tree node for open/close bracket pair. */
class PddlBracketNode extends PddlSyntaxNode {
constructor() {
super(...arguments);
this._isClosed = false;
}
/**
* Sets the bracket close token.
* @param token pddl bracket close token
*/
setCloseBracket(token) {
this._isClosed = true;
this.closeToken = token;
this.addChild(new PddlSyntaxNode(token, this));
this.recalculateEnd(token);
}
getCloseBracket() {
return this.closeToken;
}
get isClosed() {
return this._isClosed;
}
getNestedChildren() {
return this.getChildren()
.filter(child => child.getToken() !== this.closeToken);
}
getText() {
var _a, _b;
return super.getText() + ((_b = (_a = this.closeToken) === null || _a === void 0 ? void 0 : _a.tokenText) !== null && _b !== void 0 ? _b : '');
}
getNonCommentText() {
var _a, _b;
return super.getNonCommentText() + ((_b = (_a = this.closeToken) === null || _a === void 0 ? void 0 : _a.tokenText) !== null && _b !== void 0 ? _b : '');
}
}
exports.PddlBracketNode = PddlBracketNode;
//# sourceMappingURL=PddlSyntaxNode.js.map