jellyfin-smart-playlist/Jellyfin.Plugin.SmartPlaylist/Lisp/Compiler/Parser.cs

110 lines
3.6 KiB
C#
Raw Normal View History

2024-06-27 01:47:44 +02:00
using System.Diagnostics;
using Jellyfin.Plugin.SmartPlaylist.Lisp;
2024-06-27 01:47:44 +02:00
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);
}
2024-06-27 01:47:44 +02:00
public Expression parse() {
Token<string> token = _sts.Get();
2024-06-27 01:47:44 +02:00
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));
2024-06-27 01:47:44 +02:00
string r = "";
while (_sts.Available() > 0) {
Token<string> t = _sts.Get();
if (t.value == end.value) {
2024-06-27 01:47:44 +02:00
break;
}
r += t.value;
}
_sts.Commit();
2024-06-27 01:47:44 +02:00
return new String(r);
}
2024-12-18 00:51:40 +01:00
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);
}
2024-12-18 00:51:40 +01:00
if (";".Contains(start.value)) {
return parse_comment(start, end);
}
Debug.Assert(end != null);
2024-06-27 01:47:44 +02:00
IList<Expression> expressions = new List<Expression>();
while (_sts.Available() > 0) {
Token<string> t = _sts.Get();
if (t.value == end.value) {
_sts.Commit();
2024-06-27 01:47:44 +02:00
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);
2024-06-27 01:47:44 +02:00
expressions.Add(parse());
}
return Cons.FromList(expressions);
2024-06-27 01:47:44 +02:00
}
Expression parse_atom(AtomToken at) {
int parsed_value;
if (int.TryParse(at.value, out parsed_value)) {
_sts.Commit();
2024-06-27 01:47:44 +02:00
return new Integer(parsed_value);
}
if (at.value.Equals("t")) {
return Boolean.TRUE;
2024-06-27 01:47:44 +02:00
}
if (at.value.Equals("nil")) {
return Boolean.FALSE;
2024-06-27 01:47:44 +02:00
}
_sts.Commit();
2024-06-27 01:47:44 +02:00
return new Symbol(at.value);
}
}
}