matex icon indicating copy to clipboard operation
matex copied to clipboard

Exception: Empty argument in Evaluator->addArgument() when custom function without arguments

Open koosvanderkolk opened this issue 4 years ago • 4 comments

I have and EvalMathFunctions class, holding a 'random' function without arguments.

class EvalMathFunctions {
  static public function random() {
    return rand();
  }
}

I register this in matex:

$this->evaluator->functions = [
  'random' => ['ref' => '\\EvalMathFunctions::random', 'arc' => 0]
];

I then call the function:

$this->evaluator->execute('random()');

And get the error.

koosvanderkolk avatar Feb 03 '21 12:02 koosvanderkolk

This seems to fix it (see changes in bold)

private function getFunction(string $name) { $routine = $this->functions[$name] ?? null; $arguments = array(); if (!isset($routine) && isset($this->onFunction)) { call_user_func_array($this->onFunction, [$name, &$routine]); $this->functions[$name] = $routine; } if (!isset($routine)) throw new Exception('Unknown function: ' . $name, 6); if (isset($routine['arc']) && $routine['arc'] > 0 && !$this->getArguments($arguments)) throw new Exception('Syntax error', 1); if (isset($routine['arc']) && ($routine['arc'] != count($arguments))) throw new Exception('Invalid argument count', 3); return call_user_func_array($routine['ref'], $this->proArguments($arguments)); }

koosvanderkolk avatar Feb 03 '21 13:02 koosvanderkolk

yup, seems functions without arguments not tested yet ) thanks i'll look on it

madorin avatar Feb 03 '21 13:02 madorin

Hi @madorin, great, simple (not so simple xd) and efficient code for Evaluator ! If i understand correctly arc parameter * $routine['arc'] = null - any number of arguments * $routine['arc'] = 0 - function without arguments * $routine['arc'] > 1 - specified number of arguments So in addition to condition that wrote @koosvanderkolk

 private function getFunction(string $name)
    {
        $routine = $this->functions[$name] ?? null;
        $arguments = [];
        if (!isset($routine) && isset($this->onFunction)) {
            call_user_func_array($this->onFunction, [$name, &$routine]);
            $this->functions[$name] = $routine;
        }
        if (!isset($routine))
            throw new Exception('Unknown function: ' . $name, 6);
// +++++
        if (((isset($routine['arc']) && $routine['arc'] > 0) || is_null($routine['arc']) ) &&
            !$this->getArguments($arguments))
            throw new Exception('Syntax error', 1);
// +++++
        if (isset($routine['arc']) && ($routine['arc'] != count($arguments)))
            throw new Exception('Invalid argument count', 3);
        return call_user_func_array($routine['ref'], $this->proArguments($arguments));
}

Thanks very much for sharing.

mszyca avatar Aug 15 '21 13:08 mszyca

It works only for single function formula - formula without arguments. Example: "DATENOW()" but for 'bigger' formulas not working Example: ""some text "+ DATENOW() + "text ""

For it to work proArguments() method needs:

    private function proArguments($arguments): array
    {
// +++++
        if (empty($arguments)) {
            $this->pos += 2;
            return [];
        }
// +++++
        $ops = $this->pos;
        $otx = $this->text;
        $result = [];
        foreach ($arguments as $argument)
            $result[] = $this->perform($argument);
        $this->pos = $ops;
        $this->text = $otx;
        return $result;
    }

mszyca avatar Aug 23 '21 13:08 mszyca