/* * eval sentense like " AND TRUE FALSE" * parameters can be another function call, like AND (AND TRUE TRUE) FALSE * currently eval all parameters before apply to functor * if parameter ( and after eval function all ) does not exist in enviroment, just leave a symbol in it * in order to support IO, add special functor type __io__, which evals special, need to do IOs internally * and in order to support function, add special functor type __function__ * when eval __function__, eval sentenses inside this function until we met a "return" * if a lambda like \(x,y).x , say only one element in body, it's a terminal symbol * else treate first elememt in body as a functor and eval it */ private static EnviromentNode EvalDirectFunctionCall(ParseNode node, Enviroment enviroment, Enviroment closure) { // nodes[0] == 'var' // nodes[1] == symbol // nodes[2] == function body if (node.Nodes.Count < 1) throw new Exception("invalid direct function call"); ParseNode funcBody = node; string lambdaSymbol = funcBody.Nodes[0].Token.Text; EnviromentNode funcNode = closure.LookupSymbol(lambdaSymbol); if (funcNode == null) funcNode = enviroment.LookupSymbol(lambdaSymbol); // before apply parameters to a lambda, eval functor to get a result EvalDelayEvalBlock(funcNode); /* * sentense like * var a = \(x,y).x TRUE FALSE * FIXME */ EnviromentNode[] parameters = new EnviromentNode[funcBody.Nodes.Count - 1]; for (int index = 1; index < funcBody.Nodes.Count; index++) { ParseNode paramNode = funcBody.Nodes[index]; if (paramNode.Token.Type == TokenType.FUNCTION || paramNode.Token.Type == TokenType.IFTHENELSE ) { // parameters[index - 1] = EvalDirectFunctionCall(funcBody.Nodes[index], enviroment, null); DelayEvalBlock block = new DelayEvalBlock(funcBody.Nodes[index], enviroment); parameters[index - 1] = new EnviromentNode(enviroment); parameters[index - 1].AddDelayEvalBlock(block); } else { Token token = funcBody.Nodes[index].Token; EnviromentNode tmp = null; if (token.Type == TokenType.DIGIT) { // like foo 12; tmp = new EnviromentNode(enviroment); tmp.IValue = Int32.Parse(token.Text); tmp.ValueType = "int"; } else if (token.Type == TokenType.STRINGVAL) { // like foo "hello"; tmp = new EnviromentNode(enviroment); tmp.SValue = token.Text.Substring(1, token.Text.Length - 2); tmp.ValueType = "string"; } else if (token.Type == TokenType.LAMBDA) { /* * sentense like * return \(x,y).x * foo \(x,y).x FALSE */ tmp = new EnviromentNode(enviroment); tmp.Type = GetTypeString(funcBody.Nodes[index], null); tmp.Value = GetValueOfLambda(funcBody.Nodes[index]); tmp.GrammerNode = funcBody.Nodes[index]; tmp.ValueType = "lambda"; } else { // like foo a b; tmp = enviroment.LookupSymbol(token.Text); if (tmp == null) { tmp = new EnviromentNode(null); tmp.Symbol = token.Text; } } parameters[index - 1] = tmp; } } EnviromentNode result = null; if (funcNode.Type == "__io__") { result = ApplyIO(funcNode, parameters, enviroment); } else if (funcNode.Type == "__function__") { result = ApplyFunction(funcNode, parameters, enviroment); } else if (funcNode.Type == "__buildin__") { result = ApplyBuildinFunction(funcNode, parameters, enviroment); } else // lambda { if (parameters.Length == 0) { result = closure.LookupSymbol(lambdaSymbol); if (result == null) result = enviroment.LookupSymbol(lambdaSymbol); } else result = ApplyToLambda(lambdaSymbol, parameters, enviroment, funcNode.Enviroment); } return result; }
/* * apply parameters to a lambda * create a new enviroment block, add all parameter symbol into this enviroment * then bind parameters with these symbol * for example we have symbols in upper table: TRUE = \(x,y).x; FALSE = \(x,y).y; AND = \(p,q).p q FALSE; * then we want to eval "a = AND TRUE FALSE"; we call ApplyToLambda( AND, {TRUE, FALSE}, env) * what should be done in ApplyToLambda is * 1. create new enviroment block * 2. p bind to TRUE; q bind to FALSE * 3. call ApplyToLambda(p, {q, FALSE}) which is equal to ApplyToLambda(TRUE, {FALSE, FALSE}) * do 1-3 until we meet a terminal symbol * */ private static EnviromentNode ApplyToLambda(string lambdaSymbol, EnviromentNode[] parameters, Enviroment enviroment, Enviroment closure) { EnviromentNode lambda = enviroment.LookupSymbol(lambdaSymbol); if (lambda == null) throw new Exception("unknow symbol: " + lambdaSymbol); EvalDelayEvalBlock(lambda); // bind parameter to enviroment Enviroment newEnviro = new Enviroment(enviroment); EnviromentBlock block = new EnviromentBlock(); newEnviro.AddEnviroment(block); ParseNode paramNodes = null; if (lambda.GrammerNode.Token.Type != TokenType.LAMBDA) { paramNodes = lambda.GrammerNode.Nodes[2]; } else { paramNodes = lambda.GrammerNode; } BindParameterToEnviroment(parameters, newEnviro, paramNodes.Nodes[0]); return EvalDirectFunctionCall(paramNodes.Nodes[1], newEnviro, closure); }