Beispiel #1
0
        public static List <Atom> PrepareStandardArgumentList(List <Atom> SourceArguments, List <TokenAtom> ArgumentNames, EvaluationContext Context)
        {
            var argumentList     = new List <Atom>();
            var destinationIndex = 0;
            var sourceIndex      = 1;

            while (destinationIndex < ArgumentNames.Count && sourceIndex < SourceArguments.Count)
            {
                var destinationArgument = ArgumentNames[destinationIndex];
                var source = SourceArguments[sourceIndex];
                ++sourceIndex;
                var expandedArgument = EvaluateArguments(source, destinationArgument, Context);

                foreach (var argument in expandedArgument)
                {
                    if (destinationIndex >= ArgumentNames.Count)
                    {
                        throw new EvaluationError("Too many arguments to function.");
                    }
                    destinationArgument = ArgumentNames[destinationIndex];
                    List <Atom> addTo = null;

                    if (destinationArgument.Value.StartsWith("+") || destinationArgument.Value.StartsWith("*"))
                    {
                        if (destinationIndex == argumentList.Count)
                        {
                            var listArg = new ListAtom()
                            {
                                Value = new List <Atom>()
                            };
                            addTo = listArg.Value;
                            argumentList.Add(listArg);
                        }
                        else
                        {
                            var listArg = argumentList.Last() as ListAtom;
                            if (listArg == null)
                            {
                                throw new InvalidOperationException();
                            }
                            addTo = listArg.Value;
                        }
                    }
                    else
                    {
                        addTo = argumentList;
                        ++destinationIndex;
                    }

                    addTo.Add(argument);
                }
            }

            while (argumentList.Count < ArgumentNames.Count)
            {
                var destinationArgument = ArgumentNames[argumentList.Count];
                if (destinationArgument.Value.StartsWith("*"))
                {
                    argumentList.Add(new ListAtom()
                    {
                        Value = new List <Atom>()
                    });
                }
                else
                {
                    throw new EvaluationError("Not enough arguments to function.");
                }
            }

            if (sourceIndex < SourceArguments.Count)
            {
                throw new EvaluationError("Too many arguments to function.");
            }
            if (argumentList.Count != ArgumentNames.Count)
            {
                throw new EvaluationError("Incorrect number of arguments to function.");
            }
            if (ArgumentNames.Count > 0 && ArgumentNames.Last().Value.StartsWith("+"))
            {
                var listArg = argumentList.Last() as ListAtom;
                if (listArg == null)
                {
                    throw new InvalidOperationException();
                }
                if (listArg.Value.Count == 0)
                {
                    throw new EvaluationError("+ argument demands at least one argument.");
                }
            }

            return(argumentList);
        }
Beispiel #2
0
        private static Atom ParseAtom(StringIterator Iterator)
        {
            if (Iterator.AtEnd)
            {
                return(null);
            }

            while (Iterator.Next == ';')
            {
                while (!Iterator.AtEnd && Iterator.Next != '\n')
                {
                    Iterator.Advance();
                }
                Iterator.SkipWhitespace();
                if (Iterator.AtEnd)
                {
                    return(null);
                }
            }

            var  modifier = Modifier.None;
            Atom result   = null;

            if (Iterator.Next == '\'')
            {
                Iterator.Advance();
                modifier = Modifier.Quote;
            }
            else if (Iterator.Next == '$')
            {
                Iterator.Advance();
                modifier = Modifier.Expand;
            }
            else if (Iterator.Next == ':')
            {
                Iterator.Advance();
                modifier = Modifier.Evaluate;
            }

            if (Iterator.AtEnd)
            {
                throw new ParseError("Unexpected end of input", Iterator.place);
            }

            if (Iterator.Next == '(')
            {
                Iterator.Advance();
                Iterator.SkipWhitespace();

                var list = new ListAtom {
                    Value = new List <Atom>()
                };

                while (!Iterator.AtEnd && Iterator.Next != ')')
                {
                    list.Value.Add(ParseAtom(Iterator));
                    Iterator.SkipWhitespace();
                }

                Iterator.Advance();
                result = list;
            }
            else if (Iterator.Next == '[')
            {
                if (modifier != Modifier.None)
                {
                    throw new ParseError("Modifiers not allowed on record.", Iterator.place);
                }

                Iterator.Advance();
                Iterator.SkipWhitespace();

                var record = new RecordAtom();
                while (!Iterator.AtEnd && Iterator.Next != ']')
                {
                    var listItem = ParseAtom(Iterator) as ListAtom;
                    if (listItem == null)
                    {
                        throw new ParseError("Expected list inside record", Iterator.place);
                    }
                    if (listItem.Value.Count != 2)
                    {
                        throw new ParseError("Malformed record", Iterator.place);
                    }
                    var entryName = listItem.Value[0] as TokenAtom;
                    if (entryName == null)
                    {
                        throw new ParseError("Malformed record", Iterator.place);
                    }
                    record.Variables.Upsert(entryName.Value, listItem.Value[1]);
                }

                Iterator.Advance();
                record.Literal = true;
                result         = record;
            }
            else if ("0123456789-".Contains(Iterator.Next))
            {
                if (modifier != Modifier.None)
                {
                    throw new ParseError("Modifiers not allowed on literals.", Iterator.place);
                }
                result = ParseNumber(Iterator);
            }
            else if (Iterator.Next == '\"')
            {
                if (modifier != Modifier.None)
                {
                    throw new ParseError("Modifiers not allowed on literals.", Iterator.place);
                }
                result = ParseString(Iterator);
            }
            else
            {
                result = ParseToken(Iterator);
                if (result.Type == AtomType.Token && (result as TokenAtom).Value == "nil")
                {
                    result = new NilAtom();
                }
            }


            Iterator.SkipWhitespace();

            if (!Iterator.AtEnd && Iterator.Next == '.')
            {
                Iterator.Advance();
                Iterator.SkipWhitespace();
                var member = ParseAtom(Iterator);

                if (member.Modifier == Modifier.Expand)
                {
                    throw new ParseError("Modifier illegal in this context", Iterator.place);
                }

                result = TransformMemberAccess(new MemberAtom
                {
                    Lhs = result,
                    Rhs = member
                });
            }

            result.Modifier = modifier;

            return(result);
        }
Beispiel #3
0
        public static void InitiateCore(Action <String> StandardOutput)
        {
            CoreFunctions = new List <CoreFunction>();

            #region Vitals

            AddCoreFunction("parse str", (args, c) =>
            {
                if (args[0].Type != AtomType.String)
                {
                    throw new EvaluationError("Expected string as first argument to parse.");
                }
                return(Parse(new StringIterator((args[0] as StringAtom).Value)));
            });

            AddCoreFunction("eval atom", (args, c) =>
            {
                return(args[0].Evaluate(c));
            });

            #endregion

            #region Equality and Comparison

            AddCoreFunction("= +args", (args, c) =>
            {
                var values = (args[0] as ListAtom).Value;
                var type   = values[0].Type;
                foreach (var v in values)
                {
                    if (v.Type != type)
                    {
                        return new IntegerAtom {
                            Value = 0
                        }
                    }
                    ;
                    switch (values[0].Type)
                    {
                    case AtomType.Decimal:
                        if ((v as DecimalAtom).Value != (values[0] as DecimalAtom).Value)
                        {
                            return new IntegerAtom {
                                Value = 0
                            }
                        }
                        ;

                        break;

                    case AtomType.Integer:
                        if ((v as IntegerAtom).Value != (values[0] as IntegerAtom).Value)
                        {
                            return new IntegerAtom {
                                Value = 0
                            }
                        }
                        ;
                        break;

                    case AtomType.String:
                        if ((v as StringAtom).Value != (values[0] as StringAtom).Value)
                        {
                            return new IntegerAtom {
                                Value = 0
                            }
                        }
                        ;
                        break;

                    case AtomType.Token:
                        if ((v as TokenAtom).Value != (values[0] as TokenAtom).Value)
                        {
                            return new IntegerAtom {
                                Value = 0
                            }
                        }
                        ;
                        break;

                    case AtomType.Function:
                    case AtomType.List:
                    case AtomType.Record:
                        if (!Object.ReferenceEquals(v, values[0]))
                        {
                            return new IntegerAtom {
                                Value = 0
                            }
                        }
                        ;
                        break;
                    }
                }

                return(new IntegerAtom {
                    Value = 1
                });
            });

            #endregion

            #region Branches

            AddCoreFunction("if condition 'then 'else", (args, c) =>
            {
                var branch = args[1];
                if (args[0].Type != AtomType.Integer || (args[0] as IntegerAtom).Value == 0)
                {
                    branch = args[2];
                }
                return(branch.Evaluate(c));
            });

            #endregion

            #region Basic Math

            AddCoreFunction("+ +value", (args, c) =>
            {
                var realArgs = (args[0] as ListAtom).Value;
                foreach (var v in realArgs)
                {
                    if (v.Type != AtomType.Integer && v.Type != AtomType.Decimal)
                    {
                        throw new EvaluationError("Incorrect argument type passed to +");
                    }
                }
                if (realArgs.Count(v => v.Type == AtomType.Decimal) > 0)
                {
                    var sum = 0.0f;
                    foreach (var v in realArgs)
                    {
                        if (v.Type == AtomType.Integer)
                        {
                            sum += (v as IntegerAtom).Value;
                        }
                        else
                        {
                            sum += (v as DecimalAtom).Value;
                        }
                    }
                    return(new DecimalAtom {
                        Value = sum
                    });
                }
                else
                {
                    var sum = 0;
                    foreach (var v in realArgs)
                    {
                        sum += (v as IntegerAtom).Value;
                    }
                    return(new IntegerAtom {
                        Value = sum
                    });
                }
            });

            #endregion

            #region Output

            AddCoreFunction("print +arg", (args, c) =>
            {
                var builder = new StringBuilder();
                foreach (var v in (args[0] as ListAtom).Value)
                {
                    v.Emit(builder);
                }
                StandardOutput(builder.ToString());
                return(new StringAtom {
                    Value = builder.ToString()
                });
            });

            AddCoreFunction("format string *arg", (args, c) =>
            {
                if (args[0].Type != AtomType.String)
                {
                    throw new EvaluationError("First argument to format is not a string.");
                }
                var s = (args[0] as StringAtom).Value;
                var a = (args[1] as ListAtom).Value.Select(v => v.GetSystemValue()).ToArray();
                var r = String.Format(s, a);
                return(new StringAtom {
                    Value = r
                });
            });

            #endregion

            #region Functions

            AddCoreFunction("func 'args 'body", (args, c) =>
            {
                if (args[0].Type != AtomType.List)
                {
                    throw new EvaluationError("Expected list of argument names as first argument to func.");
                }

                var function = new FunctionAtom();
                function.DeclarationScope = c.ActiveScope;
                function.Implementation   = args[1];
                function.ArgumentNames    = new List <TokenAtom>();

                foreach (var argumentName in (args[0] as ListAtom).Value)
                {
                    if (argumentName.Type != AtomType.Token)
                    {
                        throw new EvaluationError("Malformed argument list in func.");
                    }
                    if (argumentName.Modifier == Modifier.Expand)
                    {
                        throw new EvaluationError("Expand modifier illegal on argument name in func.");
                    }
                    if (argumentName.Modifier == Modifier.Evaluate)
                    {
                        throw new EvaluationError("Evaluate modifier illegal on argument name in func.");
                    }
                    function.ArgumentNames.Add(argumentName as TokenAtom);
                }

                return(function);
            });

            AddCoreFunction("set-decl-scope func scope", (args, c) =>
            {
                if (args[0].Type != AtomType.Function)
                {
                    throw new EvaluationError("Expected function as first argument to set-decl-scope.");
                }
                if (args[1].Type != AtomType.Record)
                {
                    throw new EvaluationError("Expected record as second argument to set-decl-scope.");
                }
                (args[0] as FunctionAtom).DeclarationScope = (args[1] as RecordAtom);
                return(args[0]);
            });

            #endregion

            #region Scope And Memory

            AddCoreFunction("let 'name value", (args, c) =>
            {
                if (args[0].Type != AtomType.Token)
                {
                    throw new EvaluationError("Expected argument name as first argument to let.");
                }
                c.ActiveScope.Variables.Upsert((args[0] as TokenAtom).Value, args[1]);
                return(args[1]);
            });

            AddCoreFunction("with 'vars 'code", (args, c) =>
            {
                if (args[0].Type != AtomType.List)
                {
                    throw new EvaluationError("Expected variable set as first argument to with.");
                }

                var scope = new RecordAtom {
                    Variables = new Dictionary <string, Atom>(), Parent = c.ActiveScope
                };
                foreach (var variable in (args[0] as ListAtom).Value)
                {
                    if (variable.Type != AtomType.List || (variable as ListAtom).Value.Count != 2)
                    {
                        throw new EvaluationError("Expected pairs in variable set in first argument to with.");
                    }
                    var name  = (variable as ListAtom).Value[0];
                    var value = (variable as ListAtom).Value[1];
                    if (name.Type != AtomType.Token)
                    {
                        throw new EvaluationError("Expected variable name in pair in first argument to with.");
                    }
                    scope.Variables.Upsert((name as TokenAtom).Value, value.Evaluate(c));
                }

                c.ActiveScope = scope;
                Atom result   = null;
                try
                {
                    result = args[1].Evaluate(c);
                }
                finally
                {
                    c.ActiveScope = scope.Parent;
                }
                return(result);
            });

            #endregion

            #region Records

            AddCoreFunction("set object 'name value", (args, c) =>
            {
                if (args[0].Type != AtomType.Record)
                {
                    throw new EvaluationError("First argument to set must be a record.");
                }

                if (args[1].Type != AtomType.Token)
                {
                    throw new EvaluationError("Expected member name as second argument to set.");
                }

                (args[0] as RecordAtom).Variables.Upsert((args[1] as TokenAtom).Value, args[2]);
                return(args[2]);
            });

            AddCoreFunction("multi-set object '*pairs", (args, c) =>
            {
                if (args[0].Type != AtomType.Record)
                {
                    throw new EvaluationError("Expected record as first argument to multi-set.");
                }

                foreach (var pair in (args[1] as ListAtom).Value)
                {
                    if (pair.Type != AtomType.List)
                    {
                        throw new EvaluationError("Expected lists as repeating arguments to multi-set.");
                    }
                    var list = pair as ListAtom;
                    if (list.Value.Count != 2)
                    {
                        throw new EvaluationError("Expected pairs as repeating arguments to multi-set.");
                    }
                    if (list.Value[0].Type != AtomType.Token)
                    {
                        throw new EvaluationError("Expected token as first value in pair as repeating arguments to multi-set.");
                    }
                    var value = list.Value[1].Evaluate(c);
                    (args[0] as RecordAtom).Variables.Upsert((list.Value[0] as TokenAtom).Value, value);
                }

                return(args[0]);
            });

            AddCoreFunction("get object 'name", (args, c) =>
            {
                if (args[0].Type != AtomType.Record)
                {
                    throw new EvaluationError("First argument to get must be a record.");
                }
                if (args[1].Type != AtomType.Token)
                {
                    throw new EvaluationError("Expected member name as second argument to get.");
                }

                Atom value;
                if ((args[0] as RecordAtom).Variables.TryGetValue((args[1] as TokenAtom).Value, out value))
                {
                    return(value);
                }
                else
                {
                    throw new EvaluationError("Member not found on record.");
                }
            });

            #endregion

            #region Lists

            AddCoreFunction("list *values", (args, c) =>
            {
                return(args[0]);    // :D!!!!
            });

            AddCoreFunction("length list-or-string", (args, c) =>
            {
                if (args[0].Type == AtomType.List)
                {
                    return new IntegerAtom {
                        Value = (args[0] as ListAtom).Value.Count
                    }
                }
                ;
                else if (args[0].Type == AtomType.String)
                {
                    return new IntegerAtom {
                        Value = (args[0] as StringAtom).Value.Length
                    }
                }
                ;
                else
                {
                    throw new EvaluationError("Expected list or string as first argument to length.");
                }
            });

            AddCoreFunction("index-get list index", (args, c) =>
            {
                if (args[1].Type != AtomType.Integer)
                {
                    throw new EvaluationError("Expected integer index as second argument to index-get.");
                }
                if (args[0].Type == AtomType.List)
                {
                    return((args[0] as ListAtom).Value[(args[1] as IntegerAtom).Value]);
                }
                else if (args[0].Type == AtomType.String)
                {
                    return new IntegerAtom {
                        Value = (args[0] as StringAtom).Value[(args[1] as IntegerAtom).Value]
                    }
                }
                ;
                else
                {
                    throw new EvaluationError("Expected list or string as first argument to index-get.");
                }
            });

            AddCoreFunction("replace-at list index value", (args, c) =>
            {
                if (args[1].Type != AtomType.Integer)
                {
                    throw new EvaluationError("Expected integer index as second argument to replace-at.");
                }
                if (args[0].Type != AtomType.List)
                {
                    throw new EvaluationError("Expected list as first argument to replace-at.");
                }
                var r = new ListAtom {
                    Value = new List <Atom>((args[0] as ListAtom).Value)
                };
                r.Value[(args[1] as IntegerAtom).Value] = args[2];
                return(r);
            });

            AddCoreFunction("array count 'code", (args, c) =>
            {
                var count = args[0];
                if (count.Type != AtomType.Integer)
                {
                    throw new EvaluationError("Expected integer count as first argument to array.");
                }

                var r = new ListAtom()
                {
                    Value = new List <Atom>()
                };
                for (int i = 0; i < (count as IntegerAtom).Value; ++i)
                {
                    r.Value.Add(args[1].Evaluate(c));
                }
                return(r);
            });

            AddCoreFunction("last +list", (args, c) =>
            {
                return((args[0] as ListAtom).Value.Last());
            });

            #endregion

            #region List Manipulations

            AddCoreFunction("map 'x list 'code", (args, c) =>
            {
                if (args[0].Type != AtomType.Token)
                {
                    throw new EvaluationError("Expected argument name as first argument to map.");
                }
                if (args[1].Type != AtomType.List)
                {
                    throw new EvaluationError("Expected list as second argument to map.");
                }

                var scope = new RecordAtom {
                    Parent = c.ActiveScope
                };
                c.ActiveScope = scope;
                var r         = new List <Atom>();

                foreach (var v in (args[1] as ListAtom).Value)
                {
                    scope.Variables.Upsert((args[0] as TokenAtom).Value, v);
                    r.Add(args[2].Evaluate(c));
                }

                c.ActiveScope = scope.Parent;
                return(new ListAtom {
                    Value = r
                });
            });

            AddCoreFunction("where 'x list 'code", (args, c) =>
            {
                if (args[0].Type != AtomType.Token)
                {
                    throw new EvaluationError("Expected argument name as first argument to where.");
                }
                if (args[1].Type != AtomType.List)
                {
                    throw new EvaluationError("Expected list as second argument to where.");
                }

                var scope = new RecordAtom {
                    Parent = c.ActiveScope
                };
                c.ActiveScope = scope;
                var r         = new List <Atom>();

                foreach (var v in (args[1] as ListAtom).Value)
                {
                    scope.Variables.Upsert((args[0] as TokenAtom).Value, v);
                    var testResult = args[2].Evaluate(c);
                    if (testResult.Type == AtomType.Integer && (testResult as IntegerAtom).Value != 0)
                    {
                        r.Add(v);
                    }
                }

                c.ActiveScope = scope.Parent;
                return(new ListAtom {
                    Value = r
                });
            });

            AddCoreFunction("for 'v from to 'code", (args, c) =>
            {
                if (args[0].Type != AtomType.Token)
                {
                    throw new EvaluationError("Expected argument name as first argument to for.");
                }
                if (args[1].Type != AtomType.Integer)
                {
                    throw new EvaluationError("Expected minimum index as second argument to for.");
                }
                if (args[2].Type != AtomType.Integer)
                {
                    throw new EvaluationError("Expected maximum exclusive index as third argument to for.");
                }

                Atom v    = new NilAtom();
                var scope = new RecordAtom {
                    Parent = c.ActiveScope
                };
                c.ActiveScope = scope;

                for (int i = (args[1] as IntegerAtom).Value; i < (args[2] as IntegerAtom).Value; ++i)
                {
                    scope.Variables.Upsert((args[0] as TokenAtom).Value, new IntegerAtom {
                        Value = i
                    });
                    v = args[3].Evaluate(c);
                }

                c.ActiveScope = scope.Parent;

                return(v);
            });

            #endregion

            #region Serialization

            AddCoreFunction("serialize record", (args, c) =>
            {
                if (args[0].Type != AtomType.Record)
                {
                    throw new EvaluationError("Expect record as first argument to serialize.");
                }
                var serializer = new SerializationContext();
                var builder    = new StringBuilder();
                serializer.Serialize(args[0] as RecordAtom, builder);
                return(new StringAtom {
                    Value = builder.ToString()
                });
            });

            AddCoreFunction("to-int value", (args, c) =>
            {
                if (args[0].Type == AtomType.Integer)
                {
                    return(args[0]);
                }
                else if (args[0].Type == AtomType.Decimal)
                {
                    return new IntegerAtom {
                        Value = (int)(args[0] as DecimalAtom).Value
                    }
                }
                ;
                else if (args[0].Type == AtomType.String)
                {
                    int v = 0;

                    if (Int32.TryParse((args[0] as StringAtom).Value, out v))
                    {
                        return new IntegerAtom {
                            Value = v
                        }
                    }
                    ;
                }
                throw new EvaluationError("Could not convert value to integer.");
            });

            #endregion

            #region Files

            AddCoreFunction("write-all file text", (args, c) =>
            {
                if (args[0].Type != AtomType.String)
                {
                    throw new EvaluationError("Expected string as first argument to write-all.");
                }
                if (args[1].Type != AtomType.String)
                {
                    throw new EvaluationError("Expected string as second argument to write-all.");
                }

                System.IO.File.WriteAllText((args[0] as StringAtom).Value, (args[1] as StringAtom).Value);
                return(args[1]);
            });

            AddCoreFunction("read-all file", (args, c) =>
            {
                if (args[0].Type != AtomType.String)
                {
                    throw new EvaluationError("Expected string as first argument to read-all.");
                }
                return(new StringAtom {
                    Value = System.IO.File.ReadAllText((args[0] as StringAtom).Value)
                });
            });

            #endregion
        }
Beispiel #4
0
        public static void InitiateCore(Action <String> StandardOutput)
        {
            CoreFunctions = new List <CoreFunction>();

            foreach (var type in System.Reflection.Assembly.GetExecutingAssembly().GetTypes())
            {
                if (type.IsSubclassOf(typeof(CoreFactory)))
                {
                    (Activator.CreateInstance(type) as CoreFactory).Create();
                }
            }

            #region Vitals

            AddCoreFunction("parse str", (args, c) =>
            {
                if (args[0].Type != AtomType.String)
                {
                    throw new EvaluationError("Expected string as first argument to parse.");
                }
                return(Parse(new StringIterator((args[0] as StringAtom).Value)));
            });

            AddCoreFunction("eval atom", (args, c) =>
            {
                return(args[0].Evaluate(c));
            });

            AddCoreFunction("stot string", (args, c) =>
            {
                if (args[0].Type != AtomType.String)
                {
                    throw new EvaluationError("Expected string as first argument to stot.");
                }
                return(new TokenAtom {
                    Value = (args[0] as StringAtom).Value
                });
            });

            AddCoreFunction("ttos string", (args, c) =>
            {
                if (args[0].Type != AtomType.Token)
                {
                    throw new EvaluationError("Expected token as first argument to ttos.");
                }
                return(new StringAtom {
                    Value = (args[0] as TokenAtom).Value
                });
            });

            #endregion

            #region Equality and Comparison

            AddCoreFunction("& +args", (args, c) =>
            {
                var values = (args[0] as ListAtom).Value.Select(v => (v.Type == AtomType.Integer ? ((v as IntegerAtom).Value == 1) : (v.Type == AtomType.Nil ? false : true)));
                foreach (var v in values)
                {
                    if (!v)
                    {
                        return new IntegerAtom {
                            Value = 0
                        }
                    }
                }
                ;
                return(new IntegerAtom {
                    Value = 1
                });
            });

            AddCoreFunction("= +args", (args, c) =>
            {
                var values = (args[0] as ListAtom).Value;
                var type   = values[0].Type;
                foreach (var v in values)
                {
                    if (v.Type != type)
                    {
                        return new IntegerAtom {
                            Value = 0
                        }
                    }
                    ;
                    switch (values[0].Type)
                    {
                    case AtomType.Decimal:
                        if ((v as DecimalAtom).Value != (values[0] as DecimalAtom).Value)
                        {
                            return new IntegerAtom {
                                Value = 0
                            }
                        }
                        ;

                        break;

                    case AtomType.Integer:
                        if ((v as IntegerAtom).Value != (values[0] as IntegerAtom).Value)
                        {
                            return new IntegerAtom {
                                Value = 0
                            }
                        }
                        ;
                        break;

                    case AtomType.String:
                        if ((v as StringAtom).Value != (values[0] as StringAtom).Value)
                        {
                            return new IntegerAtom {
                                Value = 0
                            }
                        }
                        ;
                        break;

                    case AtomType.Token:
                        if ((v as TokenAtom).Value != (values[0] as TokenAtom).Value)
                        {
                            return new IntegerAtom {
                                Value = 0
                            }
                        }
                        ;
                        break;

                    case AtomType.Function:
                    case AtomType.List:
                    case AtomType.Record:
                        if (!Object.ReferenceEquals(v, values[0]))
                        {
                            return new IntegerAtom {
                                Value = 0
                            }
                        }
                        ;
                        break;
                    }
                }

                return(new IntegerAtom {
                    Value = 1
                });
            });

            #endregion

            #region Branches

            AddCoreFunction("? condition 'then 'else", (args, c) =>
            {
                var branch = args[1];
                if (args[0].Type != AtomType.Integer || (args[0] as IntegerAtom).Value == 0)
                {
                    branch = args[2];
                }
                return(branch.Evaluate(c));
            });

            AddCoreFunction("select '+branches", (args, c) =>
            {
                var branches = args[0] as ListAtom;
                foreach (var branch in branches.Value)
                {
                    if (branch.Type != AtomType.List)
                    {
                        throw new EvaluationError("Branch is not pair.");
                    }
                    if ((branch as ListAtom).Value.Count != 2)
                    {
                        throw new EvaluationError("Branch is not pair.");
                    }

                    var cond = (branch as ListAtom).Value[0].Evaluate(c);
                    if (cond.Type == AtomType.Integer && (cond as IntegerAtom).Value == 1)
                    {
                        return((branch as ListAtom).Value[1].Evaluate(c));
                    }
                }

                return(new NilAtom());
            });

            #endregion

            #region Random

            AddCoreFunction("rand min max", (args, c) =>
            {
                if (args[0].Type != AtomType.Integer)
                {
                    throw new EvaluationError("Expected integer as first argument to random.");
                }
                if (args[1].Type != AtomType.Integer)
                {
                    throw new EvaluationError("Expected integer as second argument to random.");
                }
                return(new IntegerAtom {
                    Value = Random.Next((args[0] as IntegerAtom).Value, (args[1] as IntegerAtom).Value)
                });
            });

            #endregion

            #region Output



            AddCoreFunction("format string *arg", (args, c) =>
            {
                if (args[0].Type != AtomType.String)
                {
                    throw new EvaluationError("First argument to format is not a string.");
                }
                var s = (args[0] as StringAtom).Value;
                var a = (args[1] as ListAtom).Value.Select(v => v.GetSystemValue()).ToArray();
                var r = String.Format(s, a);
                return(new StringAtom {
                    Value = r
                });
            });

            #endregion

            #region Functions

            AddCoreFunction("func 'args 'body", (args, c) =>
            {
                if (args[0].Type != AtomType.List)
                {
                    throw new EvaluationError("Expected list of argument names as first argument to func.");
                }

                var function = new FunctionAtom();
                function.DeclarationScope = c.ActiveScope;
                function.Implementation   = args[1];
                function.ArgumentNames    = new List <TokenAtom>();

                foreach (var argumentName in (args[0] as ListAtom).Value)
                {
                    if (argumentName.Type != AtomType.Token)
                    {
                        throw new EvaluationError("Malformed argument list in func.");
                    }
                    if (argumentName.Modifier == Modifier.Expand)
                    {
                        throw new EvaluationError("Expand modifier illegal on argument name in func.");
                    }
                    if (argumentName.Modifier == Modifier.Evaluate)
                    {
                        throw new EvaluationError("Evaluate modifier illegal on argument name in func.");
                    }
                    function.ArgumentNames.Add(argumentName as TokenAtom);
                }

                return(function);
            });

            AddCoreFunction("set-decl-scope func scope", (args, c) =>
            {
                if (args[0].Type != AtomType.Function)
                {
                    throw new EvaluationError("Expected function as first argument to set-decl-scope.");
                }
                if (args[1].Type != AtomType.Record)
                {
                    throw new EvaluationError("Expected record as second argument to set-decl-scope.");
                }
                (args[0] as FunctionAtom).DeclarationScope = (args[1] as RecordAtom);
                return(args[0]);
            });

            #endregion

            #region Scope And Memory

            AddCoreFunction("let 'name value", (args, c) =>
            {
                if (args[0].Type != AtomType.Token)
                {
                    throw new EvaluationError("Expected argument name as first argument to let.");
                }

                var varName = (args[0] as TokenAtom).Value;
                var scope   = c.ActiveScope;
                while (scope != null)
                {
                    if (scope.Variables.ContainsKey(varName))
                    {
                        scope.Variables.Upsert(varName, args[1]);
                        scope = null;
                    }
                    else
                    {
                        scope = scope.Parent;
                        if (scope == null)
                        {
                            throw new EvaluationError("Variable " + varName + " not found.");
                        }
                    }
                }
                return(args[1]);
            });

            AddCoreFunction("using '+vars", (args, c) =>
            {
                var scope = new RecordAtom {
                    Variables = new Dictionary <string, Atom>(), Parent = c.ActiveScope
                };
                for (int i = 0; i < (args[0] as ListAtom).Value.Count - 1; ++i)
                {
                    var variable = (args[0] as ListAtom).Value[i];
                    if (variable.Type != AtomType.List || (variable as ListAtom).Value.Count != 2)
                    {
                        throw new EvaluationError("Expected pairs in variable set in first argument to using.");
                    }
                    var name  = (variable as ListAtom).Value[0];
                    var value = (variable as ListAtom).Value[1];
                    if (name.Type != AtomType.Token)
                    {
                        throw new EvaluationError("Expected variable name in pair in first argument to using.");
                    }
                    scope.Variables.Upsert((name as TokenAtom).Value, value.Evaluate(c));
                }

                c.ActiveScope = scope;
                Atom result   = null;
                try
                {
                    result = (args[0] as ListAtom).Value.Last().Evaluate(c);
                }
                finally
                {
                    c.ActiveScope = scope.Parent;
                }
                return(result);
            });

            #endregion

            #region Records

            AddCoreFunction("set object 'name value", (args, c) =>
            {
                if (args[0].Type != AtomType.Record)
                {
                    throw new EvaluationError("First argument to set must be a record.");
                }

                if (args[1].Type != AtomType.Token)
                {
                    throw new EvaluationError("Expected member name as second argument to set.");
                }

                (args[0] as RecordAtom).Variables.Upsert((args[1] as TokenAtom).Value, args[2]);
                return(args[2]);
            });

            AddCoreFunction("multi-set object '*pairs", (args, c) =>
            {
                if (args[0].Type != AtomType.Record)
                {
                    throw new EvaluationError("Expected record as first argument to multi-set.");
                }

                foreach (var pair in (args[1] as ListAtom).Value)
                {
                    if (pair.Type != AtomType.List)
                    {
                        throw new EvaluationError("Expected lists as repeating arguments to multi-set.");
                    }
                    var list = pair as ListAtom;
                    if (list.Value.Count != 2)
                    {
                        throw new EvaluationError("Expected pairs as repeating arguments to multi-set.");
                    }
                    if (list.Value[0].Type != AtomType.Token)
                    {
                        throw new EvaluationError("Expected token as first value in pair as repeating arguments to multi-set.");
                    }
                    var value = list.Value[1].Evaluate(c);
                    (args[0] as RecordAtom).Variables.Upsert((list.Value[0] as TokenAtom).Value, value);
                }

                return(args[0]);
            });

            AddCoreFunction("with record '+vars", (args, c) =>
            {
                if (args[0].Type != AtomType.Record)
                {
                    throw new EvaluationError("Expected record as first argument to with");
                }
                if (args[1].Type != AtomType.List)
                {
                    throw new EvaluationError("Expected list as second argument to with");
                }


                var r = new RecordAtom();
                foreach (var v in (args[0] as RecordAtom).Variables)
                {
                    r.Variables.Upsert(v.Key, v.Value);
                }

                foreach (var variable in (args[1] as ListAtom).Value)
                {
                    if (variable.Type != AtomType.List || (variable as ListAtom).Value.Count != 2)
                    {
                        throw new EvaluationError("Expected pairs in variable set in second argument to with.");
                    }
                    var name  = (variable as ListAtom).Value[0];
                    var value = (variable as ListAtom).Value[1];
                    if (name.Type != AtomType.Token)
                    {
                        throw new EvaluationError("Expected variable name in pair in second argument to with.");
                    }
                    r.Variables.Upsert((name as TokenAtom).Value, value.Evaluate(c));
                }

                return(r);
            });

            AddCoreFunction("get object 'name", (args, c) =>
            {
                if (args[0].Type != AtomType.Record)
                {
                    throw new EvaluationError("First argument to get must be a record.");
                }
                if (args[1].Type != AtomType.Token)
                {
                    throw new EvaluationError("Expected member name as second argument to get.");
                }

                Atom value;
                if ((args[0] as RecordAtom).Variables.TryGetValue((args[1] as TokenAtom).Value, out value))
                {
                    return(value);
                }
                else
                {
                    throw new EvaluationError("Member not found on record.");
                }
            });

            AddCoreFunction("delete object 'name", (args, c) =>
            {
                if (args[0].Type != AtomType.Record)
                {
                    throw new EvaluationError("First argument to delete must be a record.");
                }
                if (args[1].Type != AtomType.Token)
                {
                    throw new EvaluationError("Expected member name as second argument to delete.");
                }

                Atom value;
                if (!(args[0] as RecordAtom).Variables.TryGetValue((args[1] as TokenAtom).Value, out value))
                {
                    value = new NilAtom();
                }

                (args[0] as RecordAtom).Variables.Remove((args[1] as TokenAtom).Value);
                return(value);
            });

            AddCoreFunction("set-parent object parent", (args, c) =>
            {
                if (args[0].Type != AtomType.Record)
                {
                    throw new EvaluationError("First argument to set-parent must be a record.");
                }
                if (args[1].Type != AtomType.Record)
                {
                    throw new EvaluationError("Second argument to set-parent must be a record.");
                }

                (args[0] as RecordAtom).Parent = (args[1] as RecordAtom);
                return(args[0]);
            });

            #endregion

            #region Lists

            AddCoreFunction("list *values", (args, c) =>
            {
                return(args[0]);    // :D!!!!
            });

            AddCoreFunction("length list-or-string", (args, c) =>
            {
                if (args[0].Type == AtomType.List)
                {
                    return new IntegerAtom {
                        Value = (args[0] as ListAtom).Value.Count
                    }
                }
                ;
                else if (args[0].Type == AtomType.String)
                {
                    return new IntegerAtom {
                        Value = (args[0] as StringAtom).Value.Length
                    }
                }
                ;
                else
                {
                    throw new EvaluationError("Expected list or string as first argument to length.");
                }
            });

            AddCoreFunction("index-get list index", (args, c) =>
            {
                if (args[1].Type != AtomType.Integer)
                {
                    throw new EvaluationError("Expected integer index as second argument to index-get.");
                }
                if (args[0].Type == AtomType.List)
                {
                    return((args[0] as ListAtom).Value[(args[1] as IntegerAtom).Value]);
                }
                else if (args[0].Type == AtomType.String)
                {
                    return new IntegerAtom {
                        Value = (args[0] as StringAtom).Value[(args[1] as IntegerAtom).Value]
                    }
                }
                ;
                else
                {
                    throw new EvaluationError("Expected list or string as first argument to index-get.");
                }
            });

            AddCoreFunction("replace-at list index value", (args, c) =>
            {
                if (args[1].Type != AtomType.Integer)
                {
                    throw new EvaluationError("Expected integer index as second argument to replace-at.");
                }
                if (args[0].Type != AtomType.List)
                {
                    throw new EvaluationError("Expected list as first argument to replace-at.");
                }
                var r = new ListAtom {
                    Value = new List <Atom>((args[0] as ListAtom).Value)
                };
                r.Value[(args[1] as IntegerAtom).Value] = args[2];
                return(r);
            });

            AddCoreFunction("array count 'code", (args, c) =>
            {
                var count = args[0];
                if (count.Type != AtomType.Integer)
                {
                    throw new EvaluationError("Expected integer count as first argument to array.");
                }

                var r = new ListAtom()
                {
                    Value = new List <Atom>()
                };
                for (int i = 0; i < (count as IntegerAtom).Value; ++i)
                {
                    r.Value.Add(args[1].Evaluate(c));
                }
                return(r);
            });

            AddCoreFunction("last +list", (args, c) =>
            {
                return((args[0] as ListAtom).Value.Last());
            });

            AddCoreFunction("reverse list", (args, c) =>
            {
                if (args[0].Type != AtomType.List)
                {
                    throw new EvaluationError("Expected list as first argument to reverse.");
                }
                return(new ListAtom {
                    Value = new List <Atom>((args[0] as ListAtom).Value.Reverse <Atom>())
                });
            });

            #endregion

            #region Loops

            AddCoreFunction("while 'condition 'body", (args, c) =>
            {
                while (true)
                {
                    var cond = args[0].Evaluate(c);
                    if (cond.Type == AtomType.Integer && (cond as IntegerAtom).Value != 0)
                    {
                        args[1].Evaluate(c);
                    }
                    else
                    {
                        break;
                    }
                }
                return(new NilAtom());
            });

            #endregion

            #region Serialization

            AddCoreFunction("serialize record", (args, c) =>
            {
                if (args[0].Type != AtomType.Record)
                {
                    throw new EvaluationError("Expect record as first argument to serialize.");
                }
                var serializer = new SerializationContext();
                var builder    = new StringBuilder();
                serializer.Serialize(args[0] as RecordAtom, builder);
                return(new StringAtom {
                    Value = builder.ToString()
                });
            });

            AddCoreFunction("to-int value", (args, c) =>
            {
                if (args[0].Type == AtomType.Integer)
                {
                    return(args[0]);
                }
                else if (args[0].Type == AtomType.Decimal)
                {
                    return new IntegerAtom {
                        Value = (int)(args[0] as DecimalAtom).Value
                    }
                }
                ;
                else if (args[0].Type == AtomType.String)
                {
                    int v = 0;

                    if (Int32.TryParse((args[0] as StringAtom).Value, out v))
                    {
                        return new IntegerAtom {
                            Value = v
                        }
                    }
                    ;
                }
                throw new EvaluationError("Could not convert value to integer.");
            });

            #endregion

            #region Files

            AddCoreFunction("write-all file text", (args, c) =>
            {
                if (args[0].Type != AtomType.String)
                {
                    throw new EvaluationError("Expected string as first argument to write-all.");
                }
                if (args[1].Type != AtomType.String)
                {
                    throw new EvaluationError("Expected string as second argument to write-all.");
                }

                System.IO.File.WriteAllText((args[0] as StringAtom).Value, (args[1] as StringAtom).Value);
                return(args[1]);
            });

            AddCoreFunction("read-all file", (args, c) =>
            {
                if (args[0].Type != AtomType.String)
                {
                    throw new EvaluationError("Expected string as first argument to read-all.");
                }
                return(new StringAtom {
                    Value = System.IO.File.ReadAllText((args[0] as StringAtom).Value)
                });
            });

            #endregion
        }