private SExp.SExp EatExpression(IToken startExpToken) { var exp = new SExp.SExp(startExpToken.Line, startExpToken.Column, new List <SExpNode>()); var token = _lexer.Eat(); do { switch (token.Kind) { case TokenKind.StartExpression: exp.Nodes.Add(EatExpression(token)); break; case TokenKind.EndExpression: if (exp.Nodes.Count > 0 && exp.Nodes[0] is Atom atom && atom.Token is IdentifierToken idToken && _systemFunctionTable.TryGet(idToken.Value, out var function)) { exp.Nodes.RemoveAt(0); exp = new FunctionSExp(function, token.Line, token.Column, exp.Nodes); } else if (exp.Nodes.Count > 0) { exp = new FunctionSExp(_systemFunctionTable.Get("list"), token.Line, token.Column, exp.Nodes); } return(exp); case TokenKind.DoubleLiteral: case TokenKind.IntegerLiteral: case TokenKind.StringLiteral: case TokenKind.Identifier: exp.Nodes.Add(new Atom(token.Line, token.Column, token)); break;
private object ExecuteFunction(FunctionSExp fexp) { var args = new Func <object> [fexp.Nodes.Count]; if (fexp.Nodes.Count > 0) { for (var i = 0; i < fexp.Nodes.Count; i++) { var node = fexp.Nodes[i]; Func <object> nodeValueFunc; switch (node) { case FunctionSExp childFExp: nodeValueFunc = () => ExecuteFunction(childFExp); break; case Atom childAtom: if (!(fexp.Function is DefFunction) && !(fexp.Function is DefFuncFunction) && !(fexp.Function is ParamsFunction) && childAtom.Token is IdentifierToken idToken) { nodeValueFunc = () => { if (_scopeManager.Contains(idToken.Value)) { return(_scopeManager.Get(idToken.Value)); } if (_customFunctionTable.Contains(idToken.Value)) { return(_customFunctionTable.GetCustomFunction(idToken.Value)); } if (_systemFunctionTable.TryGet(idToken.Value, out var sysFunc)) { return(sysFunc); } throw new InvalidOperationException($"Unknown identifier '{idToken}'"); }; } else { nodeValueFunc = () => childAtom.Token.Value; } break; // this will be an empty parameter list case SExp.SExp _: nodeValueFunc = () => new object[0]; break; default: throw new InvalidOperationException($"Expected a function or atom but encountered: {node}"); } args[i] = nodeValueFunc; } } CheckCallingArgs(fexp.Function, args); return(fexp.Function.Execute(args)); }