--- linuxsampler/trunk/src/scriptvm/tree.cpp 2019/08/29 13:44:35 3580 +++ linuxsampler/trunk/src/scriptvm/tree.cpp 2019/08/30 11:40:25 3581 @@ -11,6 +11,7 @@ #include #include "tree.h" #include "../common/global_private.h" +#include "../common/RTMath.h" #include namespace LinuxSampler { @@ -30,20 +31,96 @@ fflush(stdout); } +vmint Unit::convIntToUnitFactor(vmint iValue, VMUnit* srcUnit, VMUnit* dstUnit) { + vmfloat f = (vmfloat) iValue; + vmfloat factor = srcUnit->unitFactor() / dstUnit->unitFactor(); + if (sizeof(vmfloat) == sizeof(float)) + return llroundf(f * factor); + else + return llround(f * factor); +} + +vmint Unit::convIntToUnitFactor(vmint iValue, vmfloat srcFactor, vmfloat dstFactor) { + vmfloat f = (vmfloat) iValue; + vmfloat factor = srcFactor / dstFactor; + if (sizeof(vmfloat) == sizeof(float)) + return llroundf(f * factor); + else + return llround(f * factor); +} + +vmfloat Unit::convRealToUnitFactor(vmfloat fValue, VMUnit* srcUnit, VMUnit* dstUnit) { + vmfloat factor = srcUnit->unitFactor() / dstUnit->unitFactor(); + return fValue * factor; +} + +vmfloat Unit::convRealToUnitFactor(vmfloat fValue, vmfloat srcFactor, vmfloat dstFactor) { + vmfloat factor = srcFactor / dstFactor; + return fValue * factor; +} + +vmint IntExpr::evalIntToUnitFactor(vmfloat unitFactor) { + vmfloat f = (vmfloat) evalInt(); + vmfloat factor = this->unitFactor() / unitFactor; + if (sizeof(vmfloat) == sizeof(float)) + return llroundf(f * factor); + else + return llround(f * factor); +} + +static String _unitFactorToShortStr(vmfloat unitFactor) { + const long int tens = lround( log10(unitFactor) ); + switch (tens) { + case 3: return "k"; // kilo = 10^3 + case 2: return "h"; // hecto = 10^2 + case 1: return "da"; // deca = 10 + case 0: return "" ; // -- = 1 + case -1: return "d"; // deci = 10^-1 + case -2: return "c"; // centi = 10^-2 (this is also used for tuning "cents") + case -3: return "m"; // milli = 10^-3 + case -4: return "md"; // milli deci = 10^-4 + case -5: return "mc"; // milli centi = 10^-5 (this is also used for tuning "cents") + case -6: return "u"; // micro = 10^-6 + default: return "*10^" + ToString(tens); + } +} + +static String _unitToStr(Unit* unit) { + const StdUnit_t type = unit->unitType(); + String sType; + switch (type) { + case VM_NO_UNIT: break; + case VM_SECOND: sType = "s"; break; + case VM_HERTZ: sType = "Hz"; break; + case VM_BEL: sType = "B"; break; + } + + String prefix = _unitFactorToShortStr( unit->unitFactor() ); + + return prefix + sType; +} + String IntExpr::evalCastToStr() { - return ToString(evalInt()); + return ToString(evalInt()) + _unitToStr(this); +} + +vmfloat RealExpr::evalRealToUnitFactor(vmfloat unitFactor) { + vmfloat f = evalReal(); + vmfloat factor = this->unitFactor() / unitFactor; + return f * factor; } String RealExpr::evalCastToStr() { - return ToString(evalReal()); + return ToString(evalReal()) + _unitToStr(this); } String IntArrayExpr::evalCastToStr() { String s = "{"; for (vmint i = 0; i < arraySize(); ++i) { vmint val = evalIntElement(i); + vmfloat factor = unitFactorOfElement(i); if (i) s += ","; - s += ToString(val); + s += ToString(val) + _unitFactorToShortStr(factor); } s += "}"; return s; @@ -53,41 +130,19 @@ String s = "{"; for (vmint i = 0; i < arraySize(); ++i) { vmfloat val = evalRealElement(i); + vmfloat factor = unitFactorOfElement(i); if (i) s += ","; - s += ToString(val); + s += ToString(val) + _unitFactorToShortStr(factor); } s += "}"; return s; } -MetricPrefix_t Unit::unitPrefix(vmuint i) const { - if (i >= prefix.size()) return VM_NO_PREFIX; - return prefix[i]; -} - -void Unit::setUnit(const std::vector& prefix, StdUnit_t type) { - this->prefix.resize( prefix.size() ); - for (vmuint i = 0; i < prefix.size(); ++i) - this->prefix[i] = prefix[i]; - - unit = type; -} - -void Unit::setUnit(const MetricPrefix_t* prefixes, StdUnit_t type) { - unit = type; - prefix.clear(); - for (int i = 0; i < 2 && prefixes[i]; ++i) - prefix.add(prefixes[i]); -} - -void Unit::copyUnitFrom(const UnitRef& src) { - unit = src->unitType(); - prefix.clear(); - for (int i = 0; true; ++i) { - MetricPrefix_t p = src->unitPrefix(i); - if (!p) return; - prefix.add(p); - } +IntLiteral::IntLiteral(const IntLitDef& def) : + IntExpr(), Unit(def.unitType), + value(def.value), unitPrefixFactor(def.unitFactor), + finalVal(def.isFinal) +{ } vmint IntLiteral::evalInt() { @@ -99,6 +154,13 @@ printf("IntLiteral %lld\n", value); } +RealLiteral::RealLiteral(const RealLitDef& def) : + RealExpr(), Unit(def.unitType), + value(def.value), unitPrefixFactor(def.unitFactor), + finalVal(def.isFinal) +{ +} + vmfloat RealLiteral::evalReal() { return value; } @@ -113,16 +175,49 @@ printf("StringLiteral: '%s'\n", value.c_str()); } +Add::Add(ScalarNumberExprRef lhs, ScalarNumberExprRef rhs) : + VaritypeScalarBinaryOp(lhs, rhs), + Unit( + // lhs and rhs are forced to be same unit type at parse time, so either one is fine here + (lhs) ? lhs->unitType() : VM_NO_UNIT + ) +{ +} + vmint Add::evalInt() { IntExpr* pLHS = dynamic_cast(&*lhs); - IntExpr* pRHS = dynamic_cast(&*rhs);; - return (pLHS && pRHS) ? pLHS->evalInt() + pRHS->evalInt() : 0; + IntExpr* pRHS = dynamic_cast(&*rhs); + if (!pLHS || !pRHS) return 0; + // eval*() call is required before calling unitFactor(), since the latter does not evaluate expressions! + vmint lvalue = pLHS->evalInt(); + vmint rvalue = pRHS->evalInt(); + if (pLHS->unitFactor() == pRHS->unitFactor()) + return lvalue + rvalue; + if (pLHS->unitFactor() < pRHS->unitFactor()) + return lvalue + Unit::convIntToUnitFactor(rvalue, pRHS, pLHS); + else + return Unit::convIntToUnitFactor(lvalue, pLHS, pRHS) + rvalue; } vmfloat Add::evalReal() { RealExpr* pLHS = dynamic_cast(&*lhs); - RealExpr* pRHS = dynamic_cast(&*rhs);; - return (pLHS && pRHS) ? pLHS->evalReal() + pRHS->evalReal() : 0; + RealExpr* pRHS = dynamic_cast(&*rhs); + if (!pLHS || !pRHS) return 0; + // eval*() call is required before calling unitFactor(), since the latter does not evaluate expressions! + vmfloat lvalue = pLHS->evalReal(); + vmfloat rvalue = pRHS->evalReal(); + if (pLHS->unitFactor() == pRHS->unitFactor()) + return lvalue + rvalue; + if (pLHS->unitFactor() < pRHS->unitFactor()) + return lvalue + Unit::convRealToUnitFactor(rvalue, pRHS, pLHS); + else + return Unit::convRealToUnitFactor(lvalue, pLHS, pRHS) + rvalue; +} + +vmfloat Add::unitFactor() const { + const ScalarNumberExpr* pLHS = dynamic_cast(&*lhs); + const ScalarNumberExpr* pRHS = dynamic_cast(&*rhs); + return (pLHS->unitFactor() < pRHS->unitFactor()) ? pLHS->unitFactor() : pRHS->unitFactor(); } void Add::dump(int level) { @@ -136,16 +231,49 @@ printf(")\n"); } +Sub::Sub(ScalarNumberExprRef lhs, ScalarNumberExprRef rhs) : + VaritypeScalarBinaryOp(lhs, rhs), + Unit( + // lhs and rhs are forced to be same unit type at parse time, so either one is fine here + (lhs) ? lhs->unitType() : VM_NO_UNIT + ) +{ +} + vmint Sub::evalInt() { IntExpr* pLHS = dynamic_cast(&*lhs); - IntExpr* pRHS = dynamic_cast(&*rhs);; - return (pLHS && pRHS) ? pLHS->evalInt() - pRHS->evalInt() : 0; + IntExpr* pRHS = dynamic_cast(&*rhs); + if (!pLHS || !pRHS) return 0; + // eval*() call is required before calling unitFactor(), since the latter does not evaluate expressions! + vmint lvalue = pLHS->evalInt(); + vmint rvalue = pRHS->evalInt(); + if (pLHS->unitFactor() == pRHS->unitFactor()) + return lvalue - rvalue; + if (pLHS->unitFactor() < pRHS->unitFactor()) + return lvalue - Unit::convIntToUnitFactor(rvalue, pRHS, pLHS); + else + return Unit::convIntToUnitFactor(lvalue, pLHS, pRHS) - rvalue; } vmfloat Sub::evalReal() { RealExpr* pLHS = dynamic_cast(&*lhs); - RealExpr* pRHS = dynamic_cast(&*rhs);; - return (pLHS && pRHS) ? pLHS->evalReal() - pRHS->evalReal() : 0; + RealExpr* pRHS = dynamic_cast(&*rhs); + if (!pLHS || !pRHS) return 0; + // eval*() call is required before calling unitFactor(), since the latter does not evaluate expressions! + vmfloat lvalue = pLHS->evalReal(); + vmfloat rvalue = pRHS->evalReal(); + if (pLHS->unitFactor() == pRHS->unitFactor()) + return lvalue - rvalue; + if (pLHS->unitFactor() < pRHS->unitFactor()) + return lvalue - Unit::convRealToUnitFactor(rvalue, pRHS, pLHS); + else + return Unit::convRealToUnitFactor(lvalue, pLHS, pRHS) - rvalue; +} + +vmfloat Sub::unitFactor() const { + const ScalarNumberExpr* pLHS = dynamic_cast(&*lhs); + const ScalarNumberExpr* pRHS = dynamic_cast(&*rhs); + return (pLHS->unitFactor() < pRHS->unitFactor()) ? pLHS->unitFactor() : pRHS->unitFactor(); } void Sub::dump(int level) { @@ -159,6 +287,15 @@ printf(")\n"); } +Mul::Mul(ScalarNumberExprRef lhs, ScalarNumberExprRef rhs) : + VaritypeScalarBinaryOp(lhs, rhs), + Unit( + // currently the NKSP parser only allows a unit type on either side on multiplications + (lhs->unitType()) ? lhs->unitType() : rhs->unitType() + ) +{ +} + vmint Mul::evalInt() { IntExpr* pLHS = dynamic_cast(&*lhs); IntExpr* pRHS = dynamic_cast(&*rhs);; @@ -182,18 +319,20 @@ printf(")\n"); } -MetricPrefix_t Mul::unitPrefix(vmuint i) const { +vmfloat Mul::unitFactor() const { const ScalarNumberExpr* pLHS = dynamic_cast(&*lhs); const ScalarNumberExpr* pRHS = dynamic_cast(&*rhs); - // currently the NKSP parser only allows a unit prefix on either side - return (pLHS->unitPrefix(0)) ? pLHS->unitPrefix(i) : pRHS->unitPrefix(i); + return pLHS->unitFactor() * pRHS->unitFactor(); } -StdUnit_t Mul::unitType() const { - const ScalarNumberExpr* pLHS = dynamic_cast(&*lhs); - const ScalarNumberExpr* pRHS = dynamic_cast(&*rhs); - // currently the NKSP parser only allows a unit type on either side - return (pLHS->unitType()) ? pLHS->unitType() : pRHS->unitType(); +Div::Div(ScalarNumberExprRef lhs, ScalarNumberExprRef rhs) : + VaritypeScalarBinaryOp(lhs, rhs), + Unit( + // the NKSP parser only allows either A) a unit type on left side and none + // on right side or B) an identical unit type on both sides + (lhs->unitType() && rhs->unitType()) ? VM_NO_UNIT : lhs->unitType() + ) +{ } vmint Div::evalInt() { @@ -208,7 +347,7 @@ vmfloat Div::evalReal() { RealExpr* pLHS = dynamic_cast(&*lhs); - RealExpr* pRHS = dynamic_cast(&*rhs);; + RealExpr* pRHS = dynamic_cast(&*rhs); if (!pLHS || !pRHS) return 0; vmfloat l = pLHS->evalReal(); vmfloat r = pRHS->evalReal(); @@ -227,25 +366,15 @@ printf(")\n"); } -MetricPrefix_t Div::unitPrefix(vmuint i) const { - const ScalarNumberExpr* pLHS = dynamic_cast(&*lhs); - const ScalarNumberExpr* pRHS = dynamic_cast(&*rhs); - // currently the NKSP parser only allows either A) a unit prefix on left - // side and none on right side or B) an identical unit prefix on both sides - return (pLHS->unitPrefix(0) && pRHS->unitPrefix(0)) ? VM_NO_PREFIX : pLHS->unitPrefix(i); -} - -StdUnit_t Div::unitType() const { +vmfloat Div::unitFactor() const { const ScalarNumberExpr* pLHS = dynamic_cast(&*lhs); const ScalarNumberExpr* pRHS = dynamic_cast(&*rhs); - // the NKSP parser only allows either A) a unit type on left side and none - // on right side or B) an identical unit type on both sides - return (pLHS->unitType() && pRHS->unitType()) ? VM_NO_UNIT : pLHS->unitType(); + return pLHS->unitFactor() / pRHS->unitFactor(); } vmint Mod::evalInt() { IntExpr* pLHS = dynamic_cast(&*lhs); - IntExpr* pRHS = dynamic_cast(&*rhs);; + IntExpr* pRHS = dynamic_cast(&*rhs); return (pLHS && pRHS) ? pLHS->evalInt() % pRHS->evalInt() : 0; } @@ -369,8 +498,13 @@ return false; } -DynamicVariableCall::DynamicVariableCall(const String& name, ParserContext* ctx, VMDynVar* v) - : Variable(ctx, 0, false), dynVar(v), varName(name) +DynamicVariableCall::DynamicVariableCall(const String& name, ParserContext* ctx, VMDynVar* v) : + Variable({ + .ctx = ctx, + .elements = 0 + }), + Unit(VM_NO_UNIT), + dynVar(v), varName(name) { } @@ -400,6 +534,14 @@ printf("Dynamic Variable '%s'\n", varName.c_str()); } +FunctionCall::FunctionCall(const char* function, ArgsRef args, VMFunction* fn) : + Unit( + (fn) ? fn->returnUnitType(dynamic_cast(&*args)) : VM_NO_UNIT + ), + functionName(function), args(args), fn(fn), result(NULL) +{ +} + void FunctionCall::dump(int level) { printIndents(level); printf("FunctionCall '%s' args={\n", functionName.c_str()); @@ -414,6 +556,21 @@ return fn->returnType(dynamic_cast(&*self->args)); } +vmfloat FunctionCall::unitFactor() const { + if (!fn || !result) return VM_NO_FACTOR; + VMExpr* expr = result->resultValue(); + if (!expr) return VM_NO_FACTOR; + VMScalarNumberExpr* scalar = expr->asScalarNumberExpr(); + if (!scalar) return VM_NO_FACTOR; + return scalar->unitFactor(); +} + +bool FunctionCall::isFinal() const { + if (!fn) return false; + FunctionCall* self = const_cast(this); + return fn->returnsFinal(dynamic_cast(&*self->args)); +} + VMFnResult* FunctionCall::execVMFn() { if (!fn) return NULL; // assuming here that all argument checks (amount and types) have been made @@ -422,14 +579,14 @@ } StmtFlags_t FunctionCall::exec() { - VMFnResult* result = execVMFn(); + result = execVMFn(); if (!result) return StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED); return result->resultFlags(); } vmint FunctionCall::evalInt() { - VMFnResult* result = execVMFn(); + result = execVMFn(); if (!result) return 0; VMIntExpr* intExpr = dynamic_cast(result->resultValue()); if (!intExpr) return 0; @@ -437,7 +594,7 @@ } vmfloat FunctionCall::evalReal() { - VMFnResult* result = execVMFn(); + result = execVMFn(); if (!result) return 0; VMRealExpr* realExpr = dynamic_cast(result->resultValue()); if (!realExpr) return 0; @@ -445,21 +602,19 @@ } VMIntArrayExpr* FunctionCall::asIntArray() const { - VMFnResult* result = const_cast(this)->execVMFn(); if (!result) return 0; VMIntArrayExpr* intArrExpr = dynamic_cast(result->resultValue()); return intArrExpr; } VMRealArrayExpr* FunctionCall::asRealArray() const { - VMFnResult* result = const_cast(this)->execVMFn(); if (!result) return 0; VMRealArrayExpr* realArrExpr = dynamic_cast(result->resultValue()); return realArrExpr; } String FunctionCall::evalStr() { - VMFnResult* result = execVMFn(); + result = execVMFn(); if (!result) return ""; VMStringExpr* strExpr = dynamic_cast(result->resultValue()); if (!strExpr) return ""; @@ -467,7 +622,7 @@ } String FunctionCall::evalCastToStr() { - VMFnResult* result = execVMFn(); + result = execVMFn(); if (!result) return ""; const ExprType_t resultType = result->resultValue()->exprType(); if (resultType == STRING_EXPR) { @@ -482,20 +637,24 @@ } } -ScalarNumberVariable::ScalarNumberVariable(ParserContext* ctx, vmint _memPos, - bool _bConst, bool _bPolyphonic, - bool _bFinal) - : Variable(ctx, _memPos, _bConst), - Unit(), - polyphonic(_bPolyphonic), finalVal(_bFinal) +Variable::Variable(const VariableDecl& decl) : + context(decl.ctx), memPos(decl.memPos), bConst(decl.isConst) { } -IntVariable::IntVariable(ParserContext* ctx) - : ScalarNumberVariable(ctx, ctx ? ctx->globalIntVarCount++ : 0) +ScalarNumberVariable::ScalarNumberVariable(const VariableDecl& decl) : + Variable(decl), + Unit(decl.unitType), + unitFactorMemPos(decl.unitFactorMemPos), polyphonic(decl.isPolyphonic), + finalVal(decl.isFinal) { - //printf("globalIntVar parserctx=0x%lx memPOS=%d\n", ctx, memPos); - assert(ctx); +} + +vmfloat ScalarNumberVariable::unitFactor() const { + if (isPolyphonic()) { + return context->execContext->polyphonicUnitFactorMemory[unitFactorMemPos]; + } + return (*context->globalUnitFactorMemory)[unitFactorMemPos]; } inline static vmint postfixInc(vmint& object, vmint incBy) { @@ -504,28 +663,44 @@ return i; } -IntVariable::IntVariable(ParserContext* ctx, bool bPolyphonic, bool bConst, vmint size) - : ScalarNumberVariable( - ctx, - !ctx ? 0 : bPolyphonic ? postfixInc(ctx->polyphonicIntVarCount, size) : - postfixInc(ctx->globalIntVarCount, size), - bConst, bPolyphonic - ) -{ - //printf("IntVar size=%d parserCtx=0x%lx\n", size, (uint64_t)ctx); - if (bPolyphonic) { - //printf("polyIntVar memPOS=%d\n", memPos); - assert(ctx); - } +IntVariable::IntVariable(const VariableDecl& decl) : + ScalarNumberVariable({ + .ctx = decl.ctx, + .isPolyphonic = decl.isPolyphonic, + .isConst = decl.isConst, + .isFinal = decl.isFinal, + .elements = decl.elements, + .memPos = ( + (!decl.ctx) ? 0 : + (decl.isPolyphonic) ? + postfixInc(decl.ctx->polyphonicIntVarCount, decl.elements) : + postfixInc(decl.ctx->globalIntVarCount, decl.elements) + ), + .unitFactorMemPos = ( + (!decl.ctx) ? 0 : + (decl.isPolyphonic) ? + postfixInc(decl.ctx->polyphonicUnitFactorCount, decl.elements) : + postfixInc(decl.ctx->globalUnitFactorCount, decl.elements) + ), + .unitType = decl.unitType + }), + Unit(decl.unitType) +{ + //printf("IntVar parserctx=0x%lx memPOS=%d\n", ctx, memPos); + assert(!decl.isPolyphonic || decl.ctx); } void IntVariable::assign(Expression* expr) { IntExpr* intExpr = dynamic_cast(expr); if (intExpr) { - if (isPolyphonic()) + //NOTE: sequence matters! evalInt() must be called before getting unitFactor() ! + if (isPolyphonic()) { context->execContext->polyphonicIntMemory[memPos] = intExpr->evalInt(); - else + context->execContext->polyphonicUnitFactorMemory[unitFactorMemPos] = intExpr->unitFactor(); + } else { (*context->globalIntMemory)[memPos] = intExpr->evalInt(); + (*context->globalUnitFactorMemory)[unitFactorMemPos] = intExpr->unitFactor(); + } } } @@ -544,35 +719,44 @@ //printf("IntVariable memPos=%d\n", memPos); } -RealVariable::RealVariable(ParserContext* ctx) - : ScalarNumberVariable(ctx, ctx ? ctx->globalRealVarCount++ : 0) +RealVariable::RealVariable(const VariableDecl& decl) : + ScalarNumberVariable({ + .ctx = decl.ctx, + .isPolyphonic = decl.isPolyphonic, + .isConst = decl.isConst, + .isFinal = decl.isFinal, + .elements = decl.elements, + .memPos = ( + (!decl.ctx) ? 0 : + (decl.isPolyphonic) ? + postfixInc(decl.ctx->polyphonicRealVarCount, decl.elements) : + postfixInc(decl.ctx->globalRealVarCount, decl.elements) + ), + .unitFactorMemPos = ( + (!decl.ctx) ? 0 : + (decl.isPolyphonic) ? + postfixInc(decl.ctx->polyphonicUnitFactorCount, decl.elements) : + postfixInc(decl.ctx->globalUnitFactorCount, decl.elements) + ), + .unitType = decl.unitType + }), + Unit(decl.unitType) { - //printf("globalRealVar parserctx=0x%lx memPOS=%d\n", ctx, memPos); - assert(ctx); -} - -RealVariable::RealVariable(ParserContext* ctx, bool bPolyphonic, bool bConst, vmint size) - : ScalarNumberVariable( - ctx, - !ctx ? 0 : bPolyphonic ? postfixInc(ctx->polyphonicRealVarCount, size) : - postfixInc(ctx->globalRealVarCount, size), - bConst, bPolyphonic - ) -{ - //printf("RealVar size=%d parserCtx=0x%lx\n", size, (uint64_t)ctx); - if (bPolyphonic) { - //printf("polyRealVar memPOS=%d\n", memPos); - assert(ctx); - } + //printf("RealVar parserctx=0x%lx memPOS=%d\n", ctx, memPos); + assert(!decl.isPolyphonic || decl.ctx); } void RealVariable::assign(Expression* expr) { RealExpr* realExpr = dynamic_cast(expr); if (realExpr) { - if (isPolyphonic()) + //NOTE: sequence matters! evalReal() must be called before getting unitFactor() ! + if (isPolyphonic()) { context->execContext->polyphonicRealMemory[memPos] = realExpr->evalReal(); - else + context->execContext->polyphonicUnitFactorMemory[unitFactorMemPos] = realExpr->unitFactor(); + } else { (*context->globalRealMemory)[memPos] = realExpr->evalReal(); + (*context->globalUnitFactorMemory)[unitFactorMemPos] = realExpr->unitFactor(); + } } } @@ -591,8 +775,19 @@ //printf("RealVariable memPos=%d\n", memPos); } -ConstIntVariable::ConstIntVariable(vmint value) - : IntVariable(NULL,false,true), value(value) +ConstIntVariable::ConstIntVariable(const IntVarDef& def) : + IntVariable({ + .ctx = def.ctx, + .isPolyphonic = false, + .isConst = true, + .isFinal = def.isFinal, + .elements = 1, + .memPos = def.memPos, + .unitFactorMemPos = def.unitFactorMemPos, + .unitType = def.unitType + }), + Unit(def.unitType), + value(def.value), unitPrefixFactor(def.unitFactor) { } @@ -616,8 +811,19 @@ printf("ConstIntVariable val=%lld\n", value); } -ConstRealVariable::ConstRealVariable(vmfloat value) - : RealVariable(NULL,false,true), value(value) +ConstRealVariable::ConstRealVariable(const RealVarDef& def) : + RealVariable({ + .ctx = def.ctx, + .isPolyphonic = false, + .isConst = true, + .isFinal = def.isFinal, + .elements = 1, + .memPos = def.memPos, + .unitFactorMemPos = def.unitFactorMemPos, + .unitType = def.unitType + }), + Unit(def.unitType), + value(def.value), unitPrefixFactor(def.unitFactor) { } @@ -634,8 +840,19 @@ printf("ConstRealVariable val=%f\n", value); } -BuiltInIntVariable::BuiltInIntVariable(const String& name, VMIntPtr* ptr) - : IntVariable(NULL,false,false), name(name), ptr(ptr) +BuiltInIntVariable::BuiltInIntVariable(const String& name, VMIntPtr* ptr) : + IntVariable({ + .ctx = NULL, + .isPolyphonic = false, + .isConst = false, // may or may not be modifyable though! + .isFinal = false, + .elements = 0, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = VM_NO_UNIT + }), + Unit(VM_NO_UNIT), + name(name), ptr(ptr) { } @@ -654,8 +871,18 @@ printf("Built-in IntVar '%s'\n", name.c_str()); } -PolyphonicIntVariable::PolyphonicIntVariable(ParserContext* ctx) - : IntVariable(ctx,true,false) +PolyphonicIntVariable::PolyphonicIntVariable(const VariableDecl& decl) : + IntVariable({ + .ctx = decl.ctx, + .isPolyphonic = true, + .isConst = decl.isConst, + .isFinal = decl.isFinal, + .elements = 1, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = decl.unitType + }), + Unit(decl.unitType) { } @@ -664,8 +891,18 @@ printf("PolyphonicIntVariable\n"); } -PolyphonicRealVariable::PolyphonicRealVariable(ParserContext* ctx) - : RealVariable(ctx,true,false) +PolyphonicRealVariable::PolyphonicRealVariable(const VariableDecl& decl) : + RealVariable({ + .ctx = decl.ctx, + .isPolyphonic = true, + .isConst = decl.isConst, + .isFinal = decl.isFinal, + .elements = 1, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = decl.unitType + }), + Unit(decl.unitType) { } @@ -674,25 +911,61 @@ printf("PolyphonicRealVariable\n"); } -IntArrayVariable::IntArrayVariable(ParserContext* ctx, vmint size) - : Variable(ctx, 0, false) +IntArrayVariable::IntArrayVariable(ParserContext* ctx, vmint size) : + Variable({ + .ctx = ctx, + .isPolyphonic = false, + .isConst = false, + .isFinal = false, + .elements = 0, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = VM_NO_UNIT + }) { values.resize(size); memset(&values[0], 0, size * sizeof(vmint)); -} -IntArrayVariable::IntArrayVariable(ParserContext* ctx, vmint size, ArgsRef values, bool _bConst) - : Variable(ctx, 0, _bConst) + unitFactors.resize(size); + for (size_t i = 0; i < size; ++i) + unitFactors[i] = VM_NO_FACTOR; +} + +IntArrayVariable::IntArrayVariable(ParserContext* ctx, vmint size, + ArgsRef values, bool _bConst) : + Variable({ + .ctx = ctx, + .isPolyphonic = false, + .isConst = _bConst, + .isFinal = false, + .elements = 0, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = VM_NO_UNIT + }) { this->values.resize(size); + this->unitFactors.resize(size); for (vmint i = 0; i < values->argsCount(); ++i) { VMIntExpr* expr = dynamic_cast(values->arg(i)); - if (expr) this->values[i] = expr->evalInt(); + if (expr) { + this->values[i] = expr->evalInt(); + this->unitFactors[i] = expr->unitFactor(); + } } } -IntArrayVariable::IntArrayVariable(ParserContext* ctx, bool bConst) - : Variable(ctx, 0, bConst) +IntArrayVariable::IntArrayVariable(ParserContext* ctx, bool bConst) : + Variable({ + .ctx = ctx, + .isPolyphonic = false, + .isConst = bConst, + .isFinal = false, + .elements = 0, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = VM_NO_UNIT + }) { } @@ -706,6 +979,16 @@ values[i] = value; } +vmfloat IntArrayVariable::unitFactorOfElement(vmuint i) const { + if (i >= unitFactors.size()) return VM_NO_FACTOR; + return unitFactors[i]; +} + +void IntArrayVariable::assignElementUnitFactor(vmuint i, vmfloat factor) { + if (i >= unitFactors.size()) return; + unitFactors[i] = factor; +} + void IntArrayVariable::dump(int level) { printIndents(level); printf("IntArray("); @@ -720,25 +1003,61 @@ printf(")\n"); } -RealArrayVariable::RealArrayVariable(ParserContext* ctx, vmint size) - : Variable(ctx, 0, false) +RealArrayVariable::RealArrayVariable(ParserContext* ctx, vmint size) : + Variable({ + .ctx = ctx, + .isPolyphonic = false, + .isConst = false, + .isFinal = false, + .elements = 0, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = VM_NO_UNIT + }) { values.resize(size); memset(&values[0], 0, size * sizeof(vmfloat)); -} -RealArrayVariable::RealArrayVariable(ParserContext* ctx, vmint size, ArgsRef values, bool _bConst) - : Variable(ctx, 0, _bConst) + unitFactors.resize(size); + for (size_t i = 0; i < size; ++i) + unitFactors[i] = VM_NO_FACTOR; +} + +RealArrayVariable::RealArrayVariable(ParserContext* ctx, vmint size, + ArgsRef values, bool _bConst) : + Variable({ + .ctx = ctx, + .isPolyphonic = false, + .isConst = _bConst, + .isFinal = false, + .elements = 0, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = VM_NO_UNIT + }) { this->values.resize(size); + this->unitFactors.resize(size); for (vmint i = 0; i < values->argsCount(); ++i) { VMRealExpr* expr = dynamic_cast(values->arg(i)); - if (expr) this->values[i] = expr->evalReal(); + if (expr) { + this->values[i] = expr->evalReal(); + this->unitFactors[i] = expr->unitFactor(); + } } } -RealArrayVariable::RealArrayVariable(ParserContext* ctx, bool bConst) - : Variable(ctx, 0, bConst) +RealArrayVariable::RealArrayVariable(ParserContext* ctx, bool bConst) : + Variable({ + .ctx = ctx, + .isPolyphonic = false, + .isConst = bConst, + .isFinal = false, + .elements = 0, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = VM_NO_UNIT + }) { } @@ -752,6 +1071,16 @@ values[i] = value; } +vmfloat RealArrayVariable::unitFactorOfElement(vmuint i) const { + if (i >= unitFactors.size()) return VM_NO_FACTOR; + return unitFactors[i]; +} + +void RealArrayVariable::assignElementUnitFactor(vmuint i, vmfloat factor) { + if (i >= unitFactors.size()) return; + unitFactors[i] = factor; +} + void RealArrayVariable::dump(int level) { printIndents(level); printf("RealArray("); @@ -766,8 +1095,10 @@ printf(")\n"); } -BuiltInIntArrayVariable::BuiltInIntArrayVariable(const String& name, VMInt8Array* array) - : IntArrayVariable(NULL, false), name(name), array(array) +BuiltInIntArrayVariable::BuiltInIntArrayVariable(const String& name, + VMInt8Array* array) : + IntArrayVariable(NULL, false), + name(name), array(array) { } @@ -785,8 +1116,19 @@ printf("Built-In Int Array Variable '%s'\n", name.c_str()); } -IntArrayElement::IntArrayElement(IntArrayExprRef array, IntExprRef arrayIndex) - : IntVariable(NULL, false, false, 0), array(array), index(arrayIndex) +IntArrayElement::IntArrayElement(IntArrayExprRef array, IntExprRef arrayIndex) : + IntVariable({ + .ctx = NULL, + .isPolyphonic = (array) ? array->isPolyphonic() : false, + .isConst = (array) ? array->isConstExpr() : false, + .isFinal = false, + .elements = 0, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = VM_NO_UNIT + }), + Unit(VM_NO_UNIT), + array(array), index(arrayIndex), currentIndex(-1) { } @@ -794,29 +1136,50 @@ IntExpr* valueExpr = dynamic_cast(expr); if (!valueExpr) return; vmint value = valueExpr->evalInt(); + vmfloat unitFactor = valueExpr->unitFactor(); if (!index) return; - vmint idx = index->evalInt(); + vmint idx = currentIndex = index->evalInt(); if (idx < 0 || idx >= array->arraySize()) return; array->assignIntElement(idx, value); + array->assignElementUnitFactor(idx, unitFactor); } vmint IntArrayElement::evalInt() { if (!index) return 0; - vmint idx = index->evalInt(); + vmint idx = currentIndex = index->evalInt(); if (idx < 0 || idx >= array->arraySize()) return 0; return array->evalIntElement(idx); } +vmfloat IntArrayElement::unitFactor() const { + if (!index) return VM_NO_FACTOR; + vmint idx = currentIndex; + if (idx < 0 || idx >= array->arraySize()) return 0; + + return array->unitFactorOfElement(idx); +} + void IntArrayElement::dump(int level) { printIndents(level); printf("IntArrayElement\n"); } -RealArrayElement::RealArrayElement(RealArrayExprRef array, IntExprRef arrayIndex) - : RealVariable(NULL, false, false, 0), array(array), index(arrayIndex) +RealArrayElement::RealArrayElement(RealArrayExprRef array, IntExprRef arrayIndex) : + RealVariable({ + .ctx = NULL, + .isPolyphonic = (array) ? array->isPolyphonic() : false, + .isConst = (array) ? array->isConstExpr() : false, + .isFinal = false, + .elements = 0, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = VM_NO_UNIT + }), + Unit(VM_NO_UNIT), + array(array), index(arrayIndex), currentIndex(-1) { } @@ -824,34 +1187,52 @@ RealExpr* valueExpr = dynamic_cast(expr); if (!valueExpr) return; vmfloat value = valueExpr->evalReal(); + vmfloat unitFactor = valueExpr->unitFactor(); if (!index) return; - vmint idx = index->evalInt(); + vmint idx = currentIndex = index->evalInt(); if (idx < 0 || idx >= array->arraySize()) return; array->assignRealElement(idx, value); + array->assignElementUnitFactor(idx, unitFactor); } vmfloat RealArrayElement::evalReal() { if (!index) return 0; - vmint idx = index->evalInt(); + vmint idx = currentIndex = index->evalInt(); if (idx < 0 || idx >= array->arraySize()) return 0; return array->evalRealElement(idx); } +vmfloat RealArrayElement::unitFactor() const { + if (!index) return VM_NO_FACTOR; + vmint idx = currentIndex; + if (idx < 0 || idx >= array->arraySize()) return 0; + + return array->unitFactorOfElement(idx); +} + void RealArrayElement::dump(int level) { printIndents(level); printf("RealArrayElement\n"); } -StringVariable::StringVariable(ParserContext* ctx) - : Variable(ctx,ctx->globalStrVarCount++,false) +StringVariable::StringVariable(ParserContext* ctx) : + Variable({ + .ctx = ctx, + .elements = 1, + .memPos = ctx->globalStrVarCount++ + }) { } -StringVariable::StringVariable(ParserContext* ctx, bool bConst) - : Variable(ctx,0,bConst) +StringVariable::StringVariable(ParserContext* ctx, bool bConst) : + Variable({ + .ctx = ctx, + .memPos = 0, + .isConst = bConst + }) { } @@ -890,18 +1271,6 @@ printf("ConstStringVariable val='%s'\n", value.c_str()); } -MetricPrefix_t ScalarNumberBinaryOp::unitPrefix(vmuint i) const { - ScalarNumberExprRef l = (ScalarNumberExprRef) lhs; - ScalarNumberExprRef r = (ScalarNumberExprRef) rhs; - return (r->unitFactor() < l->unitFactor()) ? r->unitPrefix(i) : l->unitPrefix(i); -} - -StdUnit_t ScalarNumberBinaryOp::unitType() const { - ScalarNumberExprRef l = (ScalarNumberExprRef) lhs; - ScalarNumberExprRef r = (ScalarNumberExprRef) rhs; - return (l->unitType()) ? l->unitType() : r->unitType(); -} - bool ScalarNumberBinaryOp::isFinal() const { ScalarNumberExprRef l = (ScalarNumberExprRef) lhs; ScalarNumberExprRef r = (ScalarNumberExprRef) rhs; @@ -1003,25 +1372,6 @@ return false; } -// void Case::addBranch(IntExprRef condition, StatementsRef statements) { -// CaseBranchRef b = new CaseBranchRef; -// b->from = condition; -// b->statements = statements; -// branches.push_back(b); -// } -// -// void Case::addBranch(IntExprRef from, IntExprRef to, StatementsRef statements) { -// CaseBranchRef b = new CaseBranchRef; -// b->from = from; -// b->to = to; -// b->statements = statements; -// branches.push_back(b); -// } -// -// void Case::addBranch(CaseBranchRef branch) { -// branches.push_back(branch); -// } - void While::dump(int level) { printIndents(level); if (m_condition) @@ -1094,8 +1444,54 @@ return lhs->isConstExpr() && rhs->isConstExpr(); } +Relation::Relation(ExpressionRef lhs, Type type, ExpressionRef rhs) : + Unit(VM_NO_UNIT), + lhs(lhs), rhs(rhs), type(type) +{ +} + +// Equal / unequal comparison of real numbers in NKSP scripts: +// +// Unlike system level languages like C/C++ we are less conservative about +// comparing floating point numbers for 'equalness' or 'unequalness' in NKSP +// scripts. Due to the musical context of the NKSP language we automatically +// take the (to be) expected floating point tolerances into account when +// comparing two floating point numbers with each other, however only for '=' +// and '#' operators. The '<=' and '>=' still use conservative low level +// floating point comparison for not breaking their transitivity feature. + +template +struct RelComparer { + static inline bool isEqual(T_LHS a, T_RHS b) { // for int comparison ('3 = 3') + return a == b; + } + static inline bool isUnequal(T_LHS a, T_RHS b) { // for int comparison ('3 # 3') + return a != b; + } +}; + +template<> +struct RelComparer { + static inline bool isEqual(float a, float b) { // for real number comparison ('3.1 = 3.1') + return RTMath::fEqual32(a, b); + } + static inline bool isUnequal(float a, float b) { // for real number comparison ('3.1 # 3.1') + return !RTMath::fEqual32(a, b); + } +}; + +template<> +struct RelComparer { + static inline bool isEqual(double a, double b) { // for future purpose + return RTMath::fEqual64(a, b); + } + static inline bool isUnqqual(double a, double b) { // for future purpose + return !RTMath::fEqual64(a, b); + } +}; + template -static inline vmint _evalRelation(Relation::Type type, T_LHS lhs, T_RHS rhs) { +inline vmint _evalRelation(Relation::Type type, T_LHS lhs, T_RHS rhs) { switch (type) { case Relation::LESS_THAN: return lhs < rhs; @@ -1106,13 +1502,39 @@ case Relation::GREATER_OR_EQUAL: return lhs >= rhs; case Relation::EQUAL: - return lhs == rhs; + return RelComparer::isEqual(lhs, rhs); case Relation::NOT_EQUAL: - return lhs != rhs; + return RelComparer::isUnequal(lhs, rhs); } return 0; } +template +inline vmint _evalRealRelation(Relation::Type type, + T_LVALUE lvalue, T_RVALUE rvalue, + T_LEXPR* pLHS, T_REXPR* pRHS) +{ + if (pLHS->unitFactor() == pRHS->unitFactor()) + return _evalRelation(type, lvalue, rvalue); + if (pLHS->unitFactor() < pRHS->unitFactor()) + return _evalRelation(type, lvalue, Unit::convRealToUnitFactor(rvalue, pRHS, pLHS)); + else + return _evalRelation(type, Unit::convRealToUnitFactor(lvalue, pLHS, pRHS), rvalue); +} + +template +inline vmint _evalIntRelation(Relation::Type type, + vmint lvalue, vmint rvalue, + T_LEXPR* pLHS, T_REXPR* pRHS) +{ + if (pLHS->unitFactor() == pRHS->unitFactor()) + return _evalRelation(type, lvalue, rvalue); + if (pLHS->unitFactor() < pRHS->unitFactor()) + return _evalRelation(type, lvalue, Unit::convIntToUnitFactor(rvalue, pRHS, pLHS)); + else + return _evalRelation(type, Unit::convIntToUnitFactor(lvalue, pLHS, pRHS), rvalue); +} + vmint Relation::evalInt() { const ExprType_t lType = lhs->exprType(); const ExprType_t rType = rhs->exprType(); @@ -1126,20 +1548,28 @@ return 0; } } else if (lType == REAL_EXPR && rType == REAL_EXPR) { - return _evalRelation( - type, lhs->asReal()->evalReal(), rhs->asReal()->evalReal() + vmfloat lvalue = lhs->asReal()->evalReal(); + vmfloat rvalue = rhs->asReal()->evalReal(); + return _evalRealRelation( + type, lvalue, rvalue, lhs->asReal(), rhs->asReal() ); } else if (lType == REAL_EXPR && rType == INT_EXPR) { - return _evalRelation( - type, lhs->asReal()->evalReal(), rhs->asInt()->evalInt() + vmfloat lvalue = lhs->asReal()->evalReal(); + vmint rvalue = rhs->asInt()->evalInt(); + return _evalRealRelation( + type, lvalue, rvalue, lhs->asReal(), rhs->asInt() ); } else if (lType == INT_EXPR && rType == REAL_EXPR) { - return _evalRelation( - type, lhs->asInt()->evalInt(), rhs->asReal()->evalReal() + vmint lvalue = lhs->asInt()->evalInt(); + vmfloat rvalue = rhs->asReal()->evalReal(); + return _evalRealRelation( + type, lvalue, rvalue, lhs->asInt(), rhs->asReal() ); } else { - return _evalRelation( - type, lhs->asInt()->evalInt(), rhs->asInt()->evalInt() + vmint lvalue = lhs->asInt()->evalInt(); + vmint rvalue = rhs->asInt()->evalInt(); + return _evalIntRelation( + type, lvalue, rvalue, lhs->asInt(), rhs->asInt() ); } } @@ -1181,7 +1611,7 @@ vmint Or::evalInt() { IntExpr* pLHS = dynamic_cast(&*lhs); if (pLHS->evalInt()) return 1; - IntExpr* pRHS = dynamic_cast(&*rhs);; + IntExpr* pRHS = dynamic_cast(&*rhs); return (pRHS->evalInt()) ? 1 : 0; } @@ -1409,7 +1839,9 @@ for (std::map::const_iterator it = vars.begin(); it != vars.end(); ++it) { - ConstIntVariableRef ref = new ConstIntVariable(it->second); + ConstIntVariableRef ref = new ConstIntVariable({ + .value = it->second + }); vartable[it->first] = ref; } }