/*
* Copyright (c) 1998-2008 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 Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.quercus.program;
import com.caucho.quercus.Location;
import com.caucho.quercus.env.Env;
import com.caucho.quercus.env.EnvVar;
import com.caucho.quercus.env.EnvVarImpl;
import com.caucho.quercus.env.NullThisValue;
import com.caucho.quercus.env.NullValue;
import com.caucho.quercus.env.Value;
import com.caucho.quercus.env.Var;
import com.caucho.quercus.expr.Expr;
import com.caucho.quercus.expr.ExprFactory;
import com.caucho.quercus.expr.RequiredExpr;
import com.caucho.quercus.function.AbstractFunction;
import com.caucho.quercus.statement.*;
import java.util.HashMap;
import java.util.Map;
/**
* Represents sequence of statements.
*/
public class Function extends AbstractFunction {
protected final FunctionInfo _info;
protected final boolean _isReturnsReference;
protected final String _name;
protected final Arg []_args;
protected final Statement _statement;
protected boolean _hasReturn;
protected String _comment;
Function(Location location,
String name,
FunctionInfo info,
Arg []args,
Statement []statements)
{
super(location);
_name = name.intern();
_info = info;
_info.setFunction(this);
_isReturnsReference = info.isReturnsReference();
_args = args;
_statement = new BlockStatement(location, statements);
setGlobal(info.isPageStatic());
_isStatic = true;
}
public Function(ExprFactory exprFactory,
Location location,
String name,
FunctionInfo info,
Arg []args,
Statement []statements)
{
super(location);
_name = name.intern();
_info = info;
_info.setFunction(this);
_isReturnsReference = info.isReturnsReference();
_args = new Arg[args.length];
System.arraycopy(args, 0, _args, 0, args.length);
_statement = exprFactory.createBlock(location, statements);
setGlobal(info.isPageStatic());
_isStatic = true;
}
/**
* Returns the name.
*/
public String getName()
{
return _name;
}
/*
* Returns the declaring class
*/
@Override
public ClassDef getDeclaringClass()
{
return _info.getDeclaringClass();
}
/*
* Returns the declaring class
*/
@Override
public String getDeclaringClassName()
{
ClassDef declaringClass = _info.getDeclaringClass();
if (declaringClass != null)
return declaringClass.getName();
else
return null;
}
/**
* Returns the args.
*/
public Arg []getArgs()
{
return _args;
}
public boolean isObjectMethod()
{
return false;
}
/**
* True for a returns reference.
*/
public boolean isReturnsReference()
{
return _isReturnsReference;
}
/**
* Sets the documentation for this function.
*/
public void setComment(String comment)
{
_comment = comment;
}
/**
* Returns the documentation for this function.
*/
@Override
public String getComment()
{
return _comment;
}
public Value execute(Env env)
{
return null;
}
/**
* Evaluates a function's argument, handling ref vs non-ref
*/
@Override
public Value []evalArguments(Env env, Expr fun, Expr []args)
{
Value []values = new Value[args.length];
for (int i = 0; i < args.length; i++) {
Arg arg = null;
if (i < _args.length)
arg = _args[i];
if (arg == null)
values[i] = args[i].eval(env).copy();
else if (arg.isReference())
values[i] = args[i].evalRef(env);
else {
// php/0d04
values[i] = args[i].eval(env);
}
}
return values;
}
public Value call(Env env, Expr []args)
{
return callImpl(env, args, false);
}
public Value callCopy(Env env, Expr []args)
{
return callImpl(env, args, false);
}
public Value callRef(Env env, Expr []args)
{
return callImpl(env, args, true);
}
private Value callImpl(Env env, Expr []args, boolean isRef)
{
HashMap<String,EnvVar> map = new HashMap<String,EnvVar>();
Value []values = new Value[args.length];
for (int i = 0; i < args.length; i++) {
Arg arg = null;
if (i < _args.length) {
arg = _args[i];
}
if (arg == null) {
values[i] = args[i].eval(env).copy();
}
else if (arg.isReference()) {
values[i] = args[i].evalRef(env);
map.put(arg.getName(), new EnvVarImpl(values[i].toRefVar()));
}
else {
// php/0d04
values[i] = args[i].eval(env);
Var var = values[i].toVar();
map.put(arg.getName(), new EnvVarImpl(var));
values[i] = var.toValue();
}
}
for (int i = args.length; i < _args.length; i++) {
Arg arg = _args[i];
Expr defaultExpr = arg.getDefault();
if (defaultExpr == null)
return env.error("expected default expression");
else if (arg.isReference())
map.put(arg.getName(),
new EnvVarImpl(defaultExpr.evalRef(env).toVar()));
else {
map.put(arg.getName(),
new EnvVarImpl(defaultExpr.eval(env).copy().toVar()));
}
}
Map<String,EnvVar> oldMap = env.pushEnv(map);
Value []oldArgs = env.setFunctionArgs(values); // php/0476
Value oldThis;
if (isStatic()) {
// php/0967
oldThis = env.setThis(NullThisValue.NULL);
}
else
oldThis = env.getThis();
try {
Value value = _statement.execute(env);
if (value == null)
return NullValue.NULL;
else if (_isReturnsReference && isRef)
return value;
else
return value.copyReturn();
} finally {
env.restoreFunctionArgs(oldArgs);
env.popEnv(oldMap);
env.setThis(oldThis);
}
}
public Value call(Env env, Value []args)
{
return callImpl(env, args, false);
}
public Value callCopy(Env env, Value []args)
{
return callImpl(env, args, false);
}
public Value callRef(Env env, Value []args)
{
return callImpl(env, args, true);
}
private Value callImpl(Env env, Value []args, boolean isRef)
{
HashMap<String,EnvVar> map = new HashMap<String,EnvVar>(8);
for (int i = 0; i < args.length; i++) {
Arg arg = null;
if (i < _args.length) {
arg = _args[i];
}
if (arg == null) {
}
else if (arg.isReference()) {
map.put(arg.getName(), new EnvVarImpl(args[i].toRefVar()));
}
else {
Var var = args[i].copy().toVar();
if (arg.getExpectedClass() != null
&& arg.getDefault() instanceof RequiredExpr) {
env.checkTypeHint(var,
arg.getExpectedClass(),
arg.getName(),
getName());
}
// quercus/0d04
map.put(arg.getName(), new EnvVarImpl(var));
}
}
for (int i = args.length; i < _args.length; i++) {
Arg arg = _args[i];
Expr defaultExpr = arg.getDefault();
if (defaultExpr == null)
return env.error("expected default expression");
else if (arg.isReference())
map.put(arg.getName(), new EnvVarImpl(defaultExpr.evalRef(env).toVar()));
else {
map.put(arg.getName(), new EnvVarImpl(defaultExpr.eval(env).copy().toVar()));
}
}
Map<String,EnvVar> oldMap = env.pushEnv(map);
Value []oldArgs = env.setFunctionArgs(args);
Value oldThis;
if (isStatic()) {
// php/0967, php/091i
oldThis = env.setThis(NullThisValue.NULL);
}
else
oldThis = env.getThis();
try {
Value value = _statement.execute(env);
if (value == null)
return NullValue.NULL;
else if (_isReturnsReference && isRef)
return value;
else
return value.copyReturn();
} finally {
env.restoreFunctionArgs(oldArgs);
env.popEnv(oldMap);
env.setThis(oldThis);
}
}
public String toString()
{
return getClass().getSimpleName() + "[" + _name + "]";
}
}