/* * 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.ESId; /** * Expr is an intermediate form representing an expression. */ class Variable { private Function function; private ESId id; private boolean isLocal; private boolean isScope; // Is the variable initialized before it's used? private boolean isInitialized; // Is the variable ever used? private boolean isUsed; // Is the variable used by a closure? private boolean isClosureVar; // True if the variable is a global represented as a java field. private boolean isJavaGlobal; int type; Expr fullType; // True if the type is declared. private boolean isDeclared; Variable(Block block, ESId id, Expr type, boolean isLocal) { this.function = block.function; this.id = id; this.isLocal = isLocal; this.isScope = block.getDepth() > 0 || ! function.isGlobalScope(); this.type = Expr.TYPE_UNKNOWN; this.fullType = (TypeExpr) type; if (fullType != null) { this.type = fullType.getType(); isDeclared = true; } } /** * Returns the variable's name. */ ESId getId() { return id; } /** * Sets the JavaScript type. */ void setType(int type) { if (! isUsed) this.isInitialized = true; if (fullType != null) { // XXX: check type // throw new RuntimeException("mismatch type"); } else this.type = type; } /** * Declare the type of this variable. */ void declare(int javaScriptType, Expr typeExpr) { if (isDeclared && ! typeExpr.equals(this.fullType)) throw new IllegalStateException("can't declare " + this + " twice"); setType(javaScriptType, typeExpr); isDeclared = true; } /** * Sets the type of this variable. */ void setType(int newType, Expr expr) { if (! isUsed) this.isInitialized = true; if (isDeclared) return; if (newType != Expr.TYPE_UNKNOWN && newType != Expr.TYPE_JAVA) { this.type = Expr.TYPE_ES; fullType = null; return; } if (fullType == null) { } else if (! (fullType instanceof JavaTypeExpr) || ! (expr instanceof JavaTypeExpr)) { this.type = Expr.TYPE_ES; fullType = null; return; } JavaTypeExpr typeExpr = (JavaTypeExpr) expr; if (fullType != null && ! ((JavaTypeExpr) fullType).getJavaClass().equals(typeExpr.getJavaClass())) { this.type = Expr.TYPE_ES; fullType = null; return; } Class javaClass = typeExpr.getJavaClass(); if (javaClass.equals(byte.class) || javaClass.equals(short.class) || javaClass.equals(int.class)) { this.type = Expr.TYPE_INTEGER; } else if (javaClass.equals(float.class) || javaClass.equals(double.class)) { this.type = Expr.TYPE_NUMBER; } else if (javaClass.equals(boolean.class)) { this.type = Expr.TYPE_BOOLEAN; } else if (javaClass.isPrimitive()) { this.type = Expr.TYPE_ES; this.fullType = null; return; } else { this.type = newType; this.fullType = typeExpr; } } boolean isLocal() { return isLocal; } void killLocal() { isLocal = false; } /** * Returns true if this is a variable that can be used just like a * java variable. */ boolean isJavaLocal() { return isLocal && ! isClosureVar; } /** * True if the variable is a global represented by a global field. */ boolean isJavaGlobal() { return isJavaGlobal; } /** * Set the variable as a global. */ void setJavaGlobal(boolean isGlobal) { isJavaGlobal = isGlobal; isLocal = false; if (type == Expr.TYPE_UNKNOWN) type = Expr.TYPE_ES; } /** * Returns the JavaScript type of the variable. If the type hasn't * been inferred yet, the type must be ESBase. */ int getType() { if (type == Expr.TYPE_UNKNOWN) { type = Expr.TYPE_ES; isInitialized = false; } return type; } Expr getTypeExpr() { return fullType; } boolean hasInit() { return type != Expr.TYPE_UNKNOWN && isLocal && isInitialized; } boolean isScope() { return isScope; } void setUsed() { isUsed = true; if (type == Expr.TYPE_UNKNOWN) type = Expr.TYPE_ES; isInitialized = false; } void setUsedByClosure() { isClosureVar = true; setUsed(); } boolean isUsed() { return isUsed; } void setLocal() { isLocal = true; } public String toString() { return "[Variable " + id + " " + fullType + "]"; } }