package function.builtin.special; import environment.RuntimeEnvironment; import error.LispWarning; import function.ArgumentValidator; import function.LispSpecialFunction; import function.UserDefinedFunction; import sexpression.Cons; import sexpression.SExpression; import sexpression.Symbol; import table.FunctionTable; import static function.builtin.cons.LIST.makeList; import static java.text.MessageFormat.format; 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.INSTANCE; } @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 (FunctionTable.INSTANCE.isAlreadyDefined(functionName.toString())) environment.getErrorManager().handle(new RedefiningFunctionWarning(functionName.toString())); FunctionTable.INSTANCE.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 format("redefining function {0}", functionName); } } }