diff --git a/sjplayer/src/sjplayer/AbstractScheduledController.d b/sjplayer/src/sjplayer/AbstractScheduledController.d index 9949565..369beb5 100644 --- a/sjplayer/src/sjplayer/AbstractScheduledController.d +++ b/sjplayer/src/sjplayer/AbstractScheduledController.d @@ -4,12 +4,14 @@ module sjplayer.AbstractScheduledController; import std.algorithm, std.array, std.exception, + std.format, std.range.primitives, std.typecons; import sjscript; -import sjplayer.ScheduledControllerInterface, +import sjplayer.ScriptRuntimeException, + sjplayer.ScheduledControllerInterface, sjplayer.VarStoreInterface, sjplayer.util.Parameter, sjplayer.util.Period; @@ -34,23 +36,31 @@ abstract class AbstractScheduledController : ScheduledControllerInterface { public: float opIndex(string name) const { if (!time_.isNull && name == "time") return time_.get; - return this_.GetVariable(name); + const temp = this_.GetVariable(name); + if (!temp.isNull) return temp.get; + + throw new ScriptRuntimeException( + "unknown variable `%s`".format(name), srcline_, srcchar_); } private: AbstractScheduledController this_; Nullable!float time_; + + size_t srcline_, srcchar_; } void PrepareOperation(ref in ParametersBlock params) { user_vars_.clear(); - auto vars = VarStore(this); + auto vars = VarStore( + this, Nullable!float.init, params.pos.stline, params.pos.stchar); params.parameters. filter!(x => x.type == ParameterType.OnceAssign). each !(x => SetParameter(x, vars)); } void ProcessOperation(float time, ref in ParametersBlock params) { - auto vars = VarStore(this, time.nullable); + auto vars = VarStore( + this, time.nullable, params.pos.stline, params.pos.stchar); params.parameters. filter!(x => x.type != ParameterType.OnceAssign). each !(x => SetParameter(x, vars)); @@ -58,13 +68,21 @@ abstract class AbstractScheduledController : ScheduledControllerInterface { void FinalizeOperation(ref in ParametersBlock params) { } - float GetVariable(string name) const { - if (name in user_vars_) return user_vars_[name]; - return varstore_[name]; + Nullable!float GetVariable(string name) const { + if (name in user_vars_) { + return Nullable!float(user_vars_[name]); + } + auto temp = varstore_[name]; + if (!temp.isNull) return temp; + // TODO: std constants + return Nullable!float.init; } void SetParameter(ref in Parameter param, ref in VarStore vars) { - (param.name.length >= 2 && param.name[0..2] == "__"). - enforce("user defined variables must be prefixed '__'"); + if (param.name.length < 2 || param.name[0..2] != "__") { + throw new ScriptRuntimeException( + "user defined variables must be prefixed as '__'", + param.pos.stline, param.pos.stchar); + } user_vars_[param.name] = 0; param.CalculateParameter(user_vars_[param.name], vars); } @@ -114,7 +132,11 @@ ParametersBlock[] SortParametersBlock(R)(R params) auto before = Period(-1, 0); foreach (param; result) { - (!param.period.IsPeriodIntersectedToPeriod(before)).enforce(); + if (param.period.IsPeriodIntersectedToPeriod(before)) { + throw new ScriptRuntimeException( + "the period is duplicated", + param.pos.stline, param.pos.stchar); + } } return result; } diff --git a/sjplayer/src/sjplayer/ScheduledController.d b/sjplayer/src/sjplayer/ScheduledController.d index 808723d..997b496 100644 --- a/sjplayer/src/sjplayer/ScheduledController.d +++ b/sjplayer/src/sjplayer/ScheduledController.d @@ -64,17 +64,17 @@ class ScheduledController( } } - override float GetVariable(string name) const { + override Nullable!float GetVariable(string name) const { switch (name) { static foreach (map_name, code; ParameterNameMap) { case map_name: - return mixin("target_."~code); + return Nullable!float(mixin("target_."~code)); } default: } static if (MatrixModificationAvailable) { const value = matrix_factory_.GetValueByName(name); - if (!value.isNull) return value.get; + if (!value.isNull) return value; } return super.GetVariable(name); } diff --git a/sjplayer/src/sjplayer/ScriptRuntimeException.d b/sjplayer/src/sjplayer/ScriptRuntimeException.d new file mode 100644 index 0000000..0eaf3a7 --- /dev/null +++ b/sjplayer/src/sjplayer/ScriptRuntimeException.d @@ -0,0 +1,20 @@ +/// License: MIT +module sjplayer.ScriptRuntimeException; + +import sjscript; + +/// +class ScriptRuntimeException : Exception { + public: + /// + this( + string msg, size_t srcline, size_t srcchar, + string file = __FILE__, size_t line = __LINE__) { + super(msg, file, line); + this.srcline = srcline; + this.srcchar = srcchar; + } + + /// + size_t srcline, srcchar; +} diff --git a/sjplayer/src/sjplayer/VarStore.d b/sjplayer/src/sjplayer/VarStore.d index e583132..24d69b6 100644 --- a/sjplayer/src/sjplayer/VarStore.d +++ b/sjplayer/src/sjplayer/VarStore.d @@ -2,7 +2,8 @@ module sjplayer.VarStore; import std.exception, - std.format; + std.format, + std.typecons; import sjplayer.Actor, sjplayer.VarStoreInterface; @@ -15,12 +16,12 @@ class VarStore : VarStoreInterface { actor_ = actor; } - override float opIndex(string name) const { + override Nullable!float opIndex(string name) const { switch (name) { - case "actor_x": return actor_.pos.x; - case "actor_y": return actor_.pos.y; + case "actor_x": return Nullable!float(actor_.pos.x); + case "actor_y": return Nullable!float(actor_.pos.y); - default: throw new Exception("unknown variable %s".format(name)); + default: return Nullable!float.init; } } diff --git a/sjplayer/src/sjplayer/VarStoreInterface.d b/sjplayer/src/sjplayer/VarStoreInterface.d index cb497d4..b38e187 100644 --- a/sjplayer/src/sjplayer/VarStoreInterface.d +++ b/sjplayer/src/sjplayer/VarStoreInterface.d @@ -1,11 +1,13 @@ /// License: MIT module sjplayer.VarStoreInterface; +import std.typecons; + import sjscript; /// interface VarStoreInterface { public: /// - float opIndex(string name) const; + Nullable!float opIndex(string name) const; }