fix: make the parser more robust and no longer accept invalid input silently.

This commit is contained in:
redxef 2025-03-02 18:33:25 +01:00
parent 1d472ed61f
commit 2624b83a79
Signed by: redxef
GPG key ID: 7DAC3AA211CBD921
3 changed files with 25 additions and 4 deletions

View file

@ -3,7 +3,7 @@ using Jellyfin.Plugin.SmartPlaylist.Lisp;
namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler {
public class Parser {
private StringTokenStream _sts;
internal StringTokenStream _sts;
public Parser(StringTokenStream tokens) {
_sts = tokens;
}
@ -29,13 +29,18 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler {
Debug.Assert(start.value == end.value);
Debug.Assert("\"".Contains(start.value));
string r = "";
bool exit_ok = false;
while (_sts.Available() > 0) {
Token<string> t = _sts.Get();
if (t.value == end.value) {
exit_ok = true;
break;
}
r += t.value;
}
if (!exit_ok) {
throw new ApplicationException($"Failed to parse string, are you missing the closing quotes? String is: {r}");
}
_sts.Commit();
return new String(r);
}
@ -69,11 +74,16 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler {
if (";".Contains(start.value)) {
return parse_comment(start, end);
}
Debug.Assert(end != null);
if (end == null) {
throw new ApplicationException($"Don't know how to parse grouping starting with token '{start.value}'");
}
IList<Expression> expressions = new List<Expression>();
bool exit_ok = false;
while (_sts.Available() > 0) {
Token<string> t = _sts.Get();
if (t.value == end.value) {
exit_ok = true;
_sts.Commit();
break;
}
@ -87,7 +97,11 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler {
_sts.Rewind(1);
expressions.Add(parse());
}
return Cons.FromList(expressions);
var r = Cons.FromList(expressions);
if (!exit_ok) {
throw new ApplicationException($"Failed to parse grouping, are you missing some closing braces? Parsed expressions: {r}");
}
return r;
}
Expression parse_atom(AtomToken at) {

View file

@ -601,7 +601,11 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp {
throw new ApplicationException($"Not handled case '{expression}'");
}
public Expression eval(Parser p) {
return eval(p.parse());
Expression r = eval(p.parse());
if (p._sts.Available() > 0) {
throw new ApplicationException($"Did not consume all tokens, remaining program is {string.Join(" ", p._sts.Remainder())}");
}
return r;
}
public Expression eval(StringTokenStream sts) {
return eval(new Parser(sts));

View file

@ -56,6 +56,9 @@ namespace Jellyfin.Plugin.SmartPlaylist.Util {
public IStream<T> Copy() {
return new Stream<T>(_items, _cursor, _ephemeralCursor);
}
public IList<T> Remainder() {
return _items.Skip(_cursor).ToList();
}
}
}