java-commons/muscript/src/main/java/io/gitlab/jfronny/muscript/ast/dynamic/Get.java

65 lines
2.3 KiB
Java

package io.gitlab.jfronny.muscript.ast.dynamic;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.annotations.CanThrow;
import io.gitlab.jfronny.muscript.annotations.UncheckedDynamic;
import io.gitlab.jfronny.muscript.ast.literal.StringLiteral;
import io.gitlab.jfronny.muscript.compiler.*;
import io.gitlab.jfronny.muscript.data.Scope;
import io.gitlab.jfronny.muscript.data.dynamic.*;
import io.gitlab.jfronny.muscript.error.TypeMismatchException;
import java.io.IOException;
@CanThrow
@UncheckedDynamic
public class Get extends DynamicExpr {
private final DynamicExpr left;
private final Expr<?> name;
public Get(int chStart, int chEnd, DynamicExpr left, Expr<?> name) {
super(Order.Call, chStart, chEnd);
this.left = left;
this.name = name;
if (name.getResultType() != Type.String && name.getResultType() != Type.Number && name.getResultType() != Type.Dynamic) {
throw new TypeMismatchException(chStart, chEnd, Type.String, name.getResultType(), "Name must be either a string or a number");
}
}
@Override
public Dynamic<?> get(Scope dataRoot) {
Dynamic<?> left = this.left.get(dataRoot);
if (left instanceof DObject o) {
return o.get(name.asStringExpr().get(dataRoot));
} else if (left instanceof DList l) {
return l.get(name.asNumberExpr().get(dataRoot).intValue());
}
throw new DynamicTypeConversionException("object or list").locational(chStart, chEnd);
}
@Override
public DynamicExpr optimize() {
DynamicExpr left = this.left.optimize();
Expr<?> name = this.name.optimize();
return new Get(chStart, chEnd, left, name);
}
@Override
public void decompile(ExprWriter writer) throws IOException {
parenthesize(left, writer, false);
if (name instanceof StringLiteral lit && Lexer.isValidId(lit.value)) {
writer.append('.').append(lit.value);
} else {
writer.append('[');
name.decompile(writer);
writer.append(']');
}
}
@Override
public boolean equals(Object obj) {
return obj instanceof Get get && left.equals(get.left) && name.equals(get.name);
}
}