package org.dynjs.runtime.interp; import java.util.List; import org.dynjs.codegen.DereferencedReference; import org.dynjs.exception.ThrowException; import org.dynjs.parser.ast.AssignmentExpression; import org.dynjs.parser.ast.Expression; import org.dynjs.parser.ast.FunctionCallExpression; import org.dynjs.parser.ast.NewOperatorExpression; import org.dynjs.runtime.*; import org.dynjs.runtime.linker.DynJSBootstrapper; public class InvokeDynamicInterpretingVisitor extends BasicInterpretingVisitor { public InvokeDynamicInterpretingVisitor(BlockManager blockManager) { super(blockManager); } @Override public Object visit(Object context1, AssignmentExpression expr, boolean strict) { ExecutionContext context = (ExecutionContext) context1; Object lhs = expr.getLhs().accept(context, this, strict); if (!(lhs instanceof Reference)) { throw new ThrowException(context, context.createReferenceError(expr.getLhs() + " is not a reference")); } Reference lhsRef = (Reference) lhs; Object rhs = getValue(context, expr.getRhs().accept(context, this, strict)); if (lhsRef.isUnresolvableReference() && strict) { throw new ThrowException(context, context.createReferenceError(lhsRef.getReferencedName() + " is not defined")); } try { DynJSBootstrapper.getInvokeHandler().set(lhsRef, context, lhsRef.getReferencedName(), rhs); } catch (ThrowException e) { throw e; } catch (Throwable e) { throw new ThrowException(context, e); } return(rhs); // lhsRef.putValue(context, rhs); // invokedynamic("dyn:setProperty", sig(void.class, Reference.class, ExecutionContext.class, String.class, Object.class), DynJSBootstrapper.HANDLE, // DynJSBootstrapper.ARGS); } @Override public Object visit(Object context1, FunctionCallExpression expr, boolean strict) { ExecutionContext context = (ExecutionContext) context1; Object ref = expr.getMemberExpression().accept(context, this, strict); Object function = getValue(context, ref); List<Expression> argExprs = expr.getArgumentExpressions(); Object[] args = new Object[argExprs.size()]; int i = 0; for (Expression each : argExprs) { Object value = getValue(context,each.accept(context, this, strict)); args[i] = value; ++i; } Object thisValue = null; if (ref instanceof Reference) { if (((Reference) ref).isPropertyReference()) { thisValue = ((Reference) ref).getBase(); } else { thisValue = ((EnvironmentRecord) ((Reference) ref).getBase()).implicitThisValue(); } } if (thisValue == null) { thisValue = Types.UNDEFINED; } if (ref instanceof Reference) { function = new DereferencedReference((Reference) ref, function); } try { return(DynJSBootstrapper.getInvokeHandler().call(function, context, thisValue, args)); } catch (ThrowException e) { throw e; } catch (NoSuchMethodError e) { throw new ThrowException(context, context.createTypeError("not callable: " + function.toString())); } catch (Throwable e) { throw new ThrowException(context, e); } } @Override public Object visit(Object context1, NewOperatorExpression expr, boolean strict) { ExecutionContext context = (ExecutionContext) context1; Object ref = expr.getExpr().accept(context, this, strict); Object memberExpr = getValue(context, ref); Object[] args = new Object[expr.getArgumentExpressions().size()]; int i = 0; for (Expression each : expr.getArgumentExpressions()) { args[i] = getValue(context, each.accept(context, this, strict)); ++i; } Object ctor = memberExpr; if ( ref instanceof Reference && ctor instanceof JSFunction) { ctor = new DereferencedReference((Reference) ref, ctor); } try { return( DynJSBootstrapper.getInvokeHandler().construct(ctor, context, args) ); } catch (NoSuchMethodError e) { throw new ThrowException(context, context.createTypeError("cannot construct with: " + ref)); } catch (ThrowException e) { throw e; } catch (Throwable e) { throw new ThrowException(context, e); } } @Override protected Object getValue(ExecutionContext context, Object obj) { if (obj instanceof Reference) { Reference ref = (Reference) obj; String name = ref.getReferencedName(); try { Object result = DynJSBootstrapper.getInvokeHandler().get(obj, context, name); return result; } catch (ThrowException e) { throw e; } catch (NoSuchMethodError e) { if (ref.isPropertyReference() && !ref.isUnresolvableReference()) { return Types.UNDEFINED; } throw new ThrowException(context, context.createReferenceError("unable to reference: " + name)); } catch (Throwable e) { throw new ThrowException(context, e); } } else { return obj; } } }