diff --git a/Jellyfin.Plugin.SmartPlaylist/Lisp/Compiler/Parser.cs b/Jellyfin.Plugin.SmartPlaylist/Lisp/Compiler/Parser.cs index 80a20ae..b6a66be 100644 --- a/Jellyfin.Plugin.SmartPlaylist/Lisp/Compiler/Parser.cs +++ b/Jellyfin.Plugin.SmartPlaylist/Lisp/Compiler/Parser.cs @@ -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 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 expressions = new List(); + bool exit_ok = false; while (_sts.Available() > 0) { Token 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) { diff --git a/Jellyfin.Plugin.SmartPlaylist/Lisp/Interpreter.cs b/Jellyfin.Plugin.SmartPlaylist/Lisp/Interpreter.cs index 2b4adb1..c450456 100644 --- a/Jellyfin.Plugin.SmartPlaylist/Lisp/Interpreter.cs +++ b/Jellyfin.Plugin.SmartPlaylist/Lisp/Interpreter.cs @@ -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)); diff --git a/Jellyfin.Plugin.SmartPlaylist/Util/Stream.cs b/Jellyfin.Plugin.SmartPlaylist/Util/Stream.cs index 08bcdc0..711a9c1 100644 --- a/Jellyfin.Plugin.SmartPlaylist/Util/Stream.cs +++ b/Jellyfin.Plugin.SmartPlaylist/Util/Stream.cs @@ -56,6 +56,9 @@ namespace Jellyfin.Plugin.SmartPlaylist.Util { public IStream Copy() { return new Stream(_items, _cursor, _ephemeralCursor); } + public IList Remainder() { + return _items.Skip(_cursor).ToList(); + } } }