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); E Equals(T other); } public abstract class Expression: IFormattable, IComparable { public abstract string ToString(string? format, IFormatProvider? provider); public abstract override int GetHashCode(); public abstract bool Equals(Expression other); public override bool Equals(object? other) { if (other is Expression other_e) { return Equals(other_e); } return false; } public static bool operator ==(Expression left, Expression right) { return left.Equals(right); } public static bool operator !=(Expression left, Expression right) { return !left.Equals(right); } } 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 int GetHashCode() { int hash = 17; hash *= 23; hash += _name.GetHashCode(); return hash; } public override bool Equals(Expression? other) { if (other is Symbol other_s) { return _name == other_s._name; } return false; } public override string ToString(string? format, IFormatProvider? provider) { return _name; } } public class Boolean : Atom { private readonly bool _value; public Boolean(bool value) { _value = value; } public bool value { get => _value; } public override int GetHashCode() { int hash = 17; hash *= 23; hash += _value.GetHashCode(); return hash; } public override bool Equals(Expression other) { if (other is Boolean other_b) { return _value == other_b.value; } return false; } public override string ToString(string? format, IFormatProvider? provider) { return _value? "t" : "nil"; } } public class Integer : Atom, IAddable, ISubtractable, IMultiplicatable, IDivisible, ISortable { private readonly int _value; public Integer(int value) { _value = value; } public int value { get => _value; } public override int GetHashCode() { int hash = 17; hash *= 23; hash += _value.GetHashCode(); return hash; } public override bool Equals(Expression other) { if (other is Integer other_i) { return _value == other_i._value; } return false; } public override string ToString(string? format, IFormatProvider? provider) { return _value.ToString(); //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 int GetHashCode() { int hash = 17; hash *= 23; hash += _value.GetHashCode(); return hash; } public override bool Equals(Expression other) { if (other is String other_s) { return _value == other_s._value; } return false; } 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 int GetHashCode() { int hash = 17; hash *= 23; hash += _value.GetHashCode(); return hash; } public override bool Equals(Expression other) { if (other is Object other_o) { return _value == other_o._value; } return false; } 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 int GetHashCode() { int hash = 17; foreach (Expression i in _expressions) { hash *= 23; hash += i.GetHashCode(); } return hash; } public override bool Equals(Expression other) { if (other is List other_l) { return _expressions == other_l._expressions; } return false; } public override string ToString(string? format, IFormatProvider? provider) { return "(" + string.Join(" ", _expressions.Select(x => x.ToString("0", provider))) + ")"; } 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); } } }