<commit_before>﻿
//          Example:
//            (def square (x) (* x x))
//            (def distance (x y) (+ (square x) (square y)))
//            (distance 4 5)
//            (distance 2 3)

using System;
using System.Collections.Generic;
using System.Linq;

namespace DSLM.Console
{
    public abstract class Node
    {
        public abstract object Eval(EvalContext context);
    }

    public class IntNode : Node
    {
        public int Value;
        public override object Eval(EvalContext context)
        {
            return Value;
        }
    }

    public class ListNode : Node
    {
        public IEnumerable<Node> Nodes;

        public override object Eval(EvalContext context)
        {
            var head = Nodes.First().Eval(context);
            var tail = Nodes.Skip(1);
            if (context.HasFunction(head.ToString()))
            {
                return context.CallFunction(head.ToString(), tail);
            }

            if (head.ToString() == "def")
            {
                var name = ((SymbolNode)tail.First()).Value;
                var args = ((ListNode)tail.Skip(1).First()).Nodes.Select(n => (n as SymbolNode).Value);
                var body = ((ListNode)tail.Skip(2).First());
                context.DefFunction(name, args, body);
                return null;
            }
            return Nodes;
        }
    }

    public class SymbolNode : Node
    {
        public string Value;

        public override object Eval(EvalContext context)
        {
            return Value;
        }
    }

    public class Parser
    {
        private IEnumerator<string> _enumerator;

        private IEnumerable<string> Tokenize(string script)
        {
            return script
                .Replace("(", " ( ")
                .Replace(")", " ) ")
                .Split(new char[] { ' ', '\t', '\n' }, StringSplitOptions.RemoveEmptyEntries);
        }

        public void SetLine(string line)
        {
            _enumerator = Tokenize(line).GetEnumerator();
            _enumerator.MoveNext();
        }

        public Node Parse()
        {
            if (_enumerator.Current == "(")
            {
                if (!_enumerator.MoveNext())
                {
                    throw new Exception("Syntax error");
                }
                var nodes = new List<Node>();
                while (_enumerator.Current != ")")
                {
                    int value;
                    if (_enumerator.Current == "(")
                    {
                        nodes.Add(Parse());
                    }
                    else if (int.TryParse(_enumerator.Current, out value))
                    {
                        nodes.Add(new IntNode()
                        {
                            Value = value
                        });
                    }
                    else
                    {
                        nodes.Add(new SymbolNode()
                        {
                            Value = _enumerator.Current
                        });
                    }

                    if (!_enumerator.MoveNext())
                    {
                        throw new Exception("Syntax error");
                    }
                }
                return new ListNode()
                {
                    Nodes = nodes
                };
            }
            throw new Exception("Syntax error");
        }
    }

    public class EvalContext
    {
        private readonly Dictionary<string, Func<string, Node[], object>> _funcs;
        private readonly Dictionary<string, string[]> _argMaps = new Dictionary<string, string[]>();

        public EvalContext()
        {
            _funcs = new Dictionary<string, Func<string, Node[], object>>()
            {
                {"+", (name, args) => (int)args[0].Eval(this) + (int)args[1].Eval(this)},
                {"-", (name, args) => (int)args[0].Eval(this) - (int)args[1].Eval(this)},
                {"*", (name, args) => (int)args[0].Eval(this) * (int)args[1].Eval(this)},
                {"/", (name, args) => (int)args[0].Eval(this) / (int)args[1].Eval(this)},
            };
        }

        public bool HasFunction(string name)
        {
            return _funcs.ContainsKey(name);
        }<commit_msg>add logic operations and "if" function<commit_after>﻿
//          Examples:
//
//            (def square (x) (* x x))
//            (def distance (x y) (+ (square x) (square y)))
//            (distance 4 5)
//            (distance 2 3)
//
//            (def fact (v) (if (< v 2) 1 (* v (fact (- v 1)))))
//            (fact 5)
//            (fact 10)            

using System;
using System.Collections.Generic;
using System.Linq;

namespace DSLM.Console
{
    public abstract class Node
    {
        public abstract object Eval(EvalContext context);
    }

    public class IntNode : Node
    {
        public int Value;
        public override object Eval(EvalContext context)
        {
            return Value;
        }
    }

    public class ListNode : Node
    {
        public IEnumerable<Node> Nodes;

        public override object Eval(EvalContext context)
        {
            var head = Nodes.First().Eval(context);
            var tail = Nodes.Skip(1);
            if (context.HasFunction(head.ToString()))
            {
                return context.CallFunction(head.ToString(), tail);
            }

            if (head.ToString() == "def")
            {
                var name = ((SymbolNode)tail.First()).Value;
                var args = ((ListNode)tail.Skip(1).First()).Nodes.Select(n => (n as SymbolNode).Value);
                var body = ((ListNode)tail.Skip(2).First());
                context.DefFunction(name, args, body);
                return null;
            }
            return Nodes;
        }
    }

    public class SymbolNode : Node
    {
        public string Value;

        public override object Eval(EvalContext context)
        {
            return Value;
        }
    }

    public class Parser
    {
        private IEnumerator<string> _enumerator;

        private IEnumerable<string> Tokenize(string script)
        {
            return script
                .Replace("(", " ( ")
                .Replace(")", " ) ")
                .Split(new char[] { ' ', '\t', '\n' }, StringSplitOptions.RemoveEmptyEntries);
        }

        public void SetLine(string line)
        {
            _enumerator = Tokenize(line).GetEnumerator();
            _enumerator.MoveNext();
        }

        public Node Parse()
        {
            if (_enumerator.Current == "(")
            {
                if (!_enumerator.MoveNext())
                {
                    throw new Exception("Syntax error");
                }
                var nodes = new List<Node>();
                while (_enumerator.Current != ")")
                {
                    int value;
                    if (_enumerator.Current == "(")
                    {
                        nodes.Add(Parse());
                    }
                    else if (int.TryParse(_enumerator.Current, out value))
                    {
                        nodes.Add(new IntNode()
                        {
                            Value = value
                        });
                    }
                    else
                    {
                        nodes.Add(new SymbolNode()
                        {
                            Value = _enumerator.Current
                        });
                    }

                    if (!_enumerator.MoveNext())
                    {
                        throw new Exception("Syntax error");
                    }
                }
                return new ListNode()
                {
                    Nodes = nodes
                };
            }
            throw new Exception("Syntax error");
        }
    }

    public class EvalContext
    {
        private readonly Dictionary<string, Func<string, Node[], object>> _funcs;
        private readonly Dictionary<string, string[]> _argMaps = new Dictionary<string, string[]>();

        public EvalContext()
        {
            _funcs = new Dictionary<string, Func<string, Node[], object>>()
            {
                {"+", (name, args) => (int)args[0].Eval(this) + (int)args[1].Eval(this)},
                {"-", (name, args) => (int)args[0].Eval(this) - (int)args[1].Eval(this)},
                {"*", (name, args) => (int)args[0].Eval(this) * (int)args[1].Eval(this)},
                {"/", (name, args) => (int)args[0].Eval(this) / (int)args[1].Eval(this)},
                {"=", (name, args) => (int)args[0].Eval(this) == (int)args[1].Eval(this) ? 1 : 0},
                {"<", (name, args) => (int)args[0].Eval(this) < (int)args[1].Eval(this) ? 1 : 0},
                {">", (name, args) => (int)args[0].Eval(this) > (int)args[1].Eval(this) ? 1 : 0},
                {"<=", (name, args) => (int)args[0].Eval(this) <= (int)args[1].Eval(this) ? 1 : 0},
                {">=", (name, args) => (int)args[0].Eval(this) >= (int)args[1].Eval(this) ? 1 : 0},
                {"<>", (name, args) => (int)args[0].Eval(this) != (int)args[1].Eval(this) ? 1 : 0},
                {
                    "if", (name, args) =>
                    {
                        var condition = (int) args[0].Eval(this);
                        if (condition == 1)
                        {
                            return args[1].Eval(this);
                        }
                        return args.Length > 2 ? args[2].Eval(this) : null;
                    }
                },
            };
        }

        public bool HasFunction(string name)
        {
            return _funcs.ContainsKey(name);
        }
{'fraction_non_alphanumeric': 0.1310535476604894, 'fraction_numerical': 0.0066550629671342275, 'mean_word_length': 1.184257602862254, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 46, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6931063', 'n_tokens_mistral': 2643, 'n_tokens_neox': 2485, 'n_words': 545}