package com.oracle.truffle.js.test.instrumentation;
import org.junit.Test;
import com.oracle.truffle.js.nodes.instrumentation.JSTags.ControlFlowBranchTag;
import com.oracle.truffle.js.nodes.instrumentation.JSTags.FunctionCallTag;
import com.oracle.truffle.js.nodes.instrumentation.JSTags.LiteralTag;
import com.oracle.truffle.js.nodes.instrumentation.JSTags.ReadElementTag;
import com.oracle.truffle.js.nodes.instrumentation.JSTags.ReadPropertyTag;
import com.oracle.truffle.js.nodes.instrumentation.JSTags.ReadVariableTag;
import com.oracle.truffle.js.nodes.instrumentation.JSTags.WritePropertyTag;
import com.oracle.truffle.js.nodes.instrumentation.JSTags.WriteVariableTag;
import com.oracle.truffle.js.runtime.objects.Undefined;
public class LocalsAccessTest extends FineGrainedAccessTest {
@Test
public void write() {
evalAllTags("(function() { var a = 42; })();");
enter(FunctionCallTag.class, (e1, call) -> {
enter(LiteralTag.class).exit(assertReturnValue(Undefined.instance));
call.input(assertUndefinedInput);
enter(LiteralTag.class).exit((e2) -> {
assertAttribute(e2, LITERAL_TYPE, LiteralTag.Type.FunctionLiteral.name());
});
call.input(assertJSFunctionInput);
enterDeclareTag("a");
enter(WriteVariableTag.class, (e3, var) -> {
enter(LiteralTag.class).exit();
var.input(42);
}).exit();
}).exit(assertReturnValue(Undefined.instance));
}
@Test
public void writeScope() {
evalAllTags("(function() { var level; (function() { (function() { level = 42; })(); })();})();");
enter(FunctionCallTag.class, (e1, call) -> {
enter(LiteralTag.class).exit(assertReturnValue(Undefined.instance));
call.input(assertUndefinedInput);
enter(LiteralTag.class).exit((e2) -> {
assertAttribute(e2, LITERAL_TYPE, LiteralTag.Type.FunctionLiteral.name());
});
call.input(assertJSFunctionInput);
enterDeclareTag("level");
enter(FunctionCallTag.class, (e2, call2) -> {
enter(LiteralTag.class).exit(assertReturnValue(Undefined.instance));
call2.input(assertUndefinedInput);
enter(LiteralTag.class).exit((e3) -> {
assertAttribute(e3, LITERAL_TYPE, LiteralTag.Type.FunctionLiteral.name());
});
call2.input(assertJSFunctionInput);
enter(FunctionCallTag.class, (e3, call3) -> {
enter(LiteralTag.class).exit(assertReturnValue(Undefined.instance));
call3.input(assertUndefinedInput);
enter(LiteralTag.class).exit((e4) -> {
assertAttribute(e4, LITERAL_TYPE, LiteralTag.Type.FunctionLiteral.name());
});
call3.input(assertJSFunctionInput);
enter(WriteVariableTag.class, (e4, var) -> {
enter(LiteralTag.class).exit();
var.input(42);
}).exit();
}).exit(assertReturnValue(Undefined.instance));
}).exit(assertReturnValue(Undefined.instance));
}).exit(assertReturnValue(Undefined.instance));
}
@Test
public void read() {
evalAllTags("(function() { var a = 42; return a; })();");
enter(FunctionCallTag.class, (e1, call) -> {
enter(LiteralTag.class).exit(assertReturnValue(Undefined.instance));
call.input(assertUndefinedInput);
enter(LiteralTag.class).exit((e2) -> {
assertAttribute(e2, LITERAL_TYPE, LiteralTag.Type.FunctionLiteral.name());
});
call.input(assertJSFunctionInput);
enterDeclareTag("a");
enter(WriteVariableTag.class, (e2, var) -> {
enter(LiteralTag.class).exit();
var.input(42);
}).exit();
enter(ControlFlowBranchTag.class, (e4, v) -> {
assertAttribute(e4, TYPE, ControlFlowBranchTag.Type.Return.name());
enter(ReadVariableTag.class).exit();
v.input(42);
}).exitMaybeControlFlowException();
}).exit();
}
@Test
public void readConst() {
evalAllTags("(function() { const a = 42; return a; })();");
enter(FunctionCallTag.class, (e1, call) -> {
enter(LiteralTag.class).exit(assertReturnValue(Undefined.instance));
call.input(assertUndefinedInput);
enter(LiteralTag.class).exit((e2) -> {
assertAttribute(e2, LITERAL_TYPE, LiteralTag.Type.FunctionLiteral.name());
});
call.input(assertJSFunctionInput);
enterDeclareTag("a");
enter(WriteVariableTag.class, (e2, var) -> {
enter(LiteralTag.class).exit();
var.input(42);
}).exit();
enter(ControlFlowBranchTag.class, (e4, v) -> {
assertAttribute(e4, TYPE, ControlFlowBranchTag.Type.Return.name());
enter(ReadVariableTag.class).exit();
v.input(42);
}).exitMaybeControlFlowException();
}).exit(assertReturnValue(42));
}
@Test
public void forOfConst() {
evalWithTag("for(const a of [41,42]) {};", WriteVariableTag.class);
enter(WriteVariableTag.class, (e, w) -> {
w.input(41);
}).exit();
enter(WriteVariableTag.class, (e, w) -> {
w.input(42);
}).exit();
}
@Test
public void forOfVar() {
evalWithTag("for(var a of [41,42]) {};", WritePropertyTag.class);
enter(WritePropertyTag.class, (e, w) -> {
w.input(assertGlobalObjectInput);
w.input(41);
}).exit();
enter(WritePropertyTag.class, (e, w) -> {
w.input(assertGlobalObjectInput);
w.input(42);
}).exit();
}
@Test
public void readThis() {
evalWithTag("(()=>{return this;})()", ReadVariableTag.class);
enter(ReadVariableTag.class, (e, r) -> {
assertAttribute(e, NAME, "this");
}).exit();
}
@Test
public void classDeclaration() {
evalWithTags("class Klass {}", new Class[]{ReadVariableTag.class,
ReadPropertyTag.class,
ReadElementTag.class});
}
@Test
public void classDeclareExpression() {
evalWithTag("foo = class Foo {};", WritePropertyTag.class);
enter(WritePropertyTag.class, (e, write) -> {
assertAttribute(e, KEY, "foo");
write.input(assertGlobalObjectInput);
write.input(assertJSFunctionInput);
}).exit();
}
}