transcendental-lisp/src/function/builtin/special/Define.java

75 lines
2.6 KiB
Java

package function.builtin.special;
import static function.builtin.cons.LIST.makeList;
import static table.FunctionTable.*;
import java.text.MessageFormat;
import environment.RuntimeEnvironment;
import error.LispWarning;
import function.*;
import sexpression.*;
public abstract class Define extends LispSpecialFunction {
private ArgumentValidator argumentValidator;
private ArgumentValidator lambdaListIsListValidator;
private ArgumentValidator lambdaListValidator;
private RuntimeEnvironment environment;
public Define(String functionName) {
this.argumentValidator = new ArgumentValidator(functionName);
this.argumentValidator.setMinimumNumberOfArguments(2);
this.argumentValidator.setFirstArgumentExpectedType(Symbol.class);
this.lambdaListIsListValidator = new ArgumentValidator(functionName + "|lambda-list|");
this.lambdaListIsListValidator.setEveryArgumentExpectedType(Cons.class);
this.lambdaListValidator = new ArgumentValidator(functionName + "|parameter|");
this.lambdaListValidator.setEveryArgumentExpectedType(Symbol.class);
this.environment = RuntimeEnvironment.getInstance();
}
@Override
public SExpression call(Cons argumentList) {
argumentValidator.validate(argumentList);
Cons remainingArguments = (Cons) argumentList.getRest();
SExpression functionName = argumentList.getFirst();
SExpression secondArgument = remainingArguments.getFirst();
lambdaListIsListValidator.validate(makeList(secondArgument));
Cons lambdaList = (Cons) secondArgument;
lambdaListValidator.validate(lambdaList);
Cons functionBody = (Cons) remainingArguments.getRest();
UserDefinedFunction function = createFunction(functionName, lambdaList, functionBody);
if (isAlreadyDefined(functionName.toString()))
environment.getErrorManager().handle(new RedefiningFunctionWarning(functionName.toString()));
defineFunction(functionName.toString(), function);
return functionName;
}
protected abstract UserDefinedFunction createFunction(SExpression functionName, Cons lambdaList, Cons functionBody);
public class RedefiningFunctionWarning extends LispWarning {
private static final long serialVersionUID = 1L;
private String functionName;
public RedefiningFunctionWarning(String functionName) {
this.functionName = functionName;
}
@Override
public String getMessage() {
return MessageFormat.format("redefining function {0}", functionName);
}
}
}