private static Object Lambda(IEnumerable <Object> data, Environment env) { var argsArray = data.ToArray(); if (argsArray.Length < 2) { throw new System.ArgumentException( $"Wrong number of arguments for lambda: At least 2 expected instead of {argsArray.Length}."); } var formals = data.First(); var body = data.Skip(1); // Assuming formal list only. // TODO: consider other forms. // TODO: validate if items are identifiers. var symbols = (from item in ((ConsCell)formals).GetListItems() select(Symbol) item).ToArray(); return(new Procedure(_args => { // TODO: Validate many things... var lambdaEnv = new Environment(env); for (int i = 0; i < symbols.Length; i++) { lambdaEnv.AddBinding(symbols[i], _args.ElementAt(i)); } Object result = null; foreach (var expression in body) { result = expression.Evaluate(lambdaEnv); } return result; })); }
private static Object Define(IEnumerable <Object> data, Environment env) { var argsArray = data.ToArray(); ValidateArgCount(2, argsArray.Length); // TODO: Other forms. // TODO: Ensure this being called at the top only. var variable = argsArray[0]; if (!(variable is Symbol)) { throw new SyntaxException("Can only define variable."); } var value = argsArray[1].Evaluate(env); env.AddBinding((Symbol)variable, value); return(null); }
private static Object Let(IEnumerable <Object> data, Environment env) // TODO: Replace by Scheme code. { var bindings = (ConsCell)data.First(); var body = data.Skip(1); // Must have at least one. var newEnvironment = new Environment(env); foreach (var binding in bindings.GetListItems()) { var items = ((ConsCell)binding).GetListItems().ToArray(); var variable = (Symbol)items[0]; var init = items[1].Evaluate(env); newEnvironment.AddBinding(variable, init); } Object result = null; foreach (var statement in body) { result = statement.Evaluate(newEnvironment); } return(result); }
private static Object DefineSyntax(IEnumerable <Object> data, Environment env) { var argsArray = data.ToArray(); ValidateArgCount(2, argsArray.Length); // TODO: Other forms. // TODO: Ensure this being called at the top only. var keyword = argsArray[0]; if (!(keyword is Symbol)) { throw new SyntaxException("Can only define variable."); } var transformerSpec = argsArray[1]; var syntaxRules = ((ConsCell)transformerSpec).GetListItems().Skip(2); var ruleSymbols = new List <IEnumerable <Symbol> >(); var ruleTemplates = new List <Object>(); foreach (var syntaxRule in syntaxRules) { var items = ((ConsCell)syntaxRule).GetListItems(); var pattern = items.First(); var symbols = from item in ((ConsCell)pattern).GetListItems().Skip(1) select(Symbol) item; // TODO: Validate: 2 args only. var template = items.ElementAt(1); ruleSymbols.Add(symbols); ruleTemplates.Add(template); } var macro = new Macro((_data, _env) => { // Hack: Match by number of args. var __data = _data.ToArray(); var numberOfSymbols = __data.Length; foreach (var ruleSymbol in ruleSymbols) { var symbols = ruleSymbol.ToArray(); if (symbols.Length == numberOfSymbols) { var template = ruleTemplates[ruleSymbols.IndexOf(ruleSymbol)]; var rules = symbols.Zip(__data, (s, a) => new { Key = s, Value = a }) .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); return(Replace(template, rules).Evaluate(_env)); } var elipsis = new Symbol("..."); if (numberOfSymbols >= symbols.Length - 1 && symbols.Length > 0 && symbols.Last().Equals(elipsis)) { int numberOfExtraSymbols = numberOfSymbols - symbols.Length + 1; var expandedSymbols = from index in Enumerable.Range(0, numberOfExtraSymbols) select new Symbol("_" + index); // Should somehow be unique. symbols = symbols.Take(symbols.Length - 1).Concat(expandedSymbols).ToArray(); var template = ruleTemplates[ruleSymbols.IndexOf(ruleSymbol)]; var expandedTemplate = ReplaceElipsis(template, numberOfExtraSymbols); var rules = symbols.Zip(__data, (s, a) => new { Key = s, Value = a }) .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); return(Replace(expandedTemplate, rules).Evaluate(_env)); } } throw new SyntaxException($"No syntax defined for {numberOfSymbols} args."); }); env.AddBinding((Symbol)keyword, macro); return(null); }