/*
* Vitry, copyright (C) Hans Hoglund 2011
*
* This program 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 3 of the License, or
* at your option) any later version.
*
* This program 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* See COPYING.txt for details.
*/
package vitry.runtime;
import vitry.runtime.struct.Seq;
/**
* This class implements most aspects of a function, except invocation.
* Requires scope upon construction, however domain and range are mutable
* to allow for in-place type reconstruction.
*
* @author Hans Hoglund
*/
abstract class AbstractFunction extends ConstructionPattern
implements Function, Scope, TypableFunction
{
final Env<Symbol, Object> environment;
private Pattern domain;
private Seq<Pattern> range;
public AbstractFunction() {
this(AbstractEnv.<Symbol, Object>empty());
}
public AbstractFunction(Scope scope) {
this(scope.getValues(), null, null);
}
protected AbstractFunction(Env<Symbol, Object> env) {
this(env, null, null);
}
protected AbstractFunction(Env<Symbol, Object> env, Pattern domain, Seq<Pattern> range) {
this.environment = env;
this.domain = domain;
this.range = range;
}
public Object getValue(String name)
{
return getValue(Symbol.intern(name));
}
public Object getValue(Symbol name)
{
return environment.lookup(name);
}
public Env<Symbol, Object> getValues()
{
return this.environment;
}
public synchronized Pattern getDomain()
{
return domain;
}
public synchronized Seq<Pattern> getRange()
{
return range;
}
public synchronized void setDomain(Pattern domain)
{
this.domain = domain;
}
public synchronized void setRange(Seq<Pattern> range)
{
this.range = range;
}
public boolean isCompiled()
{
return true;
}
@Override
public boolean eq(Function o)
{
return o == this;
}
@Override
public boolean match(Function p)
{
return p == this;
}
public boolean eqFor(Pattern o)
{
return o.eq(this);
}
public boolean matchFor(Pattern p)
{
return p.match(this);
}
public boolean isInvertible()
{
return false;
}
public Pattern head()
{
return this.getDomain();
}
public Seq<Pattern> tail()
{
return this.getRange();
}
public boolean isNil()
{
return false;
}
public boolean hasTail()
{
return this.getRange() != null;
}
public String toString()
{
if (domain == null)
return super.toString();
if (range == null)
return domain.toString();
else
return domain.toString() + " -> " + range.toString();
}
protected static int checkArity(int arity)
{
if (arity < VitryRuntime.MIN_ARITY || arity > VitryRuntime.MAX_ARITY)
throw new IllegalArgumentException("Function must have arity a where "
+ VitryRuntime.MIN_ARITY + " < a < " + VitryRuntime.MAX_ARITY);
return arity;
}
}