jsoniq
Version:
JSONiq implementation for JavaScript
94 lines (80 loc) • 3.15 kB
text/typescript
/// <reference path="../../../../typings/tsd.d.ts" />
import * as _ from "lodash";
import * as SourceMap from "source-map";
import Position from "../../../compiler/parsers/Position";
import IteratorClause from "./IteratorClause";
import OrderByIterator from "./OrderByIterator";
import ReturnTupleIterator from "./ReturnTupleIterator";
import Iterator from "../Iterator";
export default class FLWORIterator extends Iterator {
private clauses: IteratorClause[];
constructor(position: Position, clauses: Iterator[]) {
super(position);
this.clauses = <IteratorClause[]>clauses;
}
private isMaterializingClause(it: IteratorClause): boolean {
return it instanceof OrderByIterator;
}
private serializeAsStream(node, clauses: IteratorClause[]): FLWORIterator {
node.add("(function *(){")
.add(clauses[0].serializeClause(clauses.slice(1)))
.add("})()");
return this;
}
private serializeChunk(
node: SourceMap.SourceNode,
left: IteratorClause[],
op: IteratorClause[],
right: IteratorClause[],
remaining: any[]
): FLWORIterator {
var bindings = {};
left.forEach(clause => {
if(clause.getBindingVar() !== undefined) {
bindings[clause.getBindingVar()] = true;
}
});
var leftIts = left.slice(1);
leftIts.push(new ReturnTupleIterator(this.position, Object.keys(bindings), op));
node.add("(function *(){\n")
.add("let tuples = (function *(){\n")
.add(left[0].serializeClause(leftIts))
//.add()
.add("})();")
//.add(op[0].serializeClause(op.slice(1)))
.add("tuples = r.processTuples(tuples);\n")
.add("for(var i = 0; i < tuples.length; i++) {\nlet tuple = tuples[i];\n");
_.forEach(bindings, (v, varName) => {
node.add(`let $${varName} = tuple['$${varName}'];\n`);
});
node.add(right[0].serializeClause(right.slice(1)))
.add("\n}\n})()");
if(remaining.length > 0) {
this.serializeChunk(node, remaining[0], remaining[1], remaining[2], remaining.slice(3));
}
return this;
}
serialize(): SourceMap.SourceNode {
var chunks = [[]];
this.clauses.forEach((clause, index) => {
var prev = this.clauses[index - 1];
var next = this.clauses[index + 1];
if(this.isMaterializingClause(clause) && !this.isMaterializingClause(prev)) {
chunks.push([]);
chunks[chunks.length - 1].push(clause);
if(!this.isMaterializingClause(next)) {
chunks.push([]);
}
} else {
chunks[chunks.length - 1].push(clause);
}
});
var node = super.serialize("flwor");
if(chunks.length > 1) {
this.serializeChunk(node, chunks[0], chunks[1], chunks[2], chunks.slice(3));
} else {
this.serializeAsStream(node, this.clauses);
}
return node;
}
}