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); } } }