From ad7e005c7c5e51f70c455ebd29825cb758c7a289 Mon Sep 17 00:00:00 2001 From: falsycat Date: Sat, 5 Oct 2019 00:00:00 +0000 Subject: [PATCH] [add] Added the calculate module to calculate Expression. --- sjscript/src/sjscript/Expression.d | 45 ++++++++--------- sjscript/src/sjscript/ParametersBlock.d | 4 +- sjscript/src/sjscript/calculate.d | 65 +++++++++++++++++++++++++ sjscript/src/sjscript/parse.d | 10 ++-- sjscript/test/test01.sj | 11 +++-- 5 files changed, 102 insertions(+), 33 deletions(-) create mode 100644 sjscript/src/sjscript/calculate.d diff --git a/sjscript/src/sjscript/Expression.d b/sjscript/src/sjscript/Expression.d index 6f94c50..5f288f4 100644 --- a/sjscript/src/sjscript/Expression.d +++ b/sjscript/src/sjscript/Expression.d @@ -1,19 +1,24 @@ /// License: MIT +/// +/// Types declared in this file are not considered at copying because of processing speed. +/// So you should add a const qual when use them after parsing. +/// module sjscript.Expression; -import std.variant; +import std.algorithm, + std.meta, + std.variant; /// struct Expression { public: /// - Expression opBinary(string op : "+")(Term rhs) { + Expression opBinary(string op)(Term rhs) if (op == "+" || op == "-") { + static if (op == "-") { + rhs = rhs * -1f; + } return Expression(terms ~ rhs); } - /// - Expression opBinary(string op : "-")(Term rhs) { - return Expression(terms ~ rhs*(-1f)); - } /// Term[] terms; @@ -26,26 +31,19 @@ struct Term { alias Value = Algebraic!(float, string, FunctionCall, Expression); /// - Term opBinary(string op : "*", T)(T rhs) { + Term opBinary(string op, T)(T rhs) if ((op == "*" || op == "/")) { static if (is(T == Term)) { - return Term( - numerator ~ rhs.numerator, - denominator ~ rhs.denominator); + auto rnumerator = rhs.numerator; + auto rdenominator = rhs.denominator; + } else static if (staticIndexOf!(T, Value.AllowedTypes) >= 0) { + auto rnumerator = [Value(rhs)]; + Value[] rdenominator; } else { - return Term( - numerator ~ Value(rhs), denominator); - } - } - /// - Term opBinary(string op : "/", T)(T rhs) { - static if (is(T == Term)) { - return Term( - numerator ~ rhs.denominator, - denominator ~ rhs.numerator); - } else { - return Term( - numerator, denominator ~ Value(rhs)); + static assert(false); } + static if (op == "/") swap(rnumerator, rdenominator); + + return Term(numerator ~ rnumerator, denominator ~ rdenominator); } /// @@ -59,7 +57,6 @@ struct FunctionCall { public: /// string name; - /// Expression[] args; } diff --git a/sjscript/src/sjscript/ParametersBlock.d b/sjscript/src/sjscript/ParametersBlock.d index 29d083b..3f526fd 100644 --- a/sjscript/src/sjscript/ParametersBlock.d +++ b/sjscript/src/sjscript/ParametersBlock.d @@ -24,10 +24,10 @@ struct ParametersBlock { struct Period { public: /// - size_t start; + float start; /// - size_t end; + float end; } /// diff --git a/sjscript/src/sjscript/calculate.d b/sjscript/src/sjscript/calculate.d new file mode 100644 index 0000000..59db6ec --- /dev/null +++ b/sjscript/src/sjscript/calculate.d @@ -0,0 +1,65 @@ +/// License: MIT +module sjscript.calculate; + +import std.algorithm, + std.exception, + std.format, + std.math, + std.traits, + std.variant; + +import sjscript.Expression; + +/// +enum IsVarStore(T) = + is(typeof((T vars, string name) => vars[name])) && + is(ReturnType!((T vars, string name) => vars[name]) == float); +static assert(IsVarStore!(float[string])); + +/// +struct NullVarStore { + public: + static float opIndex(string name) { + // TODO: error handling + throw new Exception("undefined variable %s".format(name)); + } + static assert(IsVarStore!NullVarStore); +} + +/// +float CalculateExpression(VarStore)(in Expression expr, VarStore vars) + if (IsVarStore!VarStore) { + return expr.terms.map!(x => x.CalculateTerm(vars)).sum; +} + +/// +float CalculateTerm(VarStore)(in Term term, VarStore vars) + if (IsVarStore!VarStore) { + auto num = 1f, den = 1f; + term.numerator. + map!(x => x.CalculateTermValue(vars)). + each!(x => num *= x); + term.denominator. + map!(x => x.CalculateTermValue(vars)). + each!(x => den *= x); + (!den.approxEqual(0)).enforce(); + return num / den; +} + +/// +float CalculateTermValue(VarStore)(in Term.Value value, VarStore vars) + if (IsVarStore!VarStore) { + return value.visit!( + (string name) => vars[name], + (float val) => val, + (in FunctionCall func) => func.CalculateFunction(vars), + (in Expression expr) => expr.CalculateExpression(vars)); +} + +/// +float CalculateFunction(VarStore)(in FunctionCall fcall, VarStore vars) + if (IsVarStore!VarStore) { + const args = fcall.args.map!(x => x.CalculateExpression(vars)); + // TODO: calling function + return 0; +} diff --git a/sjscript/src/sjscript/parse.d b/sjscript/src/sjscript/parse.d index df578d3..eb2a033 100644 --- a/sjscript/src/sjscript/parse.d +++ b/sjscript/src/sjscript/parse.d @@ -8,7 +8,8 @@ import dast.parse; import sjscript.Expression, sjscript.ParametersBlock, - sjscript.Token; + sjscript.Token, + sjscript.calculate; /// unittest { @@ -62,12 +63,13 @@ private class RuleSet { static Period ParsePeriod( @(TokenType.OpenBracket) Token, - @(TokenType.Number) Token begin, + Expression start, @(TokenType.DoubleDot) Token, - @(TokenType.Number) Token end, + Expression end, @(TokenType.CloseBracket) Token) { return Period( - begin.text.to!float.to!int, end.text.to!float.to!int); + start.CalculateExpression(NullVarStore()), + end .CalculateExpression(NullVarStore())); } static Parameter[] ParseParameterListFirstItem(Parameter param) { diff --git a/sjscript/test/test01.sj b/sjscript/test/test01.sj index 931f608..d60054f 100644 --- a/sjscript/test/test01.sj +++ b/sjscript/test/test01.sj @@ -16,7 +16,8 @@ $define shoot { translate_y += __dir_y; } -A [0..10] { +$define beat {0} +A [$beat..$beat+10] { $define sinwave_add_x {0.5} $define sinwave_add_y {0.5} $define sinwave_amp_x {0.5} @@ -24,11 +25,15 @@ A [0..10] { $define sinwave_hz {2} $sinwave } -B [10..20] { + +$define beat {10} +B [$beat..$beat+10/2] { $define horming_speed {0.1} $horming } -C [20..30] { + +$define beat {20} +C [$beat..$beat+10/2] { $define shoot_speed {0.1} $shoot }