From 6c34b1d24d16b14804139908a38777f1da01ec5d Mon Sep 17 00:00:00 2001 From: falsycat Date: Thu, 3 Oct 2019 00:00:00 +0000 Subject: [PATCH] [update] Implemented error handlings for Preprocess() function. --- sjscript/src/sjscript/exception.d | 27 ++++++++++++ sjscript/src/sjscript/preprocess.d | 67 +++++++++++++++++++++--------- 2 files changed, 75 insertions(+), 19 deletions(-) create mode 100644 sjscript/src/sjscript/exception.d diff --git a/sjscript/src/sjscript/exception.d b/sjscript/src/sjscript/exception.d new file mode 100644 index 0000000..31cf1cb --- /dev/null +++ b/sjscript/src/sjscript/exception.d @@ -0,0 +1,27 @@ +/// License: MIT +module sjscript.exception; + +import sjscript.Token; + +/// +class ScriptException : Exception { + public: + /// + this(string msg, Token token, string file = __FILE__, size_t line = __LINE__) { + super(msg, file, line); + this.token = token; + } + const Token token; +} +/// +class PreprocessException : ScriptException { + public: + mixin ExceptionConstructor; +} + +private mixin template ExceptionConstructor() { + public: + this(string msg, Token token, string file = __FILE__, size_t line = __LINE__) { + super(msg, token, file, line); + } +} diff --git a/sjscript/src/sjscript/preprocess.d b/sjscript/src/sjscript/preprocess.d index e5a7561..1c9a5f4 100644 --- a/sjscript/src/sjscript/preprocess.d +++ b/sjscript/src/sjscript/preprocess.d @@ -4,12 +4,12 @@ module sjscript.preprocess; import std.algorithm, std.array, std.conv, - std.exception, std.range, std.range.primitives, std.typecons; -import sjscript.Token; +import sjscript.Token, + sjscript.exception; /// unittest { @@ -41,6 +41,12 @@ EOS"; EOS"; assert(Tokenize(src).equal(["0", "1", "2"].cycle().take(9))); } + { + enum src = q"EOS + $unknown_template +EOS"; + assertThrown!PreprocessException(Tokenize(src).array); + } } /// @@ -114,9 +120,10 @@ private struct Preprocessor(R) if (nest == 0) break; PopFrontWithoutPreprocess(); - (!empty).enforce(); + (!empty).enforce( + "all tokens are consumed when expecting close brace", result[][$-1]); } - (result[].length >= 2).enforce(); + assert(result[].length >= 2); return result[][1..$-1]; } @@ -139,39 +146,53 @@ private struct Preprocessor(R) Preprocess(); } void DefineTemplate() { + const command = front; PopFrontWithoutPreprocess(); - (!empty).enforce(); + (!empty).enforce( + "all tokens are consumed when expecting template name", command); const name = front; - (name.type == TokenType.Ident).enforce(); + (name.type == TokenType.Ident).enforce( + "found unexpected token when expecting template body", name); PopFrontWithoutPreprocess(); - (!empty).enforce(); + (!empty).enforce( + "all tokens are consumed when expecting template body", command); - (front.type == TokenType.OpenBrace).enforce(); + (front.type == TokenType.OpenBrace).enforce( + "found unexpected token when expecting template body", name); templates_[name.text] = PopFrontBlockWithoutPreprocess(); PopFrontWithoutPreprocess(); } void ExpandRepeat() { + const command = front; PopFrontWithoutPreprocess(); - (!empty).enforce(); + (!empty).enforce( + "all tokens are consumed when expecting counter name or count", command); string counter_name; + Token counter_name_token; if (front.type == TokenType.Ident) { - counter_name = front.text; + counter_name_token = front; + counter_name = counter_name_token.text; PopFrontWithoutPreprocess(); - (!empty).enforce(); + (!empty).enforce( + "all tokens are consumed when expecting count", command); } if (counter_name != "") { - (!status_.map!"a.counter_name".canFind(counter_name)).enforce(); - (!templates_.keys.canFind(counter_name)).enforce(); + (!status_.map!"a.counter_name".canFind(counter_name) && + !templates_.keys.canFind(counter_name)). + enforce("the counter name is duplicated", counter_name_token); } - (front.type == TokenType.Number).enforce(); + (front.type == TokenType.Number).enforce( + "found unexpected token when expecting count", front); const count = front.text.to!float.to!int; PopFrontWithoutPreprocess(); - (!empty).enforce(); + (!empty).enforce( + "all tokens are consumed when expecting repeat body", command); - (front.type == TokenType.OpenBrace).enforce(); + (front.type == TokenType.OpenBrace).enforce( + "found unexpected token when expecting repeat body", front); ExpansionState state; state.tokens = PopFrontBlockWithoutPreprocess(); state.counter_max = count.to!size_t; @@ -182,13 +203,16 @@ private struct Preprocessor(R) } void ExpandTemplate() { const name = front.text[1..$]; - (name != "").enforce(); - (!status_.map!"a.name".canFind(name)).enforce(); + (name != ""). + enforce("invalid template specification", front); + (!status_.map!"a.name".canFind(name)). + enforce("recursively template expansion", front); Token[] body; const counter = GetCounterValue(name); if (counter.isNull) { - (name in templates_).enforce(); + (name in templates_). + enforce("the template is unknown", front); body = templates_[name]; } else { body = [Token(counter.get.to!string, TokenType.Number)]; @@ -215,3 +239,8 @@ private struct Preprocessor(R) ExpansionState[] status_; } + +private void enforce(T)(T val, string msg, lazy Token token, + string file = __FILE__, size_t line = __LINE__) { + if (!val) throw new PreprocessException(msg, token, file, line); +}