109 lines
3.6 KiB
C#
109 lines
3.6 KiB
C#
using System.Diagnostics;
|
|
using Jellyfin.Plugin.SmartPlaylist.Lisp;
|
|
|
|
namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler {
|
|
public class Parser {
|
|
private StringTokenStream _sts;
|
|
public Parser(StringTokenStream tokens) {
|
|
_sts = tokens;
|
|
}
|
|
public Parser(string s) {
|
|
_sts = StringTokenStream.generate(s);
|
|
}
|
|
|
|
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 SpaceToken sp:
|
|
return parse();
|
|
}
|
|
return parse();
|
|
}
|
|
|
|
Expression parse_string(GroupingToken start, GroupingToken? end) {
|
|
Debug.Assert(end != null);
|
|
Debug.Assert(start.value == end.value);
|
|
Debug.Assert("\"".Contains(start.value));
|
|
string r = "";
|
|
while (_sts.Available() > 0) {
|
|
Token<string> t = _sts.Get();
|
|
if (t.value == end.value) {
|
|
break;
|
|
}
|
|
r += t.value;
|
|
}
|
|
_sts.Commit();
|
|
return new String(r);
|
|
}
|
|
|
|
Expression parse_comment(GroupingToken start, GroupingToken? end) {
|
|
Debug.Assert(end != null);
|
|
Debug.Assert(";".Contains(start.value));
|
|
while (_sts.Available() > 0) {
|
|
Token<string> t = _sts.Get();
|
|
if (t.value == end.value) {
|
|
break;
|
|
}
|
|
}
|
|
_sts.Commit();
|
|
return parse();
|
|
}
|
|
|
|
Expression parse_quote(GroupingToken start, GroupingToken? end) {
|
|
Debug.Assert(end == null);
|
|
Debug.Assert("'".Contains(start.value));
|
|
return Cons.FromList(new Expression[]{ new Symbol("quote"), parse()});
|
|
}
|
|
|
|
Expression parse_grouping(GroupingToken start, GroupingToken? end) {
|
|
if ("\"".Contains(start.value)) {
|
|
return parse_string(start, end);
|
|
}
|
|
if ("'".Contains(start.value)) {
|
|
return parse_quote(start, end);
|
|
}
|
|
if (";".Contains(start.value)) {
|
|
return parse_comment(start, end);
|
|
}
|
|
Debug.Assert(end != null);
|
|
IList<Expression> expressions = new List<Expression>();
|
|
while (_sts.Available() > 0) {
|
|
Token<string> t = _sts.Get();
|
|
if (t.value == end.value) {
|
|
_sts.Commit();
|
|
break;
|
|
}
|
|
if (t is SpaceToken) {
|
|
// need this here because those tokens can never
|
|
// return an expression and trying to parse the last
|
|
// expression will not work if its only spaces and a
|
|
// closing parentheses.
|
|
continue;
|
|
}
|
|
_sts.Rewind(1);
|
|
expressions.Add(parse());
|
|
}
|
|
return Cons.FromList(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 Boolean.TRUE;
|
|
}
|
|
if (at.value.Equals("nil")) {
|
|
return Boolean.FALSE;
|
|
}
|
|
_sts.Commit();
|
|
return new Symbol(at.value);
|
|
}
|
|
}
|
|
}
|