using System.Diagnostics; namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler { interface IAddable where T : IAddable { static abstract T operator +(T left, T right); } interface ISubtractable where T : ISubtractable { static abstract T operator -(T left, T right); } interface IMultiplicatable where T : IMultiplicatable { static abstract T operator *(T left, T right); } interface IDivisible where T : IDivisible { static abstract T operator /(T left, T right); static abstract T operator %(T left, T right); } interface ISortable where T : ISortable { static abstract E operator >(T left, T right); static abstract E operator <(T left, T right); static abstract E operator >=(T left, T right); static abstract E operator <=(T left, T right); } interface IComparable where T : IComparable { static abstract E operator ==(T left, T right); static abstract E operator !=(T left, T right); } public abstract class Expression : IFormattable { public abstract string ToString(string? format, IFormatProvider? provider); } public abstract class Atom : Expression {} public class Symbol : Atom { private readonly string _name; public Symbol(string name) { _name = name; } public string name { get => _name; } public override string ToString(string? format, IFormatProvider? provider) { return _name; } } public class Boolean : Atom, IComparable { private readonly bool _value; public Boolean(bool value) { _value = value; } public bool value { get => _value; } public override string ToString(string? format, IFormatProvider? provider) { return _value? "t" : "nil"; } public static Boolean operator ==(Boolean a, Boolean b) { return new Boolean(a.value == b.value); } public static Boolean operator !=(Boolean a, Boolean b) { return new Boolean(a.value != b.value); } } public class Integer : Atom, IAddable, ISubtractable, IMultiplicatable, IDivisible, ISortable, IComparable { private readonly int _value; public Integer(int value) { _value = value; } public int value { get => _value; } public override string ToString(string? format, IFormatProvider? provider) { return _value.ToString("0", provider); } public static Integer operator +(Integer a, Integer b) { return new Integer(a.value + b.value); } public static Integer operator -(Integer a, Integer b) { return new Integer(a.value - b.value); } public static Integer operator *(Integer a, Integer b) { return new Integer(a.value * b.value); } public static Integer operator /(Integer a, Integer b) { return new Integer(a.value / b.value); } public static Integer operator %(Integer a, Integer b) { return new Integer(a.value % b.value); } public static Boolean operator >(Integer a, Integer b) { return new Boolean(a.value > b.value); } public static Boolean operator <(Integer a, Integer b) { return new Boolean(a.value < b.value); } public static Boolean operator >=(Integer a, Integer b) { return new Boolean(a.value >= b.value); } public static Boolean operator <=(Integer a, Integer b) { return new Boolean(a.value <= b.value); } public static Boolean operator ==(Integer a, Integer b) { return new Boolean(a.value == b.value); } public static Boolean operator !=(Integer a, Integer b) { return new Boolean(a.value != b.value); } } public class String : Atom, IAddable { private readonly string _value; public String(string value) { _value = value; } public string value { get => _value; } public override string ToString(string? format, IFormatProvider? provider) { return "\"" + _value + "\""; } public static String operator +(String a, String b) { return new String (a.value + b.value); } } public class Object : Atom { private readonly object _value; public Object(object value) { _value = value; } public object value { get => _value; } public override string ToString(string? format, IFormatProvider? provider) { return _value.ToString(); } public static Atom FromBase(object o) { switch (o) { case bool b: return new Boolean(b); case int i: return new Integer(i); case string s: return new String(s); default: return new Object(o); } } } public class List : Expression { private IList _expressions; public List(IList expressions) { _expressions = expressions; } public IList expressions { get => _expressions; } public override string ToString(string? format, IFormatProvider? provider) { string r = "("; foreach (var e in _expressions) { r += " "; r += e.ToString("0", provider); } return r + ")"; } public static List operator +(List a, List b) { List r = new List(); r.AddRange(a.expressions); r.AddRange(b.expressions); return new List(r); } } public class Parser { private StringTokenStream _sts; public Parser(StringTokenStream tokens) { _sts = tokens; } public Expression parse() { Token token = _sts.get(); switch (token) { case GroupingToken gt: return parse_grouping(gt, gt.closing_value); case AtomToken at: return parse_atom(at); case OperatorToken ot: return new Symbol(ot.value); case SpaceToken sp: return parse(); } return parse(); } Expression parse_string(GroupingToken start, GroupingToken end) { Debug.Assert(start.value == end.value); Debug.Assert("'\"".Contains(start.value)); string r = ""; while (_sts.available() > 0) { Token t = _sts.get(); if (t.value == end.value) { break; } r += t.value; } _sts.commit(); return new String(r); } Expression parse_grouping(GroupingToken start, GroupingToken end) { if ("'\"".Contains(start.value)) { return parse_string(start, end); } IList expressions = new List(); while (_sts.available() > 0) { Token t = _sts.get(); if (t.value == end.value) { _sts.commit(); break; } _sts.rewind(1); expressions.Add(parse()); } return new List(expressions); } Expression parse_atom(AtomToken at) { int parsed_value; if (int.TryParse(at.value, out parsed_value)) { _sts.commit(); return new Integer(parsed_value); } if (at.value.Equals("t")) { return new Boolean(true); } if (at.value.Equals("nil")) { return new Boolean(false); } _sts.commit(); return new Symbol(at.value); } } }