jellyfin-smart-playlist/Jellyfin.Plugin.SmartPlaylist/Lisp/Compiler/Parser.cs
2024-06-27 01:47:44 +02:00

198 lines
7 KiB
C#

using System.Diagnostics;
namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler {
interface IAddable<T> where T : IAddable<T> {
static abstract T operator +(T left, T right);
}
interface ISubtractable<T> where T : ISubtractable<T> {
static abstract T operator -(T left, T right);
}
interface IMultiplicatable<T> where T : IMultiplicatable<T> {
static abstract T operator *(T left, T right);
}
interface IDivisible<T> where T : IDivisible<T> {
static abstract T operator /(T left, T right);
static abstract T operator %(T left, T right);
}
interface IComparable<T, E> where T : IComparable<T, E> {
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);
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 {
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 class Integer : Atom, IAddable<Integer>, ISubtractable<Integer>, IMultiplicatable<Integer>, IDivisible<Integer>, IComparable<Integer, Boolean> {
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<String> {
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 List : Expression {
private IList<Expression> _expressions;
public List(IList<Expression> expressions) {
_expressions = expressions;
}
public IList<Expression> 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) {
IList<Expression> r = new List<Expression>();
r.Concat(a.expressions);
r.Concat(b.expressions);
return new List (r);
}
}
public class Parser {
private StringTokenStream _sts;
public Parser(StringTokenStream tokens) {
_sts = tokens;
}
public Expression parse() {
Token<string> 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 == end);
Debug.Assert("'\"".Contains(start.value));
string r = "";
while (_sts.available() > 0) {
Token<string> t = _sts.get();
if (t == end) {
break;
}
r += t.value;
}
_sts.commit();
return new String(r);
}
Expression parse_grouping(GroupingToken start, GroupingToken end) {
IList<Expression> expressions = new List<Expression>();
while (_sts.available() > 0) {
Token<string> t = _sts.get();
if (t.Equals(end)) {
_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);
}
}
}