[update] Implemented error handlings for Preprocess() function.
This commit is contained in:
parent
45e80f7c4f
commit
6c34b1d24d
27
sjscript/src/sjscript/exception.d
Normal file
27
sjscript/src/sjscript/exception.d
Normal file
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user