/[svn]/linuxsampler/trunk/src/scriptvm/CoreVMFunctions.cpp
ViewVC logotype

Annotation of /linuxsampler/trunk/src/scriptvm/CoreVMFunctions.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3581 - (hide annotations) (download)
Fri Aug 30 11:40:25 2019 UTC (4 years, 6 months ago) by schoenebeck
File size: 48651 byte(s)
NKSP: Allow more wider support of standard measuring units & 'final'ness.

* Raised compiler requirement to be C++14 compliant (due to severe
  restrictions regarding C-style aggregate initializer lists in C++11
  which are now massively used throughout the code base).

* NKSP VM API: Allow units and 'final'ness to be returned as result from
  built-in functions (added methods VMFunction::returnUnitType() and
  VMFunction::returnsFinal() for that purpose which must be implemented by
  built-in function implementations).

* NKSP language: Allow metric unit prefixes of numeric scalar and array
  variables to be changed freely at runtime (unlike unit types like Hz etc.
  which are still sticky parse-time features of variables which cannot be
  changed at runtime for the intentional sake of determinism).

* NKSP language: 'final' values are prohibited for array variables for now
  (attempt causes a parsers error).

* NKSP language: expressions with unit types (e.g. Hz) are prohibited for
  conditions of runtime control structures like if(), while(), select()
  (attempt causes a parser error).

* NKSP VM API: Allow built-in functions to perform their own, individual
  parse time checks of arguments going to be passed to the function at
  runtime (added method VMFunction::checkArgs() for that purpose).

* NKSP language: raise parser warning if only one operand of binary
  operators (like logical 'or' comparison) contain a 'final' value (because
  it would always yield in a 'final' result in such cases).

* NKSP language: Allow comparison (=, #, <, >, <=, >=) of values with
  different metric unit prefixes, which will behave as expected (e.g.
  result of expression '1000us < 2ms' is true).

* NKSP language: Allow adding values with different metric unit prefixes
  (e.g. result of expression '100Hz + 5kHz' is '5100Hz').

* NKSP language: Allow subtracting values with different metric unit
  prefixes (e.g. result of expression '1ms - 20us' is '980us').

* NKSP language: Allow multiplying with any metric unit prefixes
  (e.g. result of expression '2k * 3ms' is '6s'), however multiplications
  with unit types on both sides (e.g. '2s * 2s') is still prohibited since
  we don't have any considerable practical use for a term like '4s^2'
  (hence any attempt multiplying two unit types still causes parser error).

* NKSP language: Allow dividing by any metric unit prefixes and allow
  division of same unit type on both sides (e.g. expression '8kHz / 1000Hz'
  yields in unit free result '8'). So this is now a way to cast units away
  e.g. for passing the result to other expressions, certain function calls
  or variables which are not accepting any units (or that specific unit).

* NKSP language: integer arrays and real number arrays can now be converted
  to strings (e.g. for dumping their content with message() calls for
  script debugging purposes).

* NKSP language: expressions and variables with units are now correctly
  casted to strings (e.g. with message() calls).

* NKSP language: comparing real numbers for equalness (e.g. '~foo = 3.1') or
  unequalness (e.g. '~foo # 3.1') is now less strict and takes the expected
  floating point tolerances into account.

* NKSP VM API: Added methods VMScalarNumberExpr::evalCastInt() and
  VMScalarNumberExpr::evalCastReal().

* NKSP VM API: Added base class 'VMNumberArrayExpr' for classes
  'VMIntArrayExpr' and 'VMRealArrayExpr'.

* NKSP VM API: replaced all unitPrefix() (parse time) methods by
  unitFactor() (runtime) methods.

* Built-in function "exit()" supports now returning units and 'final'ness
  exclusively for test cases.

* The following built-in functions support now units as well: "abs()",
  "random()", "inc()", "dec()", "in_range()", "min()", "max()",
  "real_to_int()", "int()", "int_to_real()" and "real()".

* Built-in functions "array_equal()", "search()" and "sort()" support now
  real number arrays (correctly) as well.

* Added individual parse time checks of arguments to be passed to built-in
  functions "random()", "inc()", "dec()", "in_range()", "min()", "max()",
  "array_equal()" and "search()" specific for their individual purposes.

* Test cases: Added massive amount of NKSP test cases for standard
  measuring units and 'final' operator usage cases.

* Test cases: Added NKSP test cases for (floating point tolerance aware)
  real number equalness / unequalness comparison.

* Bumped version (2.1.1.svn8).

1 schoenebeck 2581 /*
2 schoenebeck 3551 * Copyright (c) 2014-2019 Christian Schoenebeck
3 schoenebeck 2581 *
4     * http://www.linuxsampler.org
5     *
6     * This file is part of LinuxSampler and released under the same terms.
7     * See README file for details.
8     */
9    
10     #include "CoreVMFunctions.h"
11    
12     #include <iostream>
13 schoenebeck 3221 #include <algorithm> // for std::sort()
14 schoenebeck 2619 #include <math.h>
15     #include <stdlib.h>
16 schoenebeck 2581 #include "tree.h"
17     #include "ScriptVM.h"
18 schoenebeck 3285 #include "../common/RTMath.h"
19 schoenebeck 2581
20     namespace LinuxSampler {
21    
22 schoenebeck 3581 inline bool _fEqualX(vmfloat a, vmfloat b) {
23     if (sizeof(vmfloat) == sizeof(float))
24     return RTMath::fEqual32(a, b);
25     else
26     return RTMath::fEqual64(a, b);
27     }
28    
29 schoenebeck 2727 ///////////////////////////////////////////////////////////////////////////
30     // class VMEmptyResultFunction
31    
32 schoenebeck 2581 VMFnResult* VMEmptyResultFunction::errorResult() {
33     result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
34     return &result;
35     }
36    
37 schoenebeck 2598 VMFnResult* VMEmptyResultFunction::successResult() {
38     result.flags = STMT_SUCCESS;
39     return &result;
40 schoenebeck 2596 }
41    
42 schoenebeck 2727 ///////////////////////////////////////////////////////////////////////////
43     // class VMIntResultFunction
44    
45 schoenebeck 3557 VMFnResult* VMIntResultFunction::errorResult(vmint i) {
46 schoenebeck 2598 result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
47     result.value = i;
48 schoenebeck 3581 result.unitPrefixFactor = VM_NO_FACTOR;
49 schoenebeck 2598 return &result;
50 schoenebeck 2596 }
51    
52 schoenebeck 3557 VMFnResult* VMIntResultFunction::successResult(vmint i) {
53 schoenebeck 2581 result.flags = STMT_SUCCESS;
54 schoenebeck 2598 result.value = i;
55 schoenebeck 3581 result.unitPrefixFactor = VM_NO_FACTOR;
56 schoenebeck 2581 return &result;
57     }
58    
59 schoenebeck 3581 VMFnResult* VMIntResultFunction::errorResult(VMIntFnResDef res) {
60     result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
61     result.value = res.value;
62     result.unitPrefixFactor = res.unitFactor;
63     return &result;
64     }
65    
66     VMFnResult* VMIntResultFunction::successResult(VMIntFnResDef res) {
67     result.flags = STMT_SUCCESS;
68     result.value = res.value;
69     result.unitPrefixFactor = res.unitFactor;
70     return &result;
71     }
72    
73 schoenebeck 2727 ///////////////////////////////////////////////////////////////////////////
74 schoenebeck 3573 // class VMRealResultFunction
75    
76     VMFnResult* VMRealResultFunction::errorResult(vmfloat f) {
77     result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
78     result.value = f;
79 schoenebeck 3581 result.unitPrefixFactor = VM_NO_FACTOR;
80 schoenebeck 3573 return &result;
81     }
82    
83 schoenebeck 3581 VMFnResult* VMRealResultFunction::errorResult(VMRealFnResDef res) {
84     result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
85     result.value = res.value;
86     result.unitPrefixFactor = res.unitFactor;
87     return &result;
88     }
89    
90 schoenebeck 3573 VMFnResult* VMRealResultFunction::successResult(vmfloat f) {
91     result.flags = STMT_SUCCESS;
92     result.value = f;
93 schoenebeck 3581 result.unitPrefixFactor = VM_NO_FACTOR;
94 schoenebeck 3573 return &result;
95     }
96    
97 schoenebeck 3581 VMFnResult* VMRealResultFunction::successResult(VMRealFnResDef res) {
98     result.flags = STMT_SUCCESS;
99     result.value = res.value;
100     result.unitPrefixFactor = res.unitFactor;
101     return &result;
102     }
103    
104 schoenebeck 3573 ///////////////////////////////////////////////////////////////////////////
105 schoenebeck 2727 // class VMStringResultFunction
106    
107 schoenebeck 2581 VMFnResult* VMStringResultFunction::errorResult(const String& s) {
108     result.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
109     result.value = s;
110     return &result;
111     }
112    
113     VMFnResult* VMStringResultFunction::successResult(const String& s) {
114     result.flags = STMT_SUCCESS;
115     result.value = s;
116     return &result;
117     }
118    
119 schoenebeck 2727 ///////////////////////////////////////////////////////////////////////////
120 schoenebeck 3577 // class VMScalarNumberResultFunction
121    
122     VMFnResult* VMScalarNumberResultFunction::errorResult(vmint i) {
123     intResult.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
124     intResult.value = i;
125 schoenebeck 3581 intResult.unitPrefixFactor = VM_NO_FACTOR;
126 schoenebeck 3577 return &intResult;
127     }
128    
129     VMFnResult* VMScalarNumberResultFunction::errorResult(vmfloat f) {
130     realResult.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
131     realResult.value = f;
132 schoenebeck 3581 realResult.unitPrefixFactor = VM_NO_FACTOR;
133 schoenebeck 3577 return &realResult;
134     }
135    
136     VMFnResult* VMScalarNumberResultFunction::successResult(vmint i) {
137     intResult.flags = STMT_SUCCESS;
138     intResult.value = i;
139 schoenebeck 3581 intResult.unitPrefixFactor = VM_NO_FACTOR;
140 schoenebeck 3577 return &intResult;
141     }
142    
143     VMFnResult* VMScalarNumberResultFunction::successResult(vmfloat f) {
144     realResult.flags = STMT_SUCCESS;
145     realResult.value = f;
146 schoenebeck 3581 realResult.unitPrefixFactor = VM_NO_FACTOR;
147 schoenebeck 3577 return &realResult;
148     }
149    
150 schoenebeck 3581 VMFnResult* VMScalarNumberResultFunction::errorIntResult(VMIntFnResDef res) {
151     intResult.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
152     intResult.value = res.value;
153     intResult.unitPrefixFactor = res.unitFactor;
154     return &intResult;
155     }
156    
157     VMFnResult* VMScalarNumberResultFunction::errorRealResult(VMRealFnResDef res) {
158     realResult.flags = StmtFlags_t(STMT_ABORT_SIGNALLED | STMT_ERROR_OCCURRED);
159     realResult.value = res.value;
160     realResult.unitPrefixFactor = res.unitFactor;
161     return &realResult;
162     }
163    
164     VMFnResult* VMScalarNumberResultFunction::successIntResult(VMIntFnResDef res) {
165     intResult.flags = STMT_SUCCESS;
166     intResult.value = res.value;
167     intResult.unitPrefixFactor = res.unitFactor;
168     return &intResult;
169     }
170    
171     VMFnResult* VMScalarNumberResultFunction::successRealResult(VMRealFnResDef res) {
172     realResult.flags = STMT_SUCCESS;
173     realResult.value = res.value;
174     realResult.unitPrefixFactor = res.unitFactor;
175     return &realResult;
176     }
177    
178 schoenebeck 3577 ///////////////////////////////////////////////////////////////////////////
179 schoenebeck 2727 // built-in script function: message()
180    
181 schoenebeck 3557 bool CoreVMFunction_message::acceptsArgType(vmint iArg, ExprType_t type) const {
182 schoenebeck 3573 return type == INT_EXPR || type == REAL_EXPR || type == STRING_EXPR;
183 schoenebeck 2581 }
184    
185     VMFnResult* CoreVMFunction_message::exec(VMFnArgs* args) {
186     if (!args->argsCount()) return errorResult();
187    
188 schoenebeck 3285 uint64_t usecs = RTMath::unsafeMicroSeconds(RTMath::real_clock);
189    
190 schoenebeck 2581 VMStringExpr* strExpr = dynamic_cast<VMStringExpr*>(args->arg(0));
191     if (strExpr) {
192 schoenebeck 3285 printf("[ScriptVM %.3f] %s\n", usecs/1000000.f, strExpr->evalStr().c_str());
193 schoenebeck 2581 return successResult();
194     }
195    
196 schoenebeck 3573 VMRealExpr* realExpr = dynamic_cast<VMRealExpr*>(args->arg(0));
197     if (realExpr) {
198     printf("[ScriptVM %.3f] %f\n", usecs/1000000.f, realExpr->evalReal());
199     return successResult();
200     }
201    
202 schoenebeck 2581 VMIntExpr* intExpr = dynamic_cast<VMIntExpr*>(args->arg(0));
203     if (intExpr) {
204 schoenebeck 3557 printf("[ScriptVM %.3f] %lld\n", usecs/1000000.f, (int64_t)intExpr->evalInt());
205 schoenebeck 2581 return successResult();
206     }
207    
208     return errorResult();
209     }
210    
211 schoenebeck 2727 ///////////////////////////////////////////////////////////////////////////
212     // built-in script function: exit()
213    
214 schoenebeck 3557 vmint CoreVMFunction_exit::maxAllowedArgs() const {
215 schoenebeck 3551 return (vm->isExitResultEnabled()) ? 1 : 0;
216     }
217    
218 schoenebeck 3557 bool CoreVMFunction_exit::acceptsArgType(vmint iArg, ExprType_t type) const {
219 schoenebeck 3551 if (!vm->isExitResultEnabled()) return false;
220 schoenebeck 3575 return type == INT_EXPR || type == REAL_EXPR || type == STRING_EXPR;
221 schoenebeck 3551 }
222    
223 schoenebeck 3581 bool CoreVMFunction_exit::acceptsArgUnitType(vmint iArg, StdUnit_t type) const {
224     if (!vm->isExitResultEnabled()) return false;
225     return true;
226     }
227    
228     bool CoreVMFunction_exit::acceptsArgUnitPrefix(vmint iArg, StdUnit_t type) const {
229     if (!vm->isExitResultEnabled()) return false;
230     return true;
231     }
232     bool CoreVMFunction_exit::acceptsArgFinal(vmint iArg) const {
233     if (!vm->isExitResultEnabled()) return false;
234     return true;
235     }
236    
237 schoenebeck 2581 VMFnResult* CoreVMFunction_exit::exec(VMFnArgs* args) {
238     this->result.flags = STMT_ABORT_SIGNALLED;
239 schoenebeck 3551 if (vm->isExitResultEnabled() && args->argsCount()) {
240     ExecContext* ctx = dynamic_cast<ExecContext*>(vm->currentVMExecContext());
241     switch (args->arg(0)->exprType()) {
242 schoenebeck 3581 case INT_EXPR: {
243     VMIntExpr* expr = args->arg(0)->asInt();
244     ctx->exitRes.intLiteral = IntLiteral({
245     .value = expr->evalInt(),
246     .unitFactor = expr->unitFactor(),
247     .unitType = expr->unitType(),
248     .isFinal = expr->isFinal()
249     });
250 schoenebeck 3551 ctx->exitRes.value = &ctx->exitRes.intLiteral;
251     break;
252 schoenebeck 3581 }
253     case REAL_EXPR: {
254     VMRealExpr* expr = args->arg(0)->asReal();
255     ctx->exitRes.realLiteral = RealLiteral({
256     .value = expr->evalReal(),
257     .unitFactor = expr->unitFactor(),
258     .unitType = expr->unitType(),
259     .isFinal = expr->isFinal()
260     });
261 schoenebeck 3575 ctx->exitRes.value = &ctx->exitRes.realLiteral;
262     break;
263 schoenebeck 3581 }
264 schoenebeck 3551 case STRING_EXPR:
265 schoenebeck 3581 ctx->exitRes.stringLiteral = StringLiteral(
266     args->arg(0)->asString()->evalStr()
267     );
268 schoenebeck 3551 ctx->exitRes.value = &ctx->exitRes.stringLiteral;
269     break;
270     default:
271     ; // noop - just to shut up the compiler
272     }
273     }
274 schoenebeck 2581 return &result;
275     }
276    
277 schoenebeck 2727 ///////////////////////////////////////////////////////////////////////////
278     // built-in script function: wait()
279    
280 schoenebeck 3561 bool CoreVMFunction_wait::acceptsArgUnitType(vmint iArg, StdUnit_t type) const {
281     if (iArg == 0)
282     return type == VM_NO_UNIT || type == VM_SECOND;
283     else
284     return type == VM_NO_UNIT;
285     }
286    
287 schoenebeck 3564 bool CoreVMFunction_wait::acceptsArgUnitPrefix(vmint iArg, StdUnit_t type) const {
288     return iArg == 0 && type == VM_SECOND;
289 schoenebeck 3561 }
290    
291 schoenebeck 2581 VMFnResult* CoreVMFunction_wait::exec(VMFnArgs* args) {
292     ExecContext* ctx = dynamic_cast<ExecContext*>(vm->currentVMExecContext());
293     VMIntExpr* expr = dynamic_cast<VMIntExpr*>(args->arg(0));
294 schoenebeck 3564 StdUnit_t unit = expr->unitType();
295     vmint us = (unit) ? expr->evalInt(VM_MICRO) : expr->evalInt();
296 schoenebeck 2972 if (us < 0) {
297     wrnMsg("wait(): argument may not be negative! Aborting script!");
298     this->result.flags = STMT_ABORT_SIGNALLED;
299     } else if (us == 0) {
300     wrnMsg("wait(): argument may not be zero! Aborting script!");
301     this->result.flags = STMT_ABORT_SIGNALLED;
302     } else {
303     ctx->suspendMicroseconds = us;
304     this->result.flags = STMT_SUSPEND_SIGNALLED;
305     }
306 schoenebeck 2581 return &result;
307     }
308    
309 schoenebeck 2727 ///////////////////////////////////////////////////////////////////////////
310     // built-in script function: abs()
311    
312 schoenebeck 3577 ExprType_t CoreVMFunction_abs::returnType(VMFnArgs* args) {
313     return args->arg(0)->exprType();
314     }
315    
316 schoenebeck 3581 StdUnit_t CoreVMFunction_abs::returnUnitType(VMFnArgs* args) {
317     return args->arg(0)->asScalarNumberExpr()->unitType();
318     }
319    
320     bool CoreVMFunction_abs::returnsFinal(VMFnArgs* args) {
321     return args->arg(0)->asScalarNumberExpr()->isFinal();
322     }
323    
324 schoenebeck 3557 bool CoreVMFunction_abs::acceptsArgType(vmint iArg, ExprType_t type) const {
325 schoenebeck 3577 return type == INT_EXPR || type == REAL_EXPR;
326 schoenebeck 2619 }
327    
328     VMFnResult* CoreVMFunction_abs::exec(VMFnArgs* args) {
329 schoenebeck 3577 VMExpr* arg = args->arg(0);
330 schoenebeck 3581 if (arg->exprType() == REAL_EXPR) {
331     VMRealExpr* expr = arg->asReal();
332     return successRealResult({
333     .value = ::fabs(expr->evalReal()),
334     .unitFactor = expr->unitFactor()
335     });
336     } else {
337     VMIntExpr* expr = arg->asInt();
338     return successIntResult({
339     .value = ::abs(expr->evalInt()),
340     .unitFactor = expr->unitFactor()
341     });
342     }
343 schoenebeck 2619 }
344    
345 schoenebeck 2727 ///////////////////////////////////////////////////////////////////////////
346     // built-in script function: random()
347    
348 schoenebeck 3581 ExprType_t CoreVMFunction_random::returnType(VMFnArgs* args) {
349     return (args->arg(0)->exprType() == INT_EXPR &&
350     args->arg(1)->exprType() == INT_EXPR) ? INT_EXPR : REAL_EXPR;
351     }
352    
353     StdUnit_t CoreVMFunction_random::returnUnitType(VMFnArgs* args) {
354     // we ensure in checkArgs() below (which is called before this method here)
355     // that both arguments must be of same unit type, so either one is fine here
356     return args->arg(0)->asScalarNumberExpr()->unitType();
357     }
358    
359     bool CoreVMFunction_random::returnsFinal(VMFnArgs* args) {
360     return args->arg(0)->asScalarNumberExpr()->isFinal() ||
361     args->arg(1)->asScalarNumberExpr()->isFinal();
362     }
363    
364 schoenebeck 3557 bool CoreVMFunction_random::acceptsArgType(vmint iArg, ExprType_t type) const {
365 schoenebeck 3581 return type == INT_EXPR || type == REAL_EXPR;
366 schoenebeck 2619 }
367    
368 schoenebeck 3581 void CoreVMFunction_random::checkArgs(VMFnArgs* args,
369     std::function<void(String)> err,
370     std::function<void(String)> wrn)
371     {
372     // super class checks
373     Super::checkArgs(args, err, wrn);
374    
375     // own checks ...
376     if (args->arg(0)->asScalarNumberExpr()->unitType() !=
377     args->arg(1)->asScalarNumberExpr()->unitType())
378     {
379     String a = unitTypeStr(args->arg(0)->asScalarNumberExpr()->unitType());
380     String b = unitTypeStr(args->arg(1)->asScalarNumberExpr()->unitType());
381     err("Argument 1 has unit type " + a + ", whereas argument 2 has unit type " + b + ".");
382     return;
383     }
384     if (args->arg(0)->asScalarNumberExpr()->isFinal() !=
385     args->arg(1)->asScalarNumberExpr()->isFinal())
386     {
387     String a = args->arg(0)->asScalarNumberExpr()->isFinal() ? "'final'" : "not 'final'";
388     String b = args->arg(1)->asScalarNumberExpr()->isFinal() ? "'final'" : "not 'final'";
389     wrn("Argument 1 is " + a + ", whereas argument 2 is " + b + ", function result will be final.");
390     }
391     }
392    
393 schoenebeck 2619 VMFnResult* CoreVMFunction_random::exec(VMFnArgs* args) {
394 schoenebeck 2620 float f = float(::rand()) / float(RAND_MAX);
395 schoenebeck 3581
396     VMScalarNumberExpr* arg0 = args->arg(0)->asScalarNumberExpr();
397     VMScalarNumberExpr* arg1 = args->arg(1)->asScalarNumberExpr();
398    
399     if (arg0->exprType() == INT_EXPR && arg1->exprType() == INT_EXPR) {
400     vmint iMin = args->arg(0)->asInt()->evalInt();
401     vmint iMax = args->arg(1)->asInt()->evalInt();
402     if (arg0->unitFactor() == arg1->unitFactor()) {
403     return successIntResult({
404     .value = vmint( iMin + roundf( f * float(iMax - iMin) ) ),
405     .unitFactor = arg0->unitFactor()
406     });
407     } else if (arg0->unitFactor() < arg1->unitFactor()) {
408     iMax = Unit::convIntToUnitFactor(iMax, arg1, arg0);
409     return successIntResult({
410     .value = vmint( iMin + roundf( f * float(iMax - iMin) ) ),
411     .unitFactor = arg0->unitFactor()
412     });
413     } else { // arg0->unitFactor() > arg1->unitFactor() ...
414     iMin = Unit::convIntToUnitFactor(iMin, arg0, arg1);
415     return successIntResult({
416     .value = vmint( iMin + roundf( f * float(iMax - iMin) ) ),
417     .unitFactor = arg1->unitFactor()
418     });
419     }
420     } else {
421     vmfloat fMin = arg0->evalCastReal();
422     vmfloat fMax = arg1->evalCastReal();
423     if (arg0->unitFactor() == arg1->unitFactor()) {
424     return successRealResult({
425     .value = fMin + f * (fMax - fMin),
426     .unitFactor = arg0->unitFactor()
427     });
428     } else if (arg0->unitFactor() < arg1->unitFactor()) {
429     fMax = Unit::convRealToUnitFactor(fMax, arg1, arg0);
430     return successRealResult({
431     .value = fMin + f * (fMax - fMin),
432     .unitFactor = arg0->unitFactor()
433     });
434     } else { // arg0->unitFactor() > arg1->unitFactor() ...
435     fMin = Unit::convRealToUnitFactor(fMin, arg0, arg1);
436     return successRealResult({
437     .value = fMin + f * (fMax - fMin),
438     .unitFactor = arg1->unitFactor()
439     });
440     }
441     }
442 schoenebeck 2619 }
443    
444 schoenebeck 2727 ///////////////////////////////////////////////////////////////////////////
445     // built-in script function: num_elements()
446    
447 schoenebeck 3557 bool CoreVMFunction_num_elements::acceptsArgType(vmint iArg, ExprType_t type) const {
448 schoenebeck 3581 return isArray(type);
449 schoenebeck 2619 }
450    
451     VMFnResult* CoreVMFunction_num_elements::exec(VMFnArgs* args) {
452 schoenebeck 3581 return successResult( args->arg(0)->asArray()->arraySize() );
453 schoenebeck 2619 }
454    
455 schoenebeck 2945 ///////////////////////////////////////////////////////////////////////////
456     // built-in script function: inc()
457    
458 schoenebeck 3581 StdUnit_t CoreVMFunction_inc::returnUnitType(VMFnArgs* args) {
459     return args->arg(0)->asScalarNumberExpr()->unitType();
460     }
461    
462     bool CoreVMFunction_inc::returnsFinal(VMFnArgs* args) {
463     return args->arg(0)->asScalarNumberExpr()->isFinal();
464     }
465    
466     void CoreVMFunction_inc::checkArgs(VMFnArgs* args,
467     std::function<void(String)> err,
468     std::function<void(String)> wrn)
469     {
470     // super class checks
471     Super::checkArgs(args, err, wrn);
472    
473     // own checks ...
474     if (args->arg(0)->asScalarNumberExpr()->unitType()) {
475     String unitType = unitTypeStr(args->arg(0)->asScalarNumberExpr()->unitType());
476     wrn("Argument has a unit type (" + unitType + "), only the number before the unit will be incremented by one.");
477     }
478     }
479    
480 schoenebeck 2945 VMFnResult* CoreVMFunction_inc::exec(VMFnArgs* args) {
481     VMExpr* arg = args->arg(0);
482     VMIntExpr* in = dynamic_cast<VMIntExpr*>(arg);
483     VMVariable* out = dynamic_cast<VMVariable*>(arg);
484 schoenebeck 3557 vmint i = in->evalInt() + 1;
485 schoenebeck 3581 IntLiteral tmp({
486     .value = i,
487     .unitFactor = in->unitFactor()
488     });
489 schoenebeck 2945 out->assignExpr(&tmp);
490 schoenebeck 3581 return successResult({
491     .value = i,
492     .unitFactor = in->unitFactor()
493     });
494 schoenebeck 2945 }
495    
496     ///////////////////////////////////////////////////////////////////////////
497     // built-in script function: dec()
498    
499 schoenebeck 3581 StdUnit_t CoreVMFunction_dec::returnUnitType(VMFnArgs* args) {
500     return args->arg(0)->asScalarNumberExpr()->unitType();
501     }
502    
503     bool CoreVMFunction_dec::returnsFinal(VMFnArgs* args) {
504     return args->arg(0)->asScalarNumberExpr()->isFinal();
505     }
506    
507     void CoreVMFunction_dec::checkArgs(VMFnArgs* args,
508     std::function<void(String)> err,
509     std::function<void(String)> wrn)
510     {
511     // super class checks
512     Super::checkArgs(args, err, wrn);
513    
514     // own checks ...
515     if (args->arg(0)->asScalarNumberExpr()->unitType()) {
516     String unitType = unitTypeStr(args->arg(0)->asScalarNumberExpr()->unitType());
517     wrn("Argument has a unit type (" + unitType + "), only the number before the unit will be decremented by one.");
518     }
519     }
520    
521 schoenebeck 2945 VMFnResult* CoreVMFunction_dec::exec(VMFnArgs* args) {
522     VMExpr* arg = args->arg(0);
523     VMIntExpr* in = dynamic_cast<VMIntExpr*>(arg);
524     VMVariable* out = dynamic_cast<VMVariable*>(arg);
525 schoenebeck 3557 vmint i = in->evalInt() - 1;
526 schoenebeck 3581 IntLiteral tmp({
527     .value = i,
528     .unitFactor = in->unitFactor()
529     });
530 schoenebeck 2945 out->assignExpr(&tmp);
531 schoenebeck 3581 return successResult({
532     .value = i,
533     .unitFactor = in->unitFactor()
534     });
535 schoenebeck 2945 }
536    
537 schoenebeck 2965 ///////////////////////////////////////////////////////////////////////////
538 schoenebeck 3076 // built-in script function: in_range()
539    
540 schoenebeck 3581 bool CoreVMFunction_in_range::acceptsArgType(vmint iArg, ExprType_t type) const {
541     return type == INT_EXPR || type == REAL_EXPR;
542     }
543    
544     void CoreVMFunction_in_range::checkArgs(VMFnArgs* args,
545     std::function<void(String)> err,
546     std::function<void(String)> wrn)
547     {
548     // super class checks
549     Super::checkArgs(args, err, wrn);
550    
551     // own checks ...
552     if (args->arg(0)->asScalarNumberExpr()->unitType() !=
553     args->arg(1)->asScalarNumberExpr()->unitType() ||
554     args->arg(1)->asScalarNumberExpr()->unitType() !=
555     args->arg(2)->asScalarNumberExpr()->unitType())
556     {
557     String a = unitTypeStr(args->arg(0)->asScalarNumberExpr()->unitType());
558     String b = unitTypeStr(args->arg(1)->asScalarNumberExpr()->unitType());
559     String c = unitTypeStr(args->arg(2)->asScalarNumberExpr()->unitType());
560     err("Arguments must all have same unit, however argument 1 is " + a +
561     ", argument 2 is " + b + ", argument 3 is " + c + ".");
562     return;
563 schoenebeck 3076 }
564 schoenebeck 3581 if (args->arg(0)->exprType() != args->arg(1)->exprType() ||
565     args->arg(1)->exprType() != args->arg(2)->exprType())
566     {
567     String a = typeStr(args->arg(0)->exprType());
568     String b = typeStr(args->arg(1)->exprType());
569     String c = typeStr(args->arg(2)->exprType());
570     String r = typeStr(REAL_EXPR);
571     wrn("Argument 1 is " + a + ", argument 2 is " + b +
572     ", argument 3 is " + c + ", function result will be " + r + ".");
573     }
574 schoenebeck 3076 }
575    
576 schoenebeck 3581 template<class T>
577     inline void _swapByValue(T& a, T& b) {
578     T tmp = a;
579     a = b;
580     b = tmp;
581     }
582    
583     VMFnResult* CoreVMFunction_in_range::exec(VMFnArgs* args) {
584     VMScalarNumberExpr* argNeedle = args->arg(0)->asScalarNumberExpr();
585     VMScalarNumberExpr* argLo = args->arg(1)->asScalarNumberExpr();
586     VMScalarNumberExpr* argHi = args->arg(2)->asScalarNumberExpr();
587    
588     vmfloat needle = argNeedle->evalCastReal();
589     vmfloat lo = argLo->evalCastReal();
590     vmfloat hi = argHi->evalCastReal();
591    
592     needle *= argNeedle->unitFactor();
593     lo *= argLo->unitFactor();
594     hi *= argHi->unitFactor();
595    
596     if (lo > hi) _swapByValue(lo, hi);
597    
598     return successResult(needle >= lo && needle <= hi);
599     }
600    
601 schoenebeck 3076 ///////////////////////////////////////////////////////////////////////////
602 schoenebeck 2965 // built-in script function: sh_left()
603    
604 schoenebeck 3581 bool CoreVMFunction_sh_left::returnsFinal(VMFnArgs* args) {
605     return args->arg(0)->asScalarNumberExpr()->isFinal();
606     }
607    
608 schoenebeck 2965 VMFnResult* CoreVMFunction_sh_left::exec(VMFnArgs* args) {
609 schoenebeck 3557 vmint i = args->arg(0)->asInt()->evalInt();
610     vmint n = args->arg(1)->asInt()->evalInt();
611 schoenebeck 2965 return successResult(i << n);
612     }
613    
614     ///////////////////////////////////////////////////////////////////////////
615     // built-in script function: sh_right()
616    
617 schoenebeck 3581 bool CoreVMFunction_sh_right::returnsFinal(VMFnArgs* args) {
618     return args->arg(0)->asScalarNumberExpr()->isFinal();
619     }
620    
621 schoenebeck 2965 VMFnResult* CoreVMFunction_sh_right::exec(VMFnArgs* args) {
622 schoenebeck 3557 vmint i = args->arg(0)->asInt()->evalInt();
623     vmint n = args->arg(1)->asInt()->evalInt();
624 schoenebeck 2965 return successResult(i >> n);
625     }
626    
627 schoenebeck 2970 ///////////////////////////////////////////////////////////////////////////
628     // built-in script function: min()
629    
630 schoenebeck 3577 ExprType_t CoreVMFunction_min::returnType(VMFnArgs* args) {
631     return (args->arg(0)->exprType() == REAL_EXPR ||
632     args->arg(1)->exprType() == REAL_EXPR) ? REAL_EXPR : INT_EXPR;
633     }
634    
635 schoenebeck 3581 StdUnit_t CoreVMFunction_min::returnUnitType(VMFnArgs* args) {
636     return args->arg(0)->asScalarNumberExpr()->unitType();
637     }
638    
639     bool CoreVMFunction_min::returnsFinal(VMFnArgs* args) {
640     return args->arg(0)->asScalarNumberExpr()->isFinal() ||
641     args->arg(1)->asScalarNumberExpr()->isFinal();
642     }
643    
644 schoenebeck 3577 bool CoreVMFunction_min::acceptsArgType(vmint iArg, ExprType_t type) const {
645     return type == INT_EXPR || type == REAL_EXPR;
646     }
647    
648 schoenebeck 3581 void CoreVMFunction_min::checkArgs(VMFnArgs* args,
649     std::function<void(String)> err,
650     std::function<void(String)> wrn)
651     {
652     // super class checks
653     Super::checkArgs(args, err, wrn);
654    
655     // own checks ...
656     if (args->arg(0)->asScalarNumberExpr()->unitType() !=
657     args->arg(1)->asScalarNumberExpr()->unitType())
658     {
659     String a = unitTypeStr(args->arg(0)->asScalarNumberExpr()->unitType());
660     String b = unitTypeStr(args->arg(1)->asScalarNumberExpr()->unitType());
661     err("Argument 1 has unit type " + a + ", whereas argument 2 has unit type " + b + ".");
662     return;
663     }
664     if (args->arg(0)->exprType() != args->arg(1)->exprType()) {
665     String a = typeStr(args->arg(0)->exprType());
666     String b = typeStr(args->arg(1)->exprType());
667     String c = typeStr(REAL_EXPR);
668     wrn("Argument 1 is " + a + ", whereas argument 2 is " + b + ", function result will be " + c + ".");
669     return;
670     }
671     if (args->arg(0)->asScalarNumberExpr()->isFinal() !=
672     args->arg(1)->asScalarNumberExpr()->isFinal())
673     {
674     String a = args->arg(0)->asScalarNumberExpr()->isFinal() ? "'final'" : "not 'final'";
675     String b = args->arg(1)->asScalarNumberExpr()->isFinal() ? "'final'" : "not 'final'";
676     wrn("Argument 1 is " + a + ", whereas argument 2 is " + b + ", function result will be final.");
677     }
678     }
679    
680 schoenebeck 2970 VMFnResult* CoreVMFunction_min::exec(VMFnArgs* args) {
681 schoenebeck 3581 VMScalarNumberExpr* lhs = args->arg(0)->asScalarNumberExpr();
682     VMScalarNumberExpr* rhs = args->arg(1)->asScalarNumberExpr();
683     if (lhs->exprType() == REAL_EXPR && rhs->exprType() == REAL_EXPR) {
684     vmfloat lm = lhs->asReal()->evalReal();
685     vmfloat rm = rhs->asReal()->evalReal();
686     vmfloat lprod = lm * lhs->unitFactor();
687     vmfloat rprod = rm * rhs->unitFactor();
688     return successRealResult({
689     .value = (lprod < rprod) ? lm : rm,
690     .unitFactor = (lprod < rprod) ? lhs->unitFactor() : rhs->unitFactor()
691     });
692     } else if (lhs->exprType() == REAL_EXPR && rhs->exprType() == INT_EXPR) {
693     vmfloat lm = lhs->asReal()->evalReal();
694     vmint rm = rhs->asInt()->evalInt();
695     vmfloat lprod = lm * lhs->unitFactor();
696     vmfloat rprod = rm * rhs->unitFactor();
697     return successRealResult({
698     .value = (lprod < rprod) ? lm : rm,
699     .unitFactor = (lprod < rprod) ? lhs->unitFactor() : rhs->unitFactor()
700     });
701     } else if (lhs->exprType() == INT_EXPR && rhs->exprType() == REAL_EXPR) {
702     vmint lm = lhs->asInt()->evalInt();
703     vmfloat rm = rhs->asReal()->evalReal();
704     vmfloat lprod = lm * lhs->unitFactor();
705     vmfloat rprod = rm * rhs->unitFactor();
706     return successRealResult({
707     .value = (lprod < rprod) ? lm : rm,
708     .unitFactor = (lprod < rprod) ? lhs->unitFactor() : rhs->unitFactor()
709     });
710 schoenebeck 3577 } else {
711 schoenebeck 3581 vmint lm = lhs->asInt()->evalInt();
712     vmint rm = rhs->asInt()->evalInt();
713     vmfloat lprod = lm * lhs->unitFactor();
714     vmfloat rprod = rm * rhs->unitFactor();
715     return successIntResult({
716     .value = (lprod < rprod) ? lm : rm,
717     .unitFactor = (lprod < rprod) ? lhs->unitFactor() : rhs->unitFactor()
718     });
719 schoenebeck 3577 }
720 schoenebeck 2970 }
721    
722     ///////////////////////////////////////////////////////////////////////////
723     // built-in script function: max()
724    
725 schoenebeck 3577 ExprType_t CoreVMFunction_max::returnType(VMFnArgs* args) {
726     return (args->arg(0)->exprType() == REAL_EXPR ||
727     args->arg(1)->exprType() == REAL_EXPR) ? REAL_EXPR : INT_EXPR;
728     }
729    
730 schoenebeck 3581 StdUnit_t CoreVMFunction_max::returnUnitType(VMFnArgs* args) {
731     return args->arg(0)->asScalarNumberExpr()->unitType();
732     }
733    
734     bool CoreVMFunction_max::returnsFinal(VMFnArgs* args) {
735     return args->arg(0)->asScalarNumberExpr()->isFinal() ||
736     args->arg(1)->asScalarNumberExpr()->isFinal();
737     }
738    
739 schoenebeck 3577 bool CoreVMFunction_max::acceptsArgType(vmint iArg, ExprType_t type) const {
740     return type == INT_EXPR || type == REAL_EXPR;
741     }
742    
743 schoenebeck 3581 void CoreVMFunction_max::checkArgs(VMFnArgs* args,
744     std::function<void(String)> err,
745     std::function<void(String)> wrn)
746     {
747     // super class checks
748     Super::checkArgs(args, err, wrn);
749    
750     // own checks ...
751     if (args->arg(0)->asScalarNumberExpr()->unitType() !=
752     args->arg(1)->asScalarNumberExpr()->unitType())
753     {
754     String a = unitTypeStr(args->arg(0)->asScalarNumberExpr()->unitType());
755     String b = unitTypeStr(args->arg(1)->asScalarNumberExpr()->unitType());
756     err("Argument 1 has unit type " + a + ", whereas argument 2 has unit type " + b + ".");
757     return;
758     }
759     if (args->arg(0)->exprType() != args->arg(1)->exprType()) {
760     String a = typeStr(args->arg(0)->exprType());
761     String b = typeStr(args->arg(1)->exprType());
762     String c = typeStr(REAL_EXPR);
763     wrn("Argument 1 is " + a + ", whereas argument 2 is " + b + ", function result will be " + c + ".");
764     return;
765     }
766     if (args->arg(0)->asScalarNumberExpr()->isFinal() !=
767     args->arg(1)->asScalarNumberExpr()->isFinal())
768     {
769     String a = args->arg(0)->asScalarNumberExpr()->isFinal() ? "'final'" : "not 'final'";
770     String b = args->arg(1)->asScalarNumberExpr()->isFinal() ? "'final'" : "not 'final'";
771     wrn("Argument 1 is " + a + ", whereas argument 2 is " + b + ", function result will be final.");
772     }
773     }
774    
775 schoenebeck 2970 VMFnResult* CoreVMFunction_max::exec(VMFnArgs* args) {
776 schoenebeck 3581 VMScalarNumberExpr* lhs = args->arg(0)->asScalarNumberExpr();
777     VMScalarNumberExpr* rhs = args->arg(1)->asScalarNumberExpr();
778     if (lhs->exprType() == REAL_EXPR && rhs->exprType() == REAL_EXPR) {
779     vmfloat lm = lhs->asReal()->evalReal();
780     vmfloat rm = rhs->asReal()->evalReal();
781     vmfloat lprod = lm * lhs->unitFactor();
782     vmfloat rprod = rm * rhs->unitFactor();
783     return successRealResult({
784     .value = (lprod > rprod) ? lm : rm,
785     .unitFactor = (lprod > rprod) ? lhs->unitFactor() : rhs->unitFactor()
786     });
787     } else if (lhs->exprType() == REAL_EXPR && rhs->exprType() == INT_EXPR) {
788     vmfloat lm = lhs->asReal()->evalReal();
789     vmint rm = rhs->asInt()->evalInt();
790     vmfloat lprod = lm * lhs->unitFactor();
791     vmfloat rprod = rm * rhs->unitFactor();
792     return successRealResult({
793     .value = (lprod > rprod) ? lm : rm,
794     .unitFactor = (lprod > rprod) ? lhs->unitFactor() : rhs->unitFactor()
795     });
796     } else if (lhs->exprType() == INT_EXPR && rhs->exprType() == REAL_EXPR) {
797     vmint lm = lhs->asInt()->evalInt();
798     vmfloat rm = rhs->asReal()->evalReal();
799     vmfloat lprod = lm * lhs->unitFactor();
800     vmfloat rprod = rm * rhs->unitFactor();
801     return successRealResult({
802     .value = (lprod > rprod) ? lm : rm,
803     .unitFactor = (lprod > rprod) ? lhs->unitFactor() : rhs->unitFactor()
804     });
805 schoenebeck 3577 } else {
806 schoenebeck 3581 vmint lm = lhs->asInt()->evalInt();
807     vmint rm = rhs->asInt()->evalInt();
808     vmfloat lprod = lm * lhs->unitFactor();
809     vmfloat rprod = rm * rhs->unitFactor();
810     return successIntResult({
811     .value = (lprod > rprod) ? lm : rm,
812     .unitFactor = (lprod > rprod) ? lhs->unitFactor() : rhs->unitFactor()
813     });
814 schoenebeck 3577 }
815 schoenebeck 2970 }
816    
817 schoenebeck 3221 ///////////////////////////////////////////////////////////////////////////
818     // built-in script function: array_equal()
819    
820 schoenebeck 3581 bool CoreVMFunction_array_equal::acceptsArgType(vmint iArg, ExprType_t type) const {
821     return isArray(type);
822     }
823    
824     void CoreVMFunction_array_equal::checkArgs(VMFnArgs* args,
825     std::function<void(String)> err,
826     std::function<void(String)> wrn)
827     {
828     // super class checks
829     Super::checkArgs(args, err, wrn);
830    
831     // own checks ...
832     if (args->arg(0)->exprType() != args->arg(1)->exprType()) {
833     String a = typeStr(args->arg(0)->exprType());
834     String b = typeStr(args->arg(1)->exprType());
835     err("Argument 1 is " + a + ", whereas argument 2 is " + b + ".");
836     return;
837     }
838     if (args->arg(0)->asArray()->arraySize() !=
839     args->arg(1)->asArray()->arraySize())
840     {
841     wrn("Result of function call is always false, since the passed two arrays were declared with different array sizes.");
842     }
843     }
844    
845 schoenebeck 3221 VMFnResult* CoreVMFunction_array_equal::exec(VMFnArgs* args) {
846 schoenebeck 3581 VMArrayExpr* l = args->arg(0)->asArray();
847     VMArrayExpr* r = args->arg(1)->asArray();
848 schoenebeck 3221 if (l->arraySize() != r->arraySize()) {
849 schoenebeck 3581 //wrnMsg("array_equal(): the two arrays differ in size");
850 schoenebeck 3221 return successResult(0); // false
851     }
852 schoenebeck 3557 const vmint n = l->arraySize();
853 schoenebeck 3581 // checkArgs() above ensured that we either have INT_ARR_EXPR on both sides
854     // or REAL_ARR_EXPR on both sides, so we can simplify here (a bit)
855     if (l->exprType() == INT_ARR_EXPR) {
856     VMIntArrayExpr* lia = l->asIntArray();
857     VMIntArrayExpr* ria = r->asIntArray();
858     for (vmint i = 0; i < n; ++i) {
859     vmint lvalue = lia->evalIntElement(i);
860     vmint rvalue = ria->evalIntElement(i);
861     vmfloat lfactor = lia->unitFactorOfElement(i);
862     vmfloat rfactor = ria->unitFactorOfElement(i);
863     if (lfactor == rfactor) {
864     if (lvalue != rvalue)
865     return successResult(0); // false
866     else
867     continue;
868     }
869     if (lfactor < rfactor) {
870     if (lvalue != Unit::convIntToUnitFactor(rvalue, rfactor, lfactor))
871     return successResult(0); // false
872     else
873     continue;
874     } else {
875     if (rvalue != Unit::convIntToUnitFactor(lvalue, lfactor, rfactor))
876     return successResult(0); // false
877     else
878     continue;
879     }
880     }
881     } else {
882     VMRealArrayExpr* lra = l->asRealArray();
883     VMRealArrayExpr* rra = r->asRealArray();
884     for (vmint i = 0; i < n; ++i) {
885     vmfloat lvalue = lra->evalRealElement(i);
886     vmfloat rvalue = rra->evalRealElement(i);
887     vmfloat lfactor = lra->unitFactorOfElement(i);
888     vmfloat rfactor = rra->unitFactorOfElement(i);
889     if (lfactor == rfactor) {
890     if (!_fEqualX(lvalue, rvalue))
891     return successResult(0); // false
892     else
893     continue;
894     }
895     if (lfactor < rfactor) {
896     if (!_fEqualX(lvalue, Unit::convRealToUnitFactor(rvalue, rfactor, lfactor)))
897     return successResult(0); // false
898     else
899     continue;
900     } else {
901     if (!_fEqualX(rvalue, Unit::convRealToUnitFactor(lvalue, lfactor, rfactor)))
902     return successResult(0); // false
903     else
904     continue;
905     }
906     }
907     }
908 schoenebeck 3221 return successResult(1); // true
909     }
910    
911     ///////////////////////////////////////////////////////////////////////////
912     // built-in script function: search()
913    
914 schoenebeck 3557 ExprType_t CoreVMFunction_search::argType(vmint iArg) const {
915 schoenebeck 3221 return (iArg == 0) ? INT_ARR_EXPR : INT_EXPR;
916     }
917    
918 schoenebeck 3557 bool CoreVMFunction_search::acceptsArgType(vmint iArg, ExprType_t type) const {
919 schoenebeck 3221 if (iArg == 0)
920 schoenebeck 3581 return isArray(type);
921 schoenebeck 3221 else
922 schoenebeck 3581 return type == INT_EXPR || type == REAL_EXPR;
923 schoenebeck 3221 }
924    
925 schoenebeck 3581 void CoreVMFunction_search::checkArgs(VMFnArgs* args,
926     std::function<void(String)> err,
927     std::function<void(String)> wrn)
928     {
929     // super class checks
930     Super::checkArgs(args, err, wrn);
931    
932     // own checks ...
933     if (args->arg(0)->exprType() == INT_ARR_EXPR &&
934     args->arg(1)->exprType() != INT_EXPR)
935     {
936     String a = typeStr(INT_ARR_EXPR);
937     String bIs = typeStr(args->arg(1)->exprType());
938     String bShould = typeStr(INT_EXPR);
939     err("Argument 1 is " + a + ", hence argument 2 should be " + bShould + ", is " + bIs + " though.");
940     return;
941     }
942     if (args->arg(0)->exprType() == REAL_ARR_EXPR &&
943     args->arg(1)->exprType() != REAL_EXPR)
944     {
945     String a = typeStr(REAL_ARR_EXPR);
946     String bIs = typeStr(args->arg(1)->exprType());
947     String bShould = typeStr(REAL_EXPR);
948     err("Argument 1 is " + a + ", hence argument 2 should be " + bShould + ", is " + bIs + " though.");
949     return;
950     }
951     }
952    
953 schoenebeck 3221 VMFnResult* CoreVMFunction_search::exec(VMFnArgs* args) {
954 schoenebeck 3581 VMArrayExpr* a = args->arg(0)->asArray();
955 schoenebeck 3557 const vmint n = a->arraySize();
956 schoenebeck 3581 if (a->exprType() == INT_ARR_EXPR) {
957     const vmint needle = args->arg(1)->asInt()->evalInt();
958     VMIntArrayExpr* intArray = a->asIntArray();
959     for (vmint i = 0; i < n; ++i)
960     if (intArray->evalIntElement(i) == needle)
961     return successResult(i);
962     } else { // real array ...
963     const vmfloat needle = args->arg(1)->asReal()->evalReal();
964     VMRealArrayExpr* realArray = a->asRealArray();
965     for (vmint i = 0; i < n; ++i) {
966     const vmfloat value = realArray->evalRealElement(i);
967     if (_fEqualX(value, needle))
968     return successResult(i);
969     }
970     }
971 schoenebeck 3221 return successResult(-1); // not found
972     }
973    
974     ///////////////////////////////////////////////////////////////////////////
975     // built-in script function: sort()
976    
977 schoenebeck 3557 ExprType_t CoreVMFunction_sort::argType(vmint iArg) const {
978 schoenebeck 3221 return (iArg == 0) ? INT_ARR_EXPR : INT_EXPR;
979     }
980    
981 schoenebeck 3557 bool CoreVMFunction_sort::acceptsArgType(vmint iArg, ExprType_t type) const {
982 schoenebeck 3221 if (iArg == 0)
983 schoenebeck 3581 return isArray(type);
984 schoenebeck 3221 else
985     return type == INT_EXPR;
986     }
987    
988 schoenebeck 3581 // The following structs and template classes act as adapters for allowing to
989     // use std sort algorithms on our arrays. It might look a bit more complicated
990     // than it ought to be, but there is one reason for the large amount of
991     // 'adapter' code below: the STL std algorithms rely on 'lvalues' to do their
992     // e.g. sorting) jobs, that is they expect containers to have 'localizeable'
993     // data which essentially means their data should reside somewhere in memory and
994     // directly be accessible (readable and writable) there, which is not the case
995     // with our VM interfaces which actually always require virtual getter and
996     // setter methods to be called instead. So we must emulate lvalues by custom
997     // classes/structs which forward between our getters/setters and the lvalue
998     // access operators used by the STL std algorithms.
999    
1000     struct IntArrayAccessor {
1001     static inline vmint getPrimaryValue(VMIntArrayExpr* arr, vmint index) {
1002     return arr->evalIntElement(index);
1003     }
1004     static inline void setPrimaryValue(VMIntArrayExpr* arr, vmint index, vmint value) {
1005     arr->assignIntElement(index, value);
1006     }
1007     };
1008    
1009     struct RealArrayAccessor {
1010     static inline vmfloat getPrimaryValue(VMRealArrayExpr* arr, vmint index) {
1011     return arr->evalRealElement(index);
1012     }
1013     static inline void setPrimaryValue(VMRealArrayExpr* arr, vmint index, vmfloat value) {
1014     arr->assignRealElement(index, value);
1015     }
1016     };
1017    
1018     template<class T_array> // i.e. T_array is either VMIntArrayExpr or VMRealArrayExpr
1019 schoenebeck 3221 struct ArrElemPOD {
1020 schoenebeck 3581 T_array* m_array;
1021 schoenebeck 3557 vmint m_index;
1022 schoenebeck 3221 };
1023    
1024 schoenebeck 3581 // This class is used for temporary values by std::sort().
1025     template<class T_value> // i.e. T_value is either vmint or vmfloat
1026     struct ScalarNmbrVal {
1027     T_value primValue;
1028     vmfloat unitFactor;
1029 schoenebeck 3221
1030 schoenebeck 3581 inline bool operator<(const ScalarNmbrVal& other) const {
1031     return getProdValue() < other.getProdValue();
1032     }
1033     inline bool operator>(const ScalarNmbrVal& other) const {
1034     return getProdValue() > other.getProdValue();
1035     }
1036     inline vmfloat getProdValue() const {
1037     // simple solution for both vmint and vmfloat, should be fine for just sorting
1038     return primValue * unitFactor;
1039     }
1040     };
1041    
1042     // This class emulates lvalue access (access by reference) which is used by ArrExprIter::operator*() below.
1043     template<class T_array, // T_array is either VMIntArrayExpr or VMRealArrayExpr
1044     class T_value, // T_value is either vmint or vmfloat
1045     class T_accessor> // T_accessor is either IntArrayAccessor or RealArrayAccessor
1046     class ArrElemRef : protected ArrElemPOD<T_array> {
1047 schoenebeck 3221 public:
1048 schoenebeck 3581 typedef ScalarNmbrVal<T_value> ScalarNmbrVal;
1049    
1050     inline ArrElemRef(T_array* a, vmint index) {
1051     this->m_array = a;
1052     this->m_index = index;
1053 schoenebeck 3221 }
1054 schoenebeck 3581 inline ArrElemRef(const ArrElemRef& ref) {
1055     this->m_array = ref.m_array;
1056     this->m_index = ref.m_index;
1057 schoenebeck 3221 }
1058     inline ArrElemRef& operator=(const ArrElemRef& e) {
1059 schoenebeck 3581 setPrimValue(e.getPrimValue());
1060     setUnitFactor(e.getUnitFactor());
1061 schoenebeck 3221 return *this;
1062     }
1063 schoenebeck 3581 inline ArrElemRef& operator=(ScalarNmbrVal value) {
1064     setPrimValue(value.primValue);
1065     setUnitFactor(value.unitFactor);
1066 schoenebeck 3221 return *this;
1067     }
1068     inline bool operator==(const ArrElemRef& e) const {
1069 schoenebeck 3581 return getProdValue() == e.getProdValue();
1070 schoenebeck 3221 }
1071     inline bool operator!=(const ArrElemRef& e) const {
1072     return !(operator==(e));
1073     }
1074     inline bool operator<(const ArrElemRef& e) const {
1075 schoenebeck 3581 return getProdValue() < e.getProdValue();
1076 schoenebeck 3221 }
1077     inline bool operator>(const ArrElemRef& e) const {
1078 schoenebeck 3581 return getProdValue() > e.getProdValue();
1079 schoenebeck 3221 }
1080     inline bool operator<=(const ArrElemRef& e) const {
1081 schoenebeck 3581 return getProdValue() <= e.getProdValue();
1082 schoenebeck 3221 }
1083     inline bool operator>=(const ArrElemRef& e) const {
1084 schoenebeck 3581 return getProdValue() >= e.getProdValue();
1085 schoenebeck 3221 }
1086 schoenebeck 3581 inline bool operator==(const ScalarNmbrVal& s) const {
1087     return getProdValue() == s.getProdValue();
1088 schoenebeck 3221 }
1089 schoenebeck 3581 inline bool operator!=(const ScalarNmbrVal& s) const {
1090     return !(operator==(s));
1091 schoenebeck 3221 }
1092 schoenebeck 3581 inline bool operator<(const ScalarNmbrVal& s) const {
1093     return getProdValue() < s.getProdValue();
1094     }
1095     inline bool operator>(const ScalarNmbrVal& s) const {
1096     return getProdValue() > s.getProdValue();
1097     }
1098     inline bool operator<=(const ScalarNmbrVal& s) const {
1099     return getProdValue() <= s.getProdValue();
1100     }
1101     inline bool operator>=(const ScalarNmbrVal& s) const {
1102     return getProdValue() >= s.getProdValue();
1103     }
1104     inline operator ScalarNmbrVal() {
1105     return {
1106     .primValue = getPrimValue() ,
1107     .unitFactor = getUnitFactor()
1108     };
1109     }
1110 schoenebeck 3221 protected:
1111 schoenebeck 3581 inline T_value getPrimValue() const {
1112     return T_accessor::getPrimaryValue( this->m_array, this->m_index );
1113 schoenebeck 3221 }
1114 schoenebeck 3581 inline void setPrimValue(T_value value) {
1115     T_accessor::setPrimaryValue( this->m_array, this->m_index, value );
1116 schoenebeck 3221 }
1117 schoenebeck 3581 inline vmfloat getUnitFactor() const {
1118     return this->m_array->unitFactorOfElement(this->m_index);
1119 schoenebeck 3221 }
1120 schoenebeck 3581 inline void setUnitFactor(vmfloat factor) {
1121     this->m_array->assignElementUnitFactor(this->m_index, factor);
1122 schoenebeck 3221 }
1123 schoenebeck 3581 inline vmfloat getProdValue() const {
1124     // simple solution for both vmint and vmfloat, should be fine for just sorting
1125     vmfloat primary = (vmfloat) getPrimValue();
1126     vmfloat factor = getUnitFactor();
1127     return primary * factor;
1128 schoenebeck 3221 }
1129 schoenebeck 3581
1130     // allow swap() functions below to access protected methods here
1131     friend void swap(class ArrElemRef<T_array,T_value,T_accessor> a,
1132     class ArrElemRef<T_array,T_value,T_accessor> b);
1133 schoenebeck 3221 };
1134    
1135 schoenebeck 3581 // custom iterator class to be used by std:sort() on our VM arrays
1136     template<class T_array, class T_value, class T_accessor>
1137     class ArrExprIter : public ArrElemPOD<T_array> {
1138 schoenebeck 3221 public:
1139     typedef std::random_access_iterator_tag iterator_category;
1140     typedef ssize_t difference_type;
1141 schoenebeck 3581 typedef ArrElemRef<T_array, T_value, T_accessor> ArrElemRef;
1142     typedef ArrElemRef reference; // type used by STL for access by reference
1143     typedef void pointer; // type used by STL for -> operator result, we don't use that operator at all so just void it
1144     typedef ScalarNmbrVal<T_value> value_type; // type used by STL for temporary values
1145 schoenebeck 3221
1146 schoenebeck 3581 ArrExprIter(T_array* a, vmint index) {
1147     this->m_array = a;
1148     this->m_index = index;
1149 schoenebeck 3221 }
1150 schoenebeck 3581 ArrExprIter(const ArrElemRef& ref) {
1151     this->m_array = ref.m_array;
1152     this->m_index = ref.m_index;
1153     }
1154 schoenebeck 3221 inline ArrElemRef operator*() {
1155 schoenebeck 3581 return ArrElemRef(this->m_array, this->m_index);
1156 schoenebeck 3221 }
1157     inline ArrExprIter& operator++() { // prefix increment
1158 schoenebeck 3581 ++(this->m_index);
1159 schoenebeck 3221 return *this;
1160     }
1161     inline ArrExprIter& operator--() { // prefix decrement
1162 schoenebeck 3581 --(this->m_index);
1163 schoenebeck 3221 return *this;
1164     }
1165     inline ArrExprIter operator++(int) { // postfix increment
1166     ArrExprIter it = *this;
1167 schoenebeck 3581 ++(this->m_index);
1168 schoenebeck 3221 return it;
1169     }
1170     inline ArrExprIter operator--(int) { // postfix decrement
1171     ArrExprIter it = *this;
1172 schoenebeck 3581 --(this->m_index);
1173 schoenebeck 3221 return it;
1174     }
1175 schoenebeck 3345 inline ArrExprIter& operator+=(difference_type d) {
1176 schoenebeck 3581 this->m_index += d;
1177 schoenebeck 3345 return *this;
1178     }
1179     inline ArrExprIter& operator-=(difference_type d) {
1180 schoenebeck 3581 this->m_index -= d;
1181 schoenebeck 3345 return *this;
1182     }
1183 schoenebeck 3221 inline bool operator==(const ArrExprIter& other) const {
1184 schoenebeck 3581 return this->m_index == other.m_index;
1185 schoenebeck 3221 }
1186     inline bool operator!=(const ArrExprIter& other) const {
1187 schoenebeck 3581 return this->m_index != other.m_index;
1188 schoenebeck 3221 }
1189     inline bool operator<(const ArrExprIter& other) const {
1190 schoenebeck 3581 return this->m_index < other.m_index;
1191 schoenebeck 3221 }
1192     inline bool operator>(const ArrExprIter& other) const {
1193 schoenebeck 3581 return this->m_index > other.m_index;
1194 schoenebeck 3221 }
1195     inline bool operator<=(const ArrExprIter& other) const {
1196 schoenebeck 3581 return this->m_index <= other.m_index;
1197 schoenebeck 3221 }
1198     inline bool operator>=(const ArrExprIter& other) const {
1199 schoenebeck 3581 return this->m_index >= other.m_index;
1200 schoenebeck 3221 }
1201     inline difference_type operator+(const ArrExprIter& other) const {
1202 schoenebeck 3581 return this->m_index + other.m_index;
1203 schoenebeck 3221 }
1204     inline difference_type operator-(const ArrExprIter& other) const {
1205 schoenebeck 3581 return this->m_index - other.m_index;
1206 schoenebeck 3221 }
1207     inline ArrExprIter operator-(difference_type d) const {
1208 schoenebeck 3581 return ArrExprIter(this->m_array, this->m_index - d);
1209 schoenebeck 3221 }
1210     inline ArrExprIter operator+(difference_type d) const {
1211 schoenebeck 3581 return ArrExprIter(this->m_array, this->m_index + d);
1212 schoenebeck 3221 }
1213     inline ArrExprIter operator*(difference_type factor) const {
1214 schoenebeck 3581 return ArrExprIter(this->m_array, this->m_index * factor);
1215 schoenebeck 3221 }
1216     };
1217    
1218 schoenebeck 3581 typedef ArrExprIter<VMIntArrayExpr,vmint,IntArrayAccessor> IntArrExprIter;
1219     typedef ArrExprIter<VMRealArrayExpr,vmfloat,RealArrayAccessor> RealArrExprIter;
1220    
1221     // intentionally not a template function to avoid potential clashes with other (i.e. system's) swap() functions
1222     static inline void swap(IntArrExprIter::ArrElemRef a,
1223     IntArrExprIter::ArrElemRef b)
1224     {
1225     vmint valueA = a.getPrimValue();
1226     vmint valueB = b.getPrimValue();
1227     vmfloat factorA = a.getUnitFactor();
1228     vmfloat factorB = b.getUnitFactor();
1229     a.setPrimValue(valueB);
1230     a.setUnitFactor(factorB);
1231     b.setPrimValue(valueA);
1232     b.setUnitFactor(factorA);
1233     }
1234    
1235     // intentionally not a template function to avoid potential clashes with other (i.e. system's) swap() functions
1236     static inline void swap(RealArrExprIter::ArrElemRef a,
1237     RealArrExprIter::ArrElemRef b)
1238     {
1239     vmfloat valueA = a.getPrimValue();
1240     vmfloat valueB = b.getPrimValue();
1241     vmfloat factorA = a.getUnitFactor();
1242     vmfloat factorB = b.getUnitFactor();
1243     a.setPrimValue(valueB);
1244     a.setUnitFactor(factorB);
1245     b.setPrimValue(valueA);
1246     b.setUnitFactor(factorA);
1247     }
1248    
1249     // used to sort in descending order (unlike the default behaviour of std::sort() which is ascending order)
1250     template<class T> // T is either IntArrExprIter or RealArrExprIter
1251 schoenebeck 3221 struct DescArrExprSorter {
1252 schoenebeck 3581 inline bool operator()(const typename T::value_type a, const typename T::value_type b) const {
1253 schoenebeck 3221 return a > b;
1254     }
1255     };
1256    
1257     VMFnResult* CoreVMFunction_sort::exec(VMFnArgs* args) {
1258 schoenebeck 3581 const bool bAscending =
1259 schoenebeck 3221 (args->argsCount() < 2) ? true : !args->arg(1)->asInt()->evalInt();
1260 schoenebeck 3581
1261     if (args->arg(0)->exprType() == INT_ARR_EXPR) {
1262     VMIntArrayExpr* a = args->arg(0)->asIntArray();
1263     vmint n = a->arraySize();
1264     IntArrExprIter itBegin(a, 0);
1265     IntArrExprIter itEnd(a, n);
1266     if (bAscending) {
1267     std::sort(itBegin, itEnd);
1268     } else {
1269     DescArrExprSorter<IntArrExprIter> sorter;
1270     std::sort(itBegin, itEnd, sorter);
1271     }
1272 schoenebeck 3221 } else {
1273 schoenebeck 3581 VMRealArrayExpr* a = args->arg(0)->asRealArray();
1274     vmint n = a->arraySize();
1275     RealArrExprIter itBegin(a, 0);
1276     RealArrExprIter itEnd(a, n);
1277     if (bAscending) {
1278     std::sort(itBegin, itEnd);
1279     } else {
1280     DescArrExprSorter<RealArrExprIter> sorter;
1281     std::sort(itBegin, itEnd, sorter);
1282     }
1283 schoenebeck 3221 }
1284 schoenebeck 3581
1285 schoenebeck 3221 return successResult();
1286     }
1287    
1288 schoenebeck 3573 ///////////////////////////////////////////////////////////////////////////
1289     // built-in script function: real_to_int() and int()
1290    
1291 schoenebeck 3581 StdUnit_t CoreVMFunction_real_to_int::returnUnitType(VMFnArgs* args) {
1292     return args->arg(0)->asScalarNumberExpr()->unitType();
1293     }
1294    
1295     bool CoreVMFunction_real_to_int::returnsFinal(VMFnArgs* args) {
1296     return args->arg(0)->asScalarNumberExpr()->isFinal();
1297     }
1298    
1299 schoenebeck 3573 VMFnResult* CoreVMFunction_real_to_int::exec(VMFnArgs* args) {
1300 schoenebeck 3581 VMRealExpr* realExpr = args->arg(0)->asReal();
1301     vmfloat f = realExpr->evalReal();
1302     return successResult({
1303     .value = vmint(f),
1304     .unitFactor = realExpr->unitFactor()
1305     });
1306 schoenebeck 3573 }
1307    
1308     ///////////////////////////////////////////////////////////////////////////
1309     // built-in script function: int_to_real() and real()
1310    
1311 schoenebeck 3581 StdUnit_t CoreVMFunction_int_to_real::returnUnitType(VMFnArgs* args) {
1312     return args->arg(0)->asScalarNumberExpr()->unitType();
1313     }
1314    
1315     bool CoreVMFunction_int_to_real::returnsFinal(VMFnArgs* args) {
1316     return args->arg(0)->asScalarNumberExpr()->isFinal();
1317     }
1318    
1319 schoenebeck 3573 VMFnResult* CoreVMFunction_int_to_real::exec(VMFnArgs* args) {
1320 schoenebeck 3581 VMIntExpr* intExpr = args->arg(0)->asInt();
1321     vmint i = intExpr->evalInt();
1322     return successResult({
1323     .value = vmfloat(i),
1324     .unitFactor = intExpr->unitFactor()
1325     });
1326 schoenebeck 3573 }
1327    
1328 schoenebeck 2581 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC