[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,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;
}

View File

@ -24,10 +24,10 @@ struct ParametersBlock {
struct Period {
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,
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) {

View File

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