Skip to content

Commit

Permalink
Implemented placeholder parameter #129
Browse files Browse the repository at this point in the history
  • Loading branch information
FlorianRappl committed Dec 21, 2024
1 parent bea4bcd commit 8e84466
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Improved GC allocations (#81)
- Added wrapping of `Task` in `Future` (#64)
- Added octal representation (e.g., `0o123`) for numbers
- Added insertion points (`_`) to function calls (#129)
- Added JSX syntax (#120)
- Added default `jsx` and `html` function (#120)
- Added events to `Engine` to handle uncaught errors (#121)
Expand Down
30 changes: 29 additions & 1 deletion doc/language.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,4 +270,32 @@ cos(2.5) == cos()()(2.5)
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.
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.
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.
### Placeholders
Calling a function with parameters supplied as `_` will result in a new function taking the number of used placeholders as arguments.
Example:
```
var f = (x, y, z) => x + 2 * y + 3 * z
```
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:
```
var g = (y) => f(1, y, 3)
```
With the placeholder parameter it can be written such as:
```
var g = f(1, _, 3)
```
The big advantage of this is that we get a simple way to pipe things:
```
4 | f(1, _, 3)
```
28 changes: 28 additions & 0 deletions src/Mages.Core/Ast/Walkers/OperationTreeWalker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Mages.Core.Vm.Operations;
using System;
using System.Collections.Generic;
using System.Linq;

/// <summary>
/// Represents the walker to create operations.
Expand Down Expand Up @@ -328,10 +329,12 @@ void ITreeWalker.Visit(ConditionalExpression expression)
void ITreeWalker.Visit(CallExpression expression)
{
var assigning = _assigning;
var start = _operations.Count;
_assigning = false;

expression.Validate(this);
expression.Arguments.Accept(this);
var end = _operations.Count;
expression.Function.Accept(this);

if (assigning)
Expand All @@ -340,7 +343,32 @@ void ITreeWalker.Visit(CallExpression expression)
}
else
{
var extract = 0;
_operations.Add(new GetcOperation(expression.Arguments.Count));

for (var i = start; i < end; i++)
{
if (_operations[i] is GetsOperation g && g.Name == "_")
{
var c = extract++;
_operations[i] = new GetsOperation($"_{c}");
}
}

if (extract > 0)
{
var parameters = new List<ParameterDefinition>();

for (var i = 0; i < extract; i++)
{
var name = $"_{i}";
_operations.Insert(start, new ArgOperation(extract - (i + 1), name));
parameters.Add(new ParameterDefinition(name, true));
}

_operations.Insert(start + extract, ArgsOperation.Instance);
_operations.Add(ExtractFunction(false, parameters.ToArray(), start));
}
}

_assigning = assigning;
Expand Down
2 changes: 2 additions & 0 deletions src/Mages.Core/Vm/Operations/DefOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ sealed class DefOperation(String name) : IOperation
{
private readonly String _name = name;

public String Name => _name;

public void Invoke(IExecutionContext context)
{
var value = context.Pop();
Expand Down
2 changes: 2 additions & 0 deletions src/Mages.Core/Vm/Operations/DelVarOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ sealed class DelVarOperation(String name) : IOperation
{
private readonly String _name = name;

public String Name => _name;

public void Invoke(IExecutionContext context)
{
var result = context.Scope.Remove(_name);
Expand Down
2 changes: 2 additions & 0 deletions src/Mages.Core/Vm/Operations/GetsOperation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ sealed class GetsOperation(String name) : IOperation
{
private readonly String _name = name;

public String Name => _name;

public void Invoke(IExecutionContext context)
{
var value = context.Scope.GetProperty(_name);
Expand Down

0 comments on commit 8e84466

Please sign in to comment.