import { AbstractParseTreeVisitor } from "antlr4ts/tree/AbstractParseTreeVisitor"; import { RelativeDateFormatVisitor } from "../lib/lexer-parser/RelativeDateFormatVisitor"; import { RangeDirectiveContext, TrailDirectiveContext, PeriodDirectiveContext, ResolvableExpressionContext, RelativePeriodContext, PosUnaryExprContext, NegUnaryExprContext, RelativeIdentifierContext, StaticExpressionContext, StaticPeriodContext, StaticIdentifierContext } from "../lib/lexer-parser/RelativeDateFormatParser"; import { BaseNode, NullNode, RangeNode, TimestampNode, RelativeExpressionNode, RelativeTokenNode, NumberNode, StringNode, TrailNode, PeriodNode } from "../ast-nodes"; const SECONDS = 1 const MINUTES = SECONDS*60 const HOURS = MINUTES*60 const DAYS = HOURS*24 const WEEKS = DAYS*7 export class RDFFunctionFactory extends AbstractParseTreeVisitor implements RelativeDateFormatVisitor { protected nowCache:number; constructor(now?:number){ super(); this.nowCache=now || Math.floor(+new Date/1000) } protected now() { return this.nowCache } protected defaultResult():BaseNode { return new NullNode() } visitRangeDirective(ctx: RangeDirectiveContext):BaseNode{ return new RangeNode(this.visit(ctx._begin), this.visit(ctx._end)) } visitTrailDirective(ctx: TrailDirectiveContext):BaseNode{ return new TrailNode(this.visit(ctx._end), this.visit(ctx._period)) } visitPeriodDirective(ctx: PeriodDirectiveContext):BaseNode{ var ref:RelativeExpressionNode | undefined; if(ctx._ref) { ref = this.visit(ctx._ref) }else{ ref = new RelativeExpressionNode(new TimestampNode(this.now())) } return new PeriodNode(this.visit(ctx._begin), this.visit(ctx._period), ref) } visitResolvableExpression(ctx: ResolvableExpressionContext):BaseNode { var staticTime:TimestampNode; if(ctx.staticExpression()){ staticTime = this.visit(ctx.staticExpression()!) }else{ staticTime = this.visit(ctx.staticPeriod()!) } var relPeriod:RelativeTokenNode | undefined = undefined; if(ctx.relativePeriod()){ relPeriod = this.visit(ctx.relativePeriod()!) } return new RelativeExpressionNode(staticTime, relPeriod) } visitStaticExpression(ctx: StaticExpressionContext):TimestampNode { var timestamp:number; if(ctx._first) { var acc:number = 0 for (var context of ctx._then){ acc += this.visit(context).solve() } timestamp = this.visit(ctx._first).solve() + acc }else{ timestamp = this.solveStaticExpression(ctx.payload.text) } return new TimestampNode(timestamp) } solveStaticExpression(expr:any){ if(expr == "now"){ return this.now() }else{ return parseFloat(expr) } } visitRelativePeriod(ctx: RelativePeriodContext):RelativeTokenNode{ var token:string = this.visit(ctx.relativeIdentifier()).solve() var quantity:number; if(ctx.unaryExpr()){ quantity = this.visit(ctx.unaryExpr()!).solve() }else{ quantity = parseInt(ctx.NUMBER()!.payload.text!) } return new RelativeTokenNode(token, quantity) } visitStaticPeriod(ctx: StaticPeriodContext):NumberNode{ var token:string = this.visit(ctx.staticIdentifier()).solve() var quantity:number; if(ctx.unaryExpr()){ quantity = this.visit(ctx.unaryExpr()!).solve() }else{ quantity = parseInt(ctx.NUMBER()!.payload.text!) } var period:number; switch(token){ case 's': period = quantity * SECONDS break; case 'm': period = quantity * MINUTES break; case 'h': period = quantity * HOURS break; case 'd': period = quantity * DAYS break; case 'w': period = quantity * WEEKS default: throw new Error(`Static token type ${token} is not recognized`) } return new NumberNode(period) } visitNegUnaryExpr(ctx: NegUnaryExprContext):NumberNode{ return new NumberNode(-1 * parseInt(ctx.NUMBER().payload.text!)) } visitPosUnaryExpr(ctx: PosUnaryExprContext):NumberNode{ return new NumberNode(parseInt(ctx.NUMBER().payload.text!)) } visitRelativeIdentifier(ctx: RelativeIdentifierContext):StringNode { return new StringNode(ctx.payload.text) } visitStaticIdentifier(ctx: StaticIdentifierContext):StringNode { return new StringNode(ctx.payload.text) } }