<p>A few languages, most notably Rust, have tuple-indexing syntax that looks like this:</p>
<pre class="lang-rust prettyprint-override"><code>tuple.0 // Access the first element of tuple
</code></pre>
<p>This syntax is quite similar to that for property access:</p>
<pre class="lang-rust prettyprint-override"><code>foo.bar()
</code></pre>
<p>Is it better to implement this as a separate parser rule, or to parse it as a property access, and add some special handling for the tuple type internally so that it returns the appropriate value?</p>

<syntax><rust><semantics><tuple>
How should a language with period-based tuple indexing be parsed?
CC BY-SA 4.0
2023-05-31T14:28:31.217Z
What if it's a tuple of functions? You could call `foo.0()` potentially
mousetail 'he-him'
CC BY-SA 4.0
2023-05-31T14:29:36.953Z
It's more similar to field accesses like `foo.bar`, no?
kaya3
CC BY-SA 4.0
2023-05-31T14:30:15.567Z
@mousetail Property accesses are generally parsed seperately from function calls, so that would be parsed as calling the result of accessing the `0` property of `foo` (if I went the property-access route)
Ginger
CC BY-SA 4.0
2023-05-31T14:30:23.877Z
@kaya3 Fixed that.
Ginger
CC BY-SA 4.0
2023-05-31T14:30:41.717Z
Field accesses and method accesses have ambiguity, but there is no such ambiguity for tuple accesses since none of the others can start with a number
mousetail 'he-him'
CC BY-SA 4.0
2023-05-31T14:36:14.127Z
There are languages like Java where arbitrary expressions like `foo.bar` can't be called with `()`, so a method call `foo.bar()` is an irreducible expression like `MethodCall(Ident("foo"), "bar", [])`; and there are languages like Python where `foo.bar()` is `Call(Attr(Ident("foo"), "bar"), [])`, i.e. calling the result of the property access `foo.bar`. Then there are languages like Javascript where `foo.bar()` *could* be parsed like the latter but isn't because it's semantically different from `(foo.bar)()`. I think the ambiguity only occurs in syntaxes like Javascript's.
kaya3
CC BY-SA 4.0
2023-05-31T17:02:37.280Z
Please correct me if I'm wrong, but from my understanding this question is less of a parsing question and more of an implementation/semantics question.
FireTheLost
CC BY-SA 4.0
2023-06-02T02:38:39.960Z
@kaya3 Where does ECMAScript make that distinction? §13.3.6.1 says a call is a MemberExpression followed by arguments, and a MemberExpression can be a member access (`x.f`) or a PrimaryExpression, which includes identifiers and parenthesised expressions. It also says the MemberExpression is evaluated first.
Longinus
CC BY-SA 4.0
2023-06-02T12:09:01.283Z
@Longinus I was mistaken, the form that's semantically different in Javascript is `let m = foo.bar; m();` or as an expression using the comma operator, `(0, foo.bar)()`. The difference is between a `CallMemberExpression` and a `CallExpression`, which are two different parse rules even though a `CallMemberExpression` could be represented instead as a `CallExpression` with a `MemberExpression` as its first child. The semantic difference is in the binding of `this` when the function body executes.
kaya3
<p>One thing to note about this syntax for tuple field accesses, is that it can clash with the lexical syntax for floating-point or decimal numbers. In many languages (e.g. Java, Javascript and Python), <code>.1</code> is a single token which means the number <code>0.1</code>.</p>
<p>In this case, the source <code>x.1</code> will be lexed as two tokens: an identifier <code>x</code> and a number <code>.1</code>; on the other hand, <code>x . 1</code> will be lexed as three tokens. So the parser will need to handle both cases; this is messy, and possibly even ambiguous:</p>
<ul>
<li>If your language has function calls without parentheses, then <code>f .1</code> also means calling the function <code>f</code> with the argument <code>.1</code>.</li>
<li>If your language has casts with parentheses, then <code>(T) .1</code> also means converting <code>.1</code> to type <code>T</code>.</li>
</ul>
<p>Therefore if you want this syntax for tuple field accesses, it's probably best to not allow decimal literals to begin with a decimal point. Rust, for example, gives the following syntax error if you write <code>.1</code> instead of <code>0.1</code> where a number is expected:</p>
<blockquote>
<p>error: float literals must have an integer part</p>
</blockquote>

CC BY-SA 4.0
2023-08-22T19:12:06.333Z
2023-08-22T19:12:06.333Z
kaya3
<p>You only need to parse it differently if it would be &quot;in the cracks&quot; between method accesses and field accesses. If you don't have that distinction you can parse them the same way.</p>
<p>In a language like Python where property access and method access are the same, simply allowing properties to start with a number during the parsing stage would be enough.</p>
<p>On the other hand, in a language where the difference between properties and methods needs to be known at parse time you need a more complex grammar. You would typically have a separate parser rule for all 4 cases. Something like:</p>
<pre><code>method_call := expression &quot;.&quot; identifier &quot;(&quot; argument_spec &quot;)&quot;
attribute_access := expression &quot;.&quot; identifier
tuple_attribute_access := expression &quot;.&quot; number
function_call := &quot;(&quot; expression &quot;)&quot; &quot;(&quot; argument_spec &quot;)&quot; | identifier &quot;(&quot; argument_spec &quot;)&quot;
</code></pre>
<p>There is no real possible confusion between method calls and attribute access. But the confusion between function calls combined with function calls and method calls requires breaking the syntax up in many different blocks, and thus will require special casing the tuple access.</p>
<p>This is why Rust allows <code>tuple.0()</code>  but not <code>struct.attribute()</code>.</p>
<p>If you don't have methods, disambiguate method vs property accesses later than parsing, or use a different syntax for methods than properties, you may not need to special case tuple access.</p>

CC BY-SA 4.0
2023-05-31T14:40:20.577Z
2024-10-02T09:06:40.500Z
2024-10-02T09:06:40.500Z
mousetail 'he-him'
CC BY-SA 4.0
2023-05-31T14:44:41.847Z
I don't think method calls and field-function calls must be handled separately in all languages. Not saying they mustn't at all, but I wouldn't claim that as the general case
abel1502
CC BY-SA 4.0
2023-05-31T14:45:32.467Z
@abel1502 Like I said in my last paragraph if it's not handled separately you don't need to handle tuple accesses separately either
mousetail 'he-him'
CC BY-SA 4.0
2023-05-31T14:50:16.257Z
I'm not sure Python technically fits into any of the carve-outs in the last paragraph ─ it does have methods, it doesn't disambiguate methods vs. property accesses at all (because method accesses *are* property accesses), and it doesn't use a different syntax. In Python, if `foo` is a method of `obj`'s class, then the expression `obj.foo` evaluates to a bound method on the instance. Well, CPython has special bytecode instructions `LOAD_METHOD` and `CALL_METHOD` for it for performance reasons, but that's an implementation detail; these aren't part of the language's semantics.
kaya3
CC BY-SA 4.0
2023-05-31T14:51:21.490Z
@kaya3 it falls under "disambiguate later than parsing"
mousetail 'he-him'
CC BY-SA 4.0
2023-05-31T14:52:27.527Z
In python methods and fields are parsed the exact same way but only at runtime is it decided if it's a method or not. The method could be converted to a field at runtime through various means
mousetail 'he-him'
CC BY-SA 4.0
2023-05-31T14:55:05.863Z
But it's not disambiguated at all ─ `obj.foo()` and `(obj.foo)()` are semantically equivalent in Python. There is nothing to disambiguate.
kaya3
CC BY-SA 4.0
2023-05-31T15:15:03.767Z
@kaya3 Exactly, so there is no need to parse tuple access separately either
mousetail 'he-him'
<p>Unless the language defines something completely weird and orthogonal to other forms of accessing members, I'd use a parse rule beside the regular member access and create a tuple access AST node that has a common super type with the member access AST node. In essence, it's just a record with implicit names taken from integer literals.</p>

CC BY-SA 4.0
2023-08-22T16:04:54.230Z
2023-08-22T16:04:54.230Z
feldentm
# How should a language with period-based tuple indexing be parsed?
Posted by: username_0 on 2023-05-31
A few languages, most notably Rust, have tuple-indexing syntax that looks like this:
tuple.0 // Access the first element of tuple

This syntax is quite similar to that for property access:
foo.bar()

Is it better to implement this as a separate parser rule, or to parse it as a property access, and add some special handling for the tuple type internally so that it returns the appropriate value?
**Tags:** syntax rust semantics tuple
> **Comments:**
> **username_1**: What if it's a tuple of functions? You could call `foo.0()` potentially  
> **username_2**: It's more similar to field accesses like `foo.bar`, no?  
> **username_0**: @mousetail Property accesses are generally parsed seperately from function calls, so that would be parsed as calling the result of accessing the `0` property of `foo` (if I went the property-access route)  
> **username_0**: @kaya3 Fixed that.  
> **username_1**: Field accesses and method accesses have ambiguity, but there is no such ambiguity for tuple accesses since none of the others can start with a number  
> **username_2**: There are languages like Java where arbitrary expressions like `foo.bar` can't be called with `()`, so a method call `foo.bar()` is an irreducible expression like `MethodCall(Ident("foo"), "bar", [])`; and there are languages like Python where `foo.bar()` is `Call(Attr(Ident("foo"), "bar"), [])`, i.e. calling the result of the property access `foo.bar`. Then there are languages like Javascript where `foo.bar()` *could* be parsed like the latter but isn't because it's semantically different from `(foo.bar)()`. I think the ambiguity only occurs in syntaxes like Javascript's.  
> **username_3**: Please correct me if I'm wrong, but from my understanding this question is less of a parsing question and more of an implementation/semantics question.  
> **username_4**: @kaya3 Where does ECMAScript make that distinction? §13.3.6.1 says a call is a MemberExpression followed by arguments, and a MemberExpression can be a member access (`x.f`) or a PrimaryExpression, which includes identifiers and parenthesised expressions. It also says the MemberExpression is evaluated first.  
> **username_2**: @Longinus I was mistaken, the form that's semantically different in Javascript is `let m = foo.bar; m();` or as an expression using the comma operator, `(0, foo.bar)()`. The difference is between a `CallMemberExpression` and a `CallExpression`, which are two different parse rules even though a `CallMemberExpression` could be represented instead as a `CallExpression` with a `MemberExpression` as its first child. The semantic difference is in the binding of `this` when the function body executes.  
---
## 3 answers
### Answer by username_2 on 2023-08-22. Score: 5
One thing to note about this syntax for tuple field accesses, is that it can clash with the lexical syntax for floating-point or decimal numbers. In many languages (e.g. Java, Javascript and Python), `.1` is a single token which means the number `0.1`.

In this case, the source `x.1` will be lexed as two tokens: an identifier `x` and a number `.1`; on the other hand, `x . 1` will be lexed as three tokens. So the parser will need to handle both cases; this is messy, and possibly even ambiguous:

* If your language has function calls without parentheses, then `f .1` also means calling the function `f` with the argument `.1`.
* If your language has casts with parentheses, then `(T) .1` also means converting `.1` to type `T`.

Therefore if you want this syntax for tuple field accesses, it's probably best to not allow decimal literals to begin with a decimal point. Rust, for example, gives the following syntax error if you write `.1` instead of `0.1` where a number is expected:

> error: float literals must have an integer part
---
### Answer by username_1 on 2023-05-31. Score: 2
You only need to parse it differently if it would be "in the cracks" between method accesses and field accesses. If you don't have that distinction you can parse them the same way.
In a language like Python where property access and method access are the same, simply allowing properties to start with a number during the parsing stage would be enough.
On the other hand, in a language where the difference between properties and methods needs to be known at parse time you need a more complex grammar. You would typically have a separate parser rule for all 4 cases. Something like:
method_call := expression "." identifier "(" argument_spec ")"
attribute_access := expression "." identifier
tuple_attribute_access := expression "." number
function_call := "(" expression ")" "(" argument_spec ")" | identifier "(" argument_spec ")"

There is no real possible confusion between method calls and attribute access. But the confusion between function calls combined with function calls and method calls requires breaking the syntax up in many different blocks, and thus will require special casing the tuple access.
This is why Rust allows tuple.0()  but not struct.attribute().
If you don't have methods, disambiguate method vs property accesses later than parsing, or use a different syntax for methods than properties, you may not need to special case tuple access.
> **Comments:**
> **username_5** (2023-05-31): I don't think method calls and field-function calls must be handled separately in all languages. Not saying they mustn't at all, but I wouldn't claim that as the general case  
> **username_1** (2023-05-31): @abel1502 Like I said in my last paragraph if it's not handled separately you don't need to handle tuple accesses separately either  
> **username_2** (2023-05-31): I'm not sure Python technically fits into any of the carve-outs in the last paragraph ─ it does have methods, it doesn't disambiguate methods vs. property accesses at all (because method accesses *are* property accesses), and it doesn't use a different syntax. In Python, if `foo` is a method of `obj`'s class, then the expression `obj.foo` evaluates to a bound method on the instance. Well, CPython has special bytecode instructions `LOAD_METHOD` and `CALL_METHOD` for it for performance reasons, but that's an implementation detail; these aren't part of the language's semantics.  
> **username_1** (2023-05-31): @kaya3 it falls under "disambiguate later than parsing"  
> **username_1** (2023-05-31): In python methods and fields are parsed the exact same way but only at runtime is it decided if it's a method or not. The method could be converted to a field at runtime through various means  
> **username_2** (2023-05-31): But it's not disambiguated at all ─ `obj.foo()` and `(obj.foo)()` are semantically equivalent in Python. There is nothing to disambiguate.  
> **username_1** (2023-05-31): @kaya3 Exactly, so there is no need to parse tuple access separately either  
---
### Answer by username_6 on 2023-08-22. Score: 1
Unless the language defines something completely weird and orthogonal to other forms of accessing members, I'd use a parse rule beside the regular member access and create a tuple access AST node that has a common super type with the member access AST node. In essence, it's just a record with implicit names taken from integer literals.
---
