[add] Added the calculate module to calculate Expression.
This commit is contained in:
parent
1d3ce20332
commit
ad7e005c7c
@ -1,18 +1,23 @@
|
||||
/// 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) {
|
||||
return Expression(terms ~ rhs);
|
||||
Expression opBinary(string op)(Term rhs) if (op == "+" || op == "-") {
|
||||
static if (op == "-") {
|
||||
rhs = rhs * -1f;
|
||||
}
|
||||
///
|
||||
Expression opBinary(string op : "-")(Term rhs) {
|
||||
return Expression(terms ~ rhs*(-1f));
|
||||
return Expression(terms ~ rhs);
|
||||
}
|
||||
|
||||
///
|
||||
@ -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;
|
||||
}
|
||||
|
@ -24,10 +24,10 @@ struct ParametersBlock {
|
||||
struct Period {
|
||||
public:
|
||||
///
|
||||
size_t start;
|
||||
float start;
|
||||
|
||||
///
|
||||
size_t end;
|
||||
float end;
|
||||
}
|
||||
|
||||
///
|
||||
|
65
sjscript/src/sjscript/calculate.d
Normal file
65
sjscript/src/sjscript/calculate.d
Normal 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;
|
||||
}
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
Reference in New Issue
Block a user