コード例 #1
0
        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;
            }));
        }
コード例 #2
0
        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);
        }
コード例 #3
0
        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);
        }
コード例 #4
0
        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);
        }