/*
* Copyright (c) 1998-2011 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
* Free SoftwareFoundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.es.parser;
import com.caucho.es.ESException;
import com.caucho.es.ESId;
import java.io.IOException;
/**
* Expr is an intermediate form representing an expression.
*/
class IdExpr extends Expr {
private static ESId ARGUMENTS = ESId.intern("arguments");
private Variable var;
IdExpr(Block block, Variable var)
{
super(block);
this.var = var;
if (var.getId() == ARGUMENTS) {
function.setArguments();
function.setUseAllVariables();
}
if (var.getTypeExpr() != null) {
type = var.getType();
javaType = var.getTypeExpr().getJavaClass();
}
if (! var.isLocal() && ! function.isGlobalScope() && ! var.isJavaGlobal())
function.setNeedsScope();
}
void setType(int type)
{
var.setType(type);
}
boolean isLocal()
{
return var.isLocal() && function.allowLocals();
}
boolean isJavaLocal()
{
return var.isJavaLocal() && function.allowLocals();
}
/**
* Returns true if the variable is a global represented as a Java
* field.
*/
boolean isJavaGlobal()
{
return var.isJavaGlobal();
}
void setUsed()
{
var.setUsed();
}
int getType()
{
if (! isLocal() && ! isJavaGlobal())
return TYPE_ES;
else
return var.getType();
}
Expr getTypeExpr()
{
if (! isLocal())
return null;
else
return var.getTypeExpr();
}
boolean isSimple()
{
return isJavaLocal();
}
boolean isGlobalScope()
{
return function.isGlobalScope() && ! var.isScope();
}
/**
* Returns the underlying variable.
*/
Variable getVar()
{
return var;
}
boolean isUsed()
{
return var.isUsed() || function.useAllVariables();
}
void setLocal()
{
var.setLocal();
}
ESId getId()
{
return var.getId();
}
Expr delete()
{
return new DeleteExpr(block, this);
}
Expr postfix(int op)
{
if (op == '+')
return new PostfixExpr(block, PostfixExpr.POSTINC, this);
else
return new PostfixExpr(block, PostfixExpr.POSTDEC, this);
}
Expr prefix(int op)
{
if (op == '+')
return new PostfixExpr(block, PostfixExpr.PREINC, this);
else
return new PostfixExpr(block, PostfixExpr.PREDEC, this);
}
/**
* Assigns the identifier to a value.
*/
Expr assign(Expr value)
throws ESException
{
int valueType = value.getType();
Expr typeExpr = value.getTypeExpr();
// XXX: needs to differ from getType to make type inference work
int type = var.type;
if (isLocal() || isJavaGlobal()) {
if (valueType == TYPE_UNKNOWN)
valueType = TYPE_ES;
if (typeExpr != null)
var.setType(TYPE_JAVA, typeExpr);
else if (type == TYPE_UNKNOWN)
var.setType(valueType);
else if (type == valueType) {
}
else if ((type == TYPE_INTEGER || type == TYPE_NUMBER) &&
(valueType == TYPE_INTEGER || valueType == TYPE_NUMBER))
var.setType(TYPE_NUMBER);
else
var.setType(TYPE_ES, null);
type = var.getType();
Expr newTypeExpr = var.getTypeExpr();
if (newTypeExpr == null)
javaType = null;
else
javaType = newTypeExpr.getJavaClass();
}
return new AssignExpr(block, this, value);
}
/**
* Creates a call expression from this id.
*/
CallExpr startCall()
throws ESException
{
var.setUsed();
return new CallExpr(block, this, null, false);
}
CallExpr startNew()
throws ESException
{
var.setUsed();
return new CallExpr(block, this, null, true);
}
void exprStatement(Function fun) throws ESException
{
doVoid().exprStatement(fun);
}
void printNumImpl() throws IOException
{
printImpl();
}
void printBooleanImpl() throws IOException
{
printImpl();
}
void printInt32Impl() throws IOException
{
printImpl();
}
void printStringImpl() throws IOException
{
printImpl();
}
void printImpl() throws IOException
{
cl.setLine(getFilename(), getLine());
if (isJavaLocal()) {
cl.print(getId());
}
else if (isJavaGlobal()) {
cl.print(getId());
}
else if (isGlobalScope()) {
// Need to use getGlobalVariable so an undefined variable will
// throw an exception
cl.print("_env.getGlobalVariable(");
printLiteral(getId());
cl.print(")");
} else {
cl.print("_env.getScopeProperty(");
printLiteral(getId());
cl.print(")");
}
}
void printJavaImpl() throws IOException
{
cl.setLine(getFilename(), getLine());
cl.print(getId());
}
public String toString()
{
return "[IdExpr " + getId() + "]";
}
}