diff --git a/docs/instructions/array_get.md b/docs/instructions/base/array_get.md similarity index 100% rename from docs/instructions/array_get.md rename to docs/instructions/base/array_get.md diff --git a/docs/instructions/base/array_set.md b/docs/instructions/base/array_set.md new file mode 100644 index 0000000..45fee77 --- /dev/null +++ b/docs/instructions/base/array_set.md @@ -0,0 +1,41 @@ +# array_set + +Set an item in an array using "dot" notation. + +## Parameters + +* array (`array`, `instruction`) - The array to get the value from. +* key (`string`, `instruction`) - The key to get the value for. +* value (`any`, `instruction`) - The value to set. + +## Return + +(`array`) - The array with the new value set. + +## Exceptions + +* `EvaluationException` - If there was an error while evaluating one or more parameters. +* `KeyException` - If the key is not found. +* `TypeException` - If one or more parameters are not of the expected type. + +## Instruction Example + +```json +{ + "type": "array_set", + "_": { + "array": { + "foo": { + "bar": "baz" + } + }, + "key": "foo.bar", + "value": "qux" + } +} +``` + +### Last Updated + +Monday, December 26th, 2022. +Written by [Netkas](https://git.n64.cc/netkas) \ No newline at end of file diff --git a/docs/instructions/get.md b/docs/instructions/base/get.md similarity index 100% rename from docs/instructions/get.md rename to docs/instructions/base/get.md diff --git a/docs/instructions/base/invoke.md b/docs/instructions/base/invoke.md new file mode 100644 index 0000000..42b8495 --- /dev/null +++ b/docs/instructions/base/invoke.md @@ -0,0 +1,42 @@ +# invoke + +Invokes a method under a namespace. + +## Parameters + +* namespace (`string`, `instruction`) - The namespace to invoke the method under. +* method (`string`, `instruction`) - The method to invoke. +* parameters (`array`, `instruction`) - The parameters to pass to the method. +* fail_on_error (`boolean`, `instruction`) - Whether to fail if the method throws an exception. + +## Return + +(`any`) - The return value of the method. See the method's documentation for more information. + +## Exceptions + +* `EvaluationException` - If there was an error while evaluating one or more parameters. +* `TypeException` - If one or more parameters are not of the expected type. +* `UndefinedMethodException` - If the method is not defined. +* `Exception` - If the method throws an exception and `fail_on_error` is `true`. + +## Instruction Example + +```json +{ + "type": "invoke", + "_": { + "namespace": "system", + "method": "print", + "parameters": { + "value": "Hello, world!" + }, + "fail_on_error": true + } +} +``` + +### Last Updated + +Monday, December 29th, 2022. +Written by [Netkas](https://git.n64.cc/netkas) \ No newline at end of file diff --git a/docs/instructions/base/set.md b/docs/instructions/base/set.md new file mode 100644 index 0000000..de58359 --- /dev/null +++ b/docs/instructions/base/set.md @@ -0,0 +1,35 @@ +# set + +Sets aor overwrites a variable in the environment. + +## Parameters + +* name (`string`, `instruction`) - The name of the variable to get. +* value (`any`, `instruction`) - The value to set. + +## Return + +(`null`) - Nothing. + +## Exceptions + +* `EvaluationException` - If there was an error while evaluating one or more parameters. +* `TypeException` - If one or more parameters are not of the expected type. + + +## Instruction Example + +```json +{ + "type": "set", + "_": { + "name": "foo", + "value": "bar" + } +} +``` + +### Last Updated + +Monday, December 29th, 2022. +Written by [Netkas](https://git.n64.cc/netkas) \ No newline at end of file diff --git a/src/RTEX/Objects/Program/Instructions/ArrayGet.php b/src/RTEX/Objects/Program/Instructions/Base/ArrayGet.php similarity index 80% rename from src/RTEX/Objects/Program/Instructions/ArrayGet.php rename to src/RTEX/Objects/Program/Instructions/Base/ArrayGet.php index c46a18a..b0b34ff 100644 --- a/src/RTEX/Objects/Program/Instructions/ArrayGet.php +++ b/src/RTEX/Objects/Program/Instructions/Base/ArrayGet.php @@ -2,7 +2,7 @@ /** @noinspection PhpMissingFieldTypeInspection */ - namespace RTEX\Objects\Program\Instructions; + namespace RTEX\Objects\Program\Instructions\Base; use RTEX\Abstracts\InstructionType; use RTEX\Abstracts\RegexPatterns; @@ -30,7 +30,7 @@ * * @var mixed */ - private $Value; + private $Key; /** * The name of the variable to set @@ -63,10 +63,11 @@ /** * @return mixed + * @noinspection PhpUnused */ - public function getValue(): mixed + public function getKey(): mixed { - return $this->Value; + return $this->Key; } /** @@ -74,9 +75,9 @@ * @throws InstructionException * @noinspection PhpMissingParamTypeInspection */ - public function setValue($value): void + public function setKey($value): void { - $this->Value = InstructionBuilder::fromRaw($value); + $this->Key = InstructionBuilder::fromRaw($value); } /** @@ -88,7 +89,7 @@ { return InstructionBuilder::toRaw(self::getType(), [ 'array' => $this->Array, - 'value' => $this->Value + 'key' => $this->Key ]); } @@ -101,7 +102,7 @@ { $instruction = new self(); $instruction->setArray($data['array'] ?? null); - $instruction->setValue($data['value'] ?? null); + $instruction->setKey($data['key'] ?? null); return $instruction; } @@ -115,17 +116,18 @@ */ public function eval(Engine $engine): mixed { - $value = $engine->eval($this->Value); + $key = $engine->eval($this->Key); $array = $engine->eval($this->Array); + /** @noinspection DuplicatedCode */ if (!is_array($array)) throw new KeyException(sprintf('Cannot read from non-array value of type %s', Utilities::getType($array, true))); - if(!is_string($value) && !is_int($value)) - throw new TypeException(sprintf('Cannot read from array with non-string value %s', Utilities::getType($value, true))); - if(!Validate::validateRegex($value, RegexPatterns::ArrayQuery)) - throw new KeyException(sprintf('Cannot read from array with invalid query %s', $value)); + if(!is_string($key) && !is_int($key)) + throw new TypeException(sprintf('Cannot read from array with non-string value %s', Utilities::getType($key, true))); + if(!Validate::validateRegex($key, RegexPatterns::ArrayQuery)) + throw new KeyException(sprintf('Cannot read from array with invalid query %s', $key)); - $keys = explode('.', $value); + $keys = explode('.', $key); $result = $array; foreach ($keys as $key) { @@ -135,7 +137,7 @@ } else { - throw new KeyException(sprintf('Key "%s" does not exist in array (%s)', $key, $value)); + throw new KeyException(sprintf('Key "%s" does not exist in array (%s)', $key, $key)); } } @@ -148,9 +150,9 @@ public function __toString(): string { return sprintf( - self::getType() . ' (array: %s, value: %s)', + self::getType() . ' %s[%s]', Utilities::entityToString($this->Array), - Utilities::entityToString($this->Value) + Utilities::entityToString($this->Key) ); } } \ No newline at end of file diff --git a/src/RTEX/Objects/Program/Instructions/Base/ArraySet.php b/src/RTEX/Objects/Program/Instructions/Base/ArraySet.php new file mode 100644 index 0000000..753c32b --- /dev/null +++ b/src/RTEX/Objects/Program/Instructions/Base/ArraySet.php @@ -0,0 +1,183 @@ +Array; + } + + /** + * @param mixed $variable + * @throws InstructionException + * @noinspection PhpMissingParamTypeInspection + */ + public function setArray($variable): void + { + $this->Array = InstructionBuilder::fromRaw($variable); + } + + /** + * @return mixed + * @noinspection PhpUnused + */ + public function getKey(): mixed + { + return $this->Key; + } + + /** + * @param mixed $value + * @throws InstructionException + * @noinspection PhpMissingParamTypeInspection + */ + public function setKey($value): void + { + $this->Key = InstructionBuilder::fromRaw($value); + } + + /** + * @return mixed + */ + public function getValue(): mixed + { + return $this->Value; + } + + /** + * @param mixed $Value + */ + public function setValue(mixed $Value): void + { + $this->Value = $Value; + } + + /** + * Returns an array representation of the object + * + * @return array + */ + public function toArray(): array + { + return InstructionBuilder::toRaw(self::getType(), [ + 'array' => $this->Array, + 'key' => $this->Key, + 'value' => $this->Value + ]); + } + + /** + * @param array $data + * @return InstructionInterface + * @throws InstructionException + */ + public static function fromArray(array $data): InstructionInterface + { + $instruction = new self(); + $instruction->setArray($data['array'] ?? null); + $instruction->setKey($data['key'] ?? null); + $instruction->setValue($data['value'] ?? null); + + return $instruction; + } + + /** + * @param Engine $engine + * @return array + * @throws EvaluationException + * @throws KeyException + * @throws TypeException + * @noinspection DuplicatedCode + */ + public function eval(Engine $engine): array + { + $key = $engine->eval($this->Key); + $array = $engine->eval($this->Array); + $value = $engine->eval($this->Value); + + if (!is_array($array)) + throw new KeyException(sprintf('Cannot read from non-array value of type %s', Utilities::getType($array, true))); + if(!is_string($key) && !is_int($key)) + throw new TypeException(sprintf('Cannot read from array with non-string value %s', Utilities::getType($key, true))); + if(!Validate::validateRegex($key, RegexPatterns::ArrayQuery)) + throw new KeyException(sprintf('Cannot read from array with invalid query %s', $key)); + + $keys = explode('.', $key); + $result = &$array; // use a reference so we can modify the original array + foreach ($keys as $key) + { + if (!(is_array($result) && array_key_exists($key, $result))) + throw new KeyException(sprintf('Key "%s" does not exist in array (%s)', $key, $value)); + + $result = &$result[$key]; + } + + $result = $value; + return $array; + } + + + /** + * @inheritDoc + */ + public function __toString(): string + { + return sprintf( + self::getType() . ' %s[%s]=%s', + Utilities::entityToString($this->Array), + Utilities::entityToString($this->Key), + Utilities::entityToString($this->Value) + ); + } + } \ No newline at end of file diff --git a/src/RTEX/Objects/Program/Instructions/GetVariable.php b/src/RTEX/Objects/Program/Instructions/Base/GetVariable.php similarity index 88% rename from src/RTEX/Objects/Program/Instructions/GetVariable.php rename to src/RTEX/Objects/Program/Instructions/Base/GetVariable.php index 0b958f6..e636404 100644 --- a/src/RTEX/Objects/Program/Instructions/GetVariable.php +++ b/src/RTEX/Objects/Program/Instructions/Base/GetVariable.php @@ -2,7 +2,7 @@ /** @noinspection PhpMissingFieldTypeInspection */ - namespace RTEX\Objects\Program\Instructions; + namespace RTEX\Objects\Program\Instructions\Base; use RTEX\Abstracts\InstructionType; use RTEX\Classes\InstructionBuilder; @@ -67,14 +67,9 @@ $variable = $engine->eval($this->VariableName); if(!is_string($variable)) - throw new TypeException(sprintf('Expected string, got %s', Utilities::getType($variable))); - - if (!$engine->getEnvironment()->variableExists($variable)) - throw new NameException("Variable '$variable' is not defined"); + throw new TypeException(sprintf('Expected string, got %s', Utilities::getType($variable, true))); - return $engine->getEnvironment()->getRuntimeVariable( - $engine->eval($this->VariableName) - ); + return $engine->getEnvironment()->getRuntimeVariable($variable); } /** @@ -110,7 +105,7 @@ public function __toString(): string { return sprintf( - self::getType() . ' (name: %s)', + self::getType() . ' %s', Utilities::entityToString($this->VariableName) ); } diff --git a/src/RTEX/Objects/Program/Instructions/Invoke.php b/src/RTEX/Objects/Program/Instructions/Base/Invoke.php similarity index 80% rename from src/RTEX/Objects/Program/Instructions/Invoke.php rename to src/RTEX/Objects/Program/Instructions/Base/Invoke.php index 35d98de..66ed201 100644 --- a/src/RTEX/Objects/Program/Instructions/Invoke.php +++ b/src/RTEX/Objects/Program/Instructions/Base/Invoke.php @@ -2,14 +2,16 @@ /** @noinspection PhpMissingFieldTypeInspection */ - namespace RTEX\Objects\Program\Instructions; + namespace RTEX\Objects\Program\Instructions\Base; use RTEX\Abstracts\InstructionType; use RTEX\Classes\InstructionBuilder; use RTEX\Classes\Utilities; use RTEX\Engine; - use RTEX\Exceptions\Core\MalformedInstructionException; - use RTEX\Exceptions\Core\UnsupportedVariableType; + use RTEX\Exceptions\EvaluationException; + use RTEX\Exceptions\InstructionException; + use RTEX\Exceptions\Runtime\ImportException; + use RTEX\Exceptions\Runtime\TypeException; use RTEX\Interfaces\InstructionInterface; class Invoke implements InstructionInterface @@ -60,7 +62,6 @@ /** * @return array - * @throws UnsupportedVariableType */ public function toArray(): array { @@ -68,7 +69,7 @@ 'namespace' => $this->Namespace, 'method' => $this->Method, 'parameters' => $this->Parameters, - 'fail_on_error' => $this->FailOnError, + 'fail_on_error' => $this->FailOnError, // TODO: Implement this ]); } @@ -77,8 +78,7 @@ * * @param array $data * @return InstructionInterface - * @throws MalformedInstructionException - * @throws UnsupportedVariableType + * @throws InstructionException */ public static function fromArray(array $data): InstructionInterface { @@ -96,19 +96,24 @@ * * @param Engine $engine * @return mixed - * @throws UnsupportedVariableType - * @noinspection PhpMissingReturnTypeInspection + * @throws EvaluationException + * @throws ImportException + * @throws TypeException */ - public function eval(Engine $engine) + public function eval(Engine $engine): mixed { + $namespace = $engine->eval($this->Namespace); + $method = $engine->eval($this->Method); $parameters = []; foreach($this->Parameters as $key => $value) $parameters[$key] = $engine->eval($value); - return $engine->callMethod( - $engine->eval($this->Namespace), $engine->eval($this->Method), - $parameters - ); + if(!is_string($namespace)) + throw new TypeException(sprintf('The namespace must be a string, %s given', Utilities::getType($namespace, true))); + if(!is_string($method)) + throw new TypeException(sprintf('The method must be a string, %s given', Utilities::getType($method, true))); + + return $engine->callMethod($namespace, $method, $parameters); } /** @@ -156,8 +161,7 @@ /** * @param array $Parameters - * @throws MalformedInstructionException - * @throws UnsupportedVariableType + * @throws InstructionException */ public function setParameters(array $Parameters): void { @@ -183,7 +187,6 @@ /** * @inheritDoc - * @throws UnsupportedVariableType */ public function __toString(): string { diff --git a/src/RTEX/Objects/Program/Instructions/SetVariable.php b/src/RTEX/Objects/Program/Instructions/Base/SetVariable.php similarity index 63% rename from src/RTEX/Objects/Program/Instructions/SetVariable.php rename to src/RTEX/Objects/Program/Instructions/Base/SetVariable.php index 2f11f4b..cae9156 100644 --- a/src/RTEX/Objects/Program/Instructions/SetVariable.php +++ b/src/RTEX/Objects/Program/Instructions/Base/SetVariable.php @@ -2,14 +2,15 @@ /** @noinspection PhpMissingFieldTypeInspection */ - namespace RTEX\Objects\Program\Instructions; + namespace RTEX\Objects\Program\Instructions\Base; use RTEX\Abstracts\InstructionType; use RTEX\Classes\InstructionBuilder; use RTEX\Classes\Utilities; use RTEX\Engine; - use RTEX\Exceptions\Core\MalformedInstructionException; - use RTEX\Exceptions\Core\UnsupportedVariableType; + use RTEX\Exceptions\EvaluationException; + use RTEX\Exceptions\InstructionException; + use RTEX\Exceptions\Runtime\TypeException; use RTEX\Interfaces\InstructionInterface; class SetVariable implements InstructionInterface @@ -19,7 +20,7 @@ * * @var mixed */ - private $Variable; + private $Name; /** * The value to set the variable to @@ -38,41 +39,38 @@ return InstructionType::SetVariable; } - /** * @return mixed - * @noinspection PhpMissingReturnTypeInspection + * @noinspection PhpUnused */ - public function getVariable() + public function getName(): mixed { - return $this->Variable; + return $this->Name; } /** * @param mixed $variable - * @throws UnsupportedVariableType - * @throws MalformedInstructionException + * @throws InstructionException * @noinspection PhpMissingParamTypeInspection */ - public function setVariable($variable): void + public function setName($variable): void { - $this->Variable = InstructionBuilder::fromRaw($variable); + $this->Name = InstructionBuilder::fromRaw($variable); } /** * @return mixed - * @noinspection PhpMissingReturnTypeInspection + */ - public function getValue() + public function getValue(): mixed { return $this->Value; } /** * @param mixed $value - * @throws MalformedInstructionException - * @throws UnsupportedVariableType + * @throws InstructionException * @noinspection PhpMissingParamTypeInspection */ public function setValue($value): void @@ -84,12 +82,11 @@ * Returns an array representation of the object * * @return array - * @throws UnsupportedVariableType */ public function toArray(): array { return InstructionBuilder::toRaw(self::getType(), [ - 'variable' => $this->Variable, + 'name' => $this->Name, 'value' => $this->Value ]); } @@ -97,13 +94,12 @@ /** * @param array $data * @return InstructionInterface - * @throws MalformedInstructionException - * @throws UnsupportedVariableType + * @throws InstructionException */ public static function fromArray(array $data): InstructionInterface { $instruction = new self(); - $instruction->setVariable($data['variable'] ?? null); + $instruction->setName($data['name'] ?? null); $instruction->setValue($data['value'] ?? null); return $instruction; @@ -112,25 +108,28 @@ /** * @param Engine $engine * @return void - * @throws UnsupportedVariableType + * @throws EvaluationException + * @throws TypeException */ public function eval(Engine $engine): void { - $engine->getEnvironment()->setRuntimeVariable( - $engine->eval($this->Variable), - $engine->eval($this->Value) - ); + $name = $engine->eval($this->Name); + $value = $engine->eval($this->Value); + + if(!is_string($name)) + throw new TypeException(sprintf('Variable name must be a string, %s given', Utilities::getType($name, true))); + + $engine->getEnvironment()->setRuntimeVariable($name, $value); } /** * @inheritDoc - * @throws UnsupportedVariableType */ public function __toString(): string { return sprintf( - self::getType() . ' (variable: %s, value: %s)', - Utilities::entityToString($this->Variable), + self::getType() . ' %s VALUE %s', + Utilities::entityToString($this->Name), Utilities::entityToString($this->Value) ); }