--- linuxsampler/trunk/src/scriptvm/tree.cpp 2017/05/30 17:20:02 3257 +++ linuxsampler/trunk/src/scriptvm/tree.cpp 2020/02/16 11:31:46 3747 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 - 2016 Christian Schoenebeck and Andreas Persson + * Copyright (c) 2014 - 2019 Christian Schoenebeck and Andreas Persson * * http://www.linuxsampler.org * @@ -11,13 +11,51 @@ #include #include "tree.h" #include "../common/global_private.h" +#include "../common/RTMath.h" #include +#include "CoreVMFunctions.h" // for VMIntResult, VMRealResult namespace LinuxSampler { bool isNoOperation(StatementRef statement) { - NoOperation* noOp = dynamic_cast(&*statement); - return noOp; + return statement->statementType() == STMT_NOOP; +} + +String acceptedArgTypesStr(VMFunction* fn, vmint iArg) { + static const ExprType_t allTypes[] = { + INT_EXPR, + INT_ARR_EXPR, + REAL_EXPR, + REAL_ARR_EXPR, + STRING_EXPR, + STRING_ARR_EXPR, + }; + const size_t nTypes = sizeof(allTypes) / sizeof(ExprType_t); + + std::vector supportedTypes; + for (int iType = 0; iType < nTypes; ++iType) { + const ExprType_t& type = allTypes[iType]; + if (fn->acceptsArgType(iArg, type)) + supportedTypes.push_back(type); + } + assert(!supportedTypes.empty()); + + if (supportedTypes.size() == 1) { + return typeStr(*supportedTypes.begin()); + } else { + String s = "either "; + for (size_t i = 0; i < supportedTypes.size(); ++i) { + const ExprType_t& type = supportedTypes[i]; + if (i == 0) { + s += typeStr(type); + } else if (i == supportedTypes.size() - 1) { + s += " or " + typeStr(type); + } else { + s += ", " + typeStr(type); + } + } + return s; + } } Node::Node() { @@ -31,28 +69,143 @@ 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(VMUnit* 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()) + _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) + _unitFactorToShortStr(factor); + } + s += "}"; + return s; } -/*String IntArrayExpr::evalCastToStr() { +String RealArrayExpr::evalCastToStr() { String s = "{"; - for (int i = 0; i < arraySize(); ++i) { - int val = evalIntElement(i); + 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; -}*/ +} + +IntLiteral::IntLiteral(const IntLitDef& def) : + IntExpr(), Unit(def.unitType), + value(def.value), unitPrefixFactor(def.unitFactor), + finalVal(def.isFinal) +{ +} -int IntLiteral::evalInt() { +vmint IntLiteral::evalInt() { return value; } void IntLiteral::dump(int level) { printIndents(level); - printf("IntLiteral %d\n", value); + printf("IntLiteral %" PRId64 "\n", (int64_t)value); +} + +RealLiteral::RealLiteral(const RealLitDef& def) : + RealExpr(), Unit(def.unitType), + value(def.value), unitPrefixFactor(def.unitFactor), + finalVal(def.isFinal) +{ +} + +vmfloat RealLiteral::evalReal() { + return value; +} + +void RealLiteral::dump(int level) { + printIndents(level); + printf("RealLiteral %f\n", value); } void StringLiteral::dump(int level) { @@ -60,10 +213,49 @@ printf("StringLiteral: '%s'\n", value.c_str()); } -int Add::evalInt() { +Add::Add(NumberExprRef lhs, NumberExprRef 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); + 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 NumberExpr* pLHS = dynamic_cast(&*lhs); + const NumberExpr* pRHS = dynamic_cast(&*rhs); + return (pLHS->unitFactor() < pRHS->unitFactor()) ? pLHS->unitFactor() : pRHS->unitFactor(); } void Add::dump(int level) { @@ -77,10 +269,49 @@ printf(")\n"); } -int Sub::evalInt() { +Sub::Sub(NumberExprRef lhs, NumberExprRef 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); + 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 NumberExpr* pLHS = dynamic_cast(&*lhs); + const NumberExpr* pRHS = dynamic_cast(&*rhs); + return (pLHS->unitFactor() < pRHS->unitFactor()) ? pLHS->unitFactor() : pRHS->unitFactor(); } void Sub::dump(int level) { @@ -94,12 +325,27 @@ printf(")\n"); } -int Mul::evalInt() { +Mul::Mul(NumberExprRef lhs, NumberExprRef 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);; return (pLHS && pRHS) ? pLHS->evalInt() * pRHS->evalInt() : 0; } +vmfloat Mul::evalReal() { + RealExpr* pLHS = dynamic_cast(&*lhs); + RealExpr* pRHS = dynamic_cast(&*rhs);; + return (pLHS && pRHS) ? pLHS->evalReal() * pRHS->evalReal() : 0; +} + void Mul::dump(int level) { printIndents(level); printf("Mul(\n"); @@ -111,16 +357,42 @@ printf(")\n"); } -int Div::evalInt() { +vmfloat Mul::unitFactor() const { + const NumberExpr* pLHS = dynamic_cast(&*lhs); + const NumberExpr* pRHS = dynamic_cast(&*rhs); + return pLHS->unitFactor() * pRHS->unitFactor(); +} + +Div::Div(NumberExprRef lhs, NumberExprRef 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() { IntExpr* pLHS = dynamic_cast(&*lhs); IntExpr* pRHS = dynamic_cast(&*rhs); if (!pLHS || !pRHS) return 0; - int l = pLHS->evalInt(); - int r = pRHS->evalInt(); + vmint l = pLHS->evalInt(); + vmint r = pRHS->evalInt(); if (r == 0) return 0; return l / r; } +vmfloat Div::evalReal() { + RealExpr* pLHS = dynamic_cast(&*lhs); + RealExpr* pRHS = dynamic_cast(&*rhs); + if (!pLHS || !pRHS) return 0; + vmfloat l = pLHS->evalReal(); + vmfloat r = pRHS->evalReal(); + if (r == vmfloat(0)) return 0; + return l / r; +} + void Div::dump(int level) { printIndents(level); printf("Div(\n"); @@ -132,9 +404,15 @@ printf(")\n"); } -int Mod::evalInt() { +vmfloat Div::unitFactor() const { + const NumberExpr* pLHS = dynamic_cast(&*lhs); + const NumberExpr* pRHS = dynamic_cast(&*rhs); + 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; } @@ -160,7 +438,7 @@ } bool Args::isPolyphonic() const { - for (int i = 0; i < args.size(); ++i) + for (vmint i = 0; i < args.size(); ++i) if (args[i]->isPolyphonic()) return true; return false; @@ -188,7 +466,7 @@ } EventHandler* EventHandlers::eventHandlerByName(const String& name) const { - for (int i = 0; i < args.size(); ++i) + for (vmint i = 0; i < args.size(); ++i) if (args.at(i)->eventHandlerName() == name) return const_cast(&*args.at(i)); return NULL; @@ -200,7 +478,7 @@ } bool EventHandlers::isPolyphonic() const { - for (int i = 0; i < args.size(); ++i) + for (vmint i = 0; i < args.size(); ++i) if (args[i]->isPolyphonic()) return true; return false; @@ -252,18 +530,23 @@ } bool Statements::isPolyphonic() const { - for (int i = 0; i < args.size(); ++i) + for (vmint i = 0; i < args.size(); ++i) if (args[i]->isPolyphonic()) return true; 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) { } -int DynamicVariableCall::evalInt() { +vmint DynamicVariableCall::evalInt() { VMIntExpr* expr = dynamic_cast(dynVar); if (!expr) return 0; return expr->evalInt(); @@ -289,6 +572,22 @@ 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( (fn) ? fn->allocResult(dynamic_cast(&*args)) : NULL ) +{ +} + +FunctionCall::~FunctionCall() { + if (result) { + delete result; + result = NULL; + } +} + void FunctionCall::dump(int level) { printIndents(level); printf("FunctionCall '%s' args={\n", functionName.c_str()); @@ -299,14 +598,61 @@ ExprType_t FunctionCall::exprType() const { if (!fn) return EMPTY_EXPR; - return fn->returnType(); + FunctionCall* self = const_cast(this); + 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; + VMNumberExpr* scalar = expr->asNumber(); + 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; + + // tell function where it shall dump its return value to + VMFnResult* oldRes = fn->boundResult(); + fn->bindResult(result); + // assuming here that all argument checks (amount and types) have been made // at parse time, to avoid time intensive checks on each function call - return fn->exec(dynamic_cast(&*args)); + VMFnResult* res = fn->exec(dynamic_cast(&*args)); + + // restore previous result binding of some potential toplevel or concurrent + // caller, i.e. if exactly same function is called more than one time, + // concurrently in a term by other FunctionCall objects, e.g.: + // ~c := ceil( ceil(~a) + ~b) + fn->bindResult(oldRes); + + if (!res) return res; + + VMExpr* expr = res->resultValue(); + if (!expr) return res; + + // For performance reasons we always only let 'FunctionCall' assign the unit + // type to the function's result expression, never by the function + // implementation itself, nor by other classes, because a FunctionCall + // object solely knows the unit type in O(1). + ExprType_t type = expr->exprType(); + if (type == INT_EXPR) { + VMIntResult* intRes = dynamic_cast(res); + intRes->unitBaseType = unitType(); + } else if (type == REAL_EXPR) { + VMRealResult* realRes = dynamic_cast(res); + realRes->unitBaseType = unitType(); + } + + return res; } StmtFlags_t FunctionCall::exec() { @@ -316,7 +662,7 @@ return result->resultFlags(); } -int FunctionCall::evalInt() { +vmint FunctionCall::evalInt() { VMFnResult* result = execVMFn(); if (!result) return 0; VMIntExpr* intExpr = dynamic_cast(result->resultValue()); @@ -324,13 +670,44 @@ return intExpr->evalInt(); } +vmfloat FunctionCall::evalReal() { + VMFnResult* result = execVMFn(); + if (!result) return 0; + VMRealExpr* realExpr = dynamic_cast(result->resultValue()); + if (!realExpr) return 0; + return realExpr->evalReal(); +} + VMIntArrayExpr* FunctionCall::asIntArray() const { - VMFnResult* result = const_cast(this)->execVMFn(); + //FIXME: asIntArray() not intended for evaluation semantics (for both + // performance reasons with arrays, but also to prevent undesired value + // mutation by implied (hidden) evaluation, as actually done here. We must + // force function evaluation here though, because we need it for function + // calls to be evaluated at all. This issue should be addressed cleanly by + // adjusting the API appropriately. + FunctionCall* rwSelf = const_cast(this); + VMFnResult* result = rwSelf->execVMFn(); + if (!result) return 0; VMIntArrayExpr* intArrExpr = dynamic_cast(result->resultValue()); return intArrExpr; } +VMRealArrayExpr* FunctionCall::asRealArray() const { + //FIXME: asRealArray() not intended for evaluation semantics (for both + // performance reasons with arrays, but also to prevent undesired value + // mutation by implied (hidden) evaluation, as actually done here. We must + // force function evaluation here though, because we need it for function + // calls to be evaluated at all. This issue should be addressed cleanly by + // adjusting the API appropriately. + FunctionCall* rwSelf = const_cast(this); + VMFnResult* result = rwSelf->execVMFn(); + + if (!result) return 0; + VMRealArrayExpr* realArrExpr = dynamic_cast(result->resultValue()); + return realArrExpr; +} + String FunctionCall::evalStr() { VMFnResult* result = execVMFn(); if (!result) return ""; @@ -342,52 +719,89 @@ String FunctionCall::evalCastToStr() { VMFnResult* result = execVMFn(); if (!result) return ""; - if (result->resultValue()->exprType() == STRING_EXPR) { + const ExprType_t resultType = result->resultValue()->exprType(); + if (resultType == STRING_EXPR) { VMStringExpr* strExpr = dynamic_cast(result->resultValue()); return strExpr ? strExpr->evalStr() : ""; + } else if (resultType == REAL_EXPR) { + VMRealExpr* realExpr = dynamic_cast(result->resultValue()); + return realExpr ? ToString(realExpr->evalReal()) + _unitToStr(realExpr) : ""; } else { VMIntExpr* intExpr = dynamic_cast(result->resultValue()); - return intExpr ? ToString(intExpr->evalInt()) : ""; + return intExpr ? ToString(intExpr->evalInt()) + _unitToStr(intExpr) : ""; } } -IntVariable::IntVariable(ParserContext* ctx) - : Variable(ctx, ctx ? ctx->globalIntVarCount++ : 0, false), polyphonic(false) +Variable::Variable(const VariableDecl& decl) : + context(decl.ctx), memPos(decl.memPos), bConst(decl.isConst) { - //printf("globalIntVar parserctx=0x%lx memPOS=%d\n", ctx, memPos); - assert(ctx); } -inline static int postfixInc(int& object, int incBy) { - const int i = object; +NumberVariable::NumberVariable(const VariableDecl& decl) : + Variable(decl), + Unit(decl.unitType), + unitFactorMemPos(decl.unitFactorMemPos), polyphonic(decl.isPolyphonic), + finalVal(decl.isFinal) +{ +} + +vmfloat NumberVariable::unitFactor() const { + if (isPolyphonic()) { + return context->execContext->polyphonicUnitFactorMemory[unitFactorMemPos]; + } + return (*context->globalUnitFactorMemory)[unitFactorMemPos]; +} + +inline static vmint postfixInc(vmint& object, vmint incBy) { + const vmint i = object; object += incBy; return i; } -IntVariable::IntVariable(ParserContext* ctx, bool polyphonic, bool bConst, int size) - : Variable(ctx, !ctx ? 0 : polyphonic ? postfixInc(ctx->polyphonicIntVarCount, size) : postfixInc(ctx->globalIntVarCount, size), bConst), - polyphonic(polyphonic) -{ - //printf("InvVar size=%d parserCtx=0x%lx\n", size, (uint64_t)ctx); - if (polyphonic) { - //printf("polyIntVar memPOS=%d\n", memPos); - assert(ctx); - } +IntVariable::IntVariable(const VariableDecl& decl) : + NumberVariable({ + .ctx = decl.ctx, + .isPolyphonic = decl.isPolyphonic, + .isConst = decl.isConst, + .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, + .isFinal = decl.isFinal, + }), + 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 (polyphonic) + //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(); + } } } -int IntVariable::evalInt() { +vmint IntVariable::evalInt() { //printf("IntVariable::eval pos=%d\n", memPos); - if (polyphonic) { + if (isPolyphonic()) { //printf("evalInt() poly memPos=%d execCtx=0x%lx\n", memPos, (uint64_t)context->execContext); return context->execContext->polyphonicIntMemory[memPos]; } @@ -400,9 +814,75 @@ //printf("IntVariable memPos=%d\n", memPos); } -//ConstIntVariable::ConstIntVariable(ParserContext* ctx, int value) -ConstIntVariable::ConstIntVariable(int value) - : IntVariable(NULL,false,true), value(value) +RealVariable::RealVariable(const VariableDecl& decl) : + NumberVariable({ + .ctx = decl.ctx, + .isPolyphonic = decl.isPolyphonic, + .isConst = decl.isConst, + .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, + .isFinal = decl.isFinal, + }), + Unit(decl.unitType) +{ + //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) { + //NOTE: sequence matters! evalReal() must be called before getting unitFactor() ! + if (isPolyphonic()) { + context->execContext->polyphonicRealMemory[memPos] = realExpr->evalReal(); + context->execContext->polyphonicUnitFactorMemory[unitFactorMemPos] = realExpr->unitFactor(); + } else { + (*context->globalRealMemory)[memPos] = realExpr->evalReal(); + (*context->globalUnitFactorMemory)[unitFactorMemPos] = realExpr->unitFactor(); + } + } +} + +vmfloat RealVariable::evalReal() { + //printf("RealVariable::eval pos=%d\n", memPos); + if (isPolyphonic()) { + //printf("evalReal() poly memPos=%d execCtx=0x%lx\n", memPos, (uint64_t)context->execContext); + return context->execContext->polyphonicRealMemory[memPos]; + } + return (*context->globalRealMemory)[memPos]; +} + +void RealVariable::dump(int level) { + printIndents(level); + printf("RealVariable\n"); + //printf("RealVariable memPos=%d\n", memPos); +} + +ConstIntVariable::ConstIntVariable(const IntVarDef& def) : + IntVariable({ + .ctx = def.ctx, + .isPolyphonic = false, + .isConst = true, + .elements = 1, + .memPos = def.memPos, + .unitFactorMemPos = def.unitFactorMemPos, + .unitType = def.unitType, + .isFinal = def.isFinal, + }), + Unit(def.unitType), + value(def.value), unitPrefixFactor(def.unitFactor) { } @@ -417,17 +897,57 @@ */ } -int ConstIntVariable::evalInt() { +vmint ConstIntVariable::evalInt() { return value; } void ConstIntVariable::dump(int level) { printIndents(level); - printf("ConstIntVariable val=%d\n", value); + printf("ConstIntVariable val=%" PRId64 "\n", (int64_t)value); } -BuiltInIntVariable::BuiltInIntVariable(const String& name, VMIntRelPtr* ptr) - : IntVariable(NULL,false,false), name(name), ptr(ptr) +ConstRealVariable::ConstRealVariable(const RealVarDef& def) : + RealVariable({ + .ctx = def.ctx, + .isPolyphonic = false, + .isConst = true, + .elements = 1, + .memPos = def.memPos, + .unitFactorMemPos = def.unitFactorMemPos, + .unitType = def.unitType, + .isFinal = def.isFinal, + }), + Unit(def.unitType), + value(def.value), unitPrefixFactor(def.unitFactor) +{ +} + +void ConstRealVariable::assign(Expression* expr) { + // ignore assignment +} + +vmfloat ConstRealVariable::evalReal() { + return value; +} + +void ConstRealVariable::dump(int level) { + printIndents(level); + printf("ConstRealVariable val=%f\n", value); +} + +BuiltInIntVariable::BuiltInIntVariable(const String& name, VMIntPtr* ptr) : + IntVariable({ + .ctx = NULL, + .isPolyphonic = false, + .isConst = false, // may or may not be modifyable though! + .elements = 0, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = VM_NO_UNIT, + .isFinal = false, + }), + Unit(VM_NO_UNIT), + name(name), ptr(ptr) { } @@ -437,7 +957,7 @@ ptr->assign(valueExpr->evalInt()); } -int BuiltInIntVariable::evalInt() { +vmint BuiltInIntVariable::evalInt() { return ptr->evalInt(); } @@ -446,8 +966,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, + .elements = 1, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = decl.unitType, + .isFinal = decl.isFinal, + }), + Unit(decl.unitType) { } @@ -456,62 +986,222 @@ printf("PolyphonicIntVariable\n"); } -IntArrayVariable::IntArrayVariable(ParserContext* ctx, int size) - : Variable(ctx, 0, false) +PolyphonicRealVariable::PolyphonicRealVariable(const VariableDecl& decl) : + RealVariable({ + .ctx = decl.ctx, + .isPolyphonic = true, + .isConst = decl.isConst, + .elements = 1, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = decl.unitType, + .isFinal = decl.isFinal, + }), + Unit(decl.unitType) { - values.resize(size); - memset(&values[0], 0, size * sizeof(int)); } -IntArrayVariable::IntArrayVariable(ParserContext* ctx, int size, ArgsRef values, bool _bConst) - : Variable(ctx, 0, _bConst) +void PolyphonicRealVariable::dump(int level) { + printIndents(level); + printf("PolyphonicRealVariable\n"); +} + +IntArrayVariable::IntArrayVariable(ParserContext* ctx, vmint size) : + Variable({ + .ctx = ctx, + .isPolyphonic = false, + .isConst = false, + .elements = 0, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = VM_NO_UNIT, + .isFinal = false, + }) +{ + values.resize(size); + memset(&values[0], 0, size * sizeof(vmint)); + + 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, + .elements = 0, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = VM_NO_UNIT, + .isFinal = false, + }) { this->values.resize(size); - for (int i = 0; i < values->argsCount(); ++i) { + 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, + .elements = 0, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = VM_NO_UNIT, + .isFinal = false, + }) { } -int IntArrayVariable::evalIntElement(uint i) { +vmint IntArrayVariable::evalIntElement(vmuint i) { if (i >= values.size()) return 0; return values[i]; } -void IntArrayVariable::assignIntElement(uint i, int value) { +void IntArrayVariable::assignIntElement(vmuint i, vmint value) { if (i >= values.size()) return; 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("); - for (int i = 0; i < values.size(); ++i) { + for (vmint i = 0; i < values.size(); ++i) { + if (i % 12 == 0) { + printf("\n"); + printIndents(level+1); + } + printf("%" PRId64 ", ", (int64_t)values[i]); + } + printIndents(level); + printf(")\n"); +} + +RealArrayVariable::RealArrayVariable(ParserContext* ctx, vmint size) : + Variable({ + .ctx = ctx, + .isPolyphonic = false, + .isConst = false, + .elements = 0, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = VM_NO_UNIT, + .isFinal = false, + }) +{ + values.resize(size); + memset(&values[0], 0, size * sizeof(vmfloat)); + + 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, + .elements = 0, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = VM_NO_UNIT, + .isFinal = false, + }) +{ + 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(); + this->unitFactors[i] = expr->unitFactor(); + } + } +} + +RealArrayVariable::RealArrayVariable(ParserContext* ctx, bool bConst) : + Variable({ + .ctx = ctx, + .isPolyphonic = false, + .isConst = bConst, + .elements = 0, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = VM_NO_UNIT, + .isFinal = false, + }) +{ +} + +vmfloat RealArrayVariable::evalRealElement(vmuint i) { + if (i >= values.size()) return 0; + return values[i]; +} + +void RealArrayVariable::assignRealElement(vmuint i, vmfloat value) { + if (i >= values.size()) return; + 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("); + for (vmint i = 0; i < values.size(); ++i) { if (i % 12 == 0) { printf("\n"); printIndents(level+1); } - printf("%d, ", values[i]); + printf("%f, ", values[i]); } printIndents(level); 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) { } -int BuiltInIntArrayVariable::evalIntElement(uint i) { +vmint BuiltInIntArrayVariable::evalIntElement(vmuint i) { return i >= array->size ? 0 : array->data[i]; } -void BuiltInIntArrayVariable::assignIntElement(uint i, int value) { +void BuiltInIntArrayVariable::assignIntElement(vmuint i, vmint value) { if (i >= array->size) return; array->data[i] = value; } @@ -521,43 +1211,123 @@ printf("Built-In Int Array Variable '%s'\n", name.c_str()); } -IntArrayElement::IntArrayElement(IntArrayVariableRef 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, + .elements = 0, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = VM_NO_UNIT, + .isFinal = false, + }), + Unit(VM_NO_UNIT), + array(array), index(arrayIndex), currentIndex(-1) +{ } void IntArrayElement::assign(Expression* expr) { IntExpr* valueExpr = dynamic_cast(expr); if (!valueExpr) return; - int value = valueExpr->evalInt(); + vmint value = valueExpr->evalInt(); + vmfloat unitFactor = valueExpr->unitFactor(); if (!index) return; - int idx = index->evalInt(); + vmint idx = currentIndex = index->evalInt(); if (idx < 0 || idx >= array->arraySize()) return; array->assignIntElement(idx, value); + array->assignElementUnitFactor(idx, unitFactor); } -int IntArrayElement::evalInt() { +vmint IntArrayElement::evalInt() { if (!index) return 0; - int 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"); } -StringVariable::StringVariable(ParserContext* ctx) - : Variable(ctx,ctx->globalStrVarCount++,false) +RealArrayElement::RealArrayElement(RealArrayExprRef array, IntExprRef arrayIndex) : + RealVariable({ + .ctx = NULL, + .isPolyphonic = (array) ? array->isPolyphonic() : false, + .isConst = (array) ? array->isConstExpr() : false, + .elements = 0, + .memPos = 0, + .unitFactorMemPos = 0, + .unitType = VM_NO_UNIT, + .isFinal = false, + }), + Unit(VM_NO_UNIT), + array(array), index(arrayIndex), currentIndex(-1) +{ +} + +void RealArrayElement::assign(Expression* expr) { + RealExpr* valueExpr = dynamic_cast(expr); + if (!valueExpr) return; + vmfloat value = valueExpr->evalReal(); + vmfloat unitFactor = valueExpr->unitFactor(); + + if (!index) return; + 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 = 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, + .elements = 1, + .memPos = ctx->globalStrVarCount++ + }) { } -StringVariable::StringVariable(ParserContext* ctx, bool bConst) - : Variable(ctx,0,bConst) +StringVariable::StringVariable(ParserContext* ctx, bool bConst) : + Variable({ + .ctx = ctx, + .isConst = bConst, + .memPos = 0, + }) { } @@ -573,7 +1343,7 @@ void StringVariable::dump(int level) { printIndents(level); - printf("StringVariable memPos=%d\n", memPos); + printf("StringVariable memPos=%" PRId64 "\n", (int64_t)memPos); } ConstStringVariable::ConstStringVariable(ParserContext* ctx, String _value) @@ -596,6 +1366,21 @@ printf("ConstStringVariable val='%s'\n", value.c_str()); } +bool NumberBinaryOp::isFinal() const { + NumberExprRef l = (NumberExprRef) lhs; + NumberExprRef r = (NumberExprRef) rhs; + return l->isFinal() || r->isFinal(); +} + +ExprType_t VaritypeScalarBinaryOp::exprType() const { + return (lhs->exprType() == REAL_EXPR || rhs->exprType() == REAL_EXPR) ? REAL_EXPR : INT_EXPR; +} + +String VaritypeScalarBinaryOp::evalCastToStr() { + return (exprType() == REAL_EXPR) ? + RealExpr::evalCastToStr() : IntExpr::evalCastToStr(); +} + void If::dump(int level) { printIndents(level); if (ifStatements && elseStatements) @@ -606,13 +1391,13 @@ printf("if [INVALID]\n"); } -int If::evalBranch() { +vmint If::evalBranch() { if (condition->evalInt()) return 0; if (elseStatements) return 1; return -1; } -Statements* If::branch(uint i) const { +Statements* If::branch(vmuint i) const { if (i == 0) return (Statements*) &*ifStatements; if (i == 1) return (elseStatements) ? (Statements*) &*elseStatements : NULL; return NULL; @@ -628,26 +1413,26 @@ printIndents(level); if (select) if (select->isConstExpr()) - printf("Case select %d\n", select->evalInt()); + printf("Case select %" PRId64 "\n", (int64_t)select->evalInt()); else printf("Case select [runtime expr]\n"); else printf("Case select NULL\n"); - for (int i = 0; i < branches.size(); ++i) { + for (vmint i = 0; i < branches.size(); ++i) { printIndents(level+1); CaseBranch& branch = branches[i]; if (branch.from && branch.to) if (branch.from->isConstExpr() && branch.to->isConstExpr()) - printf("case %d to %d\n", branch.from->evalInt(), branch.to->evalInt()); + printf("case %" PRId64 " to %" PRId64 "\n", (int64_t)branch.from->evalInt(), (int64_t)branch.to->evalInt()); else if (branch.from->isConstExpr() && !branch.to->isConstExpr()) - printf("case %d to [runtime expr]\n", branch.from->evalInt()); + printf("case %" PRId64 " to [runtime expr]\n", (int64_t)branch.from->evalInt()); else if (!branch.from->isConstExpr() && branch.to->isConstExpr()) - printf("case [runtime expr] to %d\n", branch.to->evalInt()); + printf("case [runtime expr] to %" PRId64 "\n", (int64_t)branch.to->evalInt()); else printf("case [runtime expr] to [runtime expr]\n"); else if (branch.from) if (branch.from->isConstExpr()) - printf("case %d\n", branch.from->evalInt()); + printf("case %" PRId64 "\n", (int64_t)branch.from->evalInt()); else printf("case [runtime expr]\n"); else @@ -655,9 +1440,9 @@ } } -int SelectCase::evalBranch() { - int value = select->evalInt(); - for (int i = 0; i < branches.size(); ++i) { +vmint SelectCase::evalBranch() { + vmint value = select->evalInt(); + for (vmint i = 0; i < branches.size(); ++i) { if (branches.at(i).from && branches.at(i).to) { // i.e. "case 4 to 7" ... if (branches.at(i).from->evalInt() <= value && branches.at(i).to->evalInt() >= value) return i; @@ -668,7 +1453,7 @@ return -1; } -Statements* SelectCase::branch(uint i) const { +Statements* SelectCase::branch(vmuint i) const { if (i < branches.size()) return const_cast( &*branches[i].statements ); return NULL; @@ -676,36 +1461,17 @@ bool SelectCase::isPolyphonic() const { if (select->isPolyphonic()) return true; - for (int i = 0; i < branches.size(); ++i) + for (vmint i = 0; i < branches.size(); ++i) if (branches[i].statements->isPolyphonic()) return true; 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) if (m_condition->isConstExpr()) - printf("while (%d) {\n", m_condition->evalInt()); + printf("while (%" PRId64 ") {\n", (int64_t)m_condition->evalInt()); else printf("while ([runtime expr]) {\n"); else @@ -724,6 +1490,22 @@ return m_condition->evalInt(); } +void SyncBlock::dump(int level) { + printIndents(level); + printf("sync {\n"); + m_statements->dump(level+1); + printIndents(level); + printf("}\n"); +} + +Statements* SyncBlock::statements() const { + return (m_statements) ? const_cast( &*m_statements ) : NULL; +} + +String Neg::evalCastToStr() { + return expr->evalCastToStr(); +} + void Neg::dump(int level) { printIndents(level); printf("Negative Expr\n"); @@ -757,28 +1539,134 @@ return lhs->isConstExpr() && rhs->isConstExpr(); } -int Relation::evalInt() { +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 +inline vmint _evalRelation(Relation::Type type, T_LHS lhs, T_RHS rhs) { switch (type) { - case LESS_THAN: - return lhs->evalInt() < rhs->evalInt(); - case GREATER_THAN: - return lhs->evalInt() > rhs->evalInt(); - case LESS_OR_EQUAL: - return lhs->evalInt() <= rhs->evalInt(); - case GREATER_OR_EQUAL: - return lhs->evalInt() >= rhs->evalInt(); - case EQUAL: - if (lhs->exprType() == STRING_EXPR || rhs->exprType() == STRING_EXPR) + case Relation::LESS_THAN: + return lhs < rhs; + case Relation::GREATER_THAN: + return lhs > rhs; + case Relation::LESS_OR_EQUAL: + return lhs <= rhs; + case Relation::GREATER_OR_EQUAL: + return lhs >= rhs; + case Relation::EQUAL: + return RelComparer::isEqual(lhs, rhs); + case Relation::NOT_EQUAL: + 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(); + if (lType == STRING_EXPR || rType == STRING_EXPR) { + switch (type) { + case EQUAL: return lhs->evalCastToStr() == rhs->evalCastToStr(); - else - return lhs->evalInt() == rhs->evalInt(); - case NOT_EQUAL: - if (lhs->exprType() == STRING_EXPR || rhs->exprType() == STRING_EXPR) + case NOT_EQUAL: return lhs->evalCastToStr() != rhs->evalCastToStr(); - else - return lhs->evalInt() != rhs->evalInt(); + default: + return 0; + } + } else if (lType == REAL_EXPR && rType == REAL_EXPR) { + 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) { + 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) { + vmint lvalue = lhs->asInt()->evalInt(); + vmfloat rvalue = rhs->asReal()->evalReal(); + return _evalRealRelation( + type, lvalue, rvalue, lhs->asInt(), rhs->asReal() + ); + } else { + vmint lvalue = lhs->asInt()->evalInt(); + vmint rvalue = rhs->asInt()->evalInt(); + return _evalIntRelation( + type, lvalue, rvalue, lhs->asInt(), rhs->asInt() + ); } - return 0; } void Relation::dump(int level) { @@ -815,10 +1703,10 @@ return lhs->isConstExpr() && rhs->isConstExpr(); } -int Or::evalInt() { +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; } @@ -833,7 +1721,7 @@ printf(")\n"); } -int BitwiseOr::evalInt() { +vmint BitwiseOr::evalInt() { IntExpr* pLHS = dynamic_cast(&*lhs); IntExpr* pRHS = dynamic_cast(&*rhs); return pLHS->evalInt() | pRHS->evalInt(); @@ -850,7 +1738,7 @@ printf(")\n"); } -int And::evalInt() { +vmint And::evalInt() { IntExpr* pLHS = dynamic_cast(&*lhs); if (!pLHS->evalInt()) return 0; IntExpr* pRHS = dynamic_cast(&*rhs); @@ -868,7 +1756,7 @@ printf(")\n"); } -int BitwiseAnd::evalInt() { +vmint BitwiseAnd::evalInt() { IntExpr* pLHS = dynamic_cast(&*lhs); IntExpr* pRHS = dynamic_cast(&*rhs); return pLHS->evalInt() & pRHS->evalInt(); @@ -901,6 +1789,21 @@ printf(")\n"); } +String Final::evalCastToStr() { + if (exprType() == REAL_EXPR) + return ToString(evalReal()); + else + return ToString(evalInt()); +} + +void Final::dump(int level) { + printIndents(level); + printf("Final(\n"); + expr->dump(level+1); + printIndents(level); + printf(")\n"); +} + StatementsRef ParserContext::userFunctionByName(const String& name) { if (!userFnTable.count(name)) { return StatementsRef(); @@ -929,6 +1832,10 @@ return globalVar(name); } +RealVariableRef ParserContext::globalRealVar(const String& name) { + return globalVar(name); +} + StringVariableRef ParserContext::globalStrVar(const String& name) { return globalVar(name); } @@ -939,9 +1846,16 @@ delete globalIntMemory; globalIntMemory = NULL; } + if (globalRealMemory) { + delete globalRealMemory; + globalRealMemory = NULL; + } } -void ParserContext::addErr(int firstLine, int lastLine, int firstColumn, int lastColumn, const char* txt) { +void ParserContext::addErr(int firstLine, int lastLine, int firstColumn, + int lastColumn, int firstByte, int lengthBytes, + const char* txt) +{ ParserIssue e; e.type = PARSER_ERROR; e.txt = txt; @@ -949,11 +1863,16 @@ e.lastLine = lastLine; e.firstColumn = firstColumn; e.lastColumn = lastColumn; + e.firstByte = firstByte; + e.lengthBytes = lengthBytes; vErrors.push_back(e); vIssues.push_back(e); } -void ParserContext::addWrn(int firstLine, int lastLine, int firstColumn, int lastColumn, const char* txt) { +void ParserContext::addWrn(int firstLine, int lastLine, int firstColumn, + int lastColumn, int firstByte, int lengthBytes, + const char* txt) +{ ParserIssue w; w.type = PARSER_WARNING; w.txt = txt; @@ -961,10 +1880,26 @@ w.lastLine = lastLine; w.firstColumn = firstColumn; w.lastColumn = lastColumn; + w.firstByte = firstByte; + w.lengthBytes = lengthBytes; vWarnings.push_back(w); vIssues.push_back(w); } +void ParserContext::addPreprocessorComment(int firstLine, int lastLine, + int firstColumn, int lastColumn, + int firstByte, int lengthBytes) +{ + CodeBlock block; + block.firstLine = firstLine; + block.lastLine = lastLine; + block.firstColumn = firstColumn; + block.lastColumn = lastColumn; + block.firstByte = firstByte; + block.lengthBytes = lengthBytes; + vPreprocessorComments.push_back(block); +} + bool ParserContext::setPreprocessorCondition(const char* name) { if (builtinPreprocessorConditions.count(name)) return false; if (userPreprocessorConditions.count(name)) return false; @@ -996,6 +1931,10 @@ return vWarnings; } +std::vector ParserContext::preprocessorComments() const { + return vPreprocessorComments; +} + VMEventHandler* ParserContext::eventHandler(uint index) { if (!handlers) return NULL; return handlers->eventHandler(index); @@ -1006,17 +1945,30 @@ return handlers->eventHandlerByName(name); } -void ParserContext::registerBuiltInConstIntVariables(const std::map& vars) { - for (std::map::const_iterator it = vars.begin(); +void ParserContext::registerBuiltInConstIntVariables(const std::map& vars) { + for (std::map::const_iterator it = vars.begin(); + it != vars.end(); ++it) + { + ConstIntVariableRef ref = new ConstIntVariable({ + .value = it->second + }); + vartable[it->first] = ref; + } +} + +void ParserContext::registerBuiltInConstRealVariables(const std::map& vars) { + for (std::map::const_iterator it = vars.begin(); it != vars.end(); ++it) { - ConstIntVariableRef ref = new ConstIntVariable(it->second); + ConstRealVariableRef ref = new ConstRealVariable({ + .value = it->second + }); vartable[it->first] = ref; } } -void ParserContext::registerBuiltInIntVariables(const std::map& vars) { - for (std::map::const_iterator it = vars.begin(); +void ParserContext::registerBuiltInIntVariables(const std::map& vars) { + for (std::map::const_iterator it = vars.begin(); it != vars.end(); ++it) { BuiltInIntVariableRef ref = new BuiltInIntVariable(it->first, it->second); @@ -1042,4 +1994,24 @@ } } +ExecContext::ExecContext() : + status(VM_EXEC_NOT_RUNNING), flags(STMT_SUCCESS), stackFrame(-1), + suspendMicroseconds(0), instructionsCount(0) +{ + exitRes.value = NULL; +} + +void ExecContext::forkTo(VMExecContext* ectx) const { + ExecContext* child = dynamic_cast(ectx); + + child->polyphonicIntMemory.copyFlatFrom(polyphonicIntMemory); + child->polyphonicRealMemory.copyFlatFrom(polyphonicRealMemory); + child->status = VM_EXEC_SUSPENDED; + child->flags = STMT_SUCCESS; + child->stack.copyFlatFrom(stack); + child->stackFrame = stackFrame; + child->suspendMicroseconds = 0; + child->instructionsCount = 0; +} + } // namespace LinuxSampler