Skip to content

Commit 8e84466

Browse files
committed
Implemented placeholder parameter #129
1 parent bea4bcd commit 8e84466

File tree

6 files changed

+64
-1
lines changed

6 files changed

+64
-1
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- Improved GC allocations (#81)
66
- Added wrapping of `Task` in `Future` (#64)
77
- Added octal representation (e.g., `0o123`) for numbers
8+
- Added insertion points (`_`) to function calls (#129)
89
- Added JSX syntax (#120)
910
- Added default `jsx` and `html` function (#120)
1011
- Added events to `Engine` to handle uncaught errors (#121)

doc/language.md

+29-1
Original file line numberDiff line numberDiff line change
@@ -270,4 +270,32 @@ cos(2.5) == cos()()(2.5)
270270
271271
are therefore equal. In the previous example two calls without any arguments result in the function itself, such that the last call is operating on `cos` itself. Auto currying is applied to any standard function, custom created function (lambda expression), and wrapped .NET function.
272272
273-
Auto currying allows to use functions to create functions without much ceremony and plays great together with the pipe operator, which expects functions requiring only a single argument on the right side.
273+
Auto currying allows to use functions to create functions without much ceremony and plays great together with the pipe operator, which expects functions requiring only a single argument on the right side.
274+
275+
### Placeholders
276+
277+
Calling a function with parameters supplied as `_` will result in a new function taking the number of used placeholders as arguments.
278+
279+
Example:
280+
281+
```
282+
var f = (x, y, z) => x + 2 * y + 3 * z
283+
```
284+
285+
Classically, this could be called like `f(x, y, z)` or with auto-currying like `f(x, y)` or even `f(x)`. But what if we would like to have a function `g(y) = f(x, y, z)`? We would need to define this alias quite explicitly:
286+
287+
```
288+
var g = (y) => f(1, y, 3)
289+
```
290+
291+
With the placeholder parameter it can be written such as:
292+
293+
```
294+
var g = f(1, _, 3)
295+
```
296+
297+
The big advantage of this is that we get a simple way to pipe things:
298+
299+
```
300+
4 | f(1, _, 3)
301+
```

src/Mages.Core/Ast/Walkers/OperationTreeWalker.cs

+28
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Mages.Core.Vm.Operations;
88
using System;
99
using System.Collections.Generic;
10+
using System.Linq;
1011

1112
/// <summary>
1213
/// Represents the walker to create operations.
@@ -328,10 +329,12 @@ void ITreeWalker.Visit(ConditionalExpression expression)
328329
void ITreeWalker.Visit(CallExpression expression)
329330
{
330331
var assigning = _assigning;
332+
var start = _operations.Count;
331333
_assigning = false;
332334

333335
expression.Validate(this);
334336
expression.Arguments.Accept(this);
337+
var end = _operations.Count;
335338
expression.Function.Accept(this);
336339

337340
if (assigning)
@@ -340,7 +343,32 @@ void ITreeWalker.Visit(CallExpression expression)
340343
}
341344
else
342345
{
346+
var extract = 0;
343347
_operations.Add(new GetcOperation(expression.Arguments.Count));
348+
349+
for (var i = start; i < end; i++)
350+
{
351+
if (_operations[i] is GetsOperation g && g.Name == "_")
352+
{
353+
var c = extract++;
354+
_operations[i] = new GetsOperation($"_{c}");
355+
}
356+
}
357+
358+
if (extract > 0)
359+
{
360+
var parameters = new List<ParameterDefinition>();
361+
362+
for (var i = 0; i < extract; i++)
363+
{
364+
var name = $"_{i}";
365+
_operations.Insert(start, new ArgOperation(extract - (i + 1), name));
366+
parameters.Add(new ParameterDefinition(name, true));
367+
}
368+
369+
_operations.Insert(start + extract, ArgsOperation.Instance);
370+
_operations.Add(ExtractFunction(false, parameters.ToArray(), start));
371+
}
344372
}
345373

346374
_assigning = assigning;

src/Mages.Core/Vm/Operations/DefOperation.cs

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ sealed class DefOperation(String name) : IOperation
99
{
1010
private readonly String _name = name;
1111

12+
public String Name => _name;
13+
1214
public void Invoke(IExecutionContext context)
1315
{
1416
var value = context.Pop();

src/Mages.Core/Vm/Operations/DelVarOperation.cs

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ sealed class DelVarOperation(String name) : IOperation
1010
{
1111
private readonly String _name = name;
1212

13+
public String Name => _name;
14+
1315
public void Invoke(IExecutionContext context)
1416
{
1517
var result = context.Scope.Remove(_name);

src/Mages.Core/Vm/Operations/GetsOperation.cs

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ sealed class GetsOperation(String name) : IOperation
1010
{
1111
private readonly String _name = name;
1212

13+
public String Name => _name;
14+
1315
public void Invoke(IExecutionContext context)
1416
{
1517
var value = context.Scope.GetProperty(_name);

0 commit comments

Comments
 (0)