diff --git a/drivers/php/composer.json b/drivers/php/composer.json new file mode 100644 index 000000000..8e0e73e6e --- /dev/null +++ b/drivers/php/composer.json @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance` + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +{ + "name": "apache/age-php", + "description": "Apache AGE PHP Driver", + "type": "library", + "license": "Apache-2.0", + "autoload": { + "psr-4": { + "Apache\\AgePhp\\": "src/" + } + }, + "authors": [ + { + "name": "Matt Hall", + "email": "matthewsimonhall@gmail.com" + } + ], + "minimum-stability": "stable", + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "9.5", + "antlr/antlr4-php-runtime": "0.8" + } +} diff --git a/drivers/php/src/AgeClient/AGTypeParse.php b/drivers/php/src/AgeClient/AGTypeParse.php new file mode 100644 index 000000000..f592169a3 --- /dev/null +++ b/drivers/php/src/AgeClient/AGTypeParse.php @@ -0,0 +1,26 @@ +agType(); + $printer = new CustomAgTypeListener(); + ParseTreeWalker::default()->walk($printer, $tree); + + return $printer->getResult(); + } +} \ No newline at end of file diff --git a/drivers/php/src/AgeClient/AgeClient.php b/drivers/php/src/AgeClient/AgeClient.php new file mode 100644 index 000000000..7ea8e75fc --- /dev/null +++ b/drivers/php/src/AgeClient/AgeClient.php @@ -0,0 +1,151 @@ +connection = pg_connect("host=$host port=$port dbname=$dbName user=$user password=$password"); + if (!$this->connection) throw new AgeClientConnectionException('Unable to connect to Postgres Database'); + + pg_query($this->connection, "CREATE EXTENSION IF NOT EXISTS age;"); + pg_query($this->connection, "LOAD 'age';"); + pg_query($this->connection, "SET search_path = ag_catalog, '\$user', public;"); + pg_query($this->connection, "GRANT USAGE ON SCHEMA ag_catalog TO $user;"); + } + + public function close(): void + { + pg_close($this->connection); + } + + /** + * Flush outbound query data on the connection and any preparedId or queryResult + */ + public function flush(): void + { + $this->prepareId = null; + $this->queryResult = null; + pg_flush($this->connection); + } + + /** + * Get the current open Postgresql connection to submit your own commands + * @return Connection + */ + public function getConnection(): Connection + { + return $this->connection; + } + + public function createGraph(string $graphName): void + { + pg_query($this->connection, "SELECT create_graph('$graphName');"); + } + + public function dropGraph(string $graphName): void + { + pg_query($this->connection, "SELECT drop_graph('$graphName', true);"); + } + + /** + * Execute Postgresql and Cypher queries, refer to Apache AGE documentation for query examples + * @param string $query - Postgresql-style query + * @return AgeClient + */ + public function query(string $query): AgeClient + { + $this->flush(); + + $queryResult = pg_query($this->connection, $query); + if ($queryResult) $this->queryResult = $queryResult; + + return $this; + } + + /** + * Execute prepared cypher-specific command without to specify Postgresql SELECT or agtypes + * @param string $graphName + * @param string $columnCount - number of agtypes returned, will throw an error if incorrect + * @param string $cypherQuery - Parameterized Cypher-style query + * @param array $params - Array of parameters to substitute for the placeholders in the original prepared cypherQuery string + * @return AgeClient + */ + public function cypherQuery(string $graphName, int $columnCount, string $cypherQuery, array $params = []): AgeClient + { + $this->flush(); + + $jsonParams = json_encode($params); + + $storedProcedureName = "cypher_stored_procedure_" . $this->storedProcedureCount++; + $statement = " + PREPARE $storedProcedureName(agtype) AS + SELECT * FROM cypher('$graphName', \$\$ $cypherQuery \$\$, \$1) as (v0 agtype"; + + for ($i = 1; $i < $columnCount; $i++) { + $statement .= sprintf(", v%d agtype", $i); + } + + $statement .= "); + EXECUTE $storedProcedureName('$jsonParams') + "; + + $queryResult = pg_query($this->connection, $statement); + if ($queryResult) $this->queryResult = $queryResult; + + return $this; + } + + /** + * Get a row as an enumerated array with parsed AgTypes + * @param int? $row + * @return array|null + * @throws AgeClientQueryException + */ + public function fetchRow(?int $row = null): array|null + { + if (!$this->queryResult) throw new AgeClientQueryException('No result from prior query to fetch from'); + $fetchResults = pg_fetch_row($this->queryResult, $row); + + $parsedResults = []; + foreach ($fetchResults as $key => $column) { + $parsedResults[$key] = $column ? AGTypeParse::parse($column) : null; + } + + return $parsedResults; + } + + /** + * Fetches all rows as an array with parsed AgTypes + * @return array|null + * @throws AgeClientQueryException + */ + public function fetchAll(): array|null + { + if (!$this->queryResult) throw new AgeClientQueryException('No result from prior query to fetch from'); + $fetchResults = pg_fetch_all($this->queryResult); + + if (!$fetchResults) return null; + + $parsedResults = []; + foreach ($fetchResults as $row) { + $rowData = []; + foreach ($row as $key => $column) { + $rowData[$key] = $column ? AGTypeParse::parse($column) : null; + } + $parsedResults[] = $rowData; + } + + return $parsedResults; + } +} \ No newline at end of file diff --git a/drivers/php/src/AgeClient/Exceptions/AgeClientConnectionException.php b/drivers/php/src/AgeClient/Exceptions/AgeClientConnectionException.php new file mode 100644 index 000000000..cdd54ab54 --- /dev/null +++ b/drivers/php/src/AgeClient/Exceptions/AgeClientConnectionException.php @@ -0,0 +1,10 @@ + skip + ; diff --git a/drivers/php/src/Parser/Agtype.interp b/drivers/php/src/Parser/Agtype.interp new file mode 100644 index 000000000..5d2ab393b --- /dev/null +++ b/drivers/php/src/Parser/Agtype.interp @@ -0,0 +1,57 @@ +token literal names: +null +'true' +'false' +'null' +'{' +',' +'}' +':' +'[' +']' +'::' +'-' +'Infinity' +'NaN' +null +null +null +null +null +null + +token symbolic names: +null +null +null +null +null +null +null +null +null +null +null +null +null +null +IDENT +STRING +INTEGER +RegularFloat +ExponentFloat +WS + +rule names: +agType +agValue +value +obj +pair +array +typeAnnotation +floatLiteral + + +atn: +[4, 1, 19, 80, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 3, 1, 22, 8, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 32, 8, 2, 1, 3, 1, 3, 1, 3, 1, 3, 5, 3, 38, 8, 3, 10, 3, 12, 3, 41, 9, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 47, 8, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 5, 5, 57, 8, 5, 10, 5, 12, 5, 60, 9, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 66, 8, 5, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 3, 7, 74, 8, 7, 1, 7, 1, 7, 3, 7, 78, 8, 7, 1, 7, 0, 0, 8, 0, 2, 4, 6, 8, 10, 12, 14, 0, 0, 87, 0, 16, 1, 0, 0, 0, 2, 19, 1, 0, 0, 0, 4, 31, 1, 0, 0, 0, 6, 46, 1, 0, 0, 0, 8, 48, 1, 0, 0, 0, 10, 65, 1, 0, 0, 0, 12, 67, 1, 0, 0, 0, 14, 77, 1, 0, 0, 0, 16, 17, 3, 2, 1, 0, 17, 18, 5, 0, 0, 1, 18, 1, 1, 0, 0, 0, 19, 21, 3, 4, 2, 0, 20, 22, 3, 12, 6, 0, 21, 20, 1, 0, 0, 0, 21, 22, 1, 0, 0, 0, 22, 3, 1, 0, 0, 0, 23, 32, 5, 15, 0, 0, 24, 32, 5, 16, 0, 0, 25, 32, 3, 14, 7, 0, 26, 32, 5, 1, 0, 0, 27, 32, 5, 2, 0, 0, 28, 32, 5, 3, 0, 0, 29, 32, 3, 6, 3, 0, 30, 32, 3, 10, 5, 0, 31, 23, 1, 0, 0, 0, 31, 24, 1, 0, 0, 0, 31, 25, 1, 0, 0, 0, 31, 26, 1, 0, 0, 0, 31, 27, 1, 0, 0, 0, 31, 28, 1, 0, 0, 0, 31, 29, 1, 0, 0, 0, 31, 30, 1, 0, 0, 0, 32, 5, 1, 0, 0, 0, 33, 34, 5, 4, 0, 0, 34, 39, 3, 8, 4, 0, 35, 36, 5, 5, 0, 0, 36, 38, 3, 8, 4, 0, 37, 35, 1, 0, 0, 0, 38, 41, 1, 0, 0, 0, 39, 37, 1, 0, 0, 0, 39, 40, 1, 0, 0, 0, 40, 42, 1, 0, 0, 0, 41, 39, 1, 0, 0, 0, 42, 43, 5, 6, 0, 0, 43, 47, 1, 0, 0, 0, 44, 45, 5, 4, 0, 0, 45, 47, 5, 6, 0, 0, 46, 33, 1, 0, 0, 0, 46, 44, 1, 0, 0, 0, 47, 7, 1, 0, 0, 0, 48, 49, 5, 15, 0, 0, 49, 50, 5, 7, 0, 0, 50, 51, 3, 2, 1, 0, 51, 9, 1, 0, 0, 0, 52, 53, 5, 8, 0, 0, 53, 58, 3, 2, 1, 0, 54, 55, 5, 5, 0, 0, 55, 57, 3, 2, 1, 0, 56, 54, 1, 0, 0, 0, 57, 60, 1, 0, 0, 0, 58, 56, 1, 0, 0, 0, 58, 59, 1, 0, 0, 0, 59, 61, 1, 0, 0, 0, 60, 58, 1, 0, 0, 0, 61, 62, 5, 9, 0, 0, 62, 66, 1, 0, 0, 0, 63, 64, 5, 8, 0, 0, 64, 66, 5, 9, 0, 0, 65, 52, 1, 0, 0, 0, 65, 63, 1, 0, 0, 0, 66, 11, 1, 0, 0, 0, 67, 68, 5, 10, 0, 0, 68, 69, 5, 14, 0, 0, 69, 13, 1, 0, 0, 0, 70, 78, 5, 17, 0, 0, 71, 78, 5, 18, 0, 0, 72, 74, 5, 11, 0, 0, 73, 72, 1, 0, 0, 0, 73, 74, 1, 0, 0, 0, 74, 75, 1, 0, 0, 0, 75, 78, 5, 12, 0, 0, 76, 78, 5, 13, 0, 0, 77, 70, 1, 0, 0, 0, 77, 71, 1, 0, 0, 0, 77, 73, 1, 0, 0, 0, 77, 76, 1, 0, 0, 0, 78, 15, 1, 0, 0, 0, 8, 21, 31, 39, 46, 58, 65, 73, 77] \ No newline at end of file diff --git a/drivers/php/src/Parser/Agtype.tokens b/drivers/php/src/Parser/Agtype.tokens new file mode 100644 index 000000000..b2036f94d --- /dev/null +++ b/drivers/php/src/Parser/Agtype.tokens @@ -0,0 +1,32 @@ +T__0=1 +T__1=2 +T__2=3 +T__3=4 +T__4=5 +T__5=6 +T__6=7 +T__7=8 +T__8=9 +T__9=10 +T__10=11 +T__11=12 +T__12=13 +IDENT=14 +STRING=15 +INTEGER=16 +RegularFloat=17 +ExponentFloat=18 +WS=19 +'true'=1 +'false'=2 +'null'=3 +'{'=4 +','=5 +'}'=6 +':'=7 +'['=8 +']'=9 +'::'=10 +'-'=11 +'Infinity'=12 +'NaN'=13 diff --git a/drivers/php/src/Parser/AgtypeBaseListener.php b/drivers/php/src/Parser/AgtypeBaseListener.php new file mode 100644 index 000000000..532055553 --- /dev/null +++ b/drivers/php/src/Parser/AgtypeBaseListener.php @@ -0,0 +1,243 @@ +visitChildren($context); + } + + /** + * {@inheritdoc} + * + * The default implementation returns the result of calling + * {@see self::visitChildren()} on `context`. + */ + public function visitAgValue(Context\AgValueContext $context) + { + return $this->visitChildren($context); + } + + /** + * {@inheritdoc} + * + * The default implementation returns the result of calling + * {@see self::visitChildren()} on `context`. + */ + public function visitStringValue(Context\StringValueContext $context) + { + return $this->visitChildren($context); + } + + /** + * {@inheritdoc} + * + * The default implementation returns the result of calling + * {@see self::visitChildren()} on `context`. + */ + public function visitIntegerValue(Context\IntegerValueContext $context) + { + return $this->visitChildren($context); + } + + /** + * {@inheritdoc} + * + * The default implementation returns the result of calling + * {@see self::visitChildren()} on `context`. + */ + public function visitFloatValue(Context\FloatValueContext $context) + { + return $this->visitChildren($context); + } + + /** + * {@inheritdoc} + * + * The default implementation returns the result of calling + * {@see self::visitChildren()} on `context`. + */ + public function visitTrueBoolean(Context\TrueBooleanContext $context) + { + return $this->visitChildren($context); + } + + /** + * {@inheritdoc} + * + * The default implementation returns the result of calling + * {@see self::visitChildren()} on `context`. + */ + public function visitFalseBoolean(Context\FalseBooleanContext $context) + { + return $this->visitChildren($context); + } + + /** + * {@inheritdoc} + * + * The default implementation returns the result of calling + * {@see self::visitChildren()} on `context`. + */ + public function visitNullValue(Context\NullValueContext $context) + { + return $this->visitChildren($context); + } + + /** + * {@inheritdoc} + * + * The default implementation returns the result of calling + * {@see self::visitChildren()} on `context`. + */ + public function visitObjectValue(Context\ObjectValueContext $context) + { + return $this->visitChildren($context); + } + + /** + * {@inheritdoc} + * + * The default implementation returns the result of calling + * {@see self::visitChildren()} on `context`. + */ + public function visitArrayValue(Context\ArrayValueContext $context) + { + return $this->visitChildren($context); + } + + /** + * {@inheritdoc} + * + * The default implementation returns the result of calling + * {@see self::visitChildren()} on `context`. + */ + public function visitObj(Context\ObjContext $context) + { + return $this->visitChildren($context); + } + + /** + * {@inheritdoc} + * + * The default implementation returns the result of calling + * {@see self::visitChildren()} on `context`. + */ + public function visitPair(Context\PairContext $context) + { + return $this->visitChildren($context); + } + + /** + * {@inheritdoc} + * + * The default implementation returns the result of calling + * {@see self::visitChildren()} on `context`. + */ + public function visitArray(Context\ArrayContext $context) + { + return $this->visitChildren($context); + } + + /** + * {@inheritdoc} + * + * The default implementation returns the result of calling + * {@see self::visitChildren()} on `context`. + */ + public function visitTypeAnnotation(Context\TypeAnnotationContext $context) + { + return $this->visitChildren($context); + } + + /** + * {@inheritdoc} + * + * The default implementation returns the result of calling + * {@see self::visitChildren()} on `context`. + */ + public function visitFloatLiteral(Context\FloatLiteralContext $context) + { + return $this->visitChildren($context); + } +} \ No newline at end of file diff --git a/drivers/php/src/Parser/AgtypeLexer.interp b/drivers/php/src/Parser/AgtypeLexer.interp new file mode 100644 index 000000000..c5df95442 --- /dev/null +++ b/drivers/php/src/Parser/AgtypeLexer.interp @@ -0,0 +1,81 @@ +token literal names: +null +'true' +'false' +'null' +'{' +',' +'}' +':' +'[' +']' +'::' +'-' +'Infinity' +'NaN' +null +null +null +null +null +null + +token symbolic names: +null +null +null +null +null +null +null +null +null +null +null +null +null +null +IDENT +STRING +INTEGER +RegularFloat +ExponentFloat +WS + +rule names: +T__0 +T__1 +T__2 +T__3 +T__4 +T__5 +T__6 +T__7 +T__8 +T__9 +T__10 +T__11 +T__12 +IDENT +STRING +ESC +UNICODE +HEX +SAFECODEPOINT +INTEGER +INT +RegularFloat +ExponentFloat +DECIMAL +SCIENTIFIC +WS + +channel names: +DEFAULT_TOKEN_CHANNEL +HIDDEN + +mode names: +DEFAULT_MODE + +atn: +[4, 0, 19, 183, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 5, 13, 102, 8, 13, 10, 13, 12, 13, 105, 9, 13, 1, 14, 1, 14, 1, 14, 5, 14, 110, 8, 14, 10, 14, 12, 14, 113, 9, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 3, 15, 120, 8, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 18, 1, 18, 1, 19, 3, 19, 133, 8, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 5, 20, 140, 8, 20, 10, 20, 12, 20, 143, 9, 20, 3, 20, 145, 8, 20, 1, 21, 3, 21, 148, 8, 21, 1, 21, 1, 21, 1, 21, 1, 22, 3, 22, 154, 8, 22, 1, 22, 1, 22, 3, 22, 158, 8, 22, 1, 22, 1, 22, 1, 23, 1, 23, 4, 23, 164, 8, 23, 11, 23, 12, 23, 165, 1, 24, 1, 24, 3, 24, 170, 8, 24, 1, 24, 4, 24, 173, 8, 24, 11, 24, 12, 24, 174, 1, 25, 4, 25, 178, 8, 25, 11, 25, 12, 25, 179, 1, 25, 1, 25, 0, 0, 26, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 0, 33, 0, 35, 0, 37, 0, 39, 16, 41, 0, 43, 17, 45, 18, 47, 0, 49, 0, 51, 19, 1, 0, 10, 3, 0, 65, 90, 95, 95, 97, 122, 5, 0, 36, 36, 48, 57, 65, 90, 95, 95, 97, 122, 8, 0, 34, 34, 47, 47, 92, 92, 98, 98, 102, 102, 110, 110, 114, 114, 116, 116, 3, 0, 48, 57, 65, 70, 97, 102, 3, 0, 0, 31, 34, 34, 92, 92, 1, 0, 49, 57, 1, 0, 48, 57, 2, 0, 69, 69, 101, 101, 2, 0, 43, 43, 45, 45, 3, 0, 9, 10, 13, 13, 32, 32, 189, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 1, 53, 1, 0, 0, 0, 3, 58, 1, 0, 0, 0, 5, 64, 1, 0, 0, 0, 7, 69, 1, 0, 0, 0, 9, 71, 1, 0, 0, 0, 11, 73, 1, 0, 0, 0, 13, 75, 1, 0, 0, 0, 15, 77, 1, 0, 0, 0, 17, 79, 1, 0, 0, 0, 19, 81, 1, 0, 0, 0, 21, 84, 1, 0, 0, 0, 23, 86, 1, 0, 0, 0, 25, 95, 1, 0, 0, 0, 27, 99, 1, 0, 0, 0, 29, 106, 1, 0, 0, 0, 31, 116, 1, 0, 0, 0, 33, 121, 1, 0, 0, 0, 35, 127, 1, 0, 0, 0, 37, 129, 1, 0, 0, 0, 39, 132, 1, 0, 0, 0, 41, 144, 1, 0, 0, 0, 43, 147, 1, 0, 0, 0, 45, 153, 1, 0, 0, 0, 47, 161, 1, 0, 0, 0, 49, 167, 1, 0, 0, 0, 51, 177, 1, 0, 0, 0, 53, 54, 5, 116, 0, 0, 54, 55, 5, 114, 0, 0, 55, 56, 5, 117, 0, 0, 56, 57, 5, 101, 0, 0, 57, 2, 1, 0, 0, 0, 58, 59, 5, 102, 0, 0, 59, 60, 5, 97, 0, 0, 60, 61, 5, 108, 0, 0, 61, 62, 5, 115, 0, 0, 62, 63, 5, 101, 0, 0, 63, 4, 1, 0, 0, 0, 64, 65, 5, 110, 0, 0, 65, 66, 5, 117, 0, 0, 66, 67, 5, 108, 0, 0, 67, 68, 5, 108, 0, 0, 68, 6, 1, 0, 0, 0, 69, 70, 5, 123, 0, 0, 70, 8, 1, 0, 0, 0, 71, 72, 5, 44, 0, 0, 72, 10, 1, 0, 0, 0, 73, 74, 5, 125, 0, 0, 74, 12, 1, 0, 0, 0, 75, 76, 5, 58, 0, 0, 76, 14, 1, 0, 0, 0, 77, 78, 5, 91, 0, 0, 78, 16, 1, 0, 0, 0, 79, 80, 5, 93, 0, 0, 80, 18, 1, 0, 0, 0, 81, 82, 5, 58, 0, 0, 82, 83, 5, 58, 0, 0, 83, 20, 1, 0, 0, 0, 84, 85, 5, 45, 0, 0, 85, 22, 1, 0, 0, 0, 86, 87, 5, 73, 0, 0, 87, 88, 5, 110, 0, 0, 88, 89, 5, 102, 0, 0, 89, 90, 5, 105, 0, 0, 90, 91, 5, 110, 0, 0, 91, 92, 5, 105, 0, 0, 92, 93, 5, 116, 0, 0, 93, 94, 5, 121, 0, 0, 94, 24, 1, 0, 0, 0, 95, 96, 5, 78, 0, 0, 96, 97, 5, 97, 0, 0, 97, 98, 5, 78, 0, 0, 98, 26, 1, 0, 0, 0, 99, 103, 7, 0, 0, 0, 100, 102, 7, 1, 0, 0, 101, 100, 1, 0, 0, 0, 102, 105, 1, 0, 0, 0, 103, 101, 1, 0, 0, 0, 103, 104, 1, 0, 0, 0, 104, 28, 1, 0, 0, 0, 105, 103, 1, 0, 0, 0, 106, 111, 5, 34, 0, 0, 107, 110, 3, 31, 15, 0, 108, 110, 3, 37, 18, 0, 109, 107, 1, 0, 0, 0, 109, 108, 1, 0, 0, 0, 110, 113, 1, 0, 0, 0, 111, 109, 1, 0, 0, 0, 111, 112, 1, 0, 0, 0, 112, 114, 1, 0, 0, 0, 113, 111, 1, 0, 0, 0, 114, 115, 5, 34, 0, 0, 115, 30, 1, 0, 0, 0, 116, 119, 5, 92, 0, 0, 117, 120, 7, 2, 0, 0, 118, 120, 3, 33, 16, 0, 119, 117, 1, 0, 0, 0, 119, 118, 1, 0, 0, 0, 120, 32, 1, 0, 0, 0, 121, 122, 5, 117, 0, 0, 122, 123, 3, 35, 17, 0, 123, 124, 3, 35, 17, 0, 124, 125, 3, 35, 17, 0, 125, 126, 3, 35, 17, 0, 126, 34, 1, 0, 0, 0, 127, 128, 7, 3, 0, 0, 128, 36, 1, 0, 0, 0, 129, 130, 8, 4, 0, 0, 130, 38, 1, 0, 0, 0, 131, 133, 5, 45, 0, 0, 132, 131, 1, 0, 0, 0, 132, 133, 1, 0, 0, 0, 133, 134, 1, 0, 0, 0, 134, 135, 3, 41, 20, 0, 135, 40, 1, 0, 0, 0, 136, 145, 5, 48, 0, 0, 137, 141, 7, 5, 0, 0, 138, 140, 7, 6, 0, 0, 139, 138, 1, 0, 0, 0, 140, 143, 1, 0, 0, 0, 141, 139, 1, 0, 0, 0, 141, 142, 1, 0, 0, 0, 142, 145, 1, 0, 0, 0, 143, 141, 1, 0, 0, 0, 144, 136, 1, 0, 0, 0, 144, 137, 1, 0, 0, 0, 145, 42, 1, 0, 0, 0, 146, 148, 5, 45, 0, 0, 147, 146, 1, 0, 0, 0, 147, 148, 1, 0, 0, 0, 148, 149, 1, 0, 0, 0, 149, 150, 3, 41, 20, 0, 150, 151, 3, 47, 23, 0, 151, 44, 1, 0, 0, 0, 152, 154, 5, 45, 0, 0, 153, 152, 1, 0, 0, 0, 153, 154, 1, 0, 0, 0, 154, 155, 1, 0, 0, 0, 155, 157, 3, 41, 20, 0, 156, 158, 3, 47, 23, 0, 157, 156, 1, 0, 0, 0, 157, 158, 1, 0, 0, 0, 158, 159, 1, 0, 0, 0, 159, 160, 3, 49, 24, 0, 160, 46, 1, 0, 0, 0, 161, 163, 5, 46, 0, 0, 162, 164, 7, 6, 0, 0, 163, 162, 1, 0, 0, 0, 164, 165, 1, 0, 0, 0, 165, 163, 1, 0, 0, 0, 165, 166, 1, 0, 0, 0, 166, 48, 1, 0, 0, 0, 167, 169, 7, 7, 0, 0, 168, 170, 7, 8, 0, 0, 169, 168, 1, 0, 0, 0, 169, 170, 1, 0, 0, 0, 170, 172, 1, 0, 0, 0, 171, 173, 7, 6, 0, 0, 172, 171, 1, 0, 0, 0, 173, 174, 1, 0, 0, 0, 174, 172, 1, 0, 0, 0, 174, 175, 1, 0, 0, 0, 175, 50, 1, 0, 0, 0, 176, 178, 7, 9, 0, 0, 177, 176, 1, 0, 0, 0, 178, 179, 1, 0, 0, 0, 179, 177, 1, 0, 0, 0, 179, 180, 1, 0, 0, 0, 180, 181, 1, 0, 0, 0, 181, 182, 6, 25, 0, 0, 182, 52, 1, 0, 0, 0, 15, 0, 103, 109, 111, 119, 132, 141, 144, 147, 153, 157, 165, 169, 174, 179, 1, 6, 0, 0] \ No newline at end of file diff --git a/drivers/php/src/Parser/AgtypeLexer.php b/drivers/php/src/Parser/AgtypeLexer.php new file mode 100644 index 000000000..3d9728617 --- /dev/null +++ b/drivers/php/src/Parser/AgtypeLexer.php @@ -0,0 +1,239 @@ + + */ + public const CHANNEL_NAMES = [ + 'DEFAULT_TOKEN_CHANNEL', 'HIDDEN' + ]; + + /** + * @var array + */ + public const MODE_NAMES = [ + 'DEFAULT_MODE' + ]; + + /** + * @var array + */ + public const RULE_NAMES = [ + 'T__0', 'T__1', 'T__2', 'T__3', 'T__4', 'T__5', 'T__6', 'T__7', 'T__8', + 'T__9', 'T__10', 'T__11', 'T__12', 'IDENT', 'STRING', 'ESC', 'UNICODE', + 'HEX', 'SAFECODEPOINT', 'INTEGER', 'INT', 'RegularFloat', 'ExponentFloat', + 'DECIMAL', 'SCIENTIFIC', 'WS' + ]; + + /** + * @var array + */ + private const LITERAL_NAMES = [ + null, "'true'", "'false'", "'null'", "'{'", "','", "'}'", "':'", "'['", + "']'", "'::'", "'-'", "'Infinity'", "'NaN'" + ]; + + /** + * @var array + */ + private const SYMBOLIC_NAMES = [ + null, null, null, null, null, null, null, null, null, null, null, + null, null, null, "IDENT", "STRING", "INTEGER", "RegularFloat", "ExponentFloat", + "WS" + ]; + + private const SERIALIZED_ATN = + [4, 0, 19, 183, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, + 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, + 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, + 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, + 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, + 2, 24, 7, 24, 2, 25, 7, 25, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, + 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, + 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, + 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, + 5, 13, 102, 8, 13, 10, 13, 12, 13, 105, 9, 13, 1, 14, 1, 14, 1, 14, + 5, 14, 110, 8, 14, 10, 14, 12, 14, 113, 9, 14, 1, 14, 1, 14, 1, 15, + 1, 15, 1, 15, 3, 15, 120, 8, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, + 1, 16, 1, 17, 1, 17, 1, 18, 1, 18, 1, 19, 3, 19, 133, 8, 19, 1, 19, + 1, 19, 1, 20, 1, 20, 1, 20, 5, 20, 140, 8, 20, 10, 20, 12, 20, 143, + 9, 20, 3, 20, 145, 8, 20, 1, 21, 3, 21, 148, 8, 21, 1, 21, 1, 21, + 1, 21, 1, 22, 3, 22, 154, 8, 22, 1, 22, 1, 22, 3, 22, 158, 8, 22, + 1, 22, 1, 22, 1, 23, 1, 23, 4, 23, 164, 8, 23, 11, 23, 12, 23, 165, + 1, 24, 1, 24, 3, 24, 170, 8, 24, 1, 24, 4, 24, 173, 8, 24, 11, 24, + 12, 24, 174, 1, 25, 4, 25, 178, 8, 25, 11, 25, 12, 25, 179, 1, 25, + 1, 25, 0, 0, 26, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, + 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 0, 33, + 0, 35, 0, 37, 0, 39, 16, 41, 0, 43, 17, 45, 18, 47, 0, 49, 0, 51, + 19, 1, 0, 10, 3, 0, 65, 90, 95, 95, 97, 122, 5, 0, 36, 36, 48, 57, + 65, 90, 95, 95, 97, 122, 8, 0, 34, 34, 47, 47, 92, 92, 98, 98, 102, + 102, 110, 110, 114, 114, 116, 116, 3, 0, 48, 57, 65, 70, 97, 102, + 3, 0, 0, 31, 34, 34, 92, 92, 1, 0, 49, 57, 1, 0, 48, 57, 2, 0, 69, + 69, 101, 101, 2, 0, 43, 43, 45, 45, 3, 0, 9, 10, 13, 13, 32, 32, 189, + 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, + 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, + 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, + 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, + 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, + 0, 0, 51, 1, 0, 0, 0, 1, 53, 1, 0, 0, 0, 3, 58, 1, 0, 0, 0, 5, 64, + 1, 0, 0, 0, 7, 69, 1, 0, 0, 0, 9, 71, 1, 0, 0, 0, 11, 73, 1, 0, 0, + 0, 13, 75, 1, 0, 0, 0, 15, 77, 1, 0, 0, 0, 17, 79, 1, 0, 0, 0, 19, + 81, 1, 0, 0, 0, 21, 84, 1, 0, 0, 0, 23, 86, 1, 0, 0, 0, 25, 95, 1, + 0, 0, 0, 27, 99, 1, 0, 0, 0, 29, 106, 1, 0, 0, 0, 31, 116, 1, 0, 0, + 0, 33, 121, 1, 0, 0, 0, 35, 127, 1, 0, 0, 0, 37, 129, 1, 0, 0, 0, + 39, 132, 1, 0, 0, 0, 41, 144, 1, 0, 0, 0, 43, 147, 1, 0, 0, 0, 45, + 153, 1, 0, 0, 0, 47, 161, 1, 0, 0, 0, 49, 167, 1, 0, 0, 0, 51, 177, + 1, 0, 0, 0, 53, 54, 5, 116, 0, 0, 54, 55, 5, 114, 0, 0, 55, 56, 5, + 117, 0, 0, 56, 57, 5, 101, 0, 0, 57, 2, 1, 0, 0, 0, 58, 59, 5, 102, + 0, 0, 59, 60, 5, 97, 0, 0, 60, 61, 5, 108, 0, 0, 61, 62, 5, 115, 0, + 0, 62, 63, 5, 101, 0, 0, 63, 4, 1, 0, 0, 0, 64, 65, 5, 110, 0, 0, + 65, 66, 5, 117, 0, 0, 66, 67, 5, 108, 0, 0, 67, 68, 5, 108, 0, 0, + 68, 6, 1, 0, 0, 0, 69, 70, 5, 123, 0, 0, 70, 8, 1, 0, 0, 0, 71, 72, + 5, 44, 0, 0, 72, 10, 1, 0, 0, 0, 73, 74, 5, 125, 0, 0, 74, 12, 1, + 0, 0, 0, 75, 76, 5, 58, 0, 0, 76, 14, 1, 0, 0, 0, 77, 78, 5, 91, 0, + 0, 78, 16, 1, 0, 0, 0, 79, 80, 5, 93, 0, 0, 80, 18, 1, 0, 0, 0, 81, + 82, 5, 58, 0, 0, 82, 83, 5, 58, 0, 0, 83, 20, 1, 0, 0, 0, 84, 85, + 5, 45, 0, 0, 85, 22, 1, 0, 0, 0, 86, 87, 5, 73, 0, 0, 87, 88, 5, 110, + 0, 0, 88, 89, 5, 102, 0, 0, 89, 90, 5, 105, 0, 0, 90, 91, 5, 110, + 0, 0, 91, 92, 5, 105, 0, 0, 92, 93, 5, 116, 0, 0, 93, 94, 5, 121, + 0, 0, 94, 24, 1, 0, 0, 0, 95, 96, 5, 78, 0, 0, 96, 97, 5, 97, 0, 0, + 97, 98, 5, 78, 0, 0, 98, 26, 1, 0, 0, 0, 99, 103, 7, 0, 0, 0, 100, + 102, 7, 1, 0, 0, 101, 100, 1, 0, 0, 0, 102, 105, 1, 0, 0, 0, 103, + 101, 1, 0, 0, 0, 103, 104, 1, 0, 0, 0, 104, 28, 1, 0, 0, 0, 105, 103, + 1, 0, 0, 0, 106, 111, 5, 34, 0, 0, 107, 110, 3, 31, 15, 0, 108, 110, + 3, 37, 18, 0, 109, 107, 1, 0, 0, 0, 109, 108, 1, 0, 0, 0, 110, 113, + 1, 0, 0, 0, 111, 109, 1, 0, 0, 0, 111, 112, 1, 0, 0, 0, 112, 114, + 1, 0, 0, 0, 113, 111, 1, 0, 0, 0, 114, 115, 5, 34, 0, 0, 115, 30, + 1, 0, 0, 0, 116, 119, 5, 92, 0, 0, 117, 120, 7, 2, 0, 0, 118, 120, + 3, 33, 16, 0, 119, 117, 1, 0, 0, 0, 119, 118, 1, 0, 0, 0, 120, 32, + 1, 0, 0, 0, 121, 122, 5, 117, 0, 0, 122, 123, 3, 35, 17, 0, 123, 124, + 3, 35, 17, 0, 124, 125, 3, 35, 17, 0, 125, 126, 3, 35, 17, 0, 126, + 34, 1, 0, 0, 0, 127, 128, 7, 3, 0, 0, 128, 36, 1, 0, 0, 0, 129, 130, + 8, 4, 0, 0, 130, 38, 1, 0, 0, 0, 131, 133, 5, 45, 0, 0, 132, 131, + 1, 0, 0, 0, 132, 133, 1, 0, 0, 0, 133, 134, 1, 0, 0, 0, 134, 135, + 3, 41, 20, 0, 135, 40, 1, 0, 0, 0, 136, 145, 5, 48, 0, 0, 137, 141, + 7, 5, 0, 0, 138, 140, 7, 6, 0, 0, 139, 138, 1, 0, 0, 0, 140, 143, + 1, 0, 0, 0, 141, 139, 1, 0, 0, 0, 141, 142, 1, 0, 0, 0, 142, 145, + 1, 0, 0, 0, 143, 141, 1, 0, 0, 0, 144, 136, 1, 0, 0, 0, 144, 137, + 1, 0, 0, 0, 145, 42, 1, 0, 0, 0, 146, 148, 5, 45, 0, 0, 147, 146, + 1, 0, 0, 0, 147, 148, 1, 0, 0, 0, 148, 149, 1, 0, 0, 0, 149, 150, + 3, 41, 20, 0, 150, 151, 3, 47, 23, 0, 151, 44, 1, 0, 0, 0, 152, 154, + 5, 45, 0, 0, 153, 152, 1, 0, 0, 0, 153, 154, 1, 0, 0, 0, 154, 155, + 1, 0, 0, 0, 155, 157, 3, 41, 20, 0, 156, 158, 3, 47, 23, 0, 157, 156, + 1, 0, 0, 0, 157, 158, 1, 0, 0, 0, 158, 159, 1, 0, 0, 0, 159, 160, + 3, 49, 24, 0, 160, 46, 1, 0, 0, 0, 161, 163, 5, 46, 0, 0, 162, 164, + 7, 6, 0, 0, 163, 162, 1, 0, 0, 0, 164, 165, 1, 0, 0, 0, 165, 163, + 1, 0, 0, 0, 165, 166, 1, 0, 0, 0, 166, 48, 1, 0, 0, 0, 167, 169, 7, + 7, 0, 0, 168, 170, 7, 8, 0, 0, 169, 168, 1, 0, 0, 0, 169, 170, 1, + 0, 0, 0, 170, 172, 1, 0, 0, 0, 171, 173, 7, 6, 0, 0, 172, 171, 1, + 0, 0, 0, 173, 174, 1, 0, 0, 0, 174, 172, 1, 0, 0, 0, 174, 175, 1, + 0, 0, 0, 175, 50, 1, 0, 0, 0, 176, 178, 7, 9, 0, 0, 177, 176, 1, 0, + 0, 0, 178, 179, 1, 0, 0, 0, 179, 177, 1, 0, 0, 0, 179, 180, 1, 0, + 0, 0, 180, 181, 1, 0, 0, 0, 181, 182, 6, 25, 0, 0, 182, 52, 1, 0, + 0, 0, 15, 0, 103, 109, 111, 119, 132, 141, 144, 147, 153, 157, 165, + 169, 174, 179, 1, 6, 0, 0]; + protected static $atn; + protected static $decisionToDFA; + protected static $sharedContextCache; + public function __construct(CharStream $input) + { + parent::__construct($input); + + self::initialize(); + + $this->interp = new LexerATNSimulator($this, self::$atn, self::$decisionToDFA, self::$sharedContextCache); + } + + private static function initialize(): void + { + if (self::$atn !== null) { + return; + } + + RuntimeMetaData::checkVersion('4.11.1', RuntimeMetaData::VERSION); + + $atn = (new ATNDeserializer())->deserialize(self::SERIALIZED_ATN); + + $decisionToDFA = []; + for ($i = 0, $count = $atn->getNumberOfDecisions(); $i < $count; $i++) { + $decisionToDFA[] = new DFA($atn->getDecisionState($i), $i); + } + + self::$atn = $atn; + self::$decisionToDFA = $decisionToDFA; + self::$sharedContextCache = new PredictionContextCache(); + } + + public static function vocabulary(): Vocabulary + { + static $vocabulary; + + return $vocabulary = $vocabulary ?? new VocabularyImpl(self::LITERAL_NAMES, self::SYMBOLIC_NAMES); + } + + public function getGrammarFileName(): string + { + return 'Agtype.g4'; + } + + public function getRuleNames(): array + { + return self::RULE_NAMES; + } + + public function getSerializedATN(): array + { + return self::SERIALIZED_ATN; + } + + /** + * @return array + */ + public function getChannelNames(): array + { + return self::CHANNEL_NAMES; + } + + /** + * @return array + */ + public function getModeNames(): array + { + return self::MODE_NAMES; + } + + public function getATN(): ATN + { + return self::$atn; + } + + public function getVocabulary(): Vocabulary + { + return self::vocabulary(); + } + } +} \ No newline at end of file diff --git a/drivers/php/src/Parser/AgtypeLexer.tokens b/drivers/php/src/Parser/AgtypeLexer.tokens new file mode 100644 index 000000000..b2036f94d --- /dev/null +++ b/drivers/php/src/Parser/AgtypeLexer.tokens @@ -0,0 +1,32 @@ +T__0=1 +T__1=2 +T__2=3 +T__3=4 +T__4=5 +T__5=6 +T__6=7 +T__7=8 +T__8=9 +T__9=10 +T__10=11 +T__11=12 +T__12=13 +IDENT=14 +STRING=15 +INTEGER=16 +RegularFloat=17 +ExponentFloat=18 +WS=19 +'true'=1 +'false'=2 +'null'=3 +'{'=4 +','=5 +'}'=6 +':'=7 +'['=8 +']'=9 +'::'=10 +'-'=11 +'Infinity'=12 +'NaN'=13 diff --git a/drivers/php/src/Parser/AgtypeListener.php b/drivers/php/src/Parser/AgtypeListener.php new file mode 100644 index 000000000..c447ef569 --- /dev/null +++ b/drivers/php/src/Parser/AgtypeListener.php @@ -0,0 +1,182 @@ + + */ + public const RULE_NAMES = [ + 'agType', 'agValue', 'value', 'obj', 'pair', 'array', 'typeAnnotation', + 'floatLiteral' + ]; + + /** + * @var array + */ + private const LITERAL_NAMES = [ + null, "'true'", "'false'", "'null'", "'{'", "','", "'}'", "':'", "'['", + "']'", "'::'", "'-'", "'Infinity'", "'NaN'" + ]; + + /** + * @var array + */ + private const SYMBOLIC_NAMES = [ + null, null, null, null, null, null, null, null, null, null, null, + null, null, null, "IDENT", "STRING", "INTEGER", "RegularFloat", "ExponentFloat", + "WS" + ]; + + private const SERIALIZED_ATN = + [4, 1, 19, 80, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, + 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 1, 0, 1, 0, 1, 0, 1, 1, + 1, 1, 3, 1, 22, 8, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, + 2, 3, 2, 32, 8, 2, 1, 3, 1, 3, 1, 3, 1, 3, 5, 3, 38, 8, 3, 10, 3, + 12, 3, 41, 9, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 47, 8, 3, 1, 4, 1, + 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 5, 5, 57, 8, 5, 10, 5, 12, + 5, 60, 9, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 66, 8, 5, 1, 6, 1, 6, 1, + 6, 1, 7, 1, 7, 1, 7, 3, 7, 74, 8, 7, 1, 7, 1, 7, 3, 7, 78, 8, 7, 1, + 7, 0, 0, 8, 0, 2, 4, 6, 8, 10, 12, 14, 0, 0, 87, 0, 16, 1, 0, 0, 0, + 2, 19, 1, 0, 0, 0, 4, 31, 1, 0, 0, 0, 6, 46, 1, 0, 0, 0, 8, 48, 1, + 0, 0, 0, 10, 65, 1, 0, 0, 0, 12, 67, 1, 0, 0, 0, 14, 77, 1, 0, 0, + 0, 16, 17, 3, 2, 1, 0, 17, 18, 5, 0, 0, 1, 18, 1, 1, 0, 0, 0, 19, + 21, 3, 4, 2, 0, 20, 22, 3, 12, 6, 0, 21, 20, 1, 0, 0, 0, 21, 22, 1, + 0, 0, 0, 22, 3, 1, 0, 0, 0, 23, 32, 5, 15, 0, 0, 24, 32, 5, 16, 0, + 0, 25, 32, 3, 14, 7, 0, 26, 32, 5, 1, 0, 0, 27, 32, 5, 2, 0, 0, 28, + 32, 5, 3, 0, 0, 29, 32, 3, 6, 3, 0, 30, 32, 3, 10, 5, 0, 31, 23, 1, + 0, 0, 0, 31, 24, 1, 0, 0, 0, 31, 25, 1, 0, 0, 0, 31, 26, 1, 0, 0, + 0, 31, 27, 1, 0, 0, 0, 31, 28, 1, 0, 0, 0, 31, 29, 1, 0, 0, 0, 31, + 30, 1, 0, 0, 0, 32, 5, 1, 0, 0, 0, 33, 34, 5, 4, 0, 0, 34, 39, 3, + 8, 4, 0, 35, 36, 5, 5, 0, 0, 36, 38, 3, 8, 4, 0, 37, 35, 1, 0, 0, + 0, 38, 41, 1, 0, 0, 0, 39, 37, 1, 0, 0, 0, 39, 40, 1, 0, 0, 0, 40, + 42, 1, 0, 0, 0, 41, 39, 1, 0, 0, 0, 42, 43, 5, 6, 0, 0, 43, 47, 1, + 0, 0, 0, 44, 45, 5, 4, 0, 0, 45, 47, 5, 6, 0, 0, 46, 33, 1, 0, 0, + 0, 46, 44, 1, 0, 0, 0, 47, 7, 1, 0, 0, 0, 48, 49, 5, 15, 0, 0, 49, + 50, 5, 7, 0, 0, 50, 51, 3, 2, 1, 0, 51, 9, 1, 0, 0, 0, 52, 53, 5, + 8, 0, 0, 53, 58, 3, 2, 1, 0, 54, 55, 5, 5, 0, 0, 55, 57, 3, 2, 1, + 0, 56, 54, 1, 0, 0, 0, 57, 60, 1, 0, 0, 0, 58, 56, 1, 0, 0, 0, 58, + 59, 1, 0, 0, 0, 59, 61, 1, 0, 0, 0, 60, 58, 1, 0, 0, 0, 61, 62, 5, + 9, 0, 0, 62, 66, 1, 0, 0, 0, 63, 64, 5, 8, 0, 0, 64, 66, 5, 9, 0, + 0, 65, 52, 1, 0, 0, 0, 65, 63, 1, 0, 0, 0, 66, 11, 1, 0, 0, 0, 67, + 68, 5, 10, 0, 0, 68, 69, 5, 14, 0, 0, 69, 13, 1, 0, 0, 0, 70, 78, + 5, 17, 0, 0, 71, 78, 5, 18, 0, 0, 72, 74, 5, 11, 0, 0, 73, 72, 1, + 0, 0, 0, 73, 74, 1, 0, 0, 0, 74, 75, 1, 0, 0, 0, 75, 78, 5, 12, 0, + 0, 76, 78, 5, 13, 0, 0, 77, 70, 1, 0, 0, 0, 77, 71, 1, 0, 0, 0, 77, + 73, 1, 0, 0, 0, 77, 76, 1, 0, 0, 0, 78, 15, 1, 0, 0, 0, 8, 21, 31, + 39, 46, 58, 65, 73, 77]; + protected static $atn; + protected static $decisionToDFA; + protected static $sharedContextCache; + + public function __construct(TokenStream $input) + { + parent::__construct($input); + + self::initialize(); + + $this->interp = new ParserATNSimulator($this, self::$atn, self::$decisionToDFA, self::$sharedContextCache); + } + + private static function initialize(): void + { + if (self::$atn !== null) { + return; + } + + RuntimeMetaData::checkVersion('4.11.1', RuntimeMetaData::VERSION); + + $atn = (new ATNDeserializer())->deserialize(self::SERIALIZED_ATN); + + $decisionToDFA = []; + for ($i = 0, $count = $atn->getNumberOfDecisions(); $i < $count; $i++) { + $decisionToDFA[] = new DFA($atn->getDecisionState($i), $i); + } + + self::$atn = $atn; + self::$decisionToDFA = $decisionToDFA; + self::$sharedContextCache = new PredictionContextCache(); + } + + public function getGrammarFileName(): string + { + return "Agtype.g4"; + } + + public function getRuleNames(): array + { + return self::RULE_NAMES; + } + + public function getSerializedATN(): array + { + return self::SERIALIZED_ATN; + } + + public function getATN(): ATN + { + return self::$atn; + } + + public function getVocabulary(): Vocabulary + { + static $vocabulary; + + return $vocabulary = $vocabulary ?? new VocabularyImpl(self::LITERAL_NAMES, self::SYMBOLIC_NAMES); + } + + /** + * @throws RecognitionException + */ + public function agType(): Context\AgTypeContext + { + $localContext = new Context\AgTypeContext($this->ctx, $this->getState()); + + $this->enterRule($localContext, 0, self::RULE_agType); + + try { + $this->enterOuterAlt($localContext, 1); + $this->setState(16); + $this->agValue(); + $this->setState(17); + $this->match(self::EOF); + } catch (RecognitionException $exception) { + $localContext->exception = $exception; + $this->errorHandler->reportError($this, $exception); + $this->errorHandler->recover($this, $exception); + } finally { + $this->exitRule(); + } + + return $localContext; + } + + /** + * @throws RecognitionException + */ + public function agValue(): Context\AgValueContext + { + $localContext = new Context\AgValueContext($this->ctx, $this->getState()); + + $this->enterRule($localContext, 2, self::RULE_agValue); + + try { + $this->enterOuterAlt($localContext, 1); + $this->setState(19); + $this->value(); + $this->setState(21); + $this->errorHandler->sync($this); + $_la = $this->input->LA(1); + + if ($_la === self::T__9) { + $this->setState(20); + $this->typeAnnotation(); + } + } catch (RecognitionException $exception) { + $localContext->exception = $exception; + $this->errorHandler->reportError($this, $exception); + $this->errorHandler->recover($this, $exception); + } finally { + $this->exitRule(); + } + + return $localContext; + } + + /** + * @throws RecognitionException + */ + public function value(): Context\ValueContext + { + $localContext = new Context\ValueContext($this->ctx, $this->getState()); + + $this->enterRule($localContext, 4, self::RULE_value); + + try { + $this->setState(31); + $this->errorHandler->sync($this); + + switch ($this->input->LA(1)) { + case self::STRING: + $localContext = new Context\StringValueContext($localContext); + $this->enterOuterAlt($localContext, 1); + $this->setState(23); + $this->match(self::STRING); + break; + + case self::INTEGER: + $localContext = new Context\IntegerValueContext($localContext); + $this->enterOuterAlt($localContext, 2); + $this->setState(24); + $this->match(self::INTEGER); + break; + + case self::T__10: + case self::T__11: + case self::T__12: + case self::RegularFloat: + case self::ExponentFloat: + $localContext = new Context\FloatValueContext($localContext); + $this->enterOuterAlt($localContext, 3); + $this->setState(25); + $this->floatLiteral(); + break; + + case self::T__0: + $localContext = new Context\TrueBooleanContext($localContext); + $this->enterOuterAlt($localContext, 4); + $this->setState(26); + $this->match(self::T__0); + break; + + case self::T__1: + $localContext = new Context\FalseBooleanContext($localContext); + $this->enterOuterAlt($localContext, 5); + $this->setState(27); + $this->match(self::T__1); + break; + + case self::T__2: + $localContext = new Context\NullValueContext($localContext); + $this->enterOuterAlt($localContext, 6); + $this->setState(28); + $this->match(self::T__2); + break; + + case self::T__3: + $localContext = new Context\ObjectValueContext($localContext); + $this->enterOuterAlt($localContext, 7); + $this->setState(29); + $this->obj(); + break; + + case self::T__7: + $localContext = new Context\ArrayValueContext($localContext); + $this->enterOuterAlt($localContext, 8); + $this->setState(30); + $this->array(); + break; + + default: + throw new NoViableAltException($this); + } + } catch (RecognitionException $exception) { + $localContext->exception = $exception; + $this->errorHandler->reportError($this, $exception); + $this->errorHandler->recover($this, $exception); + } finally { + $this->exitRule(); + } + + return $localContext; + } + + /** + * @throws RecognitionException + */ + public function obj(): Context\ObjContext + { + $localContext = new Context\ObjContext($this->ctx, $this->getState()); + + $this->enterRule($localContext, 6, self::RULE_obj); + + try { + $this->setState(46); + $this->errorHandler->sync($this); + + switch ($this->getInterpreter()->adaptivePredict($this->input, 3, $this->ctx)) { + case 1: + $this->enterOuterAlt($localContext, 1); + $this->setState(33); + $this->match(self::T__3); + $this->setState(34); + $this->pair(); + $this->setState(39); + $this->errorHandler->sync($this); + + $_la = $this->input->LA(1); + while ($_la === self::T__4) { + $this->setState(35); + $this->match(self::T__4); + $this->setState(36); + $this->pair(); + $this->setState(41); + $this->errorHandler->sync($this); + $_la = $this->input->LA(1); + } + $this->setState(42); + $this->match(self::T__5); + break; + + case 2: + $this->enterOuterAlt($localContext, 2); + $this->setState(44); + $this->match(self::T__3); + $this->setState(45); + $this->match(self::T__5); + break; + } + } catch (RecognitionException $exception) { + $localContext->exception = $exception; + $this->errorHandler->reportError($this, $exception); + $this->errorHandler->recover($this, $exception); + } finally { + $this->exitRule(); + } + + return $localContext; + } + + /** + * @throws RecognitionException + */ + public function pair(): Context\PairContext + { + $localContext = new Context\PairContext($this->ctx, $this->getState()); + + $this->enterRule($localContext, 8, self::RULE_pair); + + try { + $this->enterOuterAlt($localContext, 1); + $this->setState(48); + $this->match(self::STRING); + $this->setState(49); + $this->match(self::T__6); + $this->setState(50); + $this->agValue(); + } catch (RecognitionException $exception) { + $localContext->exception = $exception; + $this->errorHandler->reportError($this, $exception); + $this->errorHandler->recover($this, $exception); + } finally { + $this->exitRule(); + } + + return $localContext; + } + + /** + * @throws RecognitionException + */ + public function array(): Context\ArrayContext + { + $localContext = new Context\ArrayContext($this->ctx, $this->getState()); + + $this->enterRule($localContext, 10, self::RULE_array); + + try { + $this->setState(65); + $this->errorHandler->sync($this); + + switch ($this->getInterpreter()->adaptivePredict($this->input, 5, $this->ctx)) { + case 1: + $this->enterOuterAlt($localContext, 1); + $this->setState(52); + $this->match(self::T__7); + $this->setState(53); + $this->agValue(); + $this->setState(58); + $this->errorHandler->sync($this); + + $_la = $this->input->LA(1); + while ($_la === self::T__4) { + $this->setState(54); + $this->match(self::T__4); + $this->setState(55); + $this->agValue(); + $this->setState(60); + $this->errorHandler->sync($this); + $_la = $this->input->LA(1); + } + $this->setState(61); + $this->match(self::T__8); + break; + + case 2: + $this->enterOuterAlt($localContext, 2); + $this->setState(63); + $this->match(self::T__7); + $this->setState(64); + $this->match(self::T__8); + break; + } + } catch (RecognitionException $exception) { + $localContext->exception = $exception; + $this->errorHandler->reportError($this, $exception); + $this->errorHandler->recover($this, $exception); + } finally { + $this->exitRule(); + } + + return $localContext; + } + + /** + * @throws RecognitionException + */ + public function typeAnnotation(): Context\TypeAnnotationContext + { + $localContext = new Context\TypeAnnotationContext($this->ctx, $this->getState()); + + $this->enterRule($localContext, 12, self::RULE_typeAnnotation); + + try { + $this->enterOuterAlt($localContext, 1); + $this->setState(67); + $this->match(self::T__9); + $this->setState(68); + $this->match(self::IDENT); + } catch (RecognitionException $exception) { + $localContext->exception = $exception; + $this->errorHandler->reportError($this, $exception); + $this->errorHandler->recover($this, $exception); + } finally { + $this->exitRule(); + } + + return $localContext; + } + + /** + * @throws RecognitionException + */ + public function floatLiteral(): Context\FloatLiteralContext + { + $localContext = new Context\FloatLiteralContext($this->ctx, $this->getState()); + + $this->enterRule($localContext, 14, self::RULE_floatLiteral); + + try { + $this->setState(77); + $this->errorHandler->sync($this); + + switch ($this->input->LA(1)) { + case self::RegularFloat: + $this->enterOuterAlt($localContext, 1); + $this->setState(70); + $this->match(self::RegularFloat); + break; + + case self::ExponentFloat: + $this->enterOuterAlt($localContext, 2); + $this->setState(71); + $this->match(self::ExponentFloat); + break; + + case self::T__10: + case self::T__11: + $this->enterOuterAlt($localContext, 3); + $this->setState(73); + $this->errorHandler->sync($this); + $_la = $this->input->LA(1); + + if ($_la === self::T__10) { + $this->setState(72); + $this->match(self::T__10); + } + $this->setState(75); + $this->match(self::T__11); + break; + + case self::T__12: + $this->enterOuterAlt($localContext, 4); + $this->setState(76); + $this->match(self::T__12); + break; + + default: + throw new NoViableAltException($this); + } + } catch (RecognitionException $exception) { + $localContext->exception = $exception; + $this->errorHandler->reportError($this, $exception); + $this->errorHandler->recover($this, $exception); + } finally { + $this->exitRule(); + } + + return $localContext; + } + } +} + +namespace Apache\AgePhp\Parser\Context { + use Antlr\Antlr4\Runtime\ParserRuleContext; + use Antlr\Antlr4\Runtime\Token; + use Antlr\Antlr4\Runtime\Tree\ParseTreeVisitor; + use Antlr\Antlr4\Runtime\Tree\TerminalNode; + use Antlr\Antlr4\Runtime\Tree\ParseTreeListener; + use Apache\AgePhp\Parser\AgtypeParser; + use Apache\AgePhp\Parser\AgtypeVisitor; + use Apache\AgePhp\Parser\AgtypeListener; + + class AgTypeContext extends ParserRuleContext + { + public function __construct(?ParserRuleContext $parent, ?int $invokingState = null) + { + parent::__construct($parent, $invokingState); + } + + public function getRuleIndex(): int + { + return AgtypeParser::RULE_agType; + } + + public function agValue(): ?AgValueContext + { + return $this->getTypedRuleContext(AgValueContext::class, 0); + } + + public function EOF(): ?TerminalNode + { + return $this->getToken(AgtypeParser::EOF, 0); + } + + public function enterRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->enterAgType($this); + } + } + + public function exitRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->exitAgType($this); + } + } + + public function accept(ParseTreeVisitor $visitor): mixed + { + if ($visitor instanceof AgtypeVisitor) { + return $visitor->visitAgType($this); + } + + return $visitor->visitChildren($this); + } + } + + class AgValueContext extends ParserRuleContext + { + public function __construct(?ParserRuleContext $parent, ?int $invokingState = null) + { + parent::__construct($parent, $invokingState); + } + + public function getRuleIndex(): int + { + return AgtypeParser::RULE_agValue; + } + + public function value(): ?ValueContext + { + return $this->getTypedRuleContext(ValueContext::class, 0); + } + + public function typeAnnotation(): ?TypeAnnotationContext + { + return $this->getTypedRuleContext(TypeAnnotationContext::class, 0); + } + + public function enterRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->enterAgValue($this); + } + } + + public function exitRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->exitAgValue($this); + } + } + + public function accept(ParseTreeVisitor $visitor): mixed + { + if ($visitor instanceof AgtypeVisitor) { + return $visitor->visitAgValue($this); + } + + return $visitor->visitChildren($this); + } + } + + class ValueContext extends ParserRuleContext + { + public function __construct(?ParserRuleContext $parent, ?int $invokingState = null) + { + parent::__construct($parent, $invokingState); + } + + public function getRuleIndex(): int + { + return AgtypeParser::RULE_value; + } + + public function copyFrom(ParserRuleContext $context): void + { + parent::copyFrom($context); + + } + } + + class NullValueContext extends ValueContext + { + public function __construct(ValueContext $context) + { + parent::__construct($context); + + $this->copyFrom($context); + } + + public function enterRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->enterNullValue($this); + } + } + + public function exitRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->exitNullValue($this); + } + } + + public function accept(ParseTreeVisitor $visitor): mixed + { + if ($visitor instanceof AgtypeVisitor) { + return $visitor->visitNullValue($this); + } + + return $visitor->visitChildren($this); + } + } + + class ObjectValueContext extends ValueContext + { + public function __construct(ValueContext $context) + { + parent::__construct($context); + + $this->copyFrom($context); + } + + public function obj(): ?ObjContext + { + return $this->getTypedRuleContext(ObjContext::class, 0); + } + + public function enterRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->enterObjectValue($this); + } + } + + public function exitRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->exitObjectValue($this); + } + } + + public function accept(ParseTreeVisitor $visitor): mixed + { + if ($visitor instanceof AgtypeVisitor) { + return $visitor->visitObjectValue($this); + } + + return $visitor->visitChildren($this); + } + } + + class IntegerValueContext extends ValueContext + { + public function __construct(ValueContext $context) + { + parent::__construct($context); + + $this->copyFrom($context); + } + + public function INTEGER(): ?TerminalNode + { + return $this->getToken(AgtypeParser::INTEGER, 0); + } + + public function enterRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->enterIntegerValue($this); + } + } + + public function exitRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->exitIntegerValue($this); + } + } + + public function accept(ParseTreeVisitor $visitor): mixed + { + if ($visitor instanceof AgtypeVisitor) { + return $visitor->visitIntegerValue($this); + } + + return $visitor->visitChildren($this); + } + } + + class TrueBooleanContext extends ValueContext + { + public function __construct(ValueContext $context) + { + parent::__construct($context); + + $this->copyFrom($context); + } + + public function enterRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->enterTrueBoolean($this); + } + } + + public function exitRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->exitTrueBoolean($this); + } + } + + public function accept(ParseTreeVisitor $visitor): mixed + { + if ($visitor instanceof AgtypeVisitor) { + return $visitor->visitTrueBoolean($this); + } + + return $visitor->visitChildren($this); + } + } + + class FalseBooleanContext extends ValueContext + { + public function __construct(ValueContext $context) + { + parent::__construct($context); + + $this->copyFrom($context); + } + + public function enterRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->enterFalseBoolean($this); + } + } + + public function exitRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->exitFalseBoolean($this); + } + } + + public function accept(ParseTreeVisitor $visitor): mixed + { + if ($visitor instanceof AgtypeVisitor) { + return $visitor->visitFalseBoolean($this); + } + + return $visitor->visitChildren($this); + } + } + + class FloatValueContext extends ValueContext + { + public function __construct(ValueContext $context) + { + parent::__construct($context); + + $this->copyFrom($context); + } + + public function floatLiteral(): ?FloatLiteralContext + { + return $this->getTypedRuleContext(FloatLiteralContext::class, 0); + } + + public function enterRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->enterFloatValue($this); + } + } + + public function exitRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->exitFloatValue($this); + } + } + + public function accept(ParseTreeVisitor $visitor): mixed + { + if ($visitor instanceof AgtypeVisitor) { + return $visitor->visitFloatValue($this); + } + + return $visitor->visitChildren($this); + } + } + + class StringValueContext extends ValueContext + { + public function __construct(ValueContext $context) + { + parent::__construct($context); + + $this->copyFrom($context); + } + + public function STRING(): ?TerminalNode + { + return $this->getToken(AgtypeParser::STRING, 0); + } + + public function enterRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->enterStringValue($this); + } + } + + public function exitRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->exitStringValue($this); + } + } + + public function accept(ParseTreeVisitor $visitor): mixed + { + if ($visitor instanceof AgtypeVisitor) { + return $visitor->visitStringValue($this); + } + + return $visitor->visitChildren($this); + } + } + + class ArrayValueContext extends ValueContext + { + public function __construct(ValueContext $context) + { + parent::__construct($context); + + $this->copyFrom($context); + } + + public function array(): ?ArrayContext + { + return $this->getTypedRuleContext(ArrayContext::class, 0); + } + + public function enterRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->enterArrayValue($this); + } + } + + public function exitRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->exitArrayValue($this); + } + } + + public function accept(ParseTreeVisitor $visitor): mixed + { + if ($visitor instanceof AgtypeVisitor) { + return $visitor->visitArrayValue($this); + } + + return $visitor->visitChildren($this); + } + } + + class ObjContext extends ParserRuleContext + { + public function __construct(?ParserRuleContext $parent, ?int $invokingState = null) + { + parent::__construct($parent, $invokingState); + } + + public function getRuleIndex(): int + { + return AgtypeParser::RULE_obj; + } + + /** + * @return array|PairContext|null + */ + public function pair(?int $index = null) + { + if ($index === null) { + return $this->getTypedRuleContexts(PairContext::class); + } + + return $this->getTypedRuleContext(PairContext::class, $index); + } + + public function enterRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->enterObj($this); + } + } + + public function exitRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->exitObj($this); + } + } + + public function accept(ParseTreeVisitor $visitor): mixed + { + if ($visitor instanceof AgtypeVisitor) { + return $visitor->visitObj($this); + } + + return $visitor->visitChildren($this); + } + } + + class PairContext extends ParserRuleContext + { + public function __construct(?ParserRuleContext $parent, ?int $invokingState = null) + { + parent::__construct($parent, $invokingState); + } + + public function getRuleIndex(): int + { + return AgtypeParser::RULE_pair; + } + + public function STRING(): ?TerminalNode + { + return $this->getToken(AgtypeParser::STRING, 0); + } + + public function agValue(): ?AgValueContext + { + return $this->getTypedRuleContext(AgValueContext::class, 0); + } + + public function enterRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->enterPair($this); + } + } + + public function exitRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->exitPair($this); + } + } + + public function accept(ParseTreeVisitor $visitor): mixed + { + if ($visitor instanceof AgtypeVisitor) { + return $visitor->visitPair($this); + } + + return $visitor->visitChildren($this); + } + } + + class ArrayContext extends ParserRuleContext + { + public function __construct(?ParserRuleContext $parent, ?int $invokingState = null) + { + parent::__construct($parent, $invokingState); + } + + public function getRuleIndex(): int + { + return AgtypeParser::RULE_array; + } + + /** + * @return array|AgValueContext|null + */ + public function agValue(?int $index = null) + { + if ($index === null) { + return $this->getTypedRuleContexts(AgValueContext::class); + } + + return $this->getTypedRuleContext(AgValueContext::class, $index); + } + + public function enterRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->enterArray($this); + } + } + + public function exitRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->exitArray($this); + } + } + + public function accept(ParseTreeVisitor $visitor): mixed + { + if ($visitor instanceof AgtypeVisitor) { + return $visitor->visitArray($this); + } + + return $visitor->visitChildren($this); + } + } + + class TypeAnnotationContext extends ParserRuleContext + { + public function __construct(?ParserRuleContext $parent, ?int $invokingState = null) + { + parent::__construct($parent, $invokingState); + } + + public function getRuleIndex(): int + { + return AgtypeParser::RULE_typeAnnotation; + } + + public function IDENT(): ?TerminalNode + { + return $this->getToken(AgtypeParser::IDENT, 0); + } + + public function enterRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->enterTypeAnnotation($this); + } + } + + public function exitRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->exitTypeAnnotation($this); + } + } + + public function accept(ParseTreeVisitor $visitor): mixed + { + if ($visitor instanceof AgtypeVisitor) { + return $visitor->visitTypeAnnotation($this); + } + + return $visitor->visitChildren($this); + } + } + + class FloatLiteralContext extends ParserRuleContext + { + public function __construct(?ParserRuleContext $parent, ?int $invokingState = null) + { + parent::__construct($parent, $invokingState); + } + + public function getRuleIndex(): int + { + return AgtypeParser::RULE_floatLiteral; + } + + public function RegularFloat(): ?TerminalNode + { + return $this->getToken(AgtypeParser::RegularFloat, 0); + } + + public function ExponentFloat(): ?TerminalNode + { + return $this->getToken(AgtypeParser::ExponentFloat, 0); + } + + public function enterRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->enterFloatLiteral($this); + } + } + + public function exitRule(ParseTreeListener $listener): void + { + if ($listener instanceof AgtypeListener) { + $listener->exitFloatLiteral($this); + } + } + + public function accept(ParseTreeVisitor $visitor): mixed + { + if ($visitor instanceof AgtypeVisitor) { + return $visitor->visitFloatLiteral($this); + } + + return $visitor->visitChildren($this); + } + } +} \ No newline at end of file diff --git a/drivers/php/src/Parser/AgtypeVisitor.php b/drivers/php/src/Parser/AgtypeVisitor.php new file mode 100644 index 000000000..1695fd0ef --- /dev/null +++ b/drivers/php/src/Parser/AgtypeVisitor.php @@ -0,0 +1,157 @@ +prevObject)) { + $this->mergeArray(); + } else { + $this->mergeObject($key); + } + } + + public function mergeArray(): void + { + if (isset($this->prevObject) && isset($this->lastObject) && is_array($this->prevObject)) { + $this->prevObject[] = $this->lastObject; + $this->lastObject = &$this->prevObject; + array_shift($this->objectInsider); + + if (isset($this->objectInsider[1])) { + $this->prevObject = &$this->objectInsider[1]; + } else { + unset($this->prevObject); + } + } + } + + public function mergeObject(string $key): void + { + if (isset($this->prevObject) && isset($this->lastObject) && is_object($this->prevObject)) { + $this->prevObject->{$key} = $this->lastObject; + $this->lastObject = &$this->prevObject; + array_shift($this->objectInsider); + + if (isset($this->objectInsider[1])) { + $this->prevObject = &$this->objectInsider[1]; + } else { + unset($this->prevObject); + } + } + } + + public function createNewObject(): void + { + $newObject = new stdClass(); + array_unshift($this->objectInsider, $newObject); + $this->prevObject = &$this->lastObject; + $this->lastObject = &$newObject; + } + + public function createNewArray(): void + { + $newObject = []; + array_unshift($this->objectInsider, $newObject); + $this->prevObject = &$this->lastObject; + $this->lastObject = &$newObject; + } + + public function pushIfArray($value): bool + { + if (is_array($this->lastObject)) { + $this->lastObject[] = $value; + return true; + } + + return false; + } + + public function exitStringValue(StringValueContext $context): void + { + $value = $this->stripQuotes($context->getText()); + if (!$this->pushIfArray($value)) { + $this->lastValue = $value; + } + } + + public function exitIntegerValue(IntegerValueContext $context): void + { + $value = intval($context->getText()); + if (!$this->pushIfArray($value)) { + $this->lastValue = $value; + } + } + + public function exitFloatValue(FloatValueContext $context): void + { + $value = floatval($context->getText()); + if (!$this->pushIfArray($value)) { + $this->lastValue = $value; + } + } + + public function exitTrueBoolean(TrueBooleanContext $context): void + { + $value = true; + if (!$this->pushIfArray($value)) { + $this->lastValue = $value; + } + } + + public function exitFalseBoolean(FalseBooleanContext $context): void + { + $value = false; + if (!$this->pushIfArray($value)) { + $this->lastValue = $value; + } + } + + public function exitNullValue(NullValueContext $context): void + { + $value = null; + if (!$this->pushIfArray($value)) { + $this->lastValue = $value; + } + } + + public function exitFloatLiteral(FloatLiteralContext $context): void + { + $value = $context->getText(); + if (!$this->pushIfArray($value)) { + $this->lastValue = $value; + } + } + + public function enterObjectValue(ObjectValueContext $context): void + { + $this->createNewObject(); + } + + public function enterArrayValue(ArrayValueContext $context): void + { + $this->createNewArray(); + } + + public function exitObjectValue(ObjectValueContext $context): void + { + $this->mergeArray(); + } + + public function exitPair(PairContext $context): void + { + $name = $this->stripQuotes($context->STRING()->getText()); + + if (isset($this->lastValue)) { + $this->lastObject->{$name} = $this->lastValue; + unset($this->lastValue); + } else { + $this->mergeArrayOrObject($name); + } + } + + public function exitAgType(AgTypeContext $context): void + { + $this->rootObject = array_shift($this->objectInsider); + } + + public function stripQuotes(string $quotesString): mixed + { + return json_decode($quotesString); + } + + public function getResult(): mixed + { + $this->objectInsider = []; + unset($this->prevObject); + unset($this->lastObject); + + if (!$this->rootObject) { + if (isset($this->lastValue)) { + $this->rootObject = $this->lastValue; + } + } + unset($this->lastValue); + + return $this->rootObject; + } + + public function enterEveryRule(ParserRuleContext $context): void + { + + } + + public function exitEveryRule(ParserRuleContext $context): void + { + + } + + public function visitErrorNode(ErrorNode $node): void + { + + } + + public function visitTerminal(TerminalNode $node): void + { + + } +} \ No newline at end of file diff --git a/drivers/php/src/index.php b/drivers/php/src/index.php new file mode 100644 index 000000000..7807d6778 --- /dev/null +++ b/drivers/php/src/index.php @@ -0,0 +1,3 @@ + '127.0.0.1', + 'port' => 5455, + 'database' => 'pg_test', + 'user' => 'db_user', + 'password' => 'db_password', + ]; + private const TEST_GRAPH_NAME = 'age-test'; + + private static function connect(): AgeClient + { + return new AgeClient( + self::CONNECTION_DETAILS['host'], + self::CONNECTION_DETAILS['port'], + self::CONNECTION_DETAILS['database'], + self::CONNECTION_DETAILS['user'], + self::CONNECTION_DETAILS['password'], + ); + } + + public function setUp(): void + { + $this->ageClient = self::connect(); + $this->ageClient->createGraph(self::TEST_GRAPH_NAME); + } + + public function tearDown(): void + { + $this->ageClient->dropGraph(self::TEST_GRAPH_NAME); + $this->ageClient->close(); + } + + public function testCreateAndMatchFetchAll() + { + $graphName = self::TEST_GRAPH_NAME; + + $this->ageClient->query(" + SELECT * FROM cypher('$graphName', $$ + CREATE + (a:Part {part_num: '123'}), + (b:Part {part_num: '345'}), + (c:Part {part_num: '456'}), + (d:Part {part_num: '789'}) + $$) as (a agtype); + "); + + $results = $this->ageClient->query(" + SELECT * FROM cypher('$graphName', $$ + MATCH + (a:Part) + RETURN a + $$) as (a agtype); + ")->fetchAll(); + + $this->assertEquals( + [ + [ + 'a' => (object) [ + 'id' => 844424930131969, + 'label' => 'Part', + 'properties' => (object) [ + 'part_num' => '123' + ] + ] + ], + [ + 'a' => (object) [ + 'id' => 844424930131970, + 'label' => 'Part', + 'properties' => (object) [ + 'part_num' => '345' + ] + ] + ],[ + 'a' => (object) [ + 'id' => 844424930131971, + 'label' => 'Part', + 'properties' => (object) [ + 'part_num' => '456' + ] + ] + ],[ + 'a' => (object) [ + 'id' => 844424930131972, + 'label' => 'Part', + 'properties' => (object) [ + 'part_num' => '789' + ] + ] + ], + ], + $results + ); + } + + public function testCreateAndMatchFetchRow() + { + $graphName = self::TEST_GRAPH_NAME; + + $this->ageClient->query(" + SELECT * FROM cypher('$graphName', $$ + CREATE + (a:Part {part_num: '123'}), + (b:Part {part_num: '345'}), + (c:Part {part_num: '456'}), + (d:Part {part_num: '789'}) + $$) as (a agtype); + "); + + $results = $this->ageClient->query(" + SELECT * FROM cypher('$graphName', $$ + MATCH + (a:Part) + RETURN a + $$) as (a agtype); + ")->fetchRow(); + + $this->assertEquals( + [ + (object) [ + 'id' => 844424930131969, + 'label' => 'Part', + 'properties' => (object) [ + 'part_num' => '123' + ] + ] + ], + $results + ); + } + + public function testCreateAndMatchFetchNextRow() + { + $graphName = self::TEST_GRAPH_NAME; + + $this->ageClient->query(" + SELECT * FROM cypher('$graphName', $$ + CREATE + (a:Part {part_num: '123'}), + (b:Part {part_num: '345'}), + (c:Part {part_num: '456'}), + (d:Part {part_num: '789'}) + $$) as (a agtype); + "); + + $results = $this->ageClient->query(" + SELECT * FROM cypher('$graphName', $$ + MATCH + (a:Part) + RETURN a + $$) as (a agtype); + ")->fetchRow(1); + + $this->assertEquals( + [ + (object) [ + 'id' => 844424930131970, + 'label' => 'Part', + 'properties' => (object) [ + 'part_num' => '345' + ] + ] + ], + $results + ); + } + + public function testCreateAndMatchFetchInvalidRow() + { + $graphName = self::TEST_GRAPH_NAME; + + $this->ageClient->query(" + SELECT * FROM cypher('$graphName', $$ + CREATE + (a:Part {part_num: '123'}), + (b:Part {part_num: '345'}), + (c:Part {part_num: '456'}), + (d:Part {part_num: '789'}) + $$) as (a agtype); + "); + + $this->expectWarning('PHPUnit\Framework\Error\Warning'); + + $this->ageClient->query(" + SELECT * FROM cypher('$graphName', $$ + MATCH + (a:Part) + RETURN a + $$) as (a agtype); + ")->fetchRow(4); + } + + public function testReturnValue() + { + $graphName = self::TEST_GRAPH_NAME; + + $this->ageClient->query(" + SELECT * FROM cypher('$graphName', $$ + CREATE + (a:Part {part_num: '123'}), + (b:Part {part_num: '345'}), + (c:Part {part_num: '456'}), + (d:Part {part_num: '789'}) + $$) as (a agtype); + "); + + $results = $this->ageClient->query(" + SELECT * FROM cypher('$graphName', $$ + MATCH + (a:Part) + RETURN a.part_num + $$) as (a agtype); + ")->fetchAll(); + + $this->assertEquals( + [ + [ + 'a' => 123 + ], + [ + 'a' => 345 + ], + [ + 'a' => 456 + ], + [ + 'a' => 789 + ], + ], + $results + ); + } + + public function testReturnProperties() + { + $graphName = self::TEST_GRAPH_NAME; + + $this->ageClient->query(" + SELECT * FROM cypher('$graphName', $$ + CREATE + (a:Part {part_num: '123'}), + (b:Part {part_num: '345'}), + (c:Part {part_num: '456'}), + (d:Part {part_num: '789'}) + $$) as (a agtype); + "); + + $results = $this->ageClient->query(" + SELECT * FROM cypher('$graphName', $$ + MATCH + (a:Part) + RETURN properties(a) + $$) as (a agtype); + ")->fetchAll(); + + $this->assertEquals( + [ + [ + 'a' => (object) [ + 'part_num' => '123' + ] + ], + [ + 'a' => (object) [ + 'part_num' => '345' + ] + ], + [ + 'a' => (object) [ + 'part_num' => '456' + ] + ], + [ + 'a' => (object) [ + 'part_num' => '789' + ] + ] + ], + $results + ); + } + + public function testCypherQuery() + { + $graphName = self::TEST_GRAPH_NAME; + + $this->ageClient->cypherQuery($graphName, 0, " + CREATE + (a:Part {part_num: \$p1}), + (b:Part {part_num: \$p2}), + (c:Part {part_num: \$p3}), + (d:Part {part_num: \$p4}) + ",[ + 'p1' => '123', + 'p2' => '345', + 'p3' => '456', + 'p4' => '789' + ]); + + $results = $this->ageClient->cypherQuery($graphName, 0, " + MATCH + (a:Part) + RETURN a + ")->fetchRow(); + + $this->assertEquals( + [ + (object) [ + 'id' => 844424930131969, + 'label' => 'Part', + 'properties' => (object) [ + 'part_num' => '123' + ] + ] + ], + $results + ); + } + + public function testCypherQueryMultipleAgtypes() + { + $graphName = self::TEST_GRAPH_NAME; + + $this->ageClient->cypherQuery($graphName, 0, " + CREATE + (a:Person {name: \$p1}), + (b:Person {name: \$p2}), + (a)-[:KNOWS]->(b) + ",[ + 'p1' => 'Steven', + 'p2' => 'Mary' + ]); + + $results = $this->ageClient->cypherQuery($graphName, 3, " + MATCH + (a:Person {name: \$p1})-[r]-(b) + RETURN * + ",[ + 'p1' => 'Steven' + ])->fetchRow(); + + $this->assertEquals( + [ + (object) [ + 'id' => 844424930131969, + 'label' => 'Person', + 'properties' => (object) [ + 'name' => 'Steven' + ] + ], + (object) [ + 'id' => 1125899906842625, + 'label' => 'KNOWS', + 'properties' => (object) [ + ], + 'end_id' => 844424930131970, + 'start_id' => 844424930131969 + ], + (object) [ + 'id' => 844424930131970, + 'label' => 'Person', + 'properties' => (object) [ + 'name' => 'Mary' + ] + ], + ], + $results + ); + } + + public function testCypherQueryMultipleAgtypesInvalidColumnCount() + { + $graphName = self::TEST_GRAPH_NAME; + + $this->ageClient->cypherQuery($graphName, 0, " + CREATE + (a:Person {name: \$p1}), + (b:Person {name: \$p2}), + (a)-[:KNOWS]->(b) + ",[ + 'p1' => 'Steven', + 'p2' => 'Mary' + ]); + + $this->expectWarning('PHPUnit\Framework\Error\Warning'); + $this->expectWarningMessage('Query failed: ERROR: return row and column definition list do not match'); + + $results = $this->ageClient->cypherQuery($graphName, 1, " + MATCH + (a:Person {name: \$p1})-[r]-(b) + RETURN * + ",[ + 'p1' => 'Steven' + ])->fetchRow(); + + $this->assertEquals( + [ + (object) [ + 'id' => 844424930131969, + 'label' => 'Person', + 'properties' => (object) [ + 'name' => 'Steven' + ] + ] + ], + $results + ); + } + + public function testCreateDuplicateGraph() + { + $this->ageClient->dropGraph(self::TEST_GRAPH_NAME); + $this->ageClient->createGraph(self::TEST_GRAPH_NAME); + + $this->expectWarning('PHPUnit\Framework\Error\Warning'); + $this->ageClient->createGraph(self::TEST_GRAPH_NAME); + } + + public function testFetchWithoutQuery() + { + $this->expectException(AgeClientQueryException::class); + $this->expectExceptionMessage('No result from prior query to fetch from'); + $this->ageClient->fetchRow(); + } +} \ No newline at end of file diff --git a/drivers/php/test/AgtypeTest.php b/drivers/php/test/AgtypeTest.php new file mode 100644 index 000000000..d76a9db79 --- /dev/null +++ b/drivers/php/test/AgtypeTest.php @@ -0,0 +1,128 @@ +assertEquals( + (object) [ + 'id' => 844424930131969, + 'label' => "Part", + 'properties' => (object) [ + "part_num" => "123", + "number" => 3141592653589793, + "float" => 3.141592653589793 + ] + ], + AGTypeParse::parse('{"id": 844424930131969, "label": "Part", "properties": {"part_num": "123", "number": 3141592653589793, "float": 3.141592653589793}}::vertex') + ); + } + + public function testParseEdge() + { + $this->assertEquals( + (object) [ + 'id' => 1125899906842625, + 'label' => "used_by", + 'end_id' => 844424930131970, + 'start_id' => 844424930131969, + 'properties' => (object) [ + 'quantity' => 1 + ] + ], + AGTypeParse::parse('{"id": 1125899906842625, "label": "used_by", "end_id": 844424930131970, "start_id": 844424930131969, "properties": {"quantity": 1}}::edge') + ); + } + + public function testPath() + { + $this->assertEquals( + [ + (object) [ + 'id' => 844424930131969, + 'label' => "Part", + 'properties' => (object) [ + "part_num" => "123", + ] + ], + (object) [ + 'id' => 1125899906842625, + 'label' => "used_by", + 'end_id' => 844424930131970, + 'start_id' => 844424930131969, + 'properties' => (object) [ + 'quantity' => 1 + ] + ], + (object) [ + 'id' => 844424930131970, + 'label' => "Part", + 'properties' => (object) [ + "part_num" => "345", + ] + ], + ], + AGTypeParse::parse('[{"id": 844424930131969, "label": "Part", "properties": {"part_num": "123"}}::vertex, {"id": 1125899906842625, "label": "used_by", "end_id": 844424930131970, "start_id": 844424930131969, "properties": {"quantity": 1}}::edge, {"id": 844424930131970, "label": "Part", "properties": {"part_num": "345"}}::vertex]::path') + ); + } + + public function testNullProperties() + { + $this->assertEquals( + (object) [ + 'id' => 1688849860263937, + 'label' => "car", + 'properties' => (object) [ + ] + ], + AGTypeParse::parse('{"id": 1688849860263937, "label": "car", "properties": {}}::vertex') + ); + } + + public function testNestedAgtype() + { + $this->assertEquals( + (object) [ + 'id' => 1688849860263937, + 'label' => "car", + 'properties' => (object) [ + 'a' => (object) [ + 'b' => (object) [ + 'c' => (object) [ + 'd' => [ + 1, + 2, + 'A' + ] + ] + ] + ] + ] + ], + AGTypeParse::parse('{"id": 1688849860263937, "label": "car", "properties": {"a": {"b":{"c":{"d":[1, 2, "A"]}}}}}::vertex') + ); + } +} \ No newline at end of file diff --git a/drivers/php/test/README.md b/drivers/php/test/README.md new file mode 100644 index 000000000..529227ed9 --- /dev/null +++ b/drivers/php/test/README.md @@ -0,0 +1,6 @@ +Setup using docker image https://age.apache.org/age-manual/master/intro/setup.html#installing-via-docker-image + +Using command: +``` + docker run --name myPostgresDb -p 5455:5432 -e POSTGRES_USER=db_user -e POSTGRES_PASSWORD=db_password -e POSTGRES_DB=pg_test -d apache/age +``` \ No newline at end of file