This is an automated email from the ASF dual-hosted git repository.

Cole-Greer pushed a commit to branch 3.7-dev
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git


The following commit(s) were added to refs/heads/3.7-dev by this push:
     new 50de6da025 TINKERPOP-3151 Allow float literals without a leading digit 
(#3558)
50de6da025 is described below

commit 50de6da0258b1a47681100f099eeec91702aad6d
Author: kirill-stepanishin <[email protected]>
AuthorDate: Thu Jul 23 17:25:08 2026 -0700

    TINKERPOP-3151 Allow float literals without a leading digit (#3558)
    
    Assisted-by: Claude Code:claude-opus-4-8
---
 CHANGELOG.asciidoc                                 |  1 +
 .../language/grammar/GenericLiteralVisitor.java    |  2 +-
 .../grammar/GeneralLiteralVisitorTest.java         | 11 +++-
 .../Gherkin/GherkinTestRunner.cs                   |  3 +-
 .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs |  5 ++
 .../Gherkin/IgnoreException.cs                     |  8 ++-
 gremlin-go/driver/cucumber/gremlin.go              |  5 ++
 .../gremlin-javascript/test/cucumber/gremlin.js    |  5 ++
 gremlin-language/src/main/antlr4/Gremlin.g4        |  6 ++-
 .../src/main/python/tests/feature/gremlin.py       |  5 ++
 .../test/features/sideEffect/Inject.feature        | 60 ++++++++++++++++++++++
 11 files changed, 105 insertions(+), 6 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 8abe3b199a..37f9e7e4c5 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -33,6 +33,7 @@ 
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 * Added `WithComputer()` to `GraphTraversalSource` in `gremlin-go`, providing 
OLAP configuration parity with other language variants.
 * Added `FailResponseException` to `gremlin-driver` which is thrown `fail()` 
step is triggered on the server making it more consistent with embedded 
behavior.
 * Fixed `hasId()` to only unroll a collection when it is supplied as the 
single argument, aligning its behavior with `g.V()`/`g.E()`.
+* Allowed float literals without a leading digit (e.g. `.5`, `.5f`, `.5d`) in 
the Gremlin grammar to better match Groovy.
 * Fixed conjoin has incorrect null handling.
 * Removed the Mono dependency from the `gremlin-dotnet` build/release process, 
using `dotnet pack`/`dotnet nuget push` instead of `mono nuget.exe`.
 * Expanded `gremlin-python` CI matrix to test against Python 3.9, 3.10, 3.11, 
3.12, and 3.13.
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java
index a4d5a8b641..24f4fffb6c 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GenericLiteralVisitor.java
@@ -569,7 +569,7 @@ public class GenericLiteralVisitor extends 
DefaultGremlinBaseVisitor<Object> {
     @Override
     public Object visitGenericLiteralRange(final 
GremlinParser.GenericLiteralRangeContext ctx) {
         final int childIndexOfParameterStart = 0;
-        final int childIndexOfParameterEnd = 3;
+        final int childIndexOfParameterEnd = 2;
         final ParseTree startContext = 
ctx.getChild(childIndexOfParameterStart);
         final ParseTree endContext = ctx.getChild(childIndexOfParameterEnd);
 
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GeneralLiteralVisitorTest.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GeneralLiteralVisitorTest.java
index e39d9df55b..fe013cb3be 100644
--- 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GeneralLiteralVisitorTest.java
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/language/grammar/GeneralLiteralVisitorTest.java
@@ -424,7 +424,16 @@ public class GeneralLiteralVisitorTest {
                     {"1.0E+12d", "1.0E12", "java.lang.Double"},
                     {"-0.1E-12D", "-0.1E-12", "java.lang.Double"},
                     {"1E12d", "1E12", "java.lang.Double"},
-                    {"1D", "1", "java.lang.Double"}
+                    {"1D", "1", "java.lang.Double"},
+
+                    // float literals without a leading digit (e.g. .5)
+                    {".5", ".5", "java.math.BigDecimal"},
+                    {".5m", ".5", "java.math.BigDecimal"},
+                    {".5f", ".5", "java.lang.Float"},
+                    {".5d", ".5", "java.lang.Double"},
+                    {"-.5f", "-.5", "java.lang.Float"},
+                    {".5E2", ".5E2", "java.math.BigDecimal"},
+                    {".5E-2d", ".5E-2", "java.lang.Double"}
             });
         }
 
diff --git 
a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs
index 5462260cff..1d5199e377 100644
--- 
a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs
+++ 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs
@@ -49,7 +49,8 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
             {
                 // Add here the name of scenarios to ignore and the reason, 
e.g.:
                 {"g_withStrategiesXProductiveByStrategyX_V_group_byXageX", 
IgnoreReason.NullKeysInMapNotSupported},
-                
{"g_withStrategiesXProductiveByStrategyX_V_groupCount_byXageX", 
IgnoreReason.NullKeysInMapNotSupported}
+                
{"g_withStrategiesXProductiveByStrategyX_V_groupCount_byXageX", 
IgnoreReason.NullKeysInMapNotSupported},
+                {"g_injectXpoint5fX", 
IgnoreReason.FloatLiteralTypeNotPreserved}
             };
 
         private static class Keywords
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index ba2f9ab357..73378300f4 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -1539,6 +1539,11 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_injectXnull_1_3_nullX_asXaX_selectXaX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.Inject<object>(null,1,3,null).As("a").Select<object>("a")}}, 
                {"g_injectX1_3lX_injectX100_300X", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.Inject(1,3).Inject(100,300)}}, 
                {"g_injectXbigintBoundaryValuesX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.Inject(p["xx1"],p["xx2"],p["xx3"])}}, 
+               {"g_injectXpoint5X", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(0.5)}}, 
+               {"g_injectXpoint5fX", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(0.5)}}, 
+               {"g_injectXpoint5dX", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(0.5)}}, 
+               {"g_injectX1to5X", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(new List<object> 
{1, 2, 3, 4, 5})}}, 
+               {"g_injectXaTocX", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) =>g.Inject(new List<object> 
{"a", "b", "c"})}}, 
                {"g_io_readXkryoX", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) 
=>g.Io<object>("data/tinkerpop-modern.kryo").Read(), (g,p) =>g.V(), (g,p) 
=>g.E()}}, 
                {"g_io_read_withXreader_gryoX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) 
=>g.Io<object>("data/tinkerpop-modern.kryo").With("~tinkerpop.io.reader","gryo").Read(),
 (g,p) =>g.V(), (g,p) =>g.E()}}, 
                {"g_io_readXgraphsonX", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) 
=>g.Io<object>("data/tinkerpop-modern.json").Read(), (g,p) =>g.V(), (g,p) 
=>g.E()}}, 
diff --git 
a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/IgnoreException.cs 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/IgnoreException.cs
index 3eb59d4f57..feafc86bf3 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/IgnoreException.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/IgnoreException.cs
@@ -60,6 +60,12 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
         /// <summary>
         /// The GLV suite does not test against a graph that has null property 
values enabled.
         /// </summary>
-        NullPropertyValuesNotSupportedOnTestGraph
+        NullPropertyValuesNotSupportedOnTestGraph,
+
+        /// <summary>
+        /// The translator does not preserve the numeric type of a float 
literal, so a value such as
+        /// <c>.5f</c> is emitted as a bare <c>0.5</c> and read back as a 
<c>double</c> rather than a <c>float</c>.
+        /// </summary>
+        FloatLiteralTypeNotPreserved
     }
 }
\ No newline at end of file
diff --git a/gremlin-go/driver/cucumber/gremlin.go 
b/gremlin-go/driver/cucumber/gremlin.go
index 23cb7dfeba..d1de80cda4 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -1510,6 +1510,11 @@ var translationMap = map[string][]func(g 
*gremlingo.GraphTraversalSource, p map[
     "g_injectXnull_1_3_nullX_asXaX_selectXaX": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.Inject(nil, 1, 3, 
nil).As("a").Select("a")}}, 
     "g_injectX1_3lX_injectX100_300X": {func(g *gremlingo.GraphTraversalSource, 
p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(1, 
3).Inject(100, 300)}}, 
     "g_injectXbigintBoundaryValuesX": {func(g *gremlingo.GraphTraversalSource, 
p map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(p["xx1"], 
p["xx2"], p["xx3"])}}, 
+    "g_injectXpoint5X": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(0.5)}}, 
+    "g_injectXpoint5fX": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(0.5)}}, 
+    "g_injectXpoint5dX": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(0.5)}}, 
+    "g_injectX1to5X": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.Inject([]interface{}{1, 2, 3, 4, 5})}}, 
+    "g_injectXaTocX": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.Inject([]interface{}{"a", "b", "c"})}}, 
     "g_io_readXkryoX": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.Io("data/tinkerpop-modern.kryo").Read()}, func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.V()}, func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.E()}}, 
     "g_io_read_withXreader_gryoX": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.Io("data/tinkerpop-modern.kryo").With("~tinkerpop.io.reader", 
"gryo").Read()}, func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return g.V()}, func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.E()}}, 
     "g_io_readXgraphsonX": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.Io("data/tinkerpop-modern.json").Read()}, func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.V()}, func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.E()}}, 
diff --git 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
index 46f7b0d1a2..a83296fcd6 100644
--- 
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
+++ 
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
@@ -1530,6 +1530,11 @@ const gremlins = {
     g_injectXnull_1_3_nullX_asXaX_selectXaX: [function({g}) { return 
g.inject(null,1,3,null).as("a").select("a") }], 
     g_injectX1_3lX_injectX100_300X: [function({g}) { return 
g.inject(1,3).inject(100,300) }], 
     g_injectXbigintBoundaryValuesX: [function({g, xx1, xx3, xx2}) { return 
g.inject(xx1,xx2,xx3) }], 
+    g_injectXpoint5X: [function({g}) { return g.inject(0.5) }], 
+    g_injectXpoint5fX: [function({g}) { return g.inject(0.5) }], 
+    g_injectXpoint5dX: [function({g}) { return g.inject(0.5) }], 
+    g_injectX1to5X: [function({g}) { return g.inject([1, 2, 3, 4, 5]) }], 
+    g_injectXaTocX: [function({g}) { return g.inject(["a", "b", "c"]) }], 
     g_io_readXkryoX: [function({g}) { return 
g.io("data/tinkerpop-modern.kryo").read() }, function({g}) { return g.V() }, 
function({g}) { return g.E() }], 
     g_io_read_withXreader_gryoX: [function({g}) { return 
g.io("data/tinkerpop-modern.kryo").with_("~tinkerpop.io.reader","gryo").read() 
}, function({g}) { return g.V() }, function({g}) { return g.E() }], 
     g_io_readXgraphsonX: [function({g}) { return 
g.io("data/tinkerpop-modern.json").read() }, function({g}) { return g.V() }, 
function({g}) { return g.E() }], 
diff --git a/gremlin-language/src/main/antlr4/Gremlin.g4 
b/gremlin-language/src/main/antlr4/Gremlin.g4
index 0b7a224790..d19e1a95fc 100644
--- a/gremlin-language/src/main/antlr4/Gremlin.g4
+++ b/gremlin-language/src/main/antlr4/Gremlin.g4
@@ -1626,8 +1626,8 @@ genericLiteralExpr
     ;
 
 genericLiteralRange
-    : integerLiteral DOT DOT integerLiteral
-    | stringLiteral DOT DOT stringLiteral
+    : integerLiteral RANGE integerLiteral
+    | stringLiteral RANGE stringLiteral
     ;
 
 genericLiteralCollection
@@ -1875,6 +1875,7 @@ FloatingPointLiteral
 fragment
 DecimalFloatingPointLiteral
     :   Digits ('.' Digits ExponentPart? | ExponentPart) FloatTypeSuffix?
+    |    '.' Digits ExponentPart? FloatTypeSuffix?
     |    Digits FloatTypeSuffix
     ;
 
@@ -2013,6 +2014,7 @@ LBRACK : '[';
 RBRACK : ']';
 SEMI : ';';
 COMMA : ',';
+RANGE : '..';
 DOT : '.';
 COLON : ':';
 
diff --git a/gremlin-python/src/main/python/tests/feature/gremlin.py 
b/gremlin-python/src/main/python/tests/feature/gremlin.py
index 93907ae78e..3580de30dd 100644
--- a/gremlin-python/src/main/python/tests/feature/gremlin.py
+++ b/gremlin-python/src/main/python/tests/feature/gremlin.py
@@ -1512,6 +1512,11 @@ world.gremlins = {
     'g_injectXnull_1_3_nullX_asXaX_selectXaX': [(lambda 
g:g.inject(None,1,3,None).as_('a').select('a'))], 
     'g_injectX1_3lX_injectX100_300X': [(lambda 
g:g.inject(1,3).inject(100,300))], 
     'g_injectXbigintBoundaryValuesX': [(lambda g, 
xx1=None,xx3=None,xx2=None:g.inject(xx1,xx2,xx3))], 
+    'g_injectXpoint5X': [(lambda g:g.inject(float(0.5)))], 
+    'g_injectXpoint5fX': [(lambda g:g.inject(float(0.5)))], 
+    'g_injectXpoint5dX': [(lambda g:g.inject(float(0.5)))], 
+    'g_injectX1to5X': [(lambda g:g.inject([1,2,3,4,5]))], 
+    'g_injectXaTocX': [(lambda g:g.inject(['a','b','c']))], 
     'g_io_readXkryoX': [(lambda g:g.io('data/tinkerpop-modern.kryo').read()), 
(lambda g:g.V()), (lambda g:g.E())], 
     'g_io_read_withXreader_gryoX': [(lambda 
g:g.io('data/tinkerpop-modern.kryo').with_('~tinkerpop.io.reader','gryo').read()),
 (lambda g:g.V()), (lambda g:g.E())], 
     'g_io_readXgraphsonX': [(lambda 
g:g.io('data/tinkerpop-modern.json').read()), (lambda g:g.V()), (lambda 
g:g.E())], 
diff --git 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/Inject.feature
 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/Inject.feature
index 9acb57253a..148a7dea30 100644
--- 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/Inject.feature
+++ 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/Inject.feature
@@ -235,3 +235,63 @@ Feature: Step - inject()
       | d[0].n |
       | d[-129].n |
       | d[-32769].n |
+
+  @GraphComputerVerificationInjectionNotSupported
+  Scenario: g_injectXpoint5X
+    Given the modern graph
+    And the traversal of
+      """
+      g.inject(.5)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | d[0.5].m |
+
+  @GraphComputerVerificationInjectionNotSupported
+  Scenario: g_injectXpoint5fX
+    Given the modern graph
+    And the traversal of
+      """
+      g.inject(.5f)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | d[0.5].f |
+
+  @GraphComputerVerificationInjectionNotSupported
+  Scenario: g_injectXpoint5dX
+    Given the modern graph
+    And the traversal of
+      """
+      g.inject(.5d)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | d[0.5].d |
+
+  @GraphComputerVerificationInjectionNotSupported
+  Scenario: g_injectX1to5X
+    Given the modern graph
+    And the traversal of
+      """
+      g.inject(1..5)
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | l[d[1].i,d[2].i,d[3].i,d[4].i,d[5].i] |
+
+  @GraphComputerVerificationInjectionNotSupported
+  Scenario: g_injectXaTocX
+    Given the modern graph
+    And the traversal of
+      """
+      g.inject("a".."c")
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | l[a,b,c] |

Reply via email to