package io.gitlab.jfronny.muscript.ast.dynamic; import io.gitlab.jfronny.muscript.ast.DynamicExpr; import io.gitlab.jfronny.muscript.annotations.CanThrow; import io.gitlab.jfronny.muscript.annotations.UncheckedDynamic; import io.gitlab.jfronny.muscript.compiler.ExprWriter; import io.gitlab.jfronny.muscript.compiler.Order; import io.gitlab.jfronny.muscript.data.Scope; import io.gitlab.jfronny.muscript.data.dynamic.*; import io.gitlab.jfronny.muscript.data.dynamic.additional.DFinal; import io.gitlab.jfronny.muscript.error.LocationalException; import java.io.IOException; import java.util.*; import java.util.stream.Stream; @CanThrow @UncheckedDynamic public class Call extends DynamicExpr { private final DynamicExpr left; private final List args; public Call(int chStart, int chEnd, DynamicExpr left, List args) { super(Order.Call, chStart, chEnd); this.left = left; this.args = args; } @Override public Dynamic get(Scope dataRoot) { try { return left.get(dataRoot) .asCallable() .getValue() .apply(DFinal.of(args.stream().flatMap(e -> e.get(dataRoot)).toArray(Dynamic[]::new))); } catch (DynamicTypeConversionException e) { throw e.locational(chStart, chEnd); } catch (RuntimeException e) { throw new LocationalException(chStart, chEnd, "Could not perform call successfully", e); } } @Override public DynamicExpr optimize() { List 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); } @Override public void decompile(ExprWriter writer) throws IOException { parenthesize(left, writer, false); if (args.size() > 3) { writer.increaseIndent(); writer.append("(\n"); boolean first = true; for (Arg arg : args) { if (!first) writer.append(",\n"); first = false; arg.expr.decompile(writer); if (arg.variadic) writer.append("..."); } writer.decreaseIndent(); writer.append("\n)"); } else { writer.append("("); boolean first = true; for (Arg arg : args) { if (!first) writer.append(", "); first = false; arg.expr.decompile(writer); if (arg.variadic) writer.append("..."); } } } @Override public boolean equals(Object obj) { return obj instanceof Call call && left.equals(call.left) && args.equals(call.args); } public record Arg(DynamicExpr expr, boolean variadic) { public Stream> get(Scope dataRoot) { return variadic ? expr.get(dataRoot).asList().getValue().stream() : Stream.of(expr.get(dataRoot)); } public Arg optimize() { return new Arg(expr.optimize(), variadic); } } }