muScript: bind operator
This commit is contained in:
parent
0a0a9ae3bd
commit
6694aa08ed
@ -0,0 +1,37 @@
|
||||
package io.gitlab.jfronny.muscript.ast.dynamic;
|
||||
|
||||
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.data.dynamic.DFinal;
|
||||
import io.gitlab.jfronny.muscript.data.dynamic.Dynamic;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class Bind extends DynamicExpr {
|
||||
public final DynamicExpr callable;
|
||||
public final DynamicExpr parameter;
|
||||
|
||||
public Bind(int chStart, int chEnd, DynamicExpr callable, DynamicExpr parameter) {
|
||||
super(chStart, chEnd);
|
||||
this.callable = callable;
|
||||
this.parameter = parameter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dynamic<?> get(Scope dataRoot) {
|
||||
return DFinal.of(args -> {
|
||||
List<Dynamic<?>> argsWithParameter = new LinkedList<>(args.getValue());
|
||||
argsWithParameter.add(0, parameter.get(dataRoot));
|
||||
return callable.get(dataRoot)
|
||||
.asCallable()
|
||||
.getValue()
|
||||
.apply(DFinal.of(argsWithParameter));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicExpr optimize() {
|
||||
return new Bind(chStart, chEnd, callable.optimize(), parameter.optimize());
|
||||
}
|
||||
}
|
@ -35,8 +35,12 @@ public class Call extends DynamicExpr {
|
||||
|
||||
@Override
|
||||
public DynamicExpr optimize() {
|
||||
DynamicExpr left = this.left.optimize();
|
||||
List<Arg> args = new ArrayList<>();
|
||||
DynamicExpr left = this.left.optimize();
|
||||
if (left instanceof Bind bind) {
|
||||
left = bind.callable;
|
||||
args.add(new Arg(bind.parameter, false));
|
||||
}
|
||||
for (Arg arg : this.args) args.add(arg.optimize());
|
||||
return new Call(chStart, chEnd, left, args);
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ public class Lexer {
|
||||
}
|
||||
case ',' -> createToken(Token.Comma);
|
||||
case '?' -> createToken(Token.QuestionMark);
|
||||
case ':' -> createToken(Token.Colon);
|
||||
case ':' -> createToken(match(':') ? Token.DoubleColon : Token.Colon);
|
||||
case '(' -> createToken(Token.LeftParen);
|
||||
case ')' -> createToken(Token.RightParen);
|
||||
case '[' -> createToken(Token.LeftBracket);
|
||||
|
@ -232,7 +232,7 @@ public class Parser {
|
||||
private Expr<?> call() {
|
||||
Expr<?> expr = primary();
|
||||
|
||||
while (match(Token.LeftParen, Token.Dot, Token.LeftBracket)) {
|
||||
while (match(Token.LeftParen, Token.Dot, Token.LeftBracket, Token.DoubleColon)) {
|
||||
int start = previous.start;
|
||||
int end = previous.current - 1;
|
||||
expr = switch (previous.token) {
|
||||
@ -241,6 +241,10 @@ public class Parser {
|
||||
TokenData name = consume(Token.Identifier, "Expected field name after '.'.");
|
||||
yield new Get(start, end, asDynamic(expr), Expr.literal(name.start, name.current - 1, name.lexeme));
|
||||
}
|
||||
case DoubleColon -> {
|
||||
TokenData name = consume(Token.Identifier, "Expected variable name after '::'.");
|
||||
yield new Bind(start, end, new Variable(name.start, name.current - 1, name.lexeme), expr.asDynamicExpr());
|
||||
}
|
||||
case LeftBracket -> {
|
||||
expr = new Get(start, end, asDynamic(expr), expression());
|
||||
consume(Token.RightBracket, "Expected closing bracket");
|
||||
|
@ -29,5 +29,7 @@ public enum Token {
|
||||
|
||||
Semicolon,
|
||||
|
||||
DoubleColon,
|
||||
|
||||
Error, EOF
|
||||
}
|
||||
|
@ -0,0 +1,17 @@
|
||||
package io.gitlab.jfronny.muscript.test;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.Parser;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static io.gitlab.jfronny.muscript.test.util.MuTestUtil.makeArgs;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class BindTest {
|
||||
@Test
|
||||
void simpleBind() {
|
||||
assertEquals(30, Parser.parseScript("""
|
||||
fn = {n, b -> n*b*2}
|
||||
5::fn(3)
|
||||
""").run(makeArgs()).asNumber().getValue());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user