private static void AppendLines(Evaluator eval, StackFrame frame)
        {
            var(path, list) = StructureUtils.Split2(frame.args);

            if (path == null || !path.IsString)
            {
                throw new ArgumentException("First argument must be string!");
            }
            string file = (string)path.value;

            if (list == null || !list.IsPair)
            {
                throw new ArgumentException("Second argument must be list of strings!");
            }

            List <string> lines = new List <string>();

            for (Atom iter = list; iter != null; iter = iter.next)
            {
                Atom line = iter.atom;
                if (line == null || !line.IsString)
                {
                    throw new ArgumentException("Second argument must be list of strings!");
                }
                lines.Add((string)line.value);
            }

            File.AppendAllLines(file, lines, System.Text.Encoding.UTF8);

            eval.Return(null);
        }
        // TODO: Осознать, что тут происходит
        private static void TableEach(Evaluator eval, StackFrame frame)
        {
            var args = frame.args;

            var(dict, func) = StructureUtils.Split2(args);
            Context  dictionary = GetDictionary(dict);
            Function proc       = func?.value as Function;

            if (dictionary == null)
            {
                throw new ArgumentException("First argument must be table!");
            }
            if (proc == null)
            {
                throw new ArgumentException("Second argument must be procedure!");
            }

            switch (frame.state.value)
            {
            case "-eval-sexp-body-":
                var list = dictionary
                           .Select(pair => StructureUtils.List(new Atom(AtomType.String, pair.Key), pair.Value))
                           .ToArray();
                frame.temp1 = StructureUtils.List(list);
                frame.state = new Atom("-built-in-table-each-");
                break;

            case "-built-in-table-each-":
                if (eval.HaveReturn())
                {
                    frame.temp2 = StructureUtils.BuildListContainer(frame.temp2, eval.TakeReturn());
                }

                if (frame.temp1 != null)
                {
                    var pair = frame.temp1.atom;
                    frame.temp1 = frame.temp1.next;
                    var newFrame = eval.CreateFrame(
                        "-eval-sexp-args-",
                        new Atom(func, pair),
                        frame.context);
                    newFrame.function = func;
                    newFrame.args     = frame.temp1.atom;
                }
                else
                {
                    eval.SetReturn(null);
                    frame.state = new Atom("-eval-sexp-body-");
                }

                break;
            }
        }
        public static void Contains(Evaluator eval, StackFrame frame)
        {
            var(strArg, subArg) = StructureUtils.Split2(frame.args);

            // if (!strArg.IsString) throw new ArgumentException("first argument must be string!");
            // if (!subArg.IsString) throw new ArgumentException("second argument must be string!");

            string str = strArg.value as string;
            string sub = subArg.value as string;

            eval.Return(str.Contains(sub) ? Atoms.TRUE : Atoms.FALSE);
        }
        private static void Eval(Evaluator eval, StackFrame frame)
        {
            if (!eval.HaveReturn())
            {
                var(expression, ctxAtom) = StructureUtils.Split2(frame.args);
                Context ctx = ctxAtom?.value as Context ?? frame.context.value as Context;
                eval.CreateFrame("-eval-", expression, ctx);
                return;
            }

            eval.CloseFrame();
        }
        public static void GetChar(Evaluator eval, StackFrame frame)
        {
            var(strArg, num) = StructureUtils.Split2(frame.args);

            // if (!str.IsString) throw new ArgumentException("Argument must be string!");
            // if (!num.IsNumber) throw new ArgumentException("Argument must be number!");

            string str   = strArg.value as string;
            int    index = Convert.ToInt32(num.value);
            char   res   = str[index];

            eval.Return(new Atom(AtomType.Number, res));
        }
        private static void TableImportAll(Evaluator eval, StackFrame frame)
        {
            var(src, dst) = StructureUtils.Split2(frame.args);

            if (dst == null || dst.IsPair)
            {
                dst = frame.context.atom;
            }

            var srcCtx = GetDictionary(src);
            var dstCtx = GetDictionary(dst);

            ContextUtils.ImportAllSymbols(srcCtx, dstCtx);

            eval.Return(null);
        }
        private static void AppendText(Evaluator eval, StackFrame frame)
        {
            var(path, text) = StructureUtils.Split2(frame.args);

            if (path == null || !path.IsString)
            {
                throw new ArgumentException("First argument must be string!");
            }
            string file = (string)path.value;

            if (text == null || !text.IsString)
            {
                throw new ArgumentException("Second argument must be string!");
            }
            string data = (string)text.value;

            File.AppendAllText(file, data, System.Text.Encoding.UTF8);

            eval.Return(null);
        }
        public static void Split(Evaluator eval, StackFrame frame)
        {
            var(strArg, splits) = StructureUtils.Split2(frame.args);

            // if (!strArg.IsString) throw new ArgumentException("first argument must be string!");
            // if (!splits.IsString) throw new ArgumentException("second argument must be string!");

            string str = strArg.value as string;
            string spl = splits.value as string;

            string[] list = str.Split(new string[] { spl }, StringSplitOptions.RemoveEmptyEntries);

            Atom head, tail;

            head       = tail = new Atom();
            tail.value = new Atom(AtomType.String, list[0]);
            for (int i = 1; i < list.Length; i++)
            {
                tail       = tail.next = new Atom();
                tail.value = new Atom(AtomType.String, list[0]);
            }

            eval.Return(head);
        }
        private static void Write(Evaluator eval, StackFrame frame)
        {
            var(stream, value) = StructureUtils.Split2(frame.args);

            if (stream.type != AtomType.Native)
            {
                throw new ArgumentException("Argument must be stream!");
            }

            StreamWriter writer = stream?.value as StreamWriter;

            if (writer == null)
            {
                throw new ArgumentException("Argument must be stream!");
            }

            if (value == null)
            {
                throw new ArgumentException("Second argument can't be null!");
            }

            switch (value.type)
            {
            case AtomType.Number:
                var type = UNumber.NumberType(value?.value);
                switch (type)
                {
                case UNumber.UINT_8:
                    writer.Write(Convert.ToByte(value.value));
                    break;

                case UNumber.SINT_8:
                    writer.Write(Convert.ToSByte(value.value));
                    break;

                case UNumber.UINT16:
                    writer.Write(Convert.ToUInt16(value.value));
                    break;

                case UNumber.SINT16:
                    writer.Write(Convert.ToInt16(value.value));
                    break;

                case UNumber._CHAR_:
                    writer.Write(Convert.ToChar(value.value));
                    break;

                case UNumber.UINT32:
                    writer.Write(Convert.ToUInt32(value.value));
                    break;

                case UNumber.SINT32:
                    writer.Write(Convert.ToInt32(value.value));
                    break;

                case UNumber.UINT64:
                    writer.Write(Convert.ToUInt64(value.value));
                    break;

                case UNumber.SINT64:
                    writer.Write(Convert.ToInt64(value.value));
                    break;

                case UNumber.FLO32:
                    writer.Write(Convert.ToSingle(value.value));
                    break;

                case UNumber.FLO64:
                    writer.Write(Convert.ToDouble(value.value));
                    break;

                default:
                    writer.Write(value.value);
                    break;
                }

                break;

            default:
                writer.Write(value.value);
                break;
            }

            eval.Return(null);
        }