// also now need to ensure that all arguments in regular expression // get their values looked up if they are symbols // implementation // Note : sometimes env1 will not conform, or be pertinent to what is written relation to c# loops and scheme code public override Node eval(Node node1, Environment env1) { if (node1 == null || node1.getCar() == null) { Console.WriteLine("Error: the expression is not initialized to values: null list and car"); return(Nil.getInstance()); } // for any regular defined function enclosed in parentheses, // the first element is supposed to be a function to be evaluated. // this variable will hold the final function head term we get. Node firstElem_car = node1.getCar(); // step one : if Car is a pair, evaluate it and store resulting ident, ... which ought to be // another function once evaluated... if (node1.getCar().isPair()) { // build new environment for this to be computed for. Environment envExtend = new Environment(env1); firstElem_car = node1.getCar().eval(envExtend); //report error if not a builtin/ or /closure if (firstElem_car == null || !firstElem_car.isProcedure()) { Console.WriteLine("Error: regular expression needs a function builtin/closure for first term!, __ + returning null instead."); return(Nil.getInstance()); } } else if (node1.getCar().isSymbol()) { // start loop to get closure from obstructing intermediate symbolic expression. bool first_element_is_not_closure = true; firstElem_car = node1.getCar(); while (first_element_is_not_closure) { firstElem_car = env1.lookup(firstElem_car); //report error if not a builtin/ or /closure if (firstElem_car == null) { Console.WriteLine("Error: regular expression needs a function builtin/closure for first term!, __ + returning null instead."); return(Nil.getInstance()); } else if (firstElem_car.isProcedure()) { first_element_is_not_closure = false; } } } // this would be improper end for cons regular expression. if (node1.getCdr() == null) { Console.WriteLine("error: one of regular expressions elements is null."); return(Nil.getInstance()); } // special builtIn eval case. BuiltIn givenId = null; if (firstElem_car.isBuiltIn()) { givenId = (BuiltIn)firstElem_car; // check if built in is eval // note carefully: if symbol == null, null pointer will happen. if (givenId.getSymbol().getName().Equals("eval")) { // build new environment for this to be computed for. Environment envExtend = new Environment(env1); // check for null values now so null pointer doesnt get encountered if (node1.getCdr().getCar() == null || node1.getCdr().getCdr() == null || node1.getCdr().getCdr().getCar() == null) { Console.WriteLine("Error: lacking one of the following for eval : expression or environment."); return(Nil.getInstance()); } // side maneuver. _ work out the environment first... bool environment_taken = false; Node env_symbol_to_lookup = node1.getCdr().getCdr().getCar(); Node environment_found = null; // check if symbol needs to be evaluated if (env_symbol_to_lookup.isSymbol()) { if (env1.lookup(env_symbol_to_lookup) != null) { environment_found = env1.lookup(env_symbol_to_lookup); } else { Console.WriteLine("Error: environment symbol was not found."); return(Nil.getInstance()); } } // check if expression needs to be evaluated else if (env_symbol_to_lookup.isPair()) { environment_found = env_symbol_to_lookup.eval(envExtend); } if (environment_found != null && environment_found.isEnvironment()) { environment_taken = true; } else { Console.WriteLine("Error: evaluation op_ did not find a fitting environment."); return(Nil.getInstance()); } // working on expression now Node args_to_eval = null; Node localTerms_data = node1.getCdr().getCar(); // check if second argument is code // and then evaluate if it needs more processing // for eval to implement as code if (localTerms_data.isPair() && environment_taken) { if (localTerms_data.getCar() != null && localTerms_data.getCar().isSymbol() && localTerms_data.getCar().getName().Equals("quote")) { Node args_of_Quote = localTerms_data.eval(envExtend); if (args_of_Quote != null) { // copy evaluated quote expression args_to_eval = args_of_Quote; } } else if (localTerms_data.getCar() != null && localTerms_data.getCar().isSymbol() && localTerms_data.getCar().getName().Equals("lambda")) { Node args_of_Lambda = localTerms_data.eval(envExtend); if (args_of_Lambda != null) { // copy evaluated lambda expression args_to_eval = args_of_Lambda; } } else { // this needs fine tuning for more special cases..\\ //("may have more cases... ") //?? args_to_eval = localTerms_data; } } else if (localTerms_data.isSymbol() && environment_taken) { Node node_symbol_expression = env1.lookup(localTerms_data); if (node_symbol_expression != null) { // copy evaluated symbol and then the environment args_to_eval = node_symbol_expression; } else { Console.WriteLine("Error: first expression argument symbol not found."); return(Nil.getInstance()); } } // return the built in eval of args and environment given if (args_to_eval != null) { Environment environment_copy_found = (Environment)environment_found; if (args_to_eval.isPair()) { return(args_to_eval.eval(environment_copy_found)); } else { return(args_to_eval.eval(environment_copy_found)); } } else { Console.WriteLine("Error: expression arg was null."); return(Nil.getInstance()); } } // note: looking at special eq? case // check if built in is eq? only look at case of (eq? 'exp 'exp) // note carefully: if symbol == null, null pointer will happen. if (givenId.getSymbol().getName().Equals("eq?") && node1.getCdr().getCar() != null && node1.getCdr().getCdr() != null && node1.getCdr().getCdr().getCar() != null && node1.getCdr().getCdr().getCdr() != null && node1.getCdr().getCdr().getCdr().isNull() && node1.getCdr().getCar().isPair() && node1.getCdr().getCdr().getCar().isPair() ) { // first we must check if the arguments to (eq? ... )are in fact quote arguments. Cons argument1 = (Cons)node1.getCdr().getCar(); Cons argument2 = (Cons)node1.getCdr().getCdr().getCar(); if (argument1.getForm_ofCons() is Tree.Quote && argument2.getForm_ofCons() is Tree.Quote) { String first_argument_printed = ""; String second_argument_printed = ""; // redirect output to evaulate if print of Pair nodes is same var originalConsoleOut = Console.Out; // preserve the original stream using (var writer = new StringWriter()) { Console.SetOut(writer); argument1.print(0); writer.Flush(); var myString = writer.ToString(); first_argument_printed = myString.TrimEnd('\n'); } using (var writer1 = new StringWriter()) { Console.SetOut(writer1); argument2.print(0); writer1.Flush(); var myString_2 = writer1.ToString(); second_argument_printed = myString_2.TrimEnd('\n'); } Console.SetOut(originalConsoleOut); // restore Console.Out if (first_argument_printed.Equals(second_argument_printed)) { return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } } } // security check for eof-object? builtIn test... if (givenId != null && givenId.getSymbol().getName().Equals("eof-object?")) { if (node1.getCdr().isNull() || !node1.getCdr().isPair()) { Console.WriteLine("Error: no argument for eof-object? test. the BuiltIn function eof-object? requires one argument to test."); return(Nil.getInstance()); } } } // other cases builtin or closure... Node args_given = node1.getCdr(); bool hasArguments = true; // test if there are arguments to this form function if (args_given.isNull()) { hasArguments = false; } if (hasArguments) { if (args_given.getCdr() == null || args_given.getCar() == null) { Console.WriteLine("Error: one of passed arguments in function expression is null."); return(Nil.getInstance()); } // need to evaluate args (each car separately)... and then return what is resulting list of elements... // build new environment on hand _ for each car to be computed at times. Environment envExtend1 = new Environment(env1); // this will hold the list of evaluated arguments cumulatively. Cons evaluated_argsList__in_progress; // this will hold a latest fringe of for extending fringe items. Cons fringe_cons = null; bool hasMoreDescendents = !args_given.getCdr().isNull(); if (hasMoreDescendents) { // start this off as unassigned. Cons added_fringe_con = null; // this will hold the list of evaluated arguments cumulatively. // Cons evaluated_argsList__in_progress; // check if eval is not null Node evalItem1 = args_given.getCar().eval(envExtend1); if (evalItem1 != null) { evaluated_argsList__in_progress = new Cons(evalItem1, added_fringe_con); } else { // first a detour... // // check for special case of eof-object? builtIn test if (givenId != null && givenId.getSymbol().getName().Equals("eof-object?")) { Console.WriteLine("Error: too many args for function eof-object? test. "); return(Nil.getInstance()); } // normal case where regular expression argument evaluated to null is to throw an error else { Console.WriteLine("Error: one of the args items in regular function was null. "); return(Nil.getInstance()); } } // under the alias of fringe_cons... // we will continue this reference down to assess the next fringe branch fringe_cons = evaluated_argsList__in_progress; } // dealt with the sole generation here. // no more fringes left. else { // check if eval is not null Node evalItem1 = args_given.getCar().eval(envExtend1); if (evalItem1 != null) { // first a detour... // // check for special case of eof-object? builtIn test is false if (givenId != null && givenId.getSymbol().getName().Equals("eof-object?")) { return(BoolLit.getInstance(false)); } // normal case where regular expression argument evaluated to null is to throw an error else { evaluated_argsList__in_progress = new Cons(evalItem1, Nil.getInstance()); } } else { // first a detour... // // check for special case of eof-object? builtIn test is true if (givenId != null && givenId.getSymbol().getName().Equals("eof-object?")) { return(BoolLit.getInstance(true)); } // normal case where regular expression argument evaluated to null is to throw an error else { Console.WriteLine("Error: the sole additional argument item in regular function was null. "); return(Nil.getInstance()); } } } // done with first step in two levels descendents // get rest of fringes while (hasMoreDescendents) { if (args_given.getCdr() == null) { Console.WriteLine("Error: one of the later argument items in regular function was null. "); return(Nil.getInstance()); } // precaution for null pointer so it is legal to use the cdr after this test if (args_given.getCdr().isPair()) { // build new environment for this to be computed for. Environment envExtend2 = new Environment(env1); // get next fringe descendent. args_given = args_given.getCdr(); // start this off as unassigned. Cons added_fringe_con = null; // check if additional eval items are not null Node evalItem_more = args_given.getCar().eval(envExtend2); if (evalItem_more != null) { fringe_cons.setCdr(new Cons(evalItem_more, added_fringe_con)); } else { Console.WriteLine("Error: one of the later argument items in regular function was null. "); return(Nil.getInstance()); } fringe_cons = (Cons)fringe_cons.getCdr(); } else if (args_given.getCdr().isNull()) { fringe_cons.setCdr(Nil.getInstance()); hasMoreDescendents = false; } else { // build new environment for this to be computed for. Environment envExtend2 = new Environment(env1); // get one remaining fringe descendent. args_given = args_given.getCdr(); // check if additional eval items are not null Node evalItem_more = args_given.getCar().eval(envExtend2); if (evalItem_more != null) { fringe_cons.setCdr(new Cons(evalItem_more, Nil.getInstance())); } else { Console.WriteLine("Error: one of the later argument items in regular function was null. "); return(Nil.getInstance()); } hasMoreDescendents = false; } } return(firstElem_car.apply(evaluated_argsList__in_progress)); } return(firstElem_car.apply(Nil.getInstance())); }
// TODO: The method apply() should be defined in class Node // to report an error. It should be overridden only in classes // BuiltIn and Closure. public override Node apply(Node args) { // note for all built in functions that need arguments... // // the function will never do a test to check whether args is a pair, because // args is always made a pair in special Regular for launching builtin_function apply. if (this.symbol.getName().Equals("read")) { if (args == null || !args.isNull()) { Console.WriteLine("Error: Read only needs no arguments for use."); return(Nil.getInstance()); } return((Node)Scheme4101.parser.parseExp()); } else if (this.symbol.getName().Equals("write")) { if (args == null || args.isNull()) { Console.WriteLine("Error: incorrect arguments. Nil passed, which cannot be used."); return(Nil.getInstance()); } args.getCar().print(0); return(Nil.getInstance()); } else if (this.symbol.getName().equals("set-car!")) { arg1.setCar(arg2); return(arg1); } else if (this.symbol.getName().equals("set-cdr!")) { arg1.setCdr(arg2); return(arg1); } else if (this.symbol.getName().Equals("display")) { if (args == null || args.isNull()) { Console.WriteLine("Error: incorrect arguments. Nil passed, which cannot be used."); return(Nil.getInstance()); } Tree.BuiltIn.builtIn_display__do_not_print_double_quotes = true; args.getCar().print(0); Tree.BuiltIn.builtIn_display__do_not_print_double_quotes = false; return(Nil.getInstance()); } else if (this.symbol.getName().Equals("b+")) { // if there are no arguments, report error if (args == null) { Console.WriteLine("Error: no arguments given for binary addition operation."); return(Nil.getInstance()); } // return zero if there are no arguments if (args.isNull()) { return(new IntLit(0)); } // extend for all argument vars // and //check if first args have null if (args.getCar() != null && args.getCdr() != null) { bool twoArguments_or_more; // check if second argument is is nil. if (args.getCdr().isNull()) { twoArguments_or_more = false; } // see if there is a second item , ... and check that last tail of args is nil. else if (args.getCdr().getCar() != null && args.getCdr().getCdr().isNull()) { twoArguments_or_more = true; } else if (args.getCdr().getCar() != null && !args.getCdr().getCdr().isNull()) { Console.WriteLine("Error: cannot process more than two args for binary addition."); return(Nil.getInstance()); } else { Console.WriteLine("Error: in b+ , one of arguments for expression has null node."); return(Nil.getInstance()); } if (twoArguments_or_more == false) { // check if argument is an intLit if (args.getCar().isNumber()) { // return the sole int lit node. return(args.getCar()); } else { Console.WriteLine("Error: in b+ , one of arguments for expression has null node."); return(Nil.getInstance()); } } else { if (!args.getCar().isNumber() || !args.getCdr().getCar().isNumber()) { Console.WriteLine("Error: arguments must be IntLit for binary addition."); return(Nil.getInstance()); } else { IntLit int1 = (IntLit)args.getCar(); IntLit int2 = (IntLit)args.getCdr().getCar(); return(new IntLit(int1.getInt() + int2.getInt())); } } } else { Console.WriteLine("Error: in b+ , there is a null external node"); return(Nil.getInstance()); } } else if (this.symbol.getName().Equals("b-")) { // if there are no arguments, report error if (args == null || args.isNull()) { Console.WriteLine("Error: no arguments given for binary subtraction operation."); return(Nil.getInstance()); } // extend for all argument vars // and //check if any args have null or nil. if (args != null && args.getCar() != null && args.getCdr() != null && args.getCdr().getCar() != null && args.getCdr().getCdr().isNull()) { if (!args.getCar().isNumber() || !args.getCdr().getCar().isNumber()) { Console.WriteLine("Error: arguments must be IntLit for binary subtraction."); return(Nil.getInstance()); } else { IntLit int1 = (IntLit)args.getCar(); IntLit int2 = (IntLit)args.getCdr().getCar(); return(new IntLit(int1.getInt() - int2.getInt())); } } else { Console.WriteLine("Error: more than two arguments for binary subtraction is not permissable."); return(Nil.getInstance()); } } else if (this.symbol.getName().Equals("b*")) { // if there are no arguments, report error if (args == null || args.isNull()) { Console.WriteLine("Error: no arguments given for binary multiplication operation."); return(Nil.getInstance()); } // extend for all argument vars // and //check if any args have null or nil. if (args != null && args.getCar() != null && args.getCdr() != null && args.getCdr().getCar() != null && args.getCdr().getCdr().isNull()) { if (!args.getCar().isNumber() || !args.getCdr().getCar().isNumber()) { Console.WriteLine("Error: arguments must be IntLit for binary multiplication."); return(Nil.getInstance()); } else { IntLit int1 = (IntLit)args.getCar(); IntLit int2 = (IntLit)args.getCdr().getCar(); return(new IntLit(int1.getInt() * int2.getInt())); } } else { Console.WriteLine("Error: more than two arguments for binary multiplication is not permissable."); return(Nil.getInstance()); } } else if (this.symbol.getName().Equals("b/")) { // if there are no arguments, report error if (args == null || args.isNull()) { Console.WriteLine("Error: no arguments given for binary division operation."); return(Nil.getInstance()); } // extend for all argument vars // and //check if any args have null or nil. if (args != null && args.getCar() != null && args.getCdr() != null && args.getCdr().getCar() != null && args.getCdr().getCdr().isNull()) { if (!args.getCar().isNumber() || !args.getCdr().getCar().isNumber()) { Console.WriteLine("Error: arguments must be IntLit for binary division."); return(Nil.getInstance()); } else { IntLit int1 = (IntLit)args.getCar(); IntLit int2 = (IntLit)args.getCdr().getCar(); if (int2.getInt() == 0) { Console.WriteLine("Error: input not acceptable. cannot divide by zero."); return(Nil.getInstance()); } else { return(new IntLit(int1.getInt() / int2.getInt())); } } } else { Console.WriteLine("Error: more than two arguments for binary division is not permissable."); return(Nil.getInstance()); } } else if (this.symbol.getName().Equals("b=")) { // if there are no arguments, report error if (args == null || args.isNull()) { Console.WriteLine("Error: no arguments given for binary equality test operation."); return(Nil.getInstance()); } // extend for all argument vars // and //check if any args have null or nil. if (args != null && args.getCar() != null && args.getCdr() != null && args.getCdr().getCar() != null && args.getCdr().getCdr().isNull()) { if (!args.getCar().isNumber() || !args.getCdr().getCar().isNumber()) { Console.WriteLine("Error: arguments must be IntLit for binary equality test."); return(Nil.getInstance()); } else { IntLit int1 = (IntLit)args.getCar(); IntLit int2 = (IntLit)args.getCdr().getCar(); bool resultOfTest = (int1.getInt() == int2.getInt()); if (resultOfTest) { return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } } } else { Console.WriteLine("Error: more than two arguments for binary equality test is not permissable."); return(Nil.getInstance()); } } else if (this.symbol.getName().Equals("b<")) { // if there are no arguments, report error if (args == null || args.isNull()) { Console.WriteLine("Error: no arguments given for binary less than test operation."); return(Nil.getInstance()); } // extend for all argument vars // and //check if any args have null or nil. if (args != null && args.getCar() != null && args.getCdr() != null && args.getCdr().getCar() != null && args.getCdr().getCdr().isNull()) { if (!args.getCar().isNumber() || !args.getCdr().getCar().isNumber()) { Console.WriteLine("Error: arguments must be IntLit for binary less than test."); return(Nil.getInstance()); } else { IntLit int1 = (IntLit)args.getCar(); IntLit int2 = (IntLit)args.getCdr().getCar(); bool resultOfTest = (int1.getInt() < int2.getInt()); if (resultOfTest) { return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } } } else { Console.WriteLine("Error: more than two arguments for binary less than test is not permissable."); return(Nil.getInstance()); } } else if (this.symbol.getName().Equals("b>")) { // if there are no arguments, report error if (args == null || args.isNull()) { Console.WriteLine("Error: no arguments given for binary greater than test operation."); return(Nil.getInstance()); } // extend for all argument vars // and //check if any args have null or nil. if (args != null && args.getCar() != null && args.getCdr() != null && args.getCdr().getCar() != null && args.getCdr().getCdr().isNull()) { if (!args.getCar().isNumber() || !args.getCdr().getCar().isNumber()) { Console.WriteLine("Error: arguments must be IntLit for binary greater than test."); return(Nil.getInstance()); } else { IntLit int1 = (IntLit)args.getCar(); IntLit int2 = (IntLit)args.getCdr().getCar(); bool resultOfTest = (int1.getInt() > int2.getInt()); if (resultOfTest) { return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } } } else { Console.WriteLine("Error: more than two arguments for binary greater than test is not permissable."); return(Nil.getInstance()); } } else if (this.symbol.getName().Equals("b<=")) { // if there are no arguments, report error if (args == null || args.isNull()) { Console.WriteLine("Error: no arguments given for binary less than equal than test operation."); return(Nil.getInstance()); } // extend for all argument vars // and //check if any args have null or nil. if (args != null && args.getCar() != null && args.getCdr() != null && args.getCdr().getCar() != null && args.getCdr().getCdr().isNull()) { if (!args.getCar().isNumber() || !args.getCdr().getCar().isNumber()) { Console.WriteLine("Error: arguments must be IntLit for binary less than equal than test."); return(Nil.getInstance()); } else { IntLit int1 = (IntLit)args.getCar(); IntLit int2 = (IntLit)args.getCdr().getCar(); bool resultOfTest = (int1.getInt() <= int2.getInt()); if (resultOfTest) { return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } } } else { Console.WriteLine("Error: more than two arguments for binary less than equal than test is not permissable."); return(Nil.getInstance()); } } else if (this.symbol.getName().Equals("b>=")) { // if there are no arguments, report error if (args == null || args.isNull()) { Console.WriteLine("Error: no arguments given for binary greater than equal than test operation."); return(Nil.getInstance()); } // extend for all argument vars // and //check if any args have null or nil. if (args != null && args.getCar() != null && args.getCdr() != null && args.getCdr().getCar() != null && args.getCdr().getCdr().isNull()) { if (!args.getCar().isNumber() || !args.getCdr().getCar().isNumber()) { Console.WriteLine("Error: arguments must be IntLit for binary greater than equal than test."); return(Nil.getInstance()); } else { IntLit int1 = (IntLit)args.getCar(); IntLit int2 = (IntLit)args.getCdr().getCar(); bool resultOfTest = (int1.getInt() >= int2.getInt()); if (resultOfTest) { return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } } } else { Console.WriteLine("Error: more than two arguments for binary greater than equal than test is not permissable."); return(Nil.getInstance()); } } else if (this.symbol.getName().Equals("null?")) { // if there are no arguments, report error if (args == null || args.isNull()) { Console.WriteLine("Error: no arguments given for testing null evaluation."); return(Nil.getInstance()); } // extend for all argument vars // check if number of args is correct bool argument_number_good = false; if (args != null && args.getCar() != null && args.getCdr() != null && args.getCdr().isNull()) { argument_number_good = true; } if (argument_number_good) { if (args.getCar().isNull()) { return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } } else { Console.WriteLine("Error: wrong number of arguments for test. only need 1 cons node with nil tail for argument."); return(Nil.getInstance()); } } else if (this.symbol.getName().Equals("symbol?")) { // if there are no arguments, report error if (args == null || args.isNull()) { Console.WriteLine("Error: no arguments given for testing symbol evaluation."); return(Nil.getInstance()); } // extend for all argument vars // check if number of args is correct bool argument_number_good = false; if (args != null && args.getCar() != null && args.getCdr() != null && args.getCdr().isNull()) { argument_number_good = true; } if (argument_number_good) { if (args.getCar().isSymbol()) { return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } } else { Console.WriteLine("Error: wrong number of arguments for test. only need 1 cons node with nil tail for argument."); return(Nil.getInstance()); } } else if (this.symbol.getName().Equals("number?")) { // if there are no arguments, report error if (args == null || args.isNull()) { Console.WriteLine("Error: no arguments given for testing number evaluation."); return(Nil.getInstance()); } // extend for all argument vars // check if number of args is correct bool argument_number_good = false; if (args != null && args.getCar() != null && args.getCdr() != null && args.getCdr().isNull()) { argument_number_good = true; } if (argument_number_good) { if (args.getCar().isNumber()) { return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } } else { Console.WriteLine("Error: wrong number of arguments for test. only need 1 cons node with nil tail for argument."); return(Nil.getInstance()); } } else if (this.symbol.getName().Equals("boolean?")) { // if there are no arguments, report error if (args == null || args.isNull()) { Console.WriteLine("Error: no arguments given for testing boolean evaluation."); return(Nil.getInstance()); } // extend for all argument vars // check if number of args is correct bool argument_number_good = false; if (args != null && args.getCar() != null && args.getCdr() != null && args.getCdr().isNull()) { argument_number_good = true; } if (argument_number_good) { if (args.getCar().isBool()) { return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } } else { Console.WriteLine("Error: wrong number of arguments for test. only need 1 cons node with nil tail for argument."); return(Nil.getInstance()); } } else if (this.symbol.getName().Equals("procedure?")) { // if there are no arguments, report error if (args == null || args.isNull()) { Console.WriteLine("Error: no arguments given for testing procedure evaluation."); return(Nil.getInstance()); } // extend for all argument vars // check if number of args is correct bool argument_number_good = false; if (args != null && args.getCar() != null && args.getCdr() != null && args.getCdr().isNull()) { argument_number_good = true; } if (argument_number_good) { if (args.getCar().isProcedure()) { return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } } else { Console.WriteLine("Error: wrong number of arguments for test. only need 1 cons node with nil tail for argument."); return(Nil.getInstance()); } } else if (this.symbol.getName().Equals("pair?")) { // if there are no arguments, report error if (args == null || args.isNull()) { Console.WriteLine("Error: no arguments given for testing pair evaluation."); return(Nil.getInstance()); } // extend for all argument vars // check if number of args is correct bool argument_number_good = false; if (args != null && args.getCar() != null && args.getCdr() != null && args.getCdr().isNull()) { argument_number_good = true; } if (argument_number_good) { if (args.getCar().isPair()) { return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } } else { Console.WriteLine("Error: wrong number of arguments for test. only need 1 cons node with nil tail for argument."); return(Nil.getInstance()); } } else if (this.symbol.getName().Equals("environment?")) { // if there are no arguments, report error if (args == null || args.isNull()) { Console.WriteLine("Error: no arguments given for testing environment evaluation."); return(Nil.getInstance()); } // extend for all argument vars // check if number of args is correct bool argument_number_good = false; if (args != null && args.getCar() != null && args.getCdr() != null && args.getCdr().isNull()) { argument_number_good = true; } if (argument_number_good) { if (args.getCar().isEnvironment()) { return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } } else { Console.WriteLine("Error: wrong number of arguments for test. only need 1 cons node with nil tail for argument."); return(Nil.getInstance()); } } else if (this.symbol.getName().Equals("string?")) { // if there are no arguments, report error if (args == null || args.isNull()) { Console.WriteLine("Error: no arguments given for testing string evaluation."); return(Nil.getInstance()); } // extend for all argument vars // check if number of args is correct bool argument_number_good = false; if (args != null && args.getCar() != null && args.getCdr() != null && args.getCdr().isNull()) { argument_number_good = true; } if (argument_number_good) { if (args.getCar().isString()) { return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } } else { Console.WriteLine("Error: wrong number of arguments for test. only need 1 cons node with nil tail for argument."); return(Nil.getInstance()); } } // working on predicate built in : eq? else if (this.symbol.getName().Equals("eq?")) { // if there are no arguments, report error if (args == null || args.isNull()) { Console.WriteLine("Error: no arguments given for eq? test operation."); return(Nil.getInstance()); } // extend for all argument vars // and //check if any args have null or nil. if (args != null && args.getCar() != null && args.getCdr() != null && args.getCdr().getCar() != null && args.getCdr().getCdr().isNull()) { //if (!args.getCar () || !args.getCdr ().getCar () ) // check nil/null? first // first car is nil but second item is not nil... // or the other way around (vice versa) if ((args.getCar().isNull() && !args.getCdr().getCar().isNull()) || (!args.getCar().isNull() && args.getCdr().getCar().isNull())) { return(BoolLit.getInstance(false)); } // success: both nil else if (args.getCar().isNull() && args.getCdr().getCar().isNull()) { return(BoolLit.getInstance(true)); } // first car is type symbol but second item is not symbol... // or the other way around (vice versa) else if ((args.getCar().isSymbol() && !args.getCdr().getCar().isSymbol()) || (!args.getCar().isSymbol() && args.getCdr().getCar().isSymbol())) { return(BoolLit.getInstance(false)); } // check if both symbol now... else if (args.getCar().isSymbol() && args.getCdr().getCar().isSymbol()) { // check if the symbol's are identical if (args.getCar().getName().Equals(args.getCdr().getCar().getName())) { // success: both same symbol! return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } } // first car is type number but second item is not number... // or the other way around (vice versa) else if ((args.getCar().isNumber() && !args.getCdr().getCar().isNumber()) || (!args.getCar().isNumber() && args.getCdr().getCar().isNumber())) { return(BoolLit.getInstance(false)); } // check if both number now... else if (args.getCar().isNumber() && args.getCdr().getCar().isNumber()) { // cast to new IntLits IntLit intLit_1 = (IntLit)args.getCar(); IntLit intLit_2 = (IntLit)args.getCdr().getCar(); // check if the int values's are equal if (intLit_1.getInt() == intLit_2.getInt()) { // success: both same integer! return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } } // first car is type boolean but second item is not boolean... // or the other way around (vice versa) else if ((args.getCar().isBool() && !args.getCdr().getCar().isBool()) || (!args.getCar().isBool() && args.getCdr().getCar().isBool())) { return(BoolLit.getInstance(false)); } // check if both boolean now... else if (args.getCar().isBool() && args.getCdr().getCar().isBool()) { // cast nodes as new booleanNodes BoolLit boolVal1 = (BoolLit)args.getCar(); BoolLit boolVal2 = (BoolLit)args.getCdr().getCar(); // check if the bool's equal if (boolVal1.Equals(boolVal2)) { // success: both same bool! return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } } // first car is type builtIn but second item is not builtIn... // or the other way around (vice versa) else if ((args.getCar().isBuiltIn() && !args.getCdr().getCar().isBuiltIn()) || (!args.getCar().isBuiltIn() && args.getCdr().getCar().isBuiltIn())) { return(BoolLit.getInstance(false)); } // check if both builtIn now... else if (args.getCar().isBuiltIn() && args.getCdr().getCar().isBuiltIn()) { // cast nodes as new builtIn BuiltIn builtIn_val_1 = (BuiltIn)args.getCar(); BuiltIn builtIn_val_2 = (BuiltIn)args.getCdr().getCar(); // check if the builtIn's are identical if (builtIn_val_1.getSymbol().Equals(builtIn_val_2.getSymbol())) { // success: both same builtIn! return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } } // by process of elimination //now // a object that ends up tested here would be surely a closure... // first car is type closure but second item is not closure... // or the other way around (vice versa) else if ((args.getCar().isProcedure() && !args.getCdr().getCar().isProcedure()) || (!args.getCar().isProcedure() && args.getCdr().getCar().isProcedure())) { return(BoolLit.getInstance(false)); } // check if both closure now... else if (args.getCar().isProcedure() && args.getCdr().getCar().isProcedure()) { // cast nodes as new builtIn Closure closure_val_1 = (Closure)args.getCar(); Closure closure_val_2 = (Closure)args.getCdr().getCar(); // check if the closure's are identical if (closure_val_1.Equals(closure_val_2)) { // success: both same closure! return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } } // first car is type environment but second item is not environment... // or the other way around (vice versa) else if ((args.getCar().isEnvironment() && !args.getCdr().getCar().isEnvironment()) || (!args.getCar().isEnvironment() && args.getCdr().getCar().isEnvironment())) { return(BoolLit.getInstance(false)); } // check if both environment now... else if (args.getCar().isEnvironment() && args.getCdr().getCar().isEnvironment()) { // cast nodes as new Environment Environment environ_1 = (Environment)args.getCar(); Environment environ_2 = (Environment)args.getCdr().getCar(); // check if the environment's are identical if (environ_1.Equals(environ_2)) { // success: both same environment! return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } } // first car is type String but second item is not String... // or the other way around (vice versa) else if ((args.getCar().isString() && !args.getCdr().getCar().isString()) || (!args.getCar().isString() && args.getCdr().getCar().isString())) { return(BoolLit.getInstance(false)); } // check if both String now... else if (args.getCar().isString() && args.getCdr().getCar().isString()) { // cast nodes as new StringLits StringLit String_1 = (StringLit)args.getCar(); StringLit String_2 = (StringLit)args.getCdr().getCar(); // check if the StringLit's are identical if (String_1.getString().Equals(String_2.getString())) { // success: both same StringLit! return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } } // eq? test note: there is one caveat. If the items are both quote terms... this will be handled directly in regular eval // first car is type Pair but second item is not Pair... // or the other way around (vice versa) else if ((args.getCar().isPair() && !args.getCdr().getCar().isPair()) || (!args.getCar().isPair() && args.getCdr().getCar().isPair())) { return(BoolLit.getInstance(false)); } // check if both are type Pair now... else if (args.getCar().isPair() && args.getCdr().getCar().isPair()) { // cast nodes as new cons Pair Cons cons_1 = (Cons)args.getCar(); Cons cons_2 = (Cons)args.getCdr().getCar(); // check if the Cons's are identical if (cons_1.Equals(cons_2)) { // success: both same pair reference! return(BoolLit.getInstance(true)); } else { return(BoolLit.getInstance(false)); } // illegal function for argument } else { Console.WriteLine("Error: Argument types for eq? cannot be recognized in context."); return(Nil.getInstance()); } } else { Console.WriteLine("Error: null parameter _ or _ more than two arguments for eq? test is not permissable."); return(Nil.getInstance()); } } else if (this.symbol.getName().Equals("car")) { // if there are no arguments, report error if (args == null || args.isNull()) { Console.WriteLine("Error: no arguments given for car operation."); return(Nil.getInstance()); } // check if args first item given is a pair and check if the number of arguments given is correctly 1 if (args.getCar() != null && args.getCdr() != null && args.getCdr().isNull()) { if (args.getCar().isPair()) { if (args.getCar().getCar() != null) { return(args.getCar().getCar()); } else { Console.WriteLine("Error: for car function_ , one of arguments to return is null."); return(Nil.getInstance()); } } else { Console.WriteLine("Error: for car function_ , item given is not a pair."); return(Nil.getInstance()); } } else { Console.WriteLine("Error: wrong number of arguments for car, tail is not nil. or element in arguments is null."); return(Nil.getInstance()); } } else if (this.symbol.getName().Equals("cdr")) { // if there are no arguments, report error if (args == null || args.isNull()) { Console.WriteLine("Error: no arguments given for cdr operation."); return(Nil.getInstance()); } // check if args first item given is a pair and check if the number of arguments given is correctly 1 if (args.getCar() != null && args.getCar().isPair() && args.getCdr() != null && args.getCdr().isNull()) { // check if argument's cdr is not null if (args.getCar().getCdr() != null) { return(args.getCar().getCdr()); } else { Console.WriteLine("Error: for cdr function_ , one of arguments to return is null."); return(Nil.getInstance()); } } else { Console.WriteLine("Error: for cdr, item is not pair or wrong number of arguments for cdr: tail is not nil. or element in arguments is null."); return(Nil.getInstance()); } } else { Console.WriteLine("Error: builtin is not identifiable."); return(Nil.getInstance()); } }