/*
* $Id: AbstractAssignmentNode.java,v 1.15 2002/09/16 08:05:04 jkl Exp $
*
* Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
*
* Use is subject to license terms, as defined in
* Anvil Sofware License, Version 1.1. See LICENSE
* file, or http://njet.org/license-1.1.txt
*/
package anvil.script.expression;
import anvil.ErrorListener;
import anvil.Location;
import anvil.core.Any;
import anvil.core.Array;
import anvil.codec.Code;
import anvil.script.compiler.ByteCompiler;
import anvil.script.Context;
import java.io.IOException;
import java.util.Enumeration;
/**
* class AbstractAssignmentNode
*
* @author: Jani Lehtim�ki
*/
public abstract class AbstractAssignmentNode extends MultiParent
{
protected Location _location;
public AbstractAssignmentNode(Location location, int childs)
{
super(childs);
_location = location;
}
public AbstractAssignmentNode(Parent parent)
{
super(parent);
}
public boolean isConstant()
{
return false;
}
public void check(ErrorListener context)
{
super.check(context);
int type = typeOf();
switch(type) {
case EXPR_ASSIGN:
{
final int n = childs() - 1;
for(int i=0; i<n; i++) {
if (!getChild(i).isAssignable()) {
context.error(_location, "Left side expression #"+(i+1)+" of assignment is not assignable");
}
}
}
break;
case EXPR_ASSIGN_INIT:
case EXPR_ASSIGN_ADD:
case EXPR_ASSIGN_SUBTRACT:
case EXPR_ASSIGN_MULTIPLY:
case EXPR_ASSIGN_CONCAT:
case EXPR_ASSIGN_MODULO:
case EXPR_ASSIGN_DIVIDE:
{
final int n = childs() - 1;
for(int i=0; i<n; i++) {
if (!getChild(i).isUpdatable()) {
context.error(_location, "Left side expression #"+(i+1)+" of augmented assignment is not updatable");
}
}
}
break;
}
}
public abstract String getOperator();
protected abstract String getAssignmentMethod();
protected void compileOperation(ByteCompiler context, final Node left, final Node right)
{
left.compile(context, new Node() {
public void compile(ByteCompiler context, int operation)
{
left.compile(context, GET);
right.compile(context, GET);
Code code = context.getCode();
code.invokestatic(code.getPool().addMethodRef(context.TYPE_ANY_OP,
getAssignmentMethod(), "(Lanvil/core/Any;Lanvil/core/Any;)Lanvil/core/Any;"));
}
});
}
public void compile(ByteCompiler context, Node left, Node right)
{
Code code = context.getCode();
switch(left.typeOf()) {
case EXPR_VARIABLE:
case EXPR_CONSTANT_VARIABLE:
compileOperation(context, left, right);
break;
case EXPR_ATTRIBUTE:
right.compile(context, GET);
AttributeNode attr = (AttributeNode)left;
attr.getChild().compile(context, GET);
code.astring(attr.getAttribute());
code.aload_first();
code.invokestatic(code.getPool().addMethodRef(context.TYPE_CONTEXT, getAssignmentMethod(),
"(Lanvil/core/Any;Lanvil/core/Any;Ljava/lang/String;Lanvil/script/Context;)Lanvil/core/Any;"));
break;
case Node.EXPR_REFERENCE:
right.compile(context, GET);
ReferenceNode ref = (ReferenceNode)left;
ref.getChild(0).compile(context, GET);
ref.getChild(1).compile(context, GET);
code.aload_first();
code.invokestatic(code.getPool().addMethodRef(context.TYPE_CONTEXT, getAssignmentMethod(),
"(Lanvil/core/Any;Lanvil/core/Any;Lanvil/core/Any;Lanvil/script/Context;)Lanvil/core/Any;"));
break;
case Node.EXPR_EMPTY_REFERENCE:
left.compile(context, right);
}
}
public void compile(ByteCompiler context, Node child)
{
compile(context, getChild(0), child);
}
public void compile(ByteCompiler context, int operation)
{
final Code code = context.getCode();
int n = childs() - 1;
if (n == 1) {
compile(context, getChild(0), getChild(1));
} else {
final int tmp = code.addLocal();
getChild(n).compile(context, GET);
code.astore(tmp);
final int nth = code.getPool().addMethodRef(context.TYPE_CONTEXT,
"nth", "(Lanvil/core/Any;I)Lanvil/core/Any;");
for(int i=0; i<n; i++) {
final int c = i;
compile(context, getChild(i), new Node() {
public void compile(ByteCompiler context, int operation)
{
code.aload_first();
code.aload(tmp);
code.iconst(c);
code.invokevirtual(nth);
}
});
code.pop();
}
code.aload(tmp);
code.endLocal(tmp);
}
if (operation == GET_BOOLEAN) {
context.any2boolean();
}
}
}