jsoniq
Version:
JSONiq implementation for JavaScript
139 lines (117 loc) • 4.37 kB
text/typescript
/// <reference path="../../../typings/tsd.d.ts" />
import * as Parser from "./JSONiqParser";
import ASTNode from "./ASTNode";
import Position from "./Position";
export default class JSONParseTreeHandler implements Parser.ParsingEventHandler {
private source: string;
private fileName: string;
private ast: ASTNode;
private ptr: ASTNode;
private remains: string;
private cursor: number = 0;
private lineCursor: number = 0;
private line: number = 0;
private toBeIndexed: string[] = ["VarDecl", "FunctionDecl"];
constructor(source: string, fileName: string) {
this.source = source;
this.remains = source;
this.fileName = fileName;
}
pushNode(name: string): JSONParseTreeHandler { //begin
var node = new ASTNode(name, this.ast, new Position(0, 0, 0, 0, this.fileName), undefined, []);
if (this.ast === undefined) {
this.ast = node;
this.ast.index = [];
this.ptr = node;
} else {
node.setParent(this.ptr);
this.ptr.addChild(node);
this.ptr = this.ptr.getChildren()[this.ptr.getChildren().length - 1];
}
return this;
}
popNode(): JSONParseTreeHandler {
var children = this.ptr.getChildren();
if (children.length > 0) {
var s = children[0];
var e;
//We want to skip empty non terminals. For instance:
// [108] AxisStep ::= (ReverseStep | ForwardStep) PredicateList
// [120] PredicateList ::= Predicate*
for (var i = children.length - 1; i >= 0; i--) {
e = children[i];
if (e.getPosition().getEndLine() !== 0 || e.getPosition().getEndColumn() !== 0) {
break;
}
}
this.ptr.setPosition(new Position(
s.getPosition().getStartLine(),
s.getPosition().getStartColumn(),
e.getPosition().getEndLine(),
e.getPosition().getEndColumn(),
this.fileName
));
}
//Normalize EQName && FunctionName
if (this.ptr.getName() === "FunctionName") {
this.ptr.setName("EQName");
}
if (this.ptr.getName() === "EQName" && this.ptr.getValue() === undefined) {
this.ptr.setValue(this.ptr.getChildren()[0].getValue());
this.ptr.getChildren().pop();
}
if(this.toBeIndexed.indexOf(this.ptr.getName()) !== -1) {
this.ast.index.push(this.ptr);
}
if (this.ptr.getParent() !== undefined) {
this.ptr = this.ptr.getParent();
}
return this;
}
getParseTree(): ASTNode {
return this.ast;
}
closeParseTree(): JSONParseTreeHandler {
while (this.ptr.getParent() !== undefined) {
this.popNode();
}
this.popNode();
return this;
}
reset(source: string): void {
this.source = source;
this.remains = source;
}
startNonterminal(name: string, begin: number): void {
this.pushNode(name);
}
endNonterminal(name: string, end: number): void {
this.popNode();
}
terminal(name: string, begin: number, end: number): void {
name = (name.substring(0, 1) === "'" && name.substring(name.length - 1) === "'") ? "TOKEN" : name;
this.pushNode(name);
this.setValue(this.ptr, begin, end);
this.popNode();
}
whitespace(begin: number, end: number): void {
var name = "WS";
this.pushNode(name);
this.setValue(this.ptr, begin, end);
this.popNode();
}
private setValue(node: ASTNode, begin: number, end: number) {
var e = end - this.cursor;
node.setValue(this.remains.substring(0, e));
this.remains = this.remains.substring(e);
this.cursor = end;
var sl = this.line;
var sc = this.lineCursor;
var el = sl + node.getValue().split("\n").length - 1;
var lastIdx = node.getValue().lastIndexOf("\n");
var ec = lastIdx === -1 ? sc + node.getValue().length : node.getValue().substring(lastIdx + 1).length;
this.line = el;
this.lineCursor = ec;
node.setPosition(new Position(sl, sc, el, ec, this.fileName));
}
}