Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [https://neo4j.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package org.neo4j.cypher.internal.literal.interpreter;
import java.time.Clock;
import java.time.ZoneId;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.antlr.v4.runtime.BaseErrorListener;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.DefaultErrorStrategy;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Recognizer;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.neo4j.cypher.internal.parser.AstRuleCtx;
import org.neo4j.cypher.internal.parser.v5.Cypher5Lexer;
import org.neo4j.cypher.internal.parser.v5.Cypher5Parser;
import org.neo4j.exceptions.SyntaxException;
import org.neo4j.internal.helpers.Exceptions;
import org.neo4j.values.storable.DateTimeValue;
import org.neo4j.values.storable.DateValue;
import org.neo4j.values.storable.DurationValue;
import org.neo4j.values.storable.LocalDateTimeValue;
import org.neo4j.values.storable.LocalTimeValue;
import org.neo4j.values.storable.PointValue;
import org.neo4j.values.storable.TimeValue;
import org.neo4j.values.storable.Values;
import org.neo4j.values.virtual.MapValue;
import org.neo4j.values.virtual.MapValueBuilder;
import org.neo4j.values.virtual.VirtualValues;
public class Cypher5LiteralInterpreter {
private Cypher5LiteralInterpreter() {}
public static Object parseExpression(String cypherExpression) {
final var builder = new LiteralInterpreterBuilder();
var cypherLexer = new Cypher5Lexer(CharStreams.fromString(cypherExpression));
var tokenStream = new CommonTokenStream(cypherLexer);
var parser = new Cypher5Parser(tokenStream);
parser.removeErrorListeners();
var errorStrategy = new DefaultErrorStrategy();
parser.setErrorHandler(errorStrategy);
var errorListener = new LiteralErrorListener(cypherExpression);
parser.addErrorListener(errorListener);
parser.addParseListener(builder);
final AstRuleCtx result;
try {
result = parser.expression();
} catch (UnsupportedOperationException e) {
if (errorListener.error != null) {
throw errorListener.error;
} else {
throw e;
}
}
if (errorListener.error != null) {
throw errorListener.error;
}
if (!parser.isMatchedEOF() && parser.getInputStream().LA(1) != Token.EOF) {
var offset = Optional.ofNullable(parser.getCurrentToken())
.map(Token::getStartIndex)
.orElse(0);
throw new SyntaxException("Invalid cypher expression", cypherExpression, offset);
}
return result.ast;
}
}
class LiteralInterpreterBuilder implements ParseTreeListener {
public static final ZoneId DEFAULT_ZONE_ID = ZoneId.systemDefault();
private static final Object missingAst = new Object();
@Override
public void visitTerminal(TerminalNode terminalNode) {}
@Override
public void visitErrorNode(ErrorNode errorNode) {}
@Override
public void enterEveryRule(ParserRuleContext parserRuleContext) {}
private void exitDefault(AstRuleCtx ctx) {
if (ctx.getChildCount() == 1 && ctx.getChild(0) instanceof AstRuleCtx childCtx) {
ctx.ast = childCtx.ast;
}
}
private void throwUnsupportedQuery() {
throw new UnsupportedOperationException("Query not supported in literal interpreter");
}
@Override
public void exitEveryRule(ParserRuleContext ctx) {
if (ctx.exception != null) {
return;
}
((AstRuleCtx) ctx).ast = missingAst;
switch (ctx.getRuleIndex()) {
case Cypher5Parser.RULE_numberLiteral -> exitNumberLiteral((Cypher5Parser.NumberLiteralContext) ctx);
case Cypher5Parser.RULE_literal -> exitLiteral((Cypher5Parser.LiteralContext) ctx);
case Cypher5Parser.RULE_stringLiteral -> exitStringLiteral((Cypher5Parser.StringLiteralContext) ctx);
case Cypher5Parser.RULE_listLiteral -> exitListLiteral((Cypher5Parser.ListLiteralContext) ctx);
case Cypher5Parser.RULE_map -> exitMap((Cypher5Parser.MapContext) ctx);
case Cypher5Parser.RULE_propertyKeyName -> exitPropertyKeyName((Cypher5Parser.PropertyKeyNameContext) ctx);
case Cypher5Parser.RULE_symbolicNameString -> exitSymbolicNameString(
(Cypher5Parser.SymbolicNameStringContext) ctx);
case Cypher5Parser.RULE_escapedSymbolicNameString -> exitEscapedSymbolicNameString(
(Cypher5Parser.EscapedSymbolicNameStringContext) ctx);
case Cypher5Parser.RULE_unescapedSymbolicNameString -> exitUnescapedSymbolicNameString(
(Cypher5Parser.UnescapedSymbolicNameStringContext) ctx);
case Cypher5Parser.RULE_functionInvocation -> exitFunctionInvocation(
(Cypher5Parser.FunctionInvocationContext) ctx);
case Cypher5Parser.RULE_functionArgument -> exitFunctionArgument(
(Cypher5Parser.FunctionArgumentContext) ctx);
case Cypher5Parser.RULE_functionName -> exitFunctionName((Cypher5Parser.FunctionNameContext) ctx);
case Cypher5Parser.RULE_expression -> exitDefault((AstRuleCtx) ctx);
case Cypher5Parser.RULE_expression1 -> exitExpression1((Cypher5Parser.Expression1Context) ctx);
case Cypher5Parser.RULE_expression2 -> exitDefault((AstRuleCtx) ctx);
case Cypher5Parser.RULE_expression3 -> exitDefault((AstRuleCtx) ctx);
case Cypher5Parser.RULE_expression4 -> exitDefault((AstRuleCtx) ctx);
case Cypher5Parser.RULE_expression5 -> exitDefault((AstRuleCtx) ctx);
case Cypher5Parser.RULE_expression6 -> exitDefault((AstRuleCtx) ctx);
case Cypher5Parser.RULE_expression7 -> exitDefault((AstRuleCtx) ctx);
case Cypher5Parser.RULE_expression8 -> exitDefault((AstRuleCtx) ctx);
case Cypher5Parser.RULE_expression9 -> exitDefault((AstRuleCtx) ctx);
case Cypher5Parser.RULE_expression10 -> exitDefault((AstRuleCtx) ctx);
case Cypher5Parser.RULE_expression11 -> exitDefault((AstRuleCtx) ctx);
case Cypher5Parser.RULE_namespace -> exitNameSpace((Cypher5Parser.NamespaceContext) ctx);
case Cypher5Parser.RULE_unescapedLabelSymbolicNameString -> exitUnescapedLabelSymbolicNameString(
(Cypher5Parser.UnescapedLabelSymbolicNameStringContext) ctx);
default -> exitDefault((AstRuleCtx) ctx);
}
if (((AstRuleCtx) ctx).ast == missingAst) {
throwUnsupportedQuery();
}
}
private void exitFunctionArgument(Cypher5Parser.FunctionArgumentContext ctx) {
if (ctx.getChildCount() == 1 && ctx.getChild(0) instanceof AstRuleCtx childCtx) {
ctx.ast = childCtx.ast;
}
}
private void exitFunctionInvocation(Cypher5Parser.FunctionInvocationContext ctx) {
final ZoneId DEFAULT_ZONE_ID = ZoneId.systemDefault();
if (ctx.functionName().ast instanceof String functionName) {
var arguments = ctx.functionArgument().stream().map(AstRuleCtx::ast).collect(Collectors.toList());
switch (functionName) {
case "date":
ctx.ast = createTemporalValue(
arguments, functionName, DateValue::now, DateValue::parse, DateValue::build);
break;
case "datetime":
ctx.ast = createTemporalValue(
arguments,
functionName,
DateTimeValue::now,
s -> DateTimeValue.parse(s, () -> DEFAULT_ZONE_ID),
DateTimeValue::build);
break;
case "time":
ctx.ast = createTemporalValue(
arguments,
functionName,
TimeValue::now,
s -> TimeValue.parse(s, () -> DEFAULT_ZONE_ID),
TimeValue::build);
break;
case "localtime":
ctx.ast = createTemporalValue(
arguments, functionName, LocalTimeValue::now, LocalTimeValue::parse, LocalTimeValue::build);
break;
case "localdatetime":
ctx.ast = createTemporalValue(
arguments,
functionName,
LocalDateTimeValue::now,
LocalDateTimeValue::parse,
LocalDateTimeValue::build);
break;
case "duration":
ctx.ast = createDurationValue(arguments);
break;
case "point":
ctx.ast = createPoint(arguments);
break;
default:
throwUnsupportedQuery();
}
}
}
private static T createTemporalValue(
List