[add] Added the calculate module to calculate Expression.

This commit is contained in:
falsycat 2019-10-05 00:00:00 +00:00
parent 1d3ce20332
commit ad7e005c7c
5 changed files with 102 additions and 33 deletions

View File

@ -1,18 +1,23 @@
/// License: MIT /// 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; module sjscript.Expression;
import std.variant; import std.algorithm,
std.meta,
std.variant;
/// ///
struct Expression { struct Expression {
public: public:
/// ///
Expression opBinary(string op : "+")(Term rhs) { Expression opBinary(string op)(Term rhs) if (op == "+" || op == "-") {
return Expression(terms ~ rhs); static if (op == "-") {
rhs = rhs * -1f;
} }
/// return Expression(terms ~ rhs);
Expression opBinary(string op : "-")(Term rhs) {
return Expression(terms ~ rhs*(-1f));
} }
/// ///
@ -26,26 +31,19 @@ struct Term {
alias Value = Algebraic!(float, string, FunctionCall, Expression); 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)) { static if (is(T == Term)) {
return Term( auto rnumerator = rhs.numerator;
numerator ~ rhs.numerator, auto rdenominator = rhs.denominator;
denominator ~ rhs.denominator); } else static if (staticIndexOf!(T, Value.AllowedTypes) >= 0) {
auto rnumerator = [Value(rhs)];
Value[] rdenominator;
} else { } else {
return Term( static assert(false);
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 if (op == "/") swap(rnumerator, rdenominator);
return Term(numerator ~ rnumerator, denominator ~ rdenominator);
} }
/// ///
@ -59,7 +57,6 @@ struct FunctionCall {
public: public:
/// ///
string name; string name;
/// ///
Expression[] args; Expression[] args;
} }

View File

@ -24,10 +24,10 @@ struct ParametersBlock {
struct Period { struct Period {
public: public:
/// ///
size_t start; float start;
/// ///
size_t end; float end;
} }
/// ///

View File

@ -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;
}

View File

@ -8,7 +8,8 @@ import dast.parse;
import sjscript.Expression, import sjscript.Expression,
sjscript.ParametersBlock, sjscript.ParametersBlock,
sjscript.Token; sjscript.Token,
sjscript.calculate;
/// ///
unittest { unittest {
@ -62,12 +63,13 @@ private class RuleSet {
static Period ParsePeriod( static Period ParsePeriod(
@(TokenType.OpenBracket) Token, @(TokenType.OpenBracket) Token,
@(TokenType.Number) Token begin, Expression start,
@(TokenType.DoubleDot) Token, @(TokenType.DoubleDot) Token,
@(TokenType.Number) Token end, Expression end,
@(TokenType.CloseBracket) Token) { @(TokenType.CloseBracket) Token) {
return Period( 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) { static Parameter[] ParseParameterListFirstItem(Parameter param) {

View File

@ -16,7 +16,8 @@ $define shoot {
translate_y += __dir_y; translate_y += __dir_y;
} }
A [0..10] { $define beat {0}
A [$beat..$beat+10] {
$define sinwave_add_x {0.5} $define sinwave_add_x {0.5}
$define sinwave_add_y {0.5} $define sinwave_add_y {0.5}
$define sinwave_amp_x {0.5} $define sinwave_amp_x {0.5}
@ -24,11 +25,15 @@ A [0..10] {
$define sinwave_hz {2} $define sinwave_hz {2}
$sinwave $sinwave
} }
B [10..20] {
$define beat {10}
B [$beat..$beat+10/2] {
$define horming_speed {0.1} $define horming_speed {0.1}
$horming $horming
} }
C [20..30] {
$define beat {20}
C [$beat..$beat+10/2] {
$define shoot_speed {0.1} $define shoot_speed {0.1}
$shoot $shoot
} }