public static EvalResult evaluate_System_Function(SymbolTable symbols, FunCall fun_call) { var fun_name = fun_call.value.value; EvalFunc f = (s,func) => new EvalResult(new Error(fun_call.value.line_num, "Could not match system function!")); switch (fun_name) { case "define": f = add_definition; break; case "+": f = addition; break; case "-": f = subtraction; break; case "*": f = multiplication; break; case "/": f = division; break; case "%": f = mod; break; case "head": f = head; break; case "tail": f = tail; break; case "++": f = cons; break; case "==": f = equality_test; break; case "not": f = not; break; case "&&": f = logical_and; break; case "||": f = logical_or; break; case "<": f = less_than; break; case ">": f = greater_than; break; } return f(symbols, fun_call); }
private static EvalResult gen_function_call_error(FunCall source, int definition_arg_count) { string fun_name = source.value.value; string prefix = (source.args.Count > definition_arg_count) ? "To many " : "To few"; string error_message = prefix + "arguements to " + fun_name + " it takes " + definition_arg_count.ToString(); return new EvalResult(new Error(source.value.line_num, fun_name, error_message)); }
public static EvalResult evaluate_Identity(SymbolTable symbols, FunCall val) { // Evaluate symbol if (val.value != null && val.value.type == Lexical.Symbol && symbols.ContainsKey(val.value.value)) { return evaluate_Identity(symbols, symbols[val.value.value]); } else return new EvalResult(new EvalT(symbols, val)); }
public static EvalResult cons(SymbolTable symbols, FunCall list) { return eval_args(symbols, list, "cons", 2, (s, func) => { var element = func.args[0]; var list_arg = func.args[1]; return new EvalResult(new EvalT(symbols, FunCall.id_list(new List<FunCall> { element, list_arg }))); }); }
public static EvalResult add_definition(SymbolTable symbols, FunCall val) { var new_fun_name = val.args[0].args.First().value.value; var parameters = FunCall.id_list(val.args[0].flattened_args().Skip(1).ToList()); var fun_body = val.args[1]; symbols.Add(new_fun_name, FunCall.id_list(new List<FunCall> { parameters, fun_body })); return new EvalResult(new EvalT(symbols, new FunCall(Token.symbol("Function Defined")))); }
public static EvalResult not(SymbolTable symbols, FunCall funcall) { return eval_args(symbols, funcall, "not", 1, (s, func) => { var result = func.args[0].value; if (result.type != Lexical.Bool) return new EvalResult(new Error(0, "not needs a bool argument!")); else if (result.value == "true") return new EvalResult(new EvalT(symbols, FunCall.id_val(Lexical.Bool, 0, "false"))); else return new EvalResult(new EvalT(symbols, FunCall.id_val(Lexical.Bool, 0, "true"))); }); }
public static EvalResult binary_typeCheck(SymbolTable symbols, FunCall funcall, string funcName, EvalFunc f) { var left = funcall.args[0].value; var right = funcall.args[1].value; Func<Token, bool> isNumber = token => token.type == Lexical.Int || token.type == Lexical.Float; bool areNumbers = isNumber(left) && isNumber(right); if (areNumbers || left.type == right.type) return f(symbols, funcall); else return new EvalResult(new Error(0, "Non-matching types for " + funcName)); }
public static EvalResult list_access(SymbolTable symbols, FunCall list, Func<SymbolTable, FunCall, EvalResult> list_op, string func_name) { return eval_args(symbols, list, func_name, 2, (s, func) => { var list_arg = func.args.First(); if (!isList(list_arg)) return new EvalResult(new Error(0, func_name + " must be called on a list!")); return list_op(symbols, list_arg); }); }
public static EvalResult less_than(SymbolTable symbols, FunCall funcall) { return eval_args(symbols, funcall, "<", 2, (_s, _func) => { return binary_typeCheck(symbols, funcall, "<", (s, func) => { var left = Convert.ToDouble(func.args[0].value.value); var right = Convert.ToDouble(func.args[1].value.value); var result = (left < right).ToString(); return new EvalResult(new EvalT(s, FunCall.id_val(Lexical.Bool, 0, result))); }); }); }
public static EvalResult logical_or(SymbolTable symbols, FunCall funcall) { return eval_args(symbols, funcall, "||", 2, (_s, _func) => { return binary_typeCheck(_s, _func, Lexical.Bool, Lexical.Bool, "||", (s, func) => { var left = func.args[0].value; var right = func.args[1].value; string result = ""; if (left.value == "true" || right.value == "true") result = "true"; else result = "false"; return new EvalResult(new EvalT(s, FunCall.id_val(Lexical.Bool, 0, result))); }); }); }
public static EvalResult math_op(SymbolTable symbols, FunCall fun, Func<Token, double, double> math_op, string func_name) { var args = fun.args.Select(a => evaluate_FunCall(symbols, a)); Func<FunCall, bool> isNumerical = arg => arg.value.type == Lexical.Int || arg.value.type == Lexical.Float; double sum = 0; bool seen_first_val = false; foreach (var arg in fun.args) { FunCall val = arg; if (!isNumerical(val) && symbols.ContainsKey(arg.value.value)) val = symbols[arg.value.value]; if (isNumerical(val)) { if (!seen_first_val) { sum = math_identity(val.value); seen_first_val = true; } else sum = math_op(val.value, sum); } else { string prefix = (val.value.type == Lexical.Symbol) ? "Undefined Symbol" : "Non-numerical value "; string message = prefix + val.ToString() + " given to " + func_name; var error = new Error(fun.value.line_num, val.ToString(), message); return new EvalResult(error); } } var isInt = Regex.IsMatch(sum.ToString(), @".*\.0+"); Token result = isInt ? new Token(Lexical.Int, 0, ((int)sum).ToString()) : new Token(Lexical.Float, 0, sum.ToString()); return new EvalResult(new EvalT(symbols, new FunCall(result))); }
public static EvalResult subtraction(SymbolTable symbols, FunCall fun) { return math_op(symbols, fun, perform_subtraction, "-"); }
public static EvalResult evaluate_FunCall(SymbolTable symbols, FunCall fun) { bool function = fun.value != null && fun.value.type == Lexical.Symbol; if (function) return evaluate_Function(symbols, fun); else return evaluate_Identity(symbols, fun); }
public static EvalResult evaluate_Function(SymbolTable symbols, FunCall fun_call) { var fun_name = fun_call.value.value; if (reserved_symbols.Contains(fun_name)) return evaluate_System_Function(symbols, fun_call); else if (symbols.ContainsKey(fun_name)) return evaluate_User_Function(symbols, fun_call); return null; }
public static EvalResult evaluate_User_Function(SymbolTable symbols, FunCall fun_call) { FunCall definition = symbols[fun_call.value.value]; FunCall funArgs = definition.args[0]; FunCall funBody = definition.args[1]; if (fun_call.args.Count != funArgs.args.Count) return gen_function_call_error(fun_call, funArgs.args.Count); var arg_pairs = funArgs.args.Zip(fun_call.args, (a, b) => new Tuple<FunCall, FunCall>(a, b)); // Bind args and add to symbol table foreach (var arg_pair in arg_pairs) symbols.Add(arg_pair.Item1.value.value, arg_pair.Item2); return evaluate_FunCall(symbols, funBody); }
public static EvalResult eval_args(SymbolTable symbols, FunCall funcall, string funcName, int numArgs, EvalFunc f) { var evaled_args = funcall.args.Select(i => evaluate_FunCall(symbols, i)).ToList(); if (evaled_args.Count() > numArgs) return new EvalResult(new Error(0, "Too many arguments to " + funcName + "!")); if (evaled_args.Count() < numArgs) return new EvalResult(new Error(0, "Too few arguments to " + funcName + "!")); foreach(var result in evaled_args) if (result.left == null) return new EvalResult(result.right); var results = FunCall.id_list(evaled_args.Select(a => a.left.Item2).ToList()); return f(symbols, results); }
public static List<FunCall> id(FunCall value) { return new List<FunCall> { value }; }
public static EvalResult mod(SymbolTable symbols, FunCall fun) { return math_op(symbols, fun, perform_mod, "%"); }
public static EvalResult get_head(SymbolTable symbols, FunCall result_list) { return new EvalResult(new EvalT(symbols, result_list.args_head())); }
public static EvalResult division(SymbolTable symbols, FunCall fun) { return math_op(symbols, fun, perform_division, "/"); }
public static EvalResult head(SymbolTable symbols, FunCall list) { return list_access(symbols, list, get_head, "head"); }
public static bool isList(FunCall list) { return list.value == null; }
public static EvalResult equality_test(SymbolTable symbols, FunCall funcall) { return eval_args(symbols, funcall, "==", 2, (s, func) => { var left = func.args[0]; var right = func.args[1]; string result = ""; switch (left.value.type) { case Lexical.Bool: result = (left.value.value == right.value.value).ToString(); break; case Lexical.Int: case Lexical.Float: result = (Convert.ToDouble(left.value.value) == Convert.ToDouble(right.value.value)).ToString(); break; case Lexical.String: result = (left.value.value == right.value.value).ToString(); break; default: return new EvalResult(new Error(0, "Unknown lex type passed to equality_test")); } return new EvalResult(new EvalT(symbols, FunCall.id_val(Lexical.Bool, 0, result))); }); }
public static EvalResult tail(SymbolTable symbols, FunCall list) { return list_access(symbols, list, get_tail, "tail"); }
public static EvalResult multiplication(SymbolTable symbols, FunCall fun) { return math_op(symbols, fun, perform_multiplication, "*"); }
public static EvalResult get_tail(SymbolTable symbols, FunCall result_list) { var new_list = FunCall.id_list(result_list.args_tail()); return new EvalResult(new EvalT(symbols, new_list)); }
public static EvalResult addition(SymbolTable symbols, FunCall fun) { return math_op(symbols, fun, perform_additon, "+"); }