79 lines
3.0 KiB
Java
79 lines
3.0 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.LocationalException;
|
|
import io.gitlab.jfronny.muscript.error.TypeMismatchException;
|
|
|
|
import java.io.IOException;
|
|
import java.util.stream.Stream;
|
|
|
|
@CanThrow
|
|
@UncheckedDynamic
|
|
public class Get extends DynamicExpr {
|
|
private final DynamicExpr left;
|
|
private final Expr<?> name;
|
|
|
|
public Get(CodeLocation location, DynamicExpr left, Expr<?> name) {
|
|
super(Order.Call, location);
|
|
this.left = left;
|
|
this.name = name;
|
|
if (name.getResultType() != Type.String && name.getResultType() != Type.Number && name.getResultType() != Type.Dynamic) {
|
|
throw new TypeMismatchException(location, 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 (Dynamic.isNull(left)) throw new LocationalException(location, "Could not get \"" + name.asStringExpr().get(dataRoot) + "\" because left is null");
|
|
if (left.isObject()) {
|
|
DObject o = left.asObject();
|
|
var n = name.asStringExpr().get(dataRoot);
|
|
if (!o.has(n)) throw new LocationalException(location, "Object does not contain \"" + n + "\"");
|
|
return o.get(n);
|
|
} else if (left.isList()) {
|
|
DList l = left.asList();
|
|
int idx = name.asNumberExpr().get(dataRoot).intValue();
|
|
if (idx < 0 || idx >= l.size()) throw new LocationalException(location, "Index " + idx + " is out of range for list with size " + l.size());
|
|
return l.get(idx);
|
|
}
|
|
throw new DynamicTypeConversionException("object or list", left).locational(location);
|
|
}
|
|
|
|
@Override
|
|
public DynamicExpr optimize() {
|
|
DynamicExpr left = this.left.optimize();
|
|
Expr<?> name = this.name.optimize();
|
|
return new Get(location, left, name);
|
|
}
|
|
|
|
@Override
|
|
public Stream<Expr<?>> extractSideEffects() {
|
|
return Stream.concat(left.extractSideEffects(), name.extractSideEffects());
|
|
}
|
|
|
|
@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);
|
|
}
|
|
}
|