public Node define(Node id, Node val) { Node oldVal = find(id, frame); if (oldVal != null) { // id exists in environment, update the value oldVal.setCar(val); return(new StringLit("no values returned.")); } else { // Add the new frame to the environment (front of the association list) Node newFrame = new Cons(new Cons(id, new Cons(val, null)), null); // New variable for clarity newFrame.setCdr(frame); frame = newFrame; return(new StringLit("no values returned.")); } }
// 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())); }
public override Node eval(Node node1, Environment env1) { // set up environment for scope of this let body Environment current_env_of_let = new Environment(env1); bool need_to_make_bindings = true; // this will hold the list of evaluated arguments cumulatively. // dummy value to start with Cons evaluated_argsList__in_progress = new Cons(new IntLit(1), Nil.getInstance()); // check if there are items to assign to environment... // and // check if there is an body item for evaluation of let. if (node1.getCdr() != null && node1.getCdr().isPair() && node1.getCdr().getCar() != null && node1.getCdr().getCdr() != null && node1.getCdr().getCdr().isPair()) { // Make a list of values to be bound to keys given... // __list_of_terms Node current_lead_binding_node = node1.getCdr().getCar(); // this will hold the list of evaluated arguments cumulatively. // Cons evaluated_argsList__in_progress; // assign a dummy value Cons current_fringe_of_argList = new Cons(new IntLit(1), Nil.getInstance()); bool has_more_bindings_in_list = true; // this is the case that there are no items to be associated in Frame. if (current_lead_binding_node.isNull() || !current_lead_binding_node.isPair()) { has_more_bindings_in_list = false; // now it is not necessary to bind anything need_to_make_bindings = false; } bool first_run = true; while (has_more_bindings_in_list) { if (current_lead_binding_node == null) { Console.WriteLine("Error: in Let, one of items in terms being bound has null lead node."); return(Nil.getInstance()); } //stopping criteria if (current_lead_binding_node.isNull()) { has_more_bindings_in_list = false; break; } // get values if otherwise if (current_lead_binding_node.isPair()) { Node current_key_value_pair_item = current_lead_binding_node.getCar(); // check if this term is null or empty list if (current_key_value_pair_item == null || current_key_value_pair_item.isNull()) { Console.WriteLine("Error: in Let, one of key value pairs is either null or an empty list , nil."); return(Nil.getInstance()); } // check if this term is not a pair if (!current_key_value_pair_item.isPair()) { Console.WriteLine("Error: in Let, one of key value pairs is not a key value pair cons node."); return(Nil.getInstance()); } // get evaluated value here Node node_to_add; if (current_key_value_pair_item.getCdr() != null && !current_key_value_pair_item.getCdr().isNull() && current_key_value_pair_item.getCdr().isPair()) { // first check if there is the right number of value, namely just one if (current_key_value_pair_item.getCdr().getCdr() == null || !current_key_value_pair_item.getCdr().getCdr().isNull()) { Console.WriteLine("Error: in let function call,... one of key value pairs has more than one value or a null for a tail."); return(Nil.getInstance()); } // check if item holding value is an expression that needs to be evaluated if (current_key_value_pair_item.getCdr().getCar() != null && current_key_value_pair_item.getCdr().getCar().isPair()) { // build new environment for this to be computed for. Environment envExtend = new Environment(current_env_of_let); node_to_add = current_key_value_pair_item.getCdr().getCar().eval(envExtend); } // lookup value from symbol in next case... else if (current_key_value_pair_item.getCdr().getCar() != null && !current_key_value_pair_item.getCdr().getCar().isNull() && current_key_value_pair_item.getCdr().getCar().isSymbol()) { node_to_add = current_env_of_let.lookup(current_key_value_pair_item.getCdr().getCar()); if (node_to_add == null) { Console.WriteLine("Error: one of values being bound in let is undefined in lookup, and thus null."); return(Nil.getInstance()); } // case where value is not an expression or a symbol, but only a literal } else if (current_key_value_pair_item.getCdr().getCar() != null) { node_to_add = current_key_value_pair_item.getCdr().getCar(); } else { Console.WriteLine("Error: one of values being bound in let is null."); return(Nil.getInstance()); } } else { Console.WriteLine("Error: in Let, one of items that should represent value, in a key value pair, is null or holds no value."); return(Nil.getInstance()); } // add latest value of key value pairs to cumulative list of values if (first_run) { evaluated_argsList__in_progress = new Cons(node_to_add, Nil.getInstance()); current_fringe_of_argList = evaluated_argsList__in_progress; first_run = false; } else { current_fringe_of_argList.setCdr(new Cons(node_to_add, Nil.getInstance())); current_fringe_of_argList = (Cons)current_fringe_of_argList.getCdr(); } // increment to next fringe key value pair item... current_lead_binding_node = current_lead_binding_node.getCdr(); } else { Console.WriteLine("Error: in Let, one of bindings does not have cons format."); return(Nil.getInstance()); } } } else { Console.WriteLine("Error: In let expression, ... either not enought arguments given , or null node encountered."); return(Nil.getInstance()); } if (need_to_make_bindings) { // bind each variable in key value pair // current pair of all terms being binding Node current_binding_node = node1.getCdr().getCar(); // current fring of value list Node current_fringe_of_list_of_values = evaluated_argsList__in_progress; // this will hold the list of evaluated arguments cumulatively. //Cons evaluated_argsList__in_progress; bool more_key_val_pairs_to_bind = true; while (more_key_val_pairs_to_bind) { if (current_binding_node == null) { Console.WriteLine("Error: one of key value pairs lead node is null"); return(Nil.getInstance()); } if (current_binding_node.isNull()) { more_key_val_pairs_to_bind = false; break; } if (current_binding_node.isPair()) { if (current_binding_node.getCar() == null || current_binding_node.getCar().isNull()) { Console.WriteLine("Error: in Let, one of key value pairs is either null or an empty list , nil."); return(Nil.getInstance()); } else if (!current_binding_node.getCar().isPair()) { Console.WriteLine("Error: in Let, one of bindings does not have cons format."); return(Nil.getInstance()); // go into binding association list } else if (current_binding_node.getCar().isPair()) { if (current_binding_node.getCar().getCar() == null) { Console.WriteLine("Error: in Let, one of key/symbol fields is null."); return(Nil.getInstance()); } // check if this key is actually an identifier. else if (current_binding_node.getCar().getCar().isSymbol()) { current_env_of_let.define(current_binding_node.getCar().getCar(), current_fringe_of_list_of_values.getCar()); current_fringe_of_list_of_values = current_fringe_of_list_of_values.getCdr(); current_binding_node = current_binding_node.getCdr(); } else { Console.WriteLine("Error: in Let, one of keys is not an identifier."); return(Nil.getInstance()); } } } else { Console.WriteLine("Error: in Let, pair field outer group does not have cons format."); return(Nil.getInstance()); } } } // jump ahead to body function expression of let. Node current_locale_of_body = node1.getCdr().getCdr(); if (current_locale_of_body == null) { Console.WriteLine("Error: Let's body is Null"); return(Nil.getInstance()); } // then check if the nil at list end without having anything fulfilled. // also check to rule out there not being a child a cons node. else if (current_locale_of_body.isNull() || !current_locale_of_body.isPair()) { Console.WriteLine("Error: no arguments for evaluating in Begin statement ."); return(Nil.getInstance()); } // start loop that flips through elements until we get at the last destination expression. else { // initialize the item that may be returned. Node returnItem; // set a conditional and (on hold prospect) return element. if (current_locale_of_body.getCar() == null) { Console.WriteLine("Error: one of expressions in begin's arguments null ."); return(Nil.getInstance()); } else { returnItem = current_locale_of_body.getCar().eval(current_env_of_let); } bool hasAdditionalExp = false; Node one_further_outExtending_tail = current_locale_of_body.getCdr(); // set one item extra in store of members of set of further tail items... // if it is something to start a third part in a chain of further tail cycle. // & nil term test if (one_further_outExtending_tail != null && !one_further_outExtending_tail.isNull()) { if (!one_further_outExtending_tail.isPair()) { Console.WriteLine("Error: one of tail expressions is not in correct pair procession ."); return(Nil.getInstance()); } else if (one_further_outExtending_tail.getCar() == null) { Console.WriteLine("Error: one of expressions in begin's arguments null ."); return(Nil.getInstance()); } else { // set a conditional and (on hold prospect) return element. returnItem = one_further_outExtending_tail.getCar().eval(current_env_of_let); hasAdditionalExp = true; } } // terminates with current return item. // because cant go further in chain for begin expression chain else if (one_further_outExtending_tail != null && one_further_outExtending_tail.isNull()) { hasAdditionalExp = false; // end return(returnItem); } else // ends here with error { Console.WriteLine("Error: Null encountered further on in Begin's expressions."); return(Nil.getInstance()); } // loops over each expression leading up to last. while (hasAdditionalExp) { // set end now. if (one_further_outExtending_tail.getCdr() != null && one_further_outExtending_tail.getCdr().isNull()) { //end hasAdditionalExp = false; } // go to next in sequence of cdr's else if (one_further_outExtending_tail.getCdr() != null && !one_further_outExtending_tail.getCdr().isNull()) { if (!one_further_outExtending_tail.getCdr().isPair()) { Console.WriteLine("Error: one of expressions is not in correct pair procession ."); return(Nil.getInstance()); } else if (one_further_outExtending_tail.getCdr().getCar() == null) { Console.WriteLine("Error: one of expressions in begin's arguments null ."); return(Nil.getInstance()); } else { // set a conditional and (on hold prospect) return element. returnItem = one_further_outExtending_tail.getCdr().getCar().eval(current_env_of_let); hasAdditionalExp = true; // increment to next in sequence of cdr's one_further_outExtending_tail = one_further_outExtending_tail.getCdr(); } } else // ends here with error { Console.WriteLine("Error: Null encountered further on in Begin's expressions."); return(Nil.getInstance()); } } // while loop ended return(returnItem); } }