Compare commits

...
Sign in to create a new pull request.

50 commits
master ... dev

Author SHA1 Message Date
Netkas
e9d033044c Minor changes 2023-03-05 13:57:57 -05:00
Netkas
05cc358eea Updated project.json to include a main execution point for RTEX 2022-12-31 01:41:17 -05:00
Netkas
21cd927fbe Updated \RTEX\Classes > InstructionBuilder 2022-12-30 04:26:15 -05:00
Netkas
5ed3b01889 Moved instructions to it's own namespace 2022-12-30 04:26:01 -05:00
Netkas
f96dbed955 Minor corrections 2022-12-30 04:21:44 -05:00
Netkas
b856511c43 Minor corrections 2022-12-30 04:21:30 -05:00
Netkas
4f44ad519d Updated method in \RTEX\Objects\Program\Instructions\Base > ArraySet > setValue() 2022-12-30 03:23:47 -05:00
Netkas
98744973b2 Updated Invoke instruction to use Callable instead of a combination of namespace & method 2022-12-30 03:23:01 -05:00
Netkas
be3875692c Added support for Unknown variable types (for printing to strings) 2022-12-30 03:07:04 -05:00
Netkas
88580d6ad8 Updated \RTEX\Abstracts > InstructionType 2022-12-30 03:06:42 -05:00
Netkas
753d42d159 Added Exception classes for RTEX 2022-12-30 03:06:27 -05:00
Netkas
6b45b56b1b Corrected return type in \RTEX\Interfaces > InstructionInterface 2022-12-30 03:02:58 -05:00
Netkas
671958063c Refactored Comparators instructions and added documentation 2022-12-30 03:01:38 -05:00
Netkas
f071d1dc72 Updated documentation for base instructions 2022-12-30 03:00:04 -05:00
Netkas
dc0811a271 Refactored Base instructions and added documentation 2022-12-30 02:47:43 -05:00
Netkas
deccb1f6fa Updated __toString() methods for Arithmetic Instructions 2022-12-30 02:41:41 -05:00
Netkas
e11efb01b9 Added documentation for arithmetic instructions 2022-12-30 00:46:50 -05:00
Netkas
933f194726 Refactored all Arithmetic instructions 2022-12-30 00:46:25 -05:00
Netkas
ba0dc302ff Moved Instruction Documentation 2022-12-29 16:11:06 -05:00
Netkas
63d202bad2 Refactored GreaterThanOrEquals, added documentation 2022-12-29 16:06:49 -05:00
Netkas
8ea2ddd21d Updated ArrayGet.php 2022-12-29 16:04:59 -05:00
Netkas
5a6f406ec7 Refactored GreaterThan, added documentation 2022-12-29 16:04:46 -05:00
Netkas
876621f618 Refactored GetVariable, added documentation 2022-12-29 14:21:38 -05:00
Netkas
0cbb927066 Refactored equals, added documentation 2022-12-29 14:17:56 -05:00
Netkas
172bc4866a Refactored \RTEX\Objects\Program\Instructions > Equals > eval() 2022-12-28 00:25:11 -05:00
Netkas
cfb55fd7df Updated \RTEX\Objects\Program\Instructions > ArrayGet 2022-12-28 00:21:32 -05:00
Netkas
cf36d18612 Added method \RTEX\Classes > Validate > validateRegex() 2022-12-27 02:51:54 -05:00
Netkas
66cd6d0625 Added 'double' to \RTEX\Abstracts > VariableType 2022-12-27 02:50:38 -05:00
Netkas
47b434b625 Added more instruction types to \RTEX\Abstracts > InstructionType 2022-12-27 02:47:49 -05:00
Netkas
452b923b3f Added 'array' to \RTEX\Abstracts > VariableType 2022-12-27 02:47:26 -05:00
Netkas
fcfa860116 Added \RTEX\Abstracts > RuntimeExceptionCode 2022-12-27 02:46:25 -05:00
Netkas
feb06cdb6b Added \RTEX\Abstracts > RegexPatterns 2022-12-27 02:46:09 -05:00
Netkas
48a89b65b8 Added instruction_example.png 2022-12-27 00:37:42 -05:00
Netkas
fa11bd28cd Updated README.md 2022-12-27 00:37:08 -05:00
Netkas
8cac3a3eec Added LICENSE (MIT) 2022-12-27 00:36:55 -05:00
Netkas
cd22006d70 Added CONTRIBUTING.md 2022-12-27 00:36:47 -05:00
Netkas
114e4bcc59 Added CODE_OF_CONDUCT.md 2022-12-27 00:36:23 -05:00
Netkas
fea535aad2 Refactored Divide instruction and added documentation for the instruction. 2022-12-26 23:11:48 -05:00
Netkas
574e7c51f9 Added query validation to \RTEX\Objects\Program\Instructions > ArrayGet 2022-12-26 21:05:50 -05:00
Netkas
c01ad0d6d9 Refactored ArrayGet instruction and added documentation for the instruction. 2022-12-26 21:00:24 -05:00
Netkas
7ff6dda8e0 Refactored \RTEX\Objects\Program\Instructions > Divide 2022-12-26 16:28:55 -05:00
Netkas
b6ae2efc82 Refactored \RTEX\Objects\Program\Instructions > ArrayGet 2022-12-26 16:26:44 -05:00
Netkas
6a077bb5a1 Refactored Classes 2022-12-26 16:24:32 -05:00
Netkas
05428dca07 Updated InstructionBuilder to include more methods for building instructions 2022-12-25 22:49:08 -05:00
Netkas
6e543a6e1b Updated InstructionInterface 2022-12-25 19:01:33 -05:00
Netkas
08c4b3079e Introduces various instruction additions to the base engine.
Created \RTEX\Objects\Program\Instructions > Sum
Created \RTEX\Objects\Program\Instructions > Subtract
Created \RTEX\Objects\Program\Instructions > Power
Created \RTEX\Objects\Program\Instructions > Multiply
Created \RTEX\Objects\Program\Instructions > Modulo
Created \RTEX\Objects\Program\Instructions > LessThanOrEquals
Created \RTEX\Objects\Program\Instructions > LessThan
Created \RTEX\Objects\Program\Instructions > Invoke
Created \RTEX\Objects\Program\Instructions > GreaterThanOrEquals
Created \RTEX\Objects\Program\Instructions > GreaterThan
Created \RTEX\Objects\Program\Instructions > Equals
Created \RTEX\Objects\Program\Instructions > Divide
Created \RTEX\Objects\Program\Instructions > ArrayGet
Refactored \RTEX\Objects\Program\Instructions > SetVariable
Refactored \RTEX\Objects\Program\Instructions > GetVariable
2022-12-25 18:56:54 -05:00
Netkas
68b50a1a21 Added idea files 2022-12-23 00:10:53 -05:00
Netkas
a21df6a41d Added .gitignore for .idea 2022-12-23 00:10:40 -05:00
Netkas
d136f3f9da Added project.json 2022-12-23 00:10:25 -05:00
Netkas
7e5207c45a Added base files, with the basic ability to add/remove variables from the Runtime. 2022-12-23 00:10:02 -05:00
90 changed files with 6311 additions and 0 deletions

8
.idea/.gitignore generated vendored Normal file
View file

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View file

@ -0,0 +1,26 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="IncorrectHttpHeaderInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="customHeaders">
<set>
<option value="Subject" />
<option value="Reply-To" />
<option value="X-JSON-Schema" />
<option value="X-JSON-Type" />
<option value="X-JSON-Path" />
<option value="X-Java-Type" />
<option value="X-Region-Id" />
<option value="X-GraphQL-Variables" />
<option value="X-SSH-Private-Key" />
<option value="X-Args-0" />
<option value="X-Args-1" />
<option value="X-Args-2" />
<option value="X-Args-3" />
<option value="X-Args-4" />
<option value="X-Args-5" />
</set>
</option>
</inspection_tool>
</profile>
</component>

8
.idea/modules.xml generated Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/rtex-engine.iml" filepath="$PROJECT_DIR$/.idea/rtex-engine.iml" />
</modules>
</component>
</project>

29
.idea/php.xml generated Normal file
View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MessDetectorOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCSFixerOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCodeSnifferOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PhpIncludePathManager">
<include_path>
<path value="/usr/share/php" />
<path value="/etc/ncc" />
<path value="/var/ncc/packages/net.nosial.optslib=1.0.1" />
<path value="/var/ncc/packages/net.nosial.loglib=1.0.0" />
<path value="/var/ncc/packages/net.nosial.rtex_filesystem=1.0.0" />
<path value="/var/ncc/packages/com.cheprasov.php_redis_client=1.10.0" />
</include_path>
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.2" />
<component name="PhpStanOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PsalmOptionsConfiguration">
<option name="transferred" value="true" />
</component>
</project>

12
.idea/rtex-engine.iml generated Normal file
View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

6
.idea/vcs.xml generated Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

15
.idea/webResources.xml generated Normal file
View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="WebResourcesPaths">
<contentEntries>
<entry url="file://$PROJECT_DIR$">
<entryData>
<resourceRoots>
<path value="file://$PROJECT_DIR$/instructions" />
<path value="file://$PROJECT_DIR$/types" />
</resourceRoots>
</entryData>
</entry>
</contentEntries>
</component>
</project>

46
CODE_OF_CONDUCT.md Normal file
View file

@ -0,0 +1,46 @@
# Code of Conduct
RTEX Engine is committed to fostering a welcoming and inclusive community. We ask that all contributors adhere to the
following Code of Conduct in all interactions within the project.
## Our Standards
We expect all members of the RTEX Engine community to:
- Be respectful and considerate towards others.
- Show empathy towards others and actively listen to their ideas and opinions.
- Use welcoming and inclusive language.
- Respect the opinions and experiences of others.
- Refrain from discrimination, harassment, or other inappropriate behavior.
## Unacceptable Behavior
Unacceptable behavior includes, but is not limited to:
- Discrimination or harassment based on race, ethnicity, nationality, religion, gender, gender identity and expression,
sexual orientation, age, disability, or any other characteristic protected by law.
- Personal attacks, insults, or derogatory comments.
- Posting, sharing, or distributing inappropriate or offensive content.
- Spamming, trolling, or engaging in other disruptive behavior.
## Consequences of Unacceptable Behavior
Unacceptable behavior will not be tolerated and may result in the temporary or permanent removal of privileges, at the
discretion of the project maintainers.
## Reporting Unacceptable Behavior
If you witness or experience unacceptable behavior, please report it by:
- Contacting a project maintainer directly.
- Filing a report using the [RTEX Engine repository's issue tracker](https://git.n64.cc/nosial/cognize/rtex-engine/-/issues).
All reports will be treated as confidential and the identity of the reporter will be protected, to the extent allowed by law.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/), version 1.4,
available at [https://www.contributor-covenant.org/version/1/4/code-of-conduct.html](https://www.contributor-covenant.org/version/1/4/code-of-conduct.html).
For answers to common questions about this code of conduct, see [https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq).

32
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,32 @@
# Contributing to RTEX Engine
Thank you for considering contributing to RTEX Engine! We welcome and appreciate all contributions, whether they be bug
reports, feature requests, or code contributions.
## Code of Conduct
We ask that all contributors adhere to our [Code of Conduct](CODE_OF_CONDUCT.md).
By participating in this project, you agree to abide by its terms.
## How to Contribute
Here are some ways you can contribute to RTEX Engine:
- Report bugs or request features by opening an issue on the [RTEX Engine repository](https://git.n64.cc/nosial/cognize/rtex-engine/-/issues).
- Contribute code by creating a pull request on the [RTEX Engine repository](https://git.n64.cc/nosial/cognize/rtex-engine). Please make sure to follow the guidelines below when creating a pull request.
### Pull Request Guidelines
- Before submitting a pull request, please make sure to complete the following steps:
- Test your changes to ensure that they work as intended.
- Update the documentation, if necessary.
- Follow the project's coding style and conventions.
- Squash your commits into a single commit (if necessary).
- Rebase your branch on the latest version of the `master` branch.
## Copyright and License
RTEX Engine is copyright Nosial and is licensed under the MIT License. Please see the
[LICENSE](LICENSE) file for more information.
By contributing to RTEX Engine, you agree to release your contributions under the MIT License.

BIN
InstructionInterface.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 KiB

14
LICENSE Normal file
View file

@ -0,0 +1,14 @@
Copyright 2022 Nosial - All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

14
Makefile Normal file
View file

@ -0,0 +1,14 @@
debug:
ncc build --config="debug"
release:
ncc build --config="release"
install:
ncc package install --package="build/release/net.nosial.rtex.ncc" --skip-dependencies --reinstall -y
install-debug:
ncc package install --package="build/debug/net.nosial.rtex.ncc" --skip-dependencies --reinstall -y
uninstall:
ncc package uninstall -y --package="net.nosial.rtex"

146
README.md Normal file
View file

@ -0,0 +1,146 @@
# RTEX Engine
RTEX Engine (Acronym for Real-Time Execution Engine)
is a real-time execution engine for the execution of
instructions represented in associative arrays in
a controlled environment. RTEX is designed to
be used in such environments where you are automating
the task of creating scripts for your program to run,
or you are executing programs written by users,
but you don't want to give them the ability to
execute arbitrary code on your system
## Table of Contents
<!-- TOC -->
* [RTEX Engine](#rtex-engine)
* [Table of Contents](#table-of-contents)
* [How does it work?](#how-does-it-work)
* [Instructions](#instructions)
* [Methods & Namespaces](#methods--namespaces)
* [Builtin Instruction Sets](#builtin-instruction-sets)
* [License](#license)
* [Contributing](#contributing)
<!-- TOC -->
-----------------------------------------------------------------------------
## How does it work?
RTEX Engine operates on the simple principle of executing
instructions in order, and then moving on to the next
instruction.
[README.md](README.md)
### Instructions
Instructions are simply associative arrays that contain
information about the instruction to be executed. The
engine will then execute the instruction, and then
return the context back to the caller.
***Note:*** The below is just an example of what an instruction
might look like. The actual instructions are not implemented
![Instruction Example](assets/instruction_example.png)
RTEX Engine provides a limited set of instructions by default
allowing for basic functionality and operations, the builtin
functions do not provide a way to interact with the host
system or the filesystem, but you can extend the engine
with your own methods and namespaces
Since instructions are associative arrays, they can be
represented in JSON, which is a common format for data
transfer. The following is an example of a set of
instructions that is shown above in JSON format:
```json
[
{
"type": "set",
"_": {
"key": "foo",
"value": "bar"
}
},
{
"type": "invoke",
"_": {
"method": "http.get",
"parameters": {
"url": "https://example.com",
"parameters": {
"username": {
"type": "get",
"_": {
"variable": "foo"
}
},
"password": {
"type": "get",
"_": {
"variable": "bar"
}
}
}
}
}
},
{
"type": "return",
"_": {
"type": "get",
"_": {
"variable": "http_response_body"
}
}
}
]
```
### Methods & Namespaces
Methods are different to instructions in the terms
that RTEX can only expand its functionality by
creating a library works as a plugin that can be
imported by RTEX before executing the program.
Namespaces are used to avoid conflicting with
already existing method names and to make things
more organized, for example there could be a
namespace called `http` which contains methods
such as `get`, `post`, `put`, `delete`, etc. which
can be invoked by the engine via the `invoke`
instruction, methods are not the same as instructions
as they are not executed in order, they are executed
when they are invoked.
***Note:*** This functionality is a WIP, more
information will be added as it is implemented
-----------------------------------------------------------------------------
## Builtin Instruction Sets
RTEX Engine comes with a limited set of instructions by default,
but you can extend the engine with your own methods and namespaces
- base
- [get](docs/instructions/base/get.md)
- [set](docs/instructions/base/get.md)
- math
- [add](docs/instructions/add.md)
# License
RTEX Engine is licensed under the MIT License, see
[LICENSE](LICENSE) for more information
# Contributing
If you would like to contribute to RTEX Engine,
please read [CONTRIBUTING.md](CONTRIBUTING.md)
for more information

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

81
config_example.yaml Normal file
View file

@ -0,0 +1,81 @@
# Runtime configuration for RTEX, this section defines the configuration
# values used for the engine. Allowing you to set a maximum number of
# resources a program may use, or disable certain instructions.
# you can also import other NCC packages designed to extend RTEX
# such as the 'com.nosia.rtex_filesystem' package which adds IO functionality to RTEX.
runtime:
# The maximum value size in bytes, this is the maximum size of a value
# that can be stored in memory. This is used to prevent programs from
# using too much memory.
# (default: 0)
max_variable_size: 0
# The maximum number of variables that can be stored in memory at once.
# (default: 0)
max_variables: 0
# The maximum number of instructions that can be executed before the
# program is terminated.
# (default: 0)
max_stack_size: 0
# A list of instructions that are disabled, this is used to prevent
# programs from using certain instructions.
# (default: [])
instruction_blacklist:
- "eq"
- "neq"
- "gt"
- "gte"
# A list of packages to import, this is used to import packages that
# extend the functionality of RTEX.
# (default: [])
import_namespaces:
- "com.nosial.rtex_filesystem"
# Enabling supervisor mode will allow the runtime to spawn the program
# as a child process and monitor the resource usage of the child process.
# This is useful to terminate badly behaving programs. (eg; infinite loops)
# The supervisor will terminate the child process if it exceeds the
# resource limits set in the runtime section.
supervisor:
# If true, the supervisor will be enabled
enabled: true
# The maximum number of seconds a program can run for
max_execution_time: 100 # in seconds
# The maximum number of seconds a program can use the CPU for
max_cpu_time: 100 # in seconds
# The maximum number of bytes a program can use for memory
max_memory: 1000000 # in bytes
# Enabling a Redis hook will allow for easier debugging of programs.
# This will allow you to view the state of the program at any time
# This works by providing a reference ID to the program as a command-line
# argument.
#
# The engine will then connect to a Redis server and store the state of
# the program in a Redis hash. This hash will be updated every time the
# program executes an instruction.
#
# Libraries can also use this hook to store data in the Redis hash.
redis_hook:
# If true, the Redis hook will be enabled
enabled: True
# The host of the Redis server
host: "127.0.0.1"
# The port of the Redis server
port: 6379
# The password of the Redis server (optional)
password: null
# If the information should be destroyed when the program exits
destroy_on_exit: False

View file

@ -0,0 +1,32 @@
# abs
Returns the absolute value of a number.
## Parameters
* value (`integer`, `float`, `double`) - The number to get the absolute value of.
## Return
(`integer`, `float`, `double`) - The result of the absolute value.
## 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": "abs",
"_": {
"value": 10
}
}
```
### Last Updated
Monday, December 30th, 2022.
Written by [Netkas](https://git.n64.cc/netkas)

View file

@ -0,0 +1,35 @@
# div
Divide two numbers.
## Parameters
* a (`integer`, `float`, `double`) - The number to divide.
* b (`integer`, `float`, `double`) - The number to divide by.
## Return
(`integer`, `float`, `double`) - The result of the division.
## 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.
* `ZeroDivisionException` - If the divisor is zero.
## Instruction Example
```json
{
"type": "div",
"_": {
"a": 10,
"b": 2
}
}
```
### Last Updated
Monday, December 30th, 2022.
Written by [Netkas](https://git.n64.cc/netkas)

View file

@ -0,0 +1,32 @@
# floor
Returns the floor value of a number.
## Parameters
* value (`integer`, `float`, `double`) - The number to get the floor value of.
## Return
(`integer`, `float`, `double`) - The result of the floor value.
## 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": "floor",
"_": {
"value": 10.5
}
}
```
### Last Updated
Monday, December 30th, 2022.
Written by [Netkas](https://git.n64.cc/netkas)

View file

@ -0,0 +1,34 @@
# mod
Calculates the remainder of a division operation.
## Parameters
* a (`integer`, `float`, `double`) - The number to divide.
* b (`integer`, `float`, `double`) - The number to divide by.
## Return
(`integer`, `float`, `double`) - The result of the modulo operation.
## 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": "mod",
"_": {
"a": 10,
"b": 3
}
}
```
### Last Updated
Monday, December 30th, 2022.
Written by [Netkas](https://git.n64.cc/netkas)

View file

@ -0,0 +1,34 @@
# mul
Calculates the multiplication of two numbers.
## Parameters
* a (`integer`, `float`, `double`) - The number to multiply.
* b (`integer`, `float`, `double`) - The number to multiply by.
## Return
(`integer`, `float`, `double`) - The result of the multiplication.
## 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": "mul",
"_": {
"a": 10,
"b": 3
}
}
```
### Last Updated
Monday, December 30th, 2022.
Written by [Netkas](https://git.n64.cc/netkas)

View file

@ -0,0 +1,34 @@
# pow
Calculates the power of a number.
## Parameters
* a (`integer`, `float`, `double`) - The number to raise to a power.
* b (`integer`, `float`, `double`) - The power to raise the number to.
## Return
(`integer`, `float`, `double`) - The result of the power calculation.
## 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": "pow",
"_": {
"a": 2,
"b": 3
}
}
```
### Last Updated
Monday, December 30th, 2022.
Written by [Netkas](https://git.n64.cc/netkas)

View file

@ -0,0 +1,33 @@
# round
Rounds a number to a given precision.
## Parameters
* value (`integer`, `float`, `double`) - The number to round.
* precision (`integer`) - The number of decimal places to round to. (default: 0)
## Return
(`integer`, `float`, `double`) - The result of the rounding.
## 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": "abs",
"_": {
"value": 10
}
}
```
### Last Updated
Monday, December 30th, 2022.
Written by [Netkas](https://git.n64.cc/netkas)

View file

@ -0,0 +1,32 @@
# square_root
Calculates the square root of a number.
## Parameters
* value (`integer`, `float`, `double`) - The number to calculate the square root of.
## Return
(`integer`, `float`, `double`) - The result of the square root calculation.
## 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": "square_root",
"_": {
"value": 4
}
}
```
### Last Updated
Monday, December 30th, 2022.
Written by [Netkas](https://git.n64.cc/netkas)

View file

@ -0,0 +1,34 @@
# sub
Subtract two numbers.
## Parameters
* a (`integer`, `float`, `double`) - The number to subtract from.
* b (`integer`, `float`, `double`) - The number to subtract.
## Return
(`integer`, `float`, `double`) - The result of the subtraction.
## 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": "sub",
"_": {
"a": 10,
"b": 2
}
}
```
### Last Updated
Monday, December 30th, 2022.
Written by [Netkas](https://git.n64.cc/netkas)

View file

@ -0,0 +1,34 @@
# sum
Calculates the sum of two numbers.
## Parameters
* a (`integer`, `float`, `double`) - The first number to add.
* b (`integer`, `float`, `double`) - The second number to add.
## Return
(`integer`, `float`, `double`) - The result of the addition.
## 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": "sum",
"_": {
"a": 10,
"b": 2
}
}
```
### Last Updated
Monday, December 30th, 2022.
Written by [Netkas](https://git.n64.cc/netkas)

View file

@ -0,0 +1,39 @@
# array_get
Get an item from an array using "dot" notation.
## Parameters
* array (`array`) - The array to get the value from.
* key (`string`) - The key to get the value for.
## Return
(mixed) - The value of the key or throws an exception if the key is not found.
## 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_get",
"_": {
"array": {
"foo": {
"bar": "baz"
}
},
"key": "foo.bar"
}
}
```
### Last Updated
Monday, December 26th, 2022.
Written by [Netkas](https://git.n64.cc/netkas)

View file

@ -0,0 +1,41 @@
# array_set
Set an item in an array using "dot" notation.
## Parameters
* array (`array`) - The array to get the value from.
* key (`string`) - The key to get the value for.
* value (`any`) - 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)

View file

@ -0,0 +1,34 @@
# get
Gets an existing variable from the environment.
## Parameters
* name (`string`) - The name of the variable to get.
## Return
(`any`) - The value of the variable.
## 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.
* `NameException` - If the variable does not exist.
## Instruction Example
```json
{
"type": "get",
"_": {
"name": "foo"
}
}
```
### Last Updated
Monday, December 29th, 2022.
Written by [Netkas](https://git.n64.cc/netkas)

View file

@ -0,0 +1,40 @@
# invoke
Invokes a method under a namespace.
## Parameters
* callable (`string`) - The callable to invoke. (e.g. `namespace.method`, `system.print`, `time.now`)
* parameters (`array`) - The parameters to pass to the method.
* fail_on_error (`boolean`) - 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",
"_": {
"callable": "system.print",
"parameters": {
"value": "Hello, world!"
},
"fail_on_error": true
}
}
```
### Last Updated
Monday, December 30th, 2022.
Written by [Netkas](https://git.n64.cc/netkas)

View file

@ -0,0 +1,35 @@
# set
Sets aor overwrites a variable in the environment.
## Parameters
* name (`string`) - The name of the variable to get.
* value (`any`) - 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)

View file

@ -0,0 +1,35 @@
# eq
Returns true if the two values are equal, false otherwise.
## Parameters
* a (`integer`, `float`, `double`, `string`, `boolean`) - The first value to compare.
* b (`integer`, `float`, `double`, `string`, `boolean`) - The second value to compare.
## Return
(`boolean`) - True if the two values are equal, false otherwise.
## 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": "eq",
"_": {
"a": "foo",
"b": "foo"
}
}
```
### Last Updated
Monday, December 30th, 2022.
Written by [Netkas](https://git.n64.cc/netkas)

View file

@ -0,0 +1,34 @@
# gt
Returns true if the first argument is greater than the second argument.
## Parameters
* a (`integer`, `float`, `double`) - The first number.
* b (`integer`, `float`, `double`) - The second number.
## Return
(`boolean`) - True if the first argument is greater than the second argument.
## 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": "gt",
"_": {
"a": 10,
"b": 2
}
}
```
### Last Updated
Monday, December 30th, 2022.
Written by [Netkas](https://git.n64.cc/netkas)

View file

@ -0,0 +1,34 @@
# gte
Returns true if the first argument is greater than or equal to the second argument.
## Parameters
* a (`integer`, `float`, `double`) - The first number.
* b (`integer`, `float`, `double`) - The second number.
## Return
(`boolean`) - True if the first argument is greater than or equal to the second argument.
## 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": "gte",
"_": {
"a": 10,
"b": 2
}
}
```
### Last Updated
Monday, December 30th, 2022.
Written by [Netkas](https://git.n64.cc/netkas)

View file

@ -0,0 +1,34 @@
# lt
Returns true if the first argument is less than the second argument.
## Parameters
* a (`integer`, `float`, `double`) - The first number.
* b (`integer`, `float`, `double`) - The second number.
## Return
(`boolean`) - True if the first argument is less than the second argument.
## 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": "lt",
"_": {
"a": 10,
"b": 2
}
}
```
### Last Updated
Monday, December 30th, 2022.
Written by [Netkas](https://git.n64.cc/netkas)

View file

@ -0,0 +1,34 @@
# lte
Returns true if the first argument is less than or equal to the second argument.
## Parameters
* a (`integer`, `float`, `double`) - The first number.
* b (`integer`, `float`, `double`) - The second number.
## Return
(`boolean`) - True if the first argument is less than or equal to the second argument.
## 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": "lte",
"_": {
"a": 10,
"b": 2
}
}
```
### Last Updated
Monday, December 30th, 2022.
Written by [Netkas](https://git.n64.cc/netkas)

View file

@ -0,0 +1,35 @@
# neq
Returns true if the first argument is not equal to the second argument.
## Parameters
* a (`integer`, `float`, `double`, `string`, `boolean`) - The first value to compare.
* b (`integer`, `float`, `double`, `string`, `boolean`) - The second value to compare.
## Return
(`boolean`) - True if the first argument is not equal to the second argument.
## 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": "neq",
"_": {
"a": "foo",
"b": "foo"
}
}
```
### Last Updated
Monday, December 30th, 2022.
Written by [Netkas](https://git.n64.cc/netkas)

88
project.json Normal file
View file

@ -0,0 +1,88 @@
{
"project": {
"compiler": {
"extension": "php",
"minimum_version": "8.0",
"maximum_version": "8.1"
},
"update_source": {
"source": "nosial/cognize.rtex-engine@n64",
"repository": {
"name": "n64",
"type": "gitlab",
"host": "git.n64.cc",
"ssl": true
}
},
"options": []
},
"assembly": {
"name": "Real-Time Execution Engine",
"description": "An engine to execute instructions in real-time",
"company": "Nosial",
"package": "net.nosial.rtex",
"version": "1.0.0",
"uuid": "306c25c2-825f-11ed-b106-ad30777c00c3"
},
"execution_policies": {
"main": {
"runner": "php",
"exec": {
"target": "bin/main",
"working_directory": "%CWD%",
"silent": false,
"tty": true
}
}
},
"build": {
"source_path": "src",
"default_configuration": "release",
"main": {
"policy": "main",
"create_symlink": true
},
"define_constants": {
"ASSEMBLY_NAME": "%ASSEMBLY.NAME%",
"ASSEMBLY_PACKAGE": "%ASSEMBLY.PACKAGE%",
"ASSEMBLY_VERSION": "%ASSEMBLY.VERSION%",
"ASSEMBLY_UID": "%ASSEMBLY.UID%"
},
"dependencies": [
{
"name": "net.nosial.optslib",
"version": "latest",
"source_type": "remote",
"source": "nosial/libs.opts=latest@n64"
},
{
"name": "net.nosial.loglib",
"version": "latest",
"source_type": "remote",
"source": "nosial/libs.log=latest@n64"
},
{
"name": "com.cheprasov.php_redis_client",
"version": "latest",
"source_type": "remote",
"source": "cheprasov/php-redis-client=latest@composer"
}
],
"configurations": [
{
"name": "debug",
"output_path": "build/debug",
"define_constants": {
"DEBUG": "1"
}
},
{
"name": "release",
"output_path": "build/release",
"define_constants": {
"DEBUG": "0"
}
}
]
}
}

View file

@ -0,0 +1,60 @@
<?php
namespace RTEX\Abstracts;
abstract class InstructionType
{
// Arithmetic
const Sum = 'sum';
const Subtract = 'sub';
const Divide = 'div';
const Multiply = 'mul';
const Modulo = 'mod';
const Power = 'pow';
const SquareRoot = 'sqrt';
const Absolute = 'abs';
const Round = 'round';
const Floor = 'floor';
// Base
const Invoke = 'invoke';
const ArrayGet = 'array_get';
const ArraySet = 'array_set';
const GetVariable = 'get';
const SetVariable = 'set';
// Comparators
const Equals = 'eq';
const NotEquals = 'neq';
const GreaterThan = 'gt';
const GreaterThanOrEqual = 'gte';
const LessThan = 'lt';
const LessThanOrEqual = 'lte';
const All = [
self::Sum,
self::Subtract,
self::Divide,
self::Multiply,
self::Modulo,
self::Power,
self::SquareRoot,
self::Absolute,
self::Round,
self::Floor,
self::Invoke,
self::GetVariable,
self::SetVariable,
self::ArrayGet,
self::ArraySet,
self::Equals,
self::GreaterThan,
self::GreaterThanOrEqual,
self::LessThan,
self::LessThanOrEqual,
self::NotEquals,
];
}

View file

@ -0,0 +1,14 @@
<?php
namespace RTEX\Abstracts;
abstract class RegexPatterns
{
/**
* Matches an array query value
*
* Matches: foo.bar, foo.0.bar, foo.bar.bazz.bar.0, 0.bar.bazz
* Does not match: foo..bar, foo.bar., foo..bar.bazz, foo-bar
*/
const ArrayQuery = '/^\d*(\.\w+)*$/';
}

View file

@ -0,0 +1,14 @@
<?php
namespace RTEX\Abstracts;
abstract class RuntimeExceptionCode
{
const Exception = 0;
const ImportException = -100;
const KeyException = -101;
const NameException = -102;
const TypeException = -103;
const UndefinedMethodException = -104;
const ZeroDivisionException = -105;
}

View file

@ -0,0 +1,35 @@
<?php
namespace RTEX\Abstracts;
abstract class VariableType
{
const String = 'string';
const Integer = 'integer';
const Float = 'float';
const Double = 'double';
const Boolean = 'boolean';
const Array = 'array';
const Null = 'null';
const Instruction = 'instruction';
const Unknown = 'unknown';
const All = [
self::String,
self::Integer,
self::Float,
self::Double,
self::Boolean,
self::Array,
self::Null,
self::Instruction
];
}

View file

@ -0,0 +1,465 @@
<?php
namespace RTEX\Classes;
use RTEX\Abstracts\InstructionType;
use RTEX\Exceptions\InstructionException;
use RTEX\Interfaces\InstructionInterface;
use RTEX\Objects\Instructions\Arithmetic\Absolute;
use RTEX\Objects\Instructions\Arithmetic\Divide;
use RTEX\Objects\Instructions\Arithmetic\Floor;
use RTEX\Objects\Instructions\Arithmetic\Modulo;
use RTEX\Objects\Instructions\Arithmetic\Multiply;
use RTEX\Objects\Instructions\Arithmetic\Power;
use RTEX\Objects\Instructions\Arithmetic\Round;
use RTEX\Objects\Instructions\Arithmetic\SquareRoot;
use RTEX\Objects\Instructions\Arithmetic\Subtract;
use RTEX\Objects\Instructions\Arithmetic\Sum;
use RTEX\Objects\Instructions\Base\ArrayGet;
use RTEX\Objects\Instructions\Base\ArraySet;
use RTEX\Objects\Instructions\Base\GetVariable;
use RTEX\Objects\Instructions\Base\Invoke;
use RTEX\Objects\Instructions\Base\SetVariable;
use RTEX\Objects\Instructions\Comparators\Equals;
use RTEX\Objects\Instructions\Comparators\GreaterThan;
use RTEX\Objects\Instructions\Comparators\GreaterThanOrEqual;
use RTEX\Objects\Instructions\Comparators\LessThan;
use RTEX\Objects\Instructions\Comparators\LessThanOrEqual;
use RTEX\Objects\Instructions\Comparators\NotEquals;
class InstructionBuilder
{
/**
* Re-constructs instructions and variable types from an array representation
*
* @param $value
* @return array|mixed|InstructionInterface|null
* @throws InstructionException
*/
public static function fromRaw($value): mixed
{
// Check if it's a supported variable type
if(!Validate::supportedVariableType($value))
//throw new UnsupportedVariableType(gettype($value));
// Check if it's an instruction
if (is_array($value) && (isset($value['_']) && isset($value['type'])))
{
// Return the constructed InstructionInterface object
return match ($value['type'])
{
// Arithmetic operations
InstructionType::Absolute => Absolute::fromArray($value['_']),
InstructionType::Divide => Divide::fromArray($value['_']),
InstructionType::Floor => Floor::fromArray($value['_']),
InstructionType::Modulo => Modulo::fromArray($value['_']),
InstructionType::Multiply => Multiply::fromArray($value['_']),
InstructionType::Power => Power::fromArray($value['_']),
InstructionType::Round => Round::fromArray($value['_']),
InstructionType::SquareRoot => SquareRoot::fromArray($value['_']),
InstructionType::Subtract => Subtract::fromArray($value['_']),
InstructionType::Sum => Sum::fromArray($value['_']),
// Base instructions
InstructionType::Invoke => Invoke::fromArray($value['_']),
InstructionType::GetVariable => GetVariable::fromArray($value['_']),
InstructionType::SetVariable => SetVariable::fromArray($value['_']),
InstructionType::ArrayGet => ArrayGet::fromArray($value['_']),
InstructionType::ArraySet => ArraySet::fromArray($value['_']),
// Comparators
InstructionType::Equals => Equals::fromArray($value['_']),
InstructionType::GreaterThan => GreaterThan::fromArray($value['_']),
InstructionType::GreaterThanOrEqual => GreaterThanOrEqual::fromArray($value['_']),
InstructionType::LessThan => LessThan::fromArray($value['_']),
InstructionType::LessThanOrEqual => LessThanOrEqual::fromArray($value['_']),
InstructionType::NotEquals => NotEquals::fromArray($value['_']),
// Default (Unknown)
default => throw new InstructionException(sprintf('Unknown instruction type "%s"', $value['type'])),
};
}
// Recursive call if it's an array
elseif(is_array($value))
{
$output = [];
foreach ($value as $key => $item)
$output[$key] = self::fromRaw($item);
return $output;
}
// Return the value if it's not an array or an instruction
return $value;
}
/**
* Returns an array representation of an instruction
* (Note, you must provide the array representation of the instruction's arguments)
*
* @param $type
* @param $value
* @return array
*/
public static function toRaw($type, $value): array
{
return [
'type' => $type,
'_' => Utilities::toArray($value),
];
}
/**
* Returns the absolute value of a number
*
* @param $value float|int|InstructionInterface The number to get the absolute value of
* @return InstructionInterface
* @throws InstructionException
*/
public static function abs(InstructionInterface|float|int $value): InstructionInterface
{
$instruction = new Absolute();
$instruction->setValue($value);
return $instruction;
}
/**
* Divides two numbers and returns the result
*
* @param $a float|int|InstructionInterface The dividend
* @param $b float|int|InstructionInterface The divisor
* @return InstructionInterface
* @throws InstructionException
*/
public static function div(InstructionInterface|float|int $a, InstructionInterface|float|int $b): InstructionInterface
{
$instruction = new Divide();
$instruction->setA($a);
$instruction->setB($b);
return $instruction;
}
/**
* Returns the largest integer less than or equal to a number
*
* @param $value float|int|InstructionInterface The number to get the floor of
* @return InstructionInterface
* @throws InstructionException
*/
public static function floor(InstructionInterface|float|int $value): InstructionInterface
{
$instruction = new Floor();
$instruction->setValue($value);
return $instruction;
}
/**
* Returns the remainder of a division
*
* @param $a float|int|InstructionInterface The dividend
* @param $b float|int|InstructionInterface The divisor
* @return InstructionInterface
* @throws InstructionException
*/
public static function mod(InstructionInterface|float|int $a, InstructionInterface|float|int $b): InstructionInterface
{
$instruction = new Modulo();
$instruction->setA($a);
$instruction->setB($b);
return $instruction;
}
/**
* Multiplies two numbers and returns the result
*
* @param $a float|int|InstructionInterface The first number
* @param $b float|int|InstructionInterface The second number
* @return InstructionInterface
* @throws InstructionException
*/
public static function mul(InstructionInterface|float|int $a, InstructionInterface|float|int $b): InstructionInterface
{
$instruction = new Multiply();
$instruction->setA($a);
$instruction->setB($b);
return $instruction;
}
/**
* Raises a number to a power and returns the result
*
* @param $a float|int|InstructionInterface The base number
* @param $b float|int|InstructionInterface The exponent
* @return InstructionInterface
* @throws InstructionException
*/
public static function pow(InstructionInterface|float|int $a, InstructionInterface|float|int $b): InstructionInterface
{
$instruction = new Power();
$instruction->setA($a);
$instruction->setB($b);
return $instruction;
}
/**
* Rounds a number to a given precision
*
* @param $value float|int|InstructionInterface The number to round
* @param $precision int|InstructionInterface The precision to round to
* @return InstructionInterface
* @throws InstructionException
*/
public static function round(InstructionInterface|float|int $value, InstructionInterface|int $precision=0): InstructionInterface
{
$instruction = new Round();
$instruction->setValue($value);
$instruction->setPrecision($precision);
return $instruction;
}
/**
* Returns the square root of a number
*
* @param $value float|int|InstructionInterface The number to get the square root of
* @return InstructionInterface
* @throws InstructionException
*/
public static function sqrt(InstructionInterface|float|int $value): InstructionInterface
{
$instruction = new SquareRoot();
$instruction->setValue($value);
return $instruction;
}
/**
* Subtracts two numbers and returns the result
*
* @param $a float|int|InstructionInterface The minuend
* @param $b float|int|InstructionInterface The subtrahend
* @return InstructionInterface
* @throws InstructionException
*/
public static function sub(InstructionInterface|float|int $a, InstructionInterface|float|int $b): InstructionInterface
{
$instruction = new Subtract();
$instruction->setA($a);
$instruction->setB($b);
return $instruction;
}
/**
* Adds two numbers and returns the result
*
* @param $a float|int|InstructionInterface The first number
* @param $b float|int|InstructionInterface The second number
* @return InstructionInterface
* @throws InstructionException
*/
public static function sum(InstructionInterface|float|int $a, InstructionInterface|float|int $b): InstructionInterface
{
$instruction = new Sum();
$instruction->setA($a);
$instruction->setB($b);
return $instruction;
}
/**
* Returns the requested key from an array
*
* @param InstructionInterface|array $array The array to get the key from
* @param InstructionInterface|string $key The key to get (can be a string or an instruction) (eg; "foo" or "foo.bar")
* @return InstructionInterface
* @throws InstructionException
*/
public static function array_get(InstructionInterface|array $array, InstructionInterface|string $key): InstructionInterface
{
$instruction = new ArrayGet();
$instruction->setArray($array);
$instruction->setKey($key);
return $instruction;
}
/**
* Sets the requested key in an array
*
* @param InstructionInterface|array $array The array to set the key in
* @param InstructionInterface|string $key The key to get (can be a string or an instruction) (eg; "foo" or "foo.bar")
* @param mixed $value The value to set the key to
* @return InstructionInterface
* @throws InstructionException
*/
public static function array_set(InstructionInterface|array $array, InstructionInterface|string $key, mixed $value): InstructionInterface
{
$instruction = new ArraySet();
$instruction->setArray($array);
$instruction->setKey($key);
$instruction->setValue($value);
return $instruction;
}
/**
* Gets an existing variable from the environment
*
* @param InstructionInterface|string $name The name of the variable to get
* @return InstructionInterface
* @throws InstructionException
*/
public static function get(InstructionInterface|string $name): InstructionInterface
{
$instruction = new GetVariable();
$instruction->setVariableName($name);
return $instruction;
}
/**
* Invokes a callable with the given arguments
*
* @param InstructionInterface|string $callable The callable to invoke
* @param array $parameters The parameters to pass to the callable
* @param bool|InstructionBuilder $fail_on_error Whether to fail on error or not
* @return InstructionInterface
* @throws InstructionException
*/
public static function invoke(InstructionInterface|string $callable, array $parameters=[], bool|InstructionBuilder $fail_on_error=true): InstructionInterface
{
$instruction = new Invoke();
$instruction->setCallable($callable);
$instruction->setParameters($parameters);
$instruction->setFailOnError($fail_on_error);
return $instruction;
}
/**
* Sets a variable in the environment
*
* @param InstructionInterface|string $name The name of the variable to set
* @param mixed $value The value to set the variable to
* @return InstructionInterface
* @throws InstructionException
*/
public static function set(InstructionInterface|string $name, mixed $value): InstructionInterface
{
$instruction = new SetVariable();
$instruction->setName($name);
$instruction->setValue($value);
return $instruction;
}
/**
* Returns true if the two values are equal
*
* @param InstructionInterface|float|int|string $a The first value
* @param InstructionInterface|float|int|string $b The second value
* @return InstructionInterface
* @throws InstructionException
*/
public static function eq(InstructionInterface|float|int|string $a, InstructionInterface|float|int|string $b): InstructionInterface
{
$instruction = new Equals();
$instruction->setA($a);
$instruction->setB($b);
return $instruction;
}
/**
* Returns true if the two values are not equal
*
* @param InstructionInterface|float|int|string $a The first value
* @param InstructionInterface|float|int|string $b The second value
* @return InstructionInterface
* @throws InstructionException
*/
public static function neq(InstructionInterface|float|int|string $a, InstructionInterface|float|int|string $b): InstructionInterface
{
$instruction = new NotEquals();
$instruction->setA($a);
$instruction->setB($b);
return $instruction;
}
/**
* Returns true if the first value is greater than the second value
*
* @param InstructionInterface|float|int|string $a The first value
* @param InstructionInterface|float|int|string $b The second value
* @return InstructionInterface
* @throws InstructionException
*/
public static function gt(InstructionInterface|float|int|string $a, InstructionInterface|float|int|string $b): InstructionInterface
{
$instruction = new GreaterThan();
$instruction->setA($a);
$instruction->setB($b);
return $instruction;
}
/**
* Returns true if the first value is greater than or equal to the second value
*
* @param InstructionInterface|float|int|string $a The first value
* @param InstructionInterface|float|int|string $b The second value
* @return InstructionInterface
* @throws InstructionException
*/
public static function gte(InstructionInterface|float|int|string $a, InstructionInterface|float|int|string $b): InstructionInterface
{
$instruction = new GreaterThanOrEqual();
$instruction->setA($a);
$instruction->setB($b);
return $instruction;
}
/**
* Returns true if the first value is less than the second value
*
* @param InstructionInterface|float|int|string $a The first value
* @param InstructionInterface|float|int|string $b The second value
* @return InstructionInterface
* @throws InstructionException
*/
public static function lt(InstructionInterface|float|int|string $a, InstructionInterface|float|int|string $b): InstructionInterface
{
$instruction = new LessThan();
$instruction->setA($a);
$instruction->setB($b);
return $instruction;
}
/**
* Returns true if the first value is less than or equal to the second value
*
* @param InstructionInterface|float|int|string $a The first value
* @param InstructionInterface|float|int|string $b The second value
* @return InstructionInterface
* @throws InstructionException
*/
public static function lte(InstructionInterface|float|int|string $a, InstructionInterface|float|int|string $b): InstructionInterface
{
$instruction = new LessThanOrEqual();
$instruction->setA($a);
$instruction->setB($b);
return $instruction;
}
}

View file

@ -0,0 +1,27 @@
<?php /** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Classes;
use RedisClient\RedisClient;
class RedisHookInstance
{
public function __construct(string $host, int $port, ?string $password=null)
{
if(extension_loaded('redis'))
{
$this->Redis = new \Redis();
$this->Redis->connect($host, $port);
if($password !== null)
$this->Redis->auth($password);
}
else
{
$this->Redis = new RedisClient([
'host' => $host,
'port' => $port,
'password' => $password
]);
}
}
}

View file

@ -0,0 +1,105 @@
<?php
namespace RTEX\Classes;
use RTEX\Abstracts\VariableType;
use RTEX\Exceptions\Runtime\TypeException;
use RTEX\Interfaces\InstructionInterface;
class Utilities
{
/**
* Determines the type of variable, throws an exception if the type is not supported
*
* @param $input
* @param bool $return_unknown
* @return string
* @throws TypeException
*/
public static function getType($input, bool $return_unknown=false): string
{
if ($input instanceof InstructionInterface)
return VariableType::Instruction;
if (is_string($input))
return VariableType::String;
if (is_int($input))
return VariableType::Integer;
if (is_float($input))
return VariableType::Float;
if (is_double($input))
return VariableType::Double;
if (is_bool($input))
return VariableType::Boolean;
if (is_array($input))
return VariableType::Array;
if (is_null($input))
return VariableType::Null;
if ($return_unknown)
return VariableType::Unknown;
throw new TypeException(gettype($input));
}
/**
* Returns a supported variable type to an array representation
* or a single value if it's not an array or an instruction
*
* @param $input
* @return array|mixed
*/
public static function toArray($input): mixed
{
if($input instanceof InstructionInterface)
return $input->toArray();
if(is_array($input))
{
$output = [];
foreach($input as $key => $value)
$output[$key] = self::toArray($value);
return $output;
}
return $input;
}
/**
* Returns a string representation of a variable type
* or an instruction type if it's an instruction
*
* This cannot be used as a method of serialization
*
* @param $input
* @return string
*/
public static function entityToString($input): string
{
/** @var InstructionInterface $input */
if($input instanceof InstructionInterface)
return (string)$input;
if(is_array($input))
{
$output = [];
foreach($input as $key => $value)
$output[$key] = self::entityToString($value);
return json_encode($output, JSON_UNESCAPED_SLASHES);
}
if(is_string($input))
return "'$input'";
if(is_int($input))
return 'int(' . $input . ')';
if(is_float($input))
return 'float(' . $input . ')';
if(is_double($input))
return 'double(' . $input . ')';
if(is_bool($input))
return $input ? 'True' : 'False';
if(is_null($input))
return 'NULL';
return 'Unknown';
}
}

View file

@ -0,0 +1,41 @@
<?php
namespace RTEX\Classes;
use Exception;
class Validate
{
/**
* Determines if the input is a supported variable type
*
* @param $type
* @return bool
*/
public static function supportedVariableType($type): bool
{
try
{
Utilities::getType($type);
}
catch(Exception $e)
{
unset($e);
return false;
}
return true;
}
/**
* Validates the input with a regex pattern
*
* @param string $input
* @param string $pattern
* @return bool
*/
public static function validateRegex(string $input, string $pattern): bool
{
return preg_match($pattern, $input) === 1;
}
}

108
src/RTEX/Engine.php Normal file
View file

@ -0,0 +1,108 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX;
use Exception;
use LogLib\Log;
use RTEX\Exceptions\EvaluationException;
use RTEX\Interfaces\InstructionInterface;
use RTEX\Objects\Engine\Environment;
use RTEX\Objects\Program;
class Engine
{
/**
* @var Program
*/
private $Program;
/**
* @var Environment
*/
private $Environment;
public function __construct(Program $program)
{
$this->Program = $program;
$this->Environment = new Environment();
}
/**
* Executes the program by running the main script of the program
*
* @return void
* @throws EvaluationException
*/
public function run(): void
{
foreach($this->Program->getMain()->getInstructions() as $instruction)
{
$this->eval($instruction);
}
}
/**
* Evaluates the variable or instruction and returns the result
*
* @param $input
* @return mixed
* @throws EvaluationException
*/
public function eval($input): mixed
{
try
{
if($input instanceof InstructionInterface)
{
Log::debug('net.nosial.rtex', $input);
return $input->eval($this);
}
}
catch(Exception $e)
{
throw new EvaluationException($e->getMessage(), $e->getCode(), $e);
}
return $input;
}
/**
* @return Program
*/
public function getProgram(): Program
{
return $this->Program;
}
/**
* @param Program $Program
*/
public function setProgram(Program $Program): void
{
$this->Program = $Program;
}
/**
* @return Environment
*/
public function getEnvironment(): Environment
{
return $this->Environment;
}
/**
* Calls the method
*
* @param string $namespace
* @param string $method
* @param array $arguments
* @return mixed
*/
public function callMethod(string $namespace, string $method, array $arguments)
{
// TODO: Implement callMethod() method.
return null;
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace RTEX\Exceptions;
use Exception;
use Throwable;
class EvaluationException extends Exception
{
/**
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}

View file

@ -0,0 +1,18 @@
<?php
namespace RTEX\Exceptions;
use Throwable;
class InstructionException extends \Exception
{
/**
* @param string $message
* @param int $code
* @param Throwable|null $previous
*/
public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}

View file

@ -0,0 +1,18 @@
<?php
namespace RTEX\Exceptions\Runtime;
use RTEX\Abstracts\RuntimeExceptionCode;
use Throwable;
class Exception extends \Exception
{
/**
* @param string $message
* @param Throwable|null $previous
*/
public function __construct(string $message = "", ?Throwable $previous = null)
{
parent::__construct($message, RuntimeExceptionCode::Exception, $previous);
}
}

View file

@ -0,0 +1,18 @@
<?php
namespace RTEX\Exceptions\Runtime;
use RTEX\Abstracts\RuntimeExceptionCode;
use Throwable;
class ImportException extends \Exception
{
/**
* @param string $message
* @param Throwable|null $previous
*/
public function __construct(string $message = "", ?Throwable $previous = null)
{
parent::__construct($message, RuntimeExceptionCode::ImportException, $previous);
}
}

View file

@ -0,0 +1,18 @@
<?php
namespace RTEX\Exceptions\Runtime;
use RTEX\Abstracts\RuntimeExceptionCode;
use Throwable;
class KeyException extends \Exception
{
/**
* @param string $message
* @param Throwable|null $previous
*/
public function __construct(string $message = "", ?Throwable $previous = null)
{
parent::__construct($message, RuntimeExceptionCode::KeyException, $previous);
}
}

View file

@ -0,0 +1,18 @@
<?php
namespace RTEX\Exceptions\Runtime;
use RTEX\Abstracts\RuntimeExceptionCode;
use Throwable;
class NameException extends \Exception
{
/**
* @param string $message
* @param Throwable|null $previous
*/
public function __construct(string $message = "", ?Throwable $previous = null)
{
parent::__construct($message, RuntimeExceptionCode::NameException, $previous);
}
}

View file

@ -0,0 +1,18 @@
<?php
namespace RTEX\Exceptions\Runtime;
use RTEX\Abstracts\RuntimeExceptionCode;
use Throwable;
class TypeException extends \Exception
{
/**
* @param string $message
* @param Throwable|null $previous
*/
public function __construct(string $message = "", ?Throwable $previous = null)
{
parent::__construct($message, RuntimeExceptionCode::TypeException, $previous);
}
}

View file

@ -0,0 +1,18 @@
<?php
namespace RTEX\Exceptions\Runtime;
use RTEX\Abstracts\RuntimeExceptionCode;
use Throwable;
class UndefinedMethodException extends \Exception
{
/**
* @param string $message
* @param Throwable|null $previous
*/
public function __construct(string $message = "", ?Throwable $previous = null)
{
parent::__construct($message, RuntimeExceptionCode::UndefinedMethodException, $previous);
}
}

View file

@ -0,0 +1,18 @@
<?php
namespace RTEX\Exceptions\Runtime;
use RTEX\Abstracts\RuntimeExceptionCode;
use Throwable;
class ZeroDivisionException extends \Exception
{
/**
* @param string $message
* @param Throwable|null $previous
*/
public function __construct(string $message = "", ?Throwable $previous = null)
{
parent::__construct($message, RuntimeExceptionCode::ZeroDivisionException, $previous);
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace RTEX\Interfaces;
interface DefinedNamespaceInterface
{
/**
* Returns an array of available methods with their names as keys
* and their class names as values (e.g. ['clear' => ClearMethod::class])
*
* @return MethodInterface[]
*/
public static function getMethods(): array;
/**
* Returns the name of the namespace (e.g. 'console')
*
* @return string
*/
public static function getName(): string;
}

View file

@ -0,0 +1,49 @@
<?php
namespace RTEX\Interfaces;
use RTEX\Abstracts\InstructionType;
use RTEX\Engine;
interface InstructionInterface
{
/**
* Returns the type of instruction
*
* @return string
* @see InstructionType
*/
public function getType(): string;
/**
* Returns an array representation of the object
*
* @return array
*/
public function toArray(): array;
/**
* Constructs a new instruction from an array representation
*
* @param array $data
* @return InstructionInterface
*/
public static function fromArray(array $data): InstructionInterface;
/**
* Evaluates the instruction and returns the result of the evaluation
*
* @param Engine $engine
* @return mixed|void
*/
public function eval(Engine $engine);
/**
* Returns a string representation of the instruction for debugging purposes
* this is not the same as the array representation, and is not intended to be
* used for serialization
*
* @return string
*/
public function __toString(): string;
}

View file

@ -0,0 +1,18 @@
<?php
namespace RTEX\Interfaces;
use RTEX\Engine;
interface MethodInterface
{
/**
* Invokes the method with the given parameters and returns the result
* of the invocation
*
* @param Engine $engine
* @param array $parameters
* @return mixed|void
*/
public static function invoke(Engine $engine, array $parameters);
}

View file

@ -0,0 +1,57 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Engine;
use RTEX\Objects\Engine\Configuration\RedisHook;
class Configuration
{
/**
* The redis hook configuration
*
* @var RedisHook
*/
private $RedisHook;
public function __construct()
{
$this->RedisHook = new RedisHook();
}
/**
* Returns the redis hook configuration
*
* @return RedisHook
*/
public function getRedisHook(): RedisHook
{
return $this->RedisHook;
}
/**
* Returns an array representation of the configuration
*
* @return array
*/
public function toArray(): array
{
return [
'redis_hook' => $this->RedisHook->toArray()
];
}
/**
* Constructs a configuration object from an array
*
* @param array $data
* @return static
*/
public static function fromArray(array $data): self
{
$instance = new self();
$instance->RedisHook = RedisHook::fromArray(($data['redis_hook'] ?? []));
return $instance;
}
}

View file

@ -0,0 +1,172 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Engine\Configuration;
class RedisHook
{
/**
* If the hook is enabled or not
* (default: false)
*
* @var string
*/
private $Enabled;
/**
* The host of the redis server
* (default: 127.0.0.1)
*
* @var string
*/
private $Host;
/**
* The port of the redis server
* (default: 6379)
*
* @var int
*/
private $Port;
/**
* Optional. Use it only if Redis server requires password (AUTH)
* (default: null)
*
* @var string|null
*/
private $Password;
/**
* Public Constructor
*/
public function __construct()
{
$this->Enabled = false;
$this->Host = '127.0.0.1';
$this->Port = 6379;
$this->Password = null;
}
/**
* Whether the hook is enabled or not
*
* @return false|string
*/
public function isEnabled(): false|string
{
return $this->Enabled;
}
/**
* Enables the hook
*
* @returns void
*/
public function enable(): void
{
$this->Enabled = true;
}
/**
* Disables the hook
*
* @return void
*/
public function disable(): void
{
$this->Enabled = false;
}
/**
* Returns the host of the redis server
*
* @return string
*/
public function getHost(): string
{
return $this->Host;
}
/**
* Sets the host of the redis server
*
* @param string $Host
*/
public function setHost(string $Host): void
{
$this->Host = $Host;
}
/**
* Returns the port of the redis server
*
* @return int
*/
public function getPort(): int
{
return $this->Port;
}
/**
* Sets the port of the redis server
*
* @param int $Port
*/
public function setPort(int $Port): void
{
$this->Port = $Port;
}
/**
* Returns the password of the redis server
*
* @return string|null
*/
public function getPassword(): ?string
{
return $this->Password;
}
/**
* Sets the password of the redis server
*
* @param string|null $Password
*/
public function setPassword(?string $Password): void
{
$this->Password = $Password;
}
/**
* Returns an array representation of the configuration
*
* @return array
*/
public function toArray(): array
{
return [
'enabled' => $this->Enabled,
'host' => $this->Host,
'port' => $this->Port,
'password' => $this->Password
];
}
/**
* Constructs a new instance from an array
*
* @param array $data
* @return RedisHook
*/
public static function fromArray(array $data): self
{
$instance = new self();
$instance->Enabled = ($data['enabled'] ?? false);
$instance->Host = ($data['host'] ?? '127.0.0.1');
$instance->Port = ($data['port'] ?? 6379);
$instance->Password = ($data['password'] ?? null);
return $instance;
}
}

View file

@ -0,0 +1,211 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Engine\Configuration;
class Runtime
{
/**
* The maximum size a variable value can have (in bytes)
* (default: 0) (no limit)
*
* @var int
*/
private $MaxVariableSize;
/**
* The maximum number of variables that can be defined
* (default: 0) (no limit)
*
* @var int
*/
private $MaxVariables;
/**
* The maximum number of instructions that can be executed
* (default: 0) (no limit)
*
* @var int
*/
private $MaxStackSize;
/**
* An array of instructions that are not allowed to be executed
* if the script attempts to execute one of these instructions
* the engine will treat it as a fatal error and stop the execution
*
* For production environments it is recommended to disable dangerous
* instructions such as regex if you aren't supervising the engine
*
* @var string[]
*/
private $InstructionBlacklist;
/**
* An array of ncc packages to import as a namespace into the engine
* (The engine will look for a file named 'rtex.conf' in the package
* source directory and register the defined methods for that namespace)
*
* This will only work for packages designed for the engine and will
* not work for regular PHP packages (unless they include support for RTEX)
*
* Values must be in the format of 'com.example.package' (The same format as
* importing packages via the import() function)
*
* @var string[]
*/
private $ImportNamespaces;
/**
* Public Constructor
*/
public function __construct()
{
$this->MaxVariableSize = 0;
$this->MaxVariables = 0;
$this->MaxStackSize = 0;
$this->InstructionBlacklist = [];
}
/**
* @return int
*/
public function getMaxVariableSize(): int
{
return $this->MaxVariableSize;
}
/**
* @param int $MaxVariableSize
*/
public function setMaxVariableSize(int $MaxVariableSize): void
{
$this->MaxVariableSize = $MaxVariableSize;
}
/**
* @return int
*/
public function getMaxVariables(): int
{
return $this->MaxVariables;
}
/**
* @param int $MaxVariables
*/
public function setMaxVariables(int $MaxVariables): void
{
$this->MaxVariables = $MaxVariables;
}
/**
* @return int
*/
public function getMaxStackSize(): int
{
return $this->MaxStackSize;
}
/**
* @param int $MaxStackSize
*/
public function setMaxStackSize(int $MaxStackSize): void
{
$this->MaxStackSize = $MaxStackSize;
}
/**
* Returns the instruction blacklist
*
* @return array|string[]
*/
public function getInstructionBlacklist(): array
{
return $this->InstructionBlacklist;
}
/**
* Sets the instruction blacklist
*
* @param array|string[] $InstructionBlacklist
*/
public function setInstructionBlacklist(array $InstructionBlacklist): void
{
$this->InstructionBlacklist = $InstructionBlacklist;
}
/**
* Adds an instruction to the blacklist
*
* @param string $instruction
* @return void
*/
public function addInstructionToBlacklist(string $instruction): void
{
if (in_array($instruction, $this->InstructionBlacklist))
return;
$this->InstructionBlacklist[] = $instruction;
}
/**
* Removes an instruction from the blacklist
*
* @param string $instruction
* @return void
*/
public function removeInstructionFromBlacklist(string $instruction): void
{
if (!in_array($instruction, $this->InstructionBlacklist))
return;
$this->InstructionBlacklist = array_diff($this->InstructionBlacklist, [$instruction]);
}
/**
* @return string[]
*/
public function getImportNamespaces(): array
{
return $this->ImportNamespaces;
}
/**
* @param string[] $ImportNamespaces
*/
public function setImportNamespaces(array $ImportNamespaces): void
{
$this->ImportNamespaces = $ImportNamespaces;
}
/**
* Adds a namespace to the import list
*
* @param string $namespace
* @return void
*/
public function addNamespaceToImport(string $namespace): void
{
if (in_array($namespace, $this->ImportNamespaces))
return;
$this->ImportNamespaces[] = $namespace;
}
/**
* Removes a namespace from the import list
*
* @param string $namespace
* @return void
*/
public function removeNamespaceFromImport(string $namespace): void
{
if (!in_array($namespace, $this->ImportNamespaces))
return;
$this->ImportNamespaces = array_diff($this->ImportNamespaces, [$namespace]);
}
}

View file

@ -0,0 +1,109 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Engine;
use LogLib\Log;
use RTEX\Exceptions\Runtime\NameException;
class Environment
{
/**
* @var array
*/
private $RuntimeVariables;
/**
* Public Constructor
*/
public function __construct()
{
$this->RuntimeVariables = [];
}
/**
* Returns the value of the specified variable
*
* @param string $name
* @return mixed
* @throws NameException
*/
public function getRuntimeVariable(string $name): mixed
{
Log::debug('net.nosial.rtex', $name);
if (!$this->variableExists($name))
throw new NameException("Variable '$name' is not defined");
return $this->RuntimeVariables[$name];
}
/**
* Sets the value of the specified variable
*
* @param string $name
* @param mixed $value
*/
public function setRuntimeVariable(string $name, mixed $value): void
{
Log::debug('net.nosial.rtex', $name);
$this->RuntimeVariables[$name] = $value;
}
/**
* @param string $name
* @return bool
*/
public function variableExists(string $name): bool
{
return array_key_exists($name, $this->RuntimeVariables);
}
/**
* Clears the value of the specified variable
*
* @return void
* @noinspection PhpUnused
*/
public function clearRuntimeVariables(): void
{
$this->RuntimeVariables = [];
}
/**
* Counts the number of variables in the environment
*
* @return int
*/
public function countRuntimeVariables(): int
{
return count($this->RuntimeVariables);
}
/**
* Returns an array representation of the object
*
* @return array
*/
public function toArray(): array
{
return [
'variables' => $this->RuntimeVariables
];
}
/**
* Constructs a new environment from an array representation
*
* @param array $data
* @return Environment
*/
public static function fromArray(array $data): Environment
{
$environment = new Environment();
$environment->RuntimeVariables = $data['variables'];
return $environment;
}
}

View file

@ -0,0 +1,109 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Instructions\Arithmetic;
use RTEX\Abstracts\InstructionType;
use RTEX\Classes\InstructionBuilder;
use RTEX\Classes\Utilities;
use RTEX\Engine;
use RTEX\Exceptions\EvaluationException;
use RTEX\Exceptions\InstructionException;
use RTEX\Exceptions\Runtime\TypeException;
use RTEX\Interfaces\InstructionInterface;
class Absolute implements InstructionInterface
{
/**
* @var mixed
*/
private $Value;
/**
* Returns the type of instruction
*
* @return string
*/
public function getType(): string
{
return InstructionType::Absolute;
}
/**
* Returns an array representation of the instruction
*
* @return array
*/
public function toArray(): array
{
return InstructionBuilder::toRaw(self::getType(), [
'value' => $this->Value,
]);
}
/**
* Constructs a new instance of this class from an array representation
*
* @param array $data
* @return InstructionInterface
* @throws InstructionException
*/
public static function fromArray(array $data): InstructionInterface
{
$instruction = new self();
$instruction->setValue($data['value'] ?? null);
return $instruction;
}
/**
* @param Engine $engine
* @return int|float
* @throws EvaluationException
* @throws TypeException
*/
public function eval(Engine $engine): int|float
{
$value = $engine->eval($this->Value);
if(!(is_int($value) || is_float($value) || is_double($value)))
throw new TypeException(sprintf('Cannot calculate the absolute value of a non-numeric value, got %s', Utilities::getType($value, true)));
return abs($value);
}
/**
* Returns the string representation of the instruction
*
* @return string
*/
public function __toString(): string
{
return sprintf(
self::getType() . ' %s',
Utilities::entityToString($this->Value),
);
}
/**
* Gets the value of A
*
* @return mixed
*/
public function getValue(): mixed
{
return $this->Value;
}
/**
* Sets the value of A
*
* @param mixed $Value
* @throws InstructionException
*/
public function setValue(mixed $Value): void
{
$this->Value = InstructionBuilder::fromRaw($Value);
}
}

View file

@ -0,0 +1,144 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Instructions\Arithmetic;
use RTEX\Abstracts\InstructionType;
use RTEX\Classes\InstructionBuilder;
use RTEX\Classes\Utilities;
use RTEX\Engine;
use RTEX\Exceptions\EvaluationException;
use RTEX\Exceptions\InstructionException;
use RTEX\Exceptions\Runtime\TypeException;
use RTEX\Exceptions\Runtime\ZeroDivisionException;
use RTEX\Interfaces\InstructionInterface;
class Divide implements InstructionInterface
{
/**
* @var mixed
*/
private $A;
/**
* @var mixed
*/
private $B;
/**
* Returns the type of instruction
*
* @return string
*/
public function getType(): string
{
return InstructionType::Divide;
}
/**
* Returns an array representation of the instruction
*
* @return array
*/
public function toArray(): array
{
return InstructionBuilder::toRaw(self::getType(), [
'a' => $this->A,
'b' => $this->B
]);
}
/**
* Constructs a new instance of this class from an array representation
*
* @param array $data
* @return InstructionInterface
* @throws InstructionException
*/
public static function fromArray(array $data): InstructionInterface
{
$instruction = new self();
$instruction->setA($data['a'] ?? null);
$instruction->setB($data['b'] ?? null);
return $instruction;
}
/**
* @param Engine $engine
* @return int|float
* @throws EvaluationException
* @throws TypeException
* @throws ZeroDivisionException
*/
public function eval(Engine $engine): int|float
{
$a = $engine->eval($this->A);
$b = $engine->eval($this->B);
if(!(is_int($a) || is_float($a) || is_double($a)))
throw new TypeException(sprintf('Cannot divide a non-numeric value \'A\' of type %s', Utilities::getType($a, true)));
if(!(is_int($b) || is_float($b) || is_double($b)))
throw new TypeException(sprintf('Cannot divide a non-numeric value \'B\' of type %s', Utilities::getType($b, true)));
if ($b === 0)
throw new ZeroDivisionException(sprintf('Division by zero in %s', $this));
return (intval($a) / intval($b));
}
/**
* Returns the string representation of the instruction
*
* @return string
*/
public function __toString(): string
{
return sprintf(
self::getType() . ' %s / %s',
Utilities::entityToString($this->A),
Utilities::entityToString($this->B)
);
}
/**
* Gets the value of A
*
* @return mixed
*/
public function getA(): mixed
{
return $this->A;
}
/**
* Sets the value of A
*
* @param mixed $A
* @throws InstructionException
*/
public function setA(mixed $A): void
{
$this->A = InstructionBuilder::fromRaw($A);
}
/**
* Gets the value of B
*
* @return mixed
*/
public function getB(): mixed
{
return $this->B;
}
/**
* Sets the value of B
*
* @param mixed $B
* @throws InstructionException
*/
public function setB(mixed $B): void
{
$this->B = InstructionBuilder::fromRaw($B);
}
}

View file

@ -0,0 +1,109 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Instructions\Arithmetic;
use RTEX\Abstracts\InstructionType;
use RTEX\Classes\InstructionBuilder;
use RTEX\Classes\Utilities;
use RTEX\Engine;
use RTEX\Exceptions\EvaluationException;
use RTEX\Exceptions\InstructionException;
use RTEX\Exceptions\Runtime\TypeException;
use RTEX\Interfaces\InstructionInterface;
class Floor implements InstructionInterface
{
/**
* @var mixed
*/
private $Value;
/**
* Returns the type of instruction
*
* @return string
*/
public function getType(): string
{
return InstructionType::Floor;
}
/**
* Returns an array representation of the instruction
*
* @return array
*/
public function toArray(): array
{
return InstructionBuilder::toRaw(self::getType(), [
'value' => $this->Value,
]);
}
/**
* Constructs a new instance of this class from an array representation
*
* @param array $data
* @return InstructionInterface
* @throws InstructionException
*/
public static function fromArray(array $data): InstructionInterface
{
$instruction = new self();
$instruction->setValue($data['value'] ?? null);
return $instruction;
}
/**
* @param Engine $engine
* @return int|float
* @throws EvaluationException
* @throws TypeException
*/
public function eval(Engine $engine): int|float
{
$value = $engine->eval($this->Value);
if(!(is_int($value) || is_float($value) || is_double($value)))
throw new TypeException(sprintf('Cannot calculate the floor value of a non-numeric value, got %s', Utilities::getType($value, true)));
return floor($value);
}
/**
* Returns the string representation of the instruction
*
* @return string
*/
public function __toString(): string
{
return sprintf(
self::getType() . ' %s',
Utilities::entityToString($this->Value),
);
}
/**
* Gets the value of A
*
* @return mixed
*/
public function getValue(): mixed
{
return $this->Value;
}
/**
* Sets the value of A
*
* @param mixed $Value
* @throws InstructionException
*/
public function setValue(mixed $Value): void
{
$this->Value = InstructionBuilder::fromRaw($Value);
}
}

View file

@ -0,0 +1,140 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Instructions\Arithmetic;
use RTEX\Abstracts\InstructionType;
use RTEX\Classes\InstructionBuilder;
use RTEX\Classes\Utilities;
use RTEX\Engine;
use RTEX\Exceptions\EvaluationException;
use RTEX\Exceptions\InstructionException;
use RTEX\Exceptions\Runtime\TypeException;
use RTEX\Interfaces\InstructionInterface;
class Modulo implements InstructionInterface
{
/**
* @var mixed
*/
private $A;
/**
* @var mixed
*/
private $B;
/**
* Returns the type of instruction
*
* @return string
*/
public function getType(): string
{
return InstructionType::Modulo;
}
/**
* Returns an array representation of the instruction
*
* @return array
*/
public function toArray(): array
{
return InstructionBuilder::toRaw(self::getType(), [
'a' => $this->A,
'b' => $this->B
]);
}
/**
* Constructs a new instance of this class from an array representation
*
* @param array $data
* @return InstructionInterface
* @throws InstructionException
*/
public static function fromArray(array $data): InstructionInterface
{
$instruction = new self();
$instruction->setA($data['a'] ?? null);
$instruction->setB($data['b'] ?? null);
return $instruction;
}
/**
* @param Engine $engine
* @return int|float
* @throws EvaluationException
* @throws TypeException
*/
public function eval(Engine $engine): int|float
{
$a = $engine->eval($this->A);
$b = $engine->eval($this->B);
if(!(is_int($a) || is_float($a) || is_double($a)))
throw new TypeException(sprintf('Cannot perform modulo operation on non-numeric value \'A\' of type %s', Utilities::getType($a, true)));
if(!(is_int($b) || is_float($b) || is_double($b)))
throw new TypeException(sprintf('Cannot perform modulo operation on non-numeric value \'B\' of type %s', Utilities::getType($b. true)));
return ($a % $b);
}
/**
* Returns the string representation of the instruction
*
* @return string
*/
public function __toString(): string
{
return sprintf(
self::getType() . ' %s %% %s',
Utilities::entityToString($this->A),
Utilities::entityToString($this->B)
);
}
/**
* Gets the value of A
*
* @return mixed
*/
public function getA(): mixed
{
return $this->A;
}
/**
* Sets the value of A
*
* @param mixed $A
* @throws InstructionException
*/
public function setA(mixed $A): void
{
$this->A = InstructionBuilder::fromRaw($A);
}
/**
* Gets the value of B
*
* @return mixed
*/
public function getB(): mixed
{
return $this->B;
}
/**
* Sets the value of B
*
* @param mixed $B
* @throws InstructionException
*/
public function setB(mixed $B): void
{
$this->B = InstructionBuilder::fromRaw($B);
}
}

View file

@ -0,0 +1,140 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Instructions\Arithmetic;
use RTEX\Abstracts\InstructionType;
use RTEX\Classes\InstructionBuilder;
use RTEX\Classes\Utilities;
use RTEX\Engine;
use RTEX\Exceptions\EvaluationException;
use RTEX\Exceptions\InstructionException;
use RTEX\Exceptions\Runtime\TypeException;
use RTEX\Interfaces\InstructionInterface;
class Multiply implements InstructionInterface
{
/**
* @var mixed
*/
private $A;
/**
* @var mixed
*/
private $B;
/**
* Returns the type of instruction
*
* @return string
*/
public function getType(): string
{
return InstructionType::Multiply;
}
/**
* Returns an array representation of the instruction
*
* @return array
*/
public function toArray(): array
{
return InstructionBuilder::toRaw(self::getType(), [
'a' => $this->A,
'b' => $this->B
]);
}
/**
* Constructs a new instance of this class from an array representation
*
* @param array $data
* @return InstructionInterface
* @throws InstructionException
*/
public static function fromArray(array $data): InstructionInterface
{
$instruction = new self();
$instruction->setA($data['a'] ?? null);
$instruction->setB($data['b'] ?? null);
return $instruction;
}
/**
* @param Engine $engine
* @return int|float
* @throws EvaluationException
* @throws TypeException
*/
public function eval(Engine $engine): int|float
{
$a = $engine->eval($this->A);
$b = $engine->eval($this->B);
if(!(is_int($a) || is_float($a) || is_double($a)))
throw new TypeException(sprintf('Cannot multiply a non-numeric value \'A\' of type \'%s\'', Utilities::getType($a, true)));
if(!(is_int($b) || is_float($b) || is_double($b)))
throw new TypeException(sprintf('Cannot multiply a non-numeric value \'B\' of type \'%s\'', Utilities::getType($b, true)));
return ($a * $b);
}
/**
* Returns the string representation of the instruction
*
* @return string
*/
public function __toString(): string
{
return sprintf(
self::getType() . ' %s * %s',
Utilities::entityToString($this->A),
Utilities::entityToString($this->B)
);
}
/**
* Gets the value of A
*
* @return mixed
*/
public function getA(): mixed
{
return $this->A;
}
/**
* Sets the value of A
*
* @param mixed $A
* @throws InstructionException
*/
public function setA(mixed $A): void
{
$this->A = InstructionBuilder::fromRaw($A);
}
/**
* Gets the value of B
*
* @return mixed
*/
public function getB(): mixed
{
return $this->B;
}
/**
* Sets the value of B
*
* @param mixed $B
* @throws InstructionException
*/
public function setB(mixed $B): void
{
$this->B = InstructionBuilder::fromRaw($B);
}
}

View file

@ -0,0 +1,140 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Instructions\Arithmetic;
use RTEX\Abstracts\InstructionType;
use RTEX\Classes\InstructionBuilder;
use RTEX\Classes\Utilities;
use RTEX\Engine;
use RTEX\Exceptions\EvaluationException;
use RTEX\Exceptions\InstructionException;
use RTEX\Exceptions\Runtime\TypeException;
use RTEX\Interfaces\InstructionInterface;
class Power implements InstructionInterface
{
/**
* @var mixed
*/
private $A;
/**
* @var mixed
*/
private $B;
/**
* Returns the type of instruction
*
* @return string
*/
public function getType(): string
{
return InstructionType::Power;
}
/**
* Returns an array representation of the instruction
*
* @return array
*/
public function toArray(): array
{
return InstructionBuilder::toRaw(self::getType(), [
'a' => $this->A,
'b' => $this->B
]);
}
/**
* Constructs a new instance of this class from an array representation
*
* @param array $data
* @return InstructionInterface
* @throws InstructionException
*/
public static function fromArray(array $data): InstructionInterface
{
$instruction = new self();
$instruction->setA($data['a'] ?? null);
$instruction->setB($data['b'] ?? null);
return $instruction;
}
/**
* @param Engine $engine
* @return int|float
* @throws TypeException
* @throws EvaluationException
*/
public function eval(Engine $engine): int|float
{
$a = $engine->eval($this->A);
$b = $engine->eval($this->B);
if(!(is_int($a) || is_float($a) || is_double($a)))
throw new TypeException(sprintf('Cannot raise \'A\' to the power of \'B\' because \'A\' is not a number (\'%s\')', Utilities::getType($a, true)));
if(!(is_int($b) || is_float($b) || is_double($b)))
throw new TypeException(sprintf('Cannot raise \'A\' to the power of \'B\' because \'B\' is not a number (\'%s\')', Utilities::getType($b, true)));
return ($a ** $b);
}
/**
* Returns the string representation of the instruction
*
* @return string
*/
public function __toString(): string
{
return sprintf(
self::getType() . ' %s ^ %s',
Utilities::entityToString($this->A),
Utilities::entityToString($this->B)
);
}
/**
* Gets the value of A
*
* @return mixed
*/
public function getA(): mixed
{
return $this->A;
}
/**
* Sets the value of A
*
* @param mixed $A
* @throws InstructionException
*/
public function setA(mixed $A): void
{
$this->A = InstructionBuilder::fromRaw($A);
}
/**
* Gets the value of B
*
* @return mixed
*/
public function getB(): mixed
{
return $this->B;
}
/**
* Sets the value of B
*
* @param mixed $B
* @throws InstructionException
*/
public function setB(mixed $B): void
{
$this->B = InstructionBuilder::fromRaw($B);
}
}

View file

@ -0,0 +1,142 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Instructions\Arithmetic;
use RTEX\Abstracts\InstructionType;
use RTEX\Classes\InstructionBuilder;
use RTEX\Classes\Utilities;
use RTEX\Engine;
use RTEX\Exceptions\EvaluationException;
use RTEX\Exceptions\InstructionException;
use RTEX\Exceptions\Runtime\TypeException;
use RTEX\Interfaces\InstructionInterface;
class Round implements InstructionInterface
{
/**
* @var mixed
*/
private $Value;
/**
* The number of decimal places to round to
*
* @var mixed
*/
private $Precision;
/**
* Returns the type of instruction
*
* @return string
*/
public function getType(): string
{
return InstructionType::Round;
}
/**
* Returns an array representation of the instruction
*
* @return array
*/
public function toArray(): array
{
return InstructionBuilder::toRaw(self::getType(), [
'value' => $this->Value,
]);
}
/**
* Constructs a new instance of this class from an array representation
*
* @param array $data
* @return InstructionInterface
* @throws InstructionException
*/
public static function fromArray(array $data): InstructionInterface
{
$instruction = new self();
$instruction->setValue($data['value'] ?? null);
return $instruction;
}
/**
* @param Engine $engine
* @return float|int
* @throws EvaluationException
* @throws TypeException
*/
public function eval(Engine $engine): int|float
{
$value = $engine->eval($this->Value);
$precision = $engine->eval($this->Precision);
if(!(is_int($value) || is_float($value) || is_double($value)))
throw new TypeException(sprintf('Cannot calculate the round value of a non-numeric value, got %s', Utilities::getType($value, true)));
if(is_null($precision))
return round($value);
if(!(is_int($precision) || is_float($precision) || is_double($precision)))
throw new TypeException(sprintf('Cannot calculate the round value of a non-numeric precision, got %s', Utilities::getType($precision, true)));
return round($value, $precision);
}
/**
* Returns the string representation of the instruction
*
* @return string
*/
public function __toString(): string
{
return sprintf(
self::getType() . ' %s',
Utilities::entityToString($this->Value),
);
}
/**
* Gets the value of A
*
* @return mixed
*/
public function getValue(): mixed
{
return $this->Value;
}
/**
* Sets the value of A
*
* @param mixed $Value
* @throws InstructionException
*/
public function setValue(mixed $Value): void
{
$this->Value = InstructionBuilder::fromRaw($Value);
}
/**
* @return mixed
* @noinspection PhpUnused
*/
public function getPrecision(): mixed
{
return $this->Precision;
}
/**
* @param mixed $Precision
* @noinspection PhpUnused
*/
public function setPrecision(mixed $Precision): void
{
$this->Precision = $Precision;
}
}

View file

@ -0,0 +1,109 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Instructions\Arithmetic;
use RTEX\Abstracts\InstructionType;
use RTEX\Classes\InstructionBuilder;
use RTEX\Classes\Utilities;
use RTEX\Engine;
use RTEX\Exceptions\EvaluationException;
use RTEX\Exceptions\InstructionException;
use RTEX\Exceptions\Runtime\TypeException;
use RTEX\Interfaces\InstructionInterface;
class SquareRoot implements InstructionInterface
{
/**
* @var mixed
*/
private $Value;
/**
* Returns the type of instruction
*
* @return string
*/
public function getType(): string
{
return InstructionType::SquareRoot;
}
/**
* Returns an array representation of the instruction
*
* @return array
*/
public function toArray(): array
{
return InstructionBuilder::toRaw(self::getType(), [
'value' => $this->Value,
]);
}
/**
* Constructs a new instance of this class from an array representation
*
* @param array $data
* @return InstructionInterface
* @throws InstructionException
*/
public static function fromArray(array $data): InstructionInterface
{
$instruction = new self();
$instruction->setValue($data['value'] ?? null);
return $instruction;
}
/**
* @param Engine $engine
* @return int|float
* @throws EvaluationException
* @throws TypeException
*/
public function eval(Engine $engine): int|float
{
$value = $engine->eval($this->Value);
if(!(is_int($value) || is_float($value) || is_double($value)))
throw new TypeException(sprintf('Cannot calculate the square root of a non-numeric \'Value\', got type %s', Utilities::getType($value, true)));
return sqrt($value);
}
/**
* Returns the string representation of the instruction
*
* @return string
*/
public function __toString(): string
{
return sprintf(
self::getType() . ' %s',
Utilities::entityToString($this->Value),
);
}
/**
* Gets the value of A
*
* @return mixed
*/
public function getValue(): mixed
{
return $this->Value;
}
/**
* Sets the value of A
*
* @param mixed $Value
* @throws InstructionException
*/
public function setValue(mixed $Value): void
{
$this->Value = InstructionBuilder::fromRaw($Value);
}
}

View file

@ -0,0 +1,140 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Instructions\Arithmetic;
use RTEX\Abstracts\InstructionType;
use RTEX\Classes\InstructionBuilder;
use RTEX\Classes\Utilities;
use RTEX\Engine;
use RTEX\Exceptions\EvaluationException;
use RTEX\Exceptions\InstructionException;
use RTEX\Exceptions\Runtime\TypeException;
use RTEX\Interfaces\InstructionInterface;
class Subtract implements InstructionInterface
{
/**
* @var mixed
*/
private $A;
/**
* @var mixed
*/
private $B;
/**
* Returns the type of instruction
*
* @return string
*/
public function getType(): string
{
return InstructionType::Subtract;
}
/**
* Returns an array representation of the instruction
*
* @return array
*/
public function toArray(): array
{
return InstructionBuilder::toRaw(self::getType(), [
'a' => $this->A,
'b' => $this->B
]);
}
/**
* Constructs a new instance of this class from an array representation
*
* @param array $data
* @return InstructionInterface
* @throws InstructionException
*/
public static function fromArray(array $data): InstructionInterface
{
$instruction = new self();
$instruction->setA($data['a'] ?? null);
$instruction->setB($data['b'] ?? null);
return $instruction;
}
/**
* @param Engine $engine
* @return int|float
* @throws EvaluationException
* @throws TypeException
*/
public function eval(Engine $engine): int|float
{
$a = $engine->eval($this->A);
$b = $engine->eval($this->B);
if(!(is_int($a) || is_float($a) || is_double($a)))
throw new TypeException(sprintf('Cannot subtract a non-numeric value of \'A\' of type \'%s\'', Utilities::getType($a, true)));
if(!(is_int($b) || is_float($b) || is_double($b)))
throw new TypeException(sprintf('Cannot subtract a non-numeric value of \'B\' of type \'%s\'', Utilities::getType($b, true)));
return ($a - $b);
}
/**
* Returns the string representation of the instruction
*
* @return string
*/
public function __toString(): string
{
return sprintf(
self::getType() . ' %s - %s',
Utilities::entityToString($this->A),
Utilities::entityToString($this->B)
);
}
/**
* Gets the value of A
*
* @return mixed
*/
public function getA(): mixed
{
return $this->A;
}
/**
* Sets the value of A
*
* @param mixed $A
* @throws InstructionException
*/
public function setA(mixed $A): void
{
$this->A = InstructionBuilder::fromRaw($A);
}
/**
* Gets the value of B
*
* @return mixed
*/
public function getB(): mixed
{
return $this->B;
}
/**
* Sets the value of B
*
* @param mixed $B
* @throws InstructionException
*/
public function setB(mixed $B): void
{
$this->B = InstructionBuilder::fromRaw($B);
}
}

View file

@ -0,0 +1,140 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Instructions\Arithmetic;
use RTEX\Abstracts\InstructionType;
use RTEX\Classes\InstructionBuilder;
use RTEX\Classes\Utilities;
use RTEX\Engine;
use RTEX\Exceptions\EvaluationException;
use RTEX\Exceptions\InstructionException;
use RTEX\Exceptions\Runtime\TypeException;
use RTEX\Interfaces\InstructionInterface;
class Sum implements InstructionInterface
{
/**
* @var mixed
*/
private $A;
/**
* @var mixed
*/
private $B;
/**
* Returns the type of instruction
*
* @return string
*/
public function getType(): string
{
return InstructionType::Sum;
}
/**
* Returns an array representation of the instruction
*
* @return array
*/
public function toArray(): array
{
return InstructionBuilder::toRaw(self::getType(), [
'a' => $this->A,
'b' => $this->B
]);
}
/**
* Constructs a new instance of this class from an array representation
*
* @param array $data
* @return InstructionInterface
* @throws InstructionException
*/
public static function fromArray(array $data): InstructionInterface
{
$instruction = new self();
$instruction->setA($data['a'] ?? null);
$instruction->setB($data['b'] ?? null);
return $instruction;
}
/**
* @param Engine $engine
* @return int|float
* @throws EvaluationException
* @throws TypeException
*/
public function eval(Engine $engine): int|float
{
$a = $engine->eval($this->A);
$b = $engine->eval($this->B);
if(!(is_int($a) || is_float($a) || is_double($a)))
throw new TypeException(sprintf('Cannot sum a non-numeric value of \'A\' of type %s', Utilities::getType($a, true)));
if(!(is_int($b) || is_float($b) || is_double($b)))
throw new TypeException(sprintf('Cannot sum a non-numeric value of \'B\' of type %s', Utilities::getType($b, true)));
return ($a + $b);
}
/**
* Returns the string representation of the instruction
*
* @return string
*/
public function __toString(): string
{
return sprintf(
self::getType() . ' %s %s',
Utilities::entityToString($this->A),
Utilities::entityToString($this->B)
);
}
/**
* Gets the value of A
*
* @return mixed
*/
public function getA(): mixed
{
return $this->A;
}
/**
* Sets the value of A
*
* @param mixed $A
* @throws InstructionException
*/
public function setA(mixed $A): void
{
$this->A = InstructionBuilder::fromRaw($A);
}
/**
* Gets the value of B
*
* @return mixed
*/
public function getB(): mixed
{
return $this->B;
}
/**
* Sets the value of B
*
* @param mixed $B
* @throws InstructionException
*/
public function setB(mixed $B): void
{
$this->B = InstructionBuilder::fromRaw($B);
}
}

View file

@ -0,0 +1,158 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Instructions\Base;
use RTEX\Abstracts\InstructionType;
use RTEX\Abstracts\RegexPatterns;
use RTEX\Classes\InstructionBuilder;
use RTEX\Classes\Utilities;
use RTEX\Classes\Validate;
use RTEX\Engine;
use RTEX\Exceptions\EvaluationException;
use RTEX\Exceptions\InstructionException;
use RTEX\Exceptions\Runtime\KeyException;
use RTEX\Exceptions\Runtime\TypeException;
use RTEX\Interfaces\InstructionInterface;
class ArrayGet implements InstructionInterface
{
/**
* The array to read from
*
* @var mixed
*/
private $Array;
/**
* The query to use to read from the array
*
* @var mixed
*/
private $Key;
/**
* The name of the variable to set
*
* @return string
*/
public function getType(): string
{
return InstructionType::ArrayGet;
}
/**
* @return mixed
* @noinspection PhpUnused
*/
public function getArray(): mixed
{
return $this->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);
}
/**
* Returns an array representation of the object
*
* @return array
*/
public function toArray(): array
{
return InstructionBuilder::toRaw(self::getType(), [
'array' => $this->Array,
'key' => $this->Key
]);
}
/**
* @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);
return $instruction;
}
/**
* @param Engine $engine
* @return mixed
* @throws EvaluationException
* @throws KeyException
* @throws TypeException
*/
public function eval(Engine $engine): mixed
{
$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($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;
foreach ($keys as $key)
{
if (is_array($result) && array_key_exists($key, $result))
{
$result = $result[$key];
}
else
{
throw new KeyException(sprintf('Key "%s" does not exist in array (%s)', $key, $key));
}
}
return $result;
}
/**
* @inheritDoc
*/
public function __toString(): string
{
return sprintf(
self::getType() . ' %s[%s]',
Utilities::entityToString($this->Array),
Utilities::entityToString($this->Key)
);
}
}

View file

@ -0,0 +1,184 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Instructions\Base;
use RTEX\Abstracts\InstructionType;
use RTEX\Abstracts\RegexPatterns;
use RTEX\Classes\InstructionBuilder;
use RTEX\Classes\Utilities;
use RTEX\Classes\Validate;
use RTEX\Engine;
use RTEX\Exceptions\EvaluationException;
use RTEX\Exceptions\InstructionException;
use RTEX\Exceptions\Runtime\KeyException;
use RTEX\Exceptions\Runtime\TypeException;
use RTEX\Interfaces\InstructionInterface;
class ArraySet implements InstructionInterface
{
/**
* The array to read from
*
* @var mixed
*/
private $Array;
/**
* The query to use to read from the array
*
* @var mixed
*/
private $Key;
/**
* The value to set the key's value to
*
* @var mixed
*/
private $Value;
/**
* The name of the variable to set
*
* @return string
*/
public function getType(): string
{
return InstructionType::ArraySet;
}
/**
* @return mixed
* @noinspection PhpUnused
*/
public function getArray(): mixed
{
return $this->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
* @throws InstructionException
*/
public function setValue(mixed $value): void
{
$this->Value = InstructionBuilder::fromRaw($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)
);
}
}

View file

@ -0,0 +1,112 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Instructions\Base;
use RTEX\Abstracts\InstructionType;
use RTEX\Classes\InstructionBuilder;
use RTEX\Classes\Utilities;
use RTEX\Engine;
use RTEX\Exceptions\EvaluationException;
use RTEX\Exceptions\InstructionException;
use RTEX\Exceptions\Runtime\NameException;
use RTEX\Exceptions\Runtime\TypeException;
use RTEX\Interfaces\InstructionInterface;
class GetVariable implements InstructionInterface
{
/**
* The name of the variable to select
*
* @var mixed
*/
private $VariableName;
/**
* Returns the type of instruction
*
* @return string
* @see InstructionType
*/
public function getType(): string
{
return InstructionType::GetVariable;
}
/**
* Returns
*
* @return mixed
* @noinspection PhpUnused
*/
public function getVariableName(): mixed
{
return $this->VariableName;
}
/**
* @param mixed $variable
* @throws InstructionException
* @noinspection PhpMissingParamTypeInspection
*/
public function setVariableName($variable): void
{
$this->VariableName = InstructionBuilder::fromRaw($variable);
}
/**
* @param Engine $engine
* @return mixed
* @throws EvaluationException
* @throws NameException
* @throws TypeException
*/
public function eval(Engine $engine): mixed
{
$variable = $engine->eval($this->VariableName);
if(!is_string($variable))
throw new TypeException(sprintf('Expected string, got %s', Utilities::getType($variable, true)));
return $engine->getEnvironment()->getRuntimeVariable($variable);
}
/**
* Returns an array representation of the object
*
* @return array
*/
public function toArray(): array
{
return InstructionBuilder::toRaw(self::getType(), [
'name' => $this->VariableName
]);
}
/**
* Constructs a new GetVariable instruction from an array representation
*
* @param array $data
* @return InstructionInterface
* @throws InstructionException
*/
public static function fromArray(array $data): InstructionInterface
{
$instruction = new self();
$instruction->setVariableName($data['name'] ?? null);
return $instruction;
}
/**
* @inheritDoc
*/
public function __toString(): string
{
return sprintf(
self::getType() . ' %s',
Utilities::entityToString($this->VariableName)
);
}
}

View file

@ -0,0 +1,197 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Instructions\Base;
use RTEX\Abstracts\InstructionType;
use RTEX\Classes\InstructionBuilder;
use RTEX\Classes\Utilities;
use RTEX\Engine;
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
{
/**
* The name of the namespace & method to invoke
*
* @var string
*/
private $Callable;
/**
* The parameters to pass to the method
*
* @var array
*/
private $Parameters;
/**
* If the execution should be stopped after the method has raised an exception
*
* @var bool
*/
private $FailOnError;
/**
* Returns the type of instruction
*
* @return string
*/
public function getType(): string
{
return InstructionType::Invoke;
}
public function __construct()
{
$this->Parameters = [];
$this->FailOnError = false;
}
/**
* @return array
*/
public function toArray(): array
{
return InstructionBuilder::toRaw(self::getType(), [
'callable' => $this->Callable,
'parameters' => $this->Parameters,
'fail_on_error' => $this->FailOnError
]);
}
/**
* Constructs an instruction from an array
*
* @param array $data
* @return InstructionInterface
* @throws InstructionException
*/
public static function fromArray(array $data): InstructionInterface
{
$instruction = new self();
$instruction->setCallable($data['callable'] ?? null);
$instruction->setParameters($data['parameters'] ?? []);
$instruction->setFailOnError($data['fail_on_error'] ?? false);
return $instruction;
}
/**
* Invokes the method and returns the result
*
* @param Engine $engine
* @return mixed
* @throws EvaluationException
* @throws ImportException
* @throws TypeException
*/
public function eval(Engine $engine): mixed
{
$callable = $engine->eval($this->Callable);
$parameters = [];
foreach($this->Parameters as $key => $value)
$parameters[$key] = $engine->eval($value);
if(!is_string($callable))
throw new TypeException(sprintf('Callable must be a string, %s given', Utilities::getType($callable, true)));
$callable = explode('.', $callable);
if(count($callable) !== 2)
throw new ImportException(sprintf('Callable must be in the format of "namespace.method", %s given', $this->Callable));
$namespace = $callable[0];
$method = $callable[1];
return $engine->callMethod($namespace, $method, $parameters);
}
/**
* @return string
* @noinspection PhpUnused
*/
public function getCallable(): string
{
return $this->Callable;
}
/**
* @param string $Callable
*/
public function setCallable(string $Callable): void
{
$this->Callable = $Callable;
}
/**
* @return array
* @noinspection PhpUnused
*/
public function getParameters(): array
{
return $this->Parameters;
}
/**
* @param array $Parameters
* @throws InstructionException
*/
public function setParameters(array $Parameters): void
{
$this->Parameters = InstructionBuilder::fromRaw($Parameters);
}
/**
* @return bool
* @noinspection PhpUnused
*/
public function isFailOnError(): bool
{
return $this->FailOnError;
}
/**
* @param bool $FailOnError
*/
public function setFailOnError(bool $FailOnError): void
{
$this->FailOnError = $FailOnError;
}
/**
* @inheritDoc
*/
public function __toString(): string
{
$parameters = [];
foreach ($this->Parameters as $key => $value)
$parameters[] = $key . ': ' . Utilities::entityToString($value);
$callable = explode('.', Utilities::entityToString($this->Callable));
if(count($callable) !== 2)
{
$namespace = 'unknown';
$method = 'unknown';
}
else
{
$namespace = $callable[0];
$method = $callable[1];
}
$results = sprintf(
self::getType() . ' %s.%s(%s)',
$namespace, $method, implode(', ', $parameters)
);
if(!$this->FailOnError)
$results .= ' #FOE';
return $results;
}
}

View file

@ -0,0 +1,136 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Instructions\Base;
use RTEX\Abstracts\InstructionType;
use RTEX\Classes\InstructionBuilder;
use RTEX\Classes\Utilities;
use RTEX\Engine;
use RTEX\Exceptions\EvaluationException;
use RTEX\Exceptions\InstructionException;
use RTEX\Exceptions\Runtime\TypeException;
use RTEX\Interfaces\InstructionInterface;
class SetVariable implements InstructionInterface
{
/**
* The name of the variable to set
*
* @var mixed
*/
private $Name;
/**
* The value to set the variable to
*
* @var mixed
*/
private $Value;
/**
* The name of the variable to set
*
* @return string
*/
public function getType(): string
{
return InstructionType::SetVariable;
}
/**
* @return mixed
* @noinspection PhpUnused
*/
public function getName(): mixed
{
return $this->Name;
}
/**
* @param mixed $variable
* @throws InstructionException
* @noinspection PhpMissingParamTypeInspection
*/
public function setName($variable): void
{
$this->Name = InstructionBuilder::fromRaw($variable);
}
/**
* @return mixed
*/
public function getValue(): mixed
{
return $this->Value;
}
/**
* @param mixed $value
* @throws InstructionException
* @noinspection PhpMissingParamTypeInspection
*/
public function setValue($value): void
{
$this->Value = InstructionBuilder::fromRaw($value);
}
/**
* Returns an array representation of the object
*
* @return array
*/
public function toArray(): array
{
return InstructionBuilder::toRaw(self::getType(), [
'name' => $this->Name,
'value' => $this->Value
]);
}
/**
* @param array $data
* @return InstructionInterface
* @throws InstructionException
*/
public static function fromArray(array $data): InstructionInterface
{
$instruction = new self();
$instruction->setName($data['name'] ?? null);
$instruction->setValue($data['value'] ?? null);
return $instruction;
}
/**
* @param Engine $engine
* @return void
* @throws EvaluationException
* @throws TypeException
*/
public function eval(Engine $engine): void
{
$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
*/
public function __toString(): string
{
return sprintf(
self::getType() . ' %s VALUE %s',
Utilities::entityToString($this->Name),
Utilities::entityToString($this->Value)
);
}
}

View file

@ -0,0 +1,133 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Instructions\Comparators;
use RTEX\Abstracts\InstructionType;
use RTEX\Classes\InstructionBuilder;
use RTEX\Classes\Utilities;
use RTEX\Engine;
use RTEX\Exceptions\EvaluationException;
use RTEX\Exceptions\InstructionException;
use RTEX\Interfaces\InstructionInterface;
class Equals implements InstructionInterface
{
/**
* @var mixed
*/
private $A;
/**
* @var mixed
*/
private $B;
/**
* Returns the type of instruction
*
* @return string
*/
public function getType(): string
{
return InstructionType::Equals;
}
/**
* Returns an array representation of the instruction
*
* @return array
*/
public function toArray(): array
{
return InstructionBuilder::toRaw(self::getType(), [
'a' => $this->A,
'b' => $this->B
]);
}
/**
* Constructs a new instance of this class from an array representation
*
* @param array $data
* @return InstructionInterface
* @throws InstructionException
*/
public static function fromArray(array $data): InstructionInterface
{
$instruction = new self();
$instruction->setA($data['a'] ?? null);
$instruction->setB($data['b'] ?? null);
return $instruction;
}
/**
* @param Engine $engine
* @return bool
* @throws EvaluationException
*/
public function eval(Engine $engine): bool
{
$a = $engine->eval($this->A);
$b = $engine->eval($this->B);
return ($a === $b);
}
/**
* Returns the string representation of the instruction
*
* @return string
*/
public function __toString(): string
{
return sprintf(
self::getType() . ' %s == %s',
Utilities::entityToString($this->A),
Utilities::entityToString($this->B)
);
}
/**
* Gets the value of A
*
* @return mixed
*/
public function getA(): mixed
{
return $this->A;
}
/**
* Sets the value of A
*
* @param mixed $A
* @throws InstructionException
*/
public function setA(mixed $A): void
{
$this->A = InstructionBuilder::fromRaw($A);
}
/**
* Gets the value of B
*
* @return mixed
*/
public function getB(): mixed
{
return $this->B;
}
/**
* Sets the value of B
*
* @param mixed $B
* @throws InstructionException
*/
public function setB(mixed $B): void
{
$this->B = InstructionBuilder::fromRaw($B);
}
}

View file

@ -0,0 +1,141 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Instructions\Comparators;
use RTEX\Abstracts\InstructionType;
use RTEX\Classes\InstructionBuilder;
use RTEX\Classes\Utilities;
use RTEX\Engine;
use RTEX\Exceptions\EvaluationException;
use RTEX\Exceptions\InstructionException;
use RTEX\Exceptions\Runtime\TypeException;
use RTEX\Interfaces\InstructionInterface;
class GreaterThan implements InstructionInterface
{
/**
* @var mixed
*/
private $A;
/**
* @var mixed
*/
private $B;
/**
* Returns the type of instruction
*
* @return string
*/
public function getType(): string
{
return InstructionType::GreaterThan;
}
/**
* Returns an array representation of the instruction
*
* @return array
*/
public function toArray(): array
{
return InstructionBuilder::toRaw(self::getType(), [
'a' => $this->A,
'b' => $this->B
]);
}
/**
* Constructs a new instance of this class from an array representation
*
* @param array $data
* @return InstructionInterface
* @throws InstructionException
*/
public static function fromArray(array $data): InstructionInterface
{
$instruction = new self();
$instruction->setA($data['a'] ?? null);
$instruction->setB($data['b'] ?? null);
return $instruction;
}
/**
* @param Engine $engine
* @return bool
* @throws EvaluationException
* @throws TypeException
*/
public function eval(Engine $engine): bool
{
/** @noinspection DuplicatedCode */
$a = $engine->eval($this->A);
$b = $engine->eval($this->B);
if (!(is_int($a) || is_float($a)) || is_double($a))
throw new TypeException(sprintf('Cannot compare a non-numeric value \'A\' of type \'%s\'', Utilities::getType($a, true)));
if (!(is_int($b) || is_float($b)) || is_double($b))
throw new TypeException(sprintf('Cannot compare a non-numeric value \'B\' of type \'%s\'', Utilities::getType($b, true)));
return ($a > $b);
}
/**
* Returns the string representation of the instruction
*
* @return string
*/
public function __toString(): string
{
return sprintf(
self::getType() . ' %s > %s',
Utilities::entityToString($this->A),
Utilities::entityToString($this->B)
);
}
/**
* Gets the value of A
*
* @return mixed
*/
public function getA(): mixed
{
return $this->A;
}
/**
* Sets the value of A
*
* @param mixed $A
* @throws InstructionException
*/
public function setA(mixed $A): void
{
$this->A = InstructionBuilder::fromRaw($A);
}
/**
* Gets the value of B
*
* @return mixed
*/
public function getB(): mixed
{
return $this->B;
}
/**
* Sets the value of B
*
* @param mixed $B
* @throws InstructionException
*/
public function setB(mixed $B): void
{
$this->B = InstructionBuilder::fromRaw($B);
}
}

View file

@ -0,0 +1,141 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Instructions\Comparators;
use RTEX\Abstracts\InstructionType;
use RTEX\Classes\InstructionBuilder;
use RTEX\Classes\Utilities;
use RTEX\Engine;
use RTEX\Exceptions\EvaluationException;
use RTEX\Exceptions\InstructionException;
use RTEX\Exceptions\Runtime\TypeException;
use RTEX\Interfaces\InstructionInterface;
class GreaterThanOrEqual implements InstructionInterface
{
/**
* @var mixed
*/
private $A;
/**
* @var mixed
*/
private $B;
/**
* Returns the type of instruction
*
* @return string
*/
public function getType(): string
{
return InstructionType::GreaterThanOrEqual;
}
/**
* Returns an array representation of the instruction
*
* @return array
*/
public function toArray(): array
{
return InstructionBuilder::toRaw(self::getType(), [
'a' => $this->A,
'b' => $this->B
]);
}
/**
* Constructs a new instance of this class from an array representation
*
* @param array $data
* @return InstructionInterface
* @throws InstructionException
*/
public static function fromArray(array $data): InstructionInterface
{
$instruction = new self();
$instruction->setA($data['a'] ?? null);
$instruction->setB($data['b'] ?? null);
return $instruction;
}
/**
* @param Engine $engine
* @return bool
* @throws EvaluationException
* @throws TypeException
*/
public function eval(Engine $engine): bool
{
/** @noinspection DuplicatedCode */
$a = $engine->eval($this->A);
$b = $engine->eval($this->B);
if (!(is_int($a) || is_float($a)) || is_double($a))
throw new TypeException(sprintf('Cannot compare a non-numeric value \'A\' of type \'%s\'', Utilities::getType($a, true)));
if (!(is_int($b) || is_float($b)) || is_double($b))
throw new TypeException(sprintf('Cannot compare a non-numeric value \'B\' of type \'%s\'', Utilities::getType($b, true)));
return ($a >= $b);
}
/**
* Returns the string representation of the instruction
*
* @return string
*/
public function __toString(): string
{
return sprintf(
self::getType() . ' %s >= %s',
Utilities::entityToString($this->A),
Utilities::entityToString($this->B)
);
}
/**
* Gets the value of A
*
* @return mixed
*/
public function getA(): mixed
{
return $this->A;
}
/**
* Sets the value of A
*
* @param mixed $A
* @throws InstructionException
*/
public function setA(mixed $A): void
{
$this->A = InstructionBuilder::fromRaw($A);
}
/**
* Gets the value of B
*
* @return mixed
*/
public function getB(): mixed
{
return $this->B;
}
/**
* Sets the value of B
*
* @param mixed $B
* @throws InstructionException
*/
public function setB(mixed $B): void
{
$this->B = InstructionBuilder::fromRaw($B);
}
}

View file

@ -0,0 +1,141 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Instructions\Comparators;
use RTEX\Abstracts\InstructionType;
use RTEX\Classes\InstructionBuilder;
use RTEX\Classes\Utilities;
use RTEX\Engine;
use RTEX\Exceptions\EvaluationException;
use RTEX\Exceptions\InstructionException;
use RTEX\Exceptions\Runtime\TypeException;
use RTEX\Interfaces\InstructionInterface;
class LessThan implements InstructionInterface
{
/**
* @var mixed
*/
private $A;
/**
* @var mixed
*/
private $B;
/**
* Returns the type of instruction
*
* @return string
*/
public function getType(): string
{
return InstructionType::LessThan;
}
/**
* Returns an array representation of the instruction
*
* @return array
*/
public function toArray(): array
{
return InstructionBuilder::toRaw(self::getType(), [
'a' => $this->A,
'b' => $this->B
]);
}
/**
* Constructs a new instance of this class from an array representation
*
* @param array $data
* @return InstructionInterface
* @throws InstructionException
*/
public static function fromArray(array $data): InstructionInterface
{
$instruction = new self();
$instruction->setA($data['a'] ?? null);
$instruction->setB($data['b'] ?? null);
return $instruction;
}
/**
* @param Engine $engine
* @return bool
* @throws EvaluationException
* @throws TypeException
*/
public function eval(Engine $engine): bool
{
/** @noinspection DuplicatedCode */
$a = $engine->eval($this->A);
$b = $engine->eval($this->B);
if (!(is_int($a) || is_float($a)) || is_double($a))
throw new TypeException(sprintf('Cannot compare a non-numeric value \'A\' of type \'%s\'', Utilities::getType($a, true)));
if (!(is_int($b) || is_float($b)) || is_double($b))
throw new TypeException(sprintf('Cannot compare a non-numeric value \'B\' of type \'%s\'', Utilities::getType($b, true)));
return ($a < $b);
}
/**
* Returns the string representation of the instruction
*
* @return string
*/
public function __toString(): string
{
return sprintf(
self::getType() . ' %s < %s',
Utilities::entityToString($this->A),
Utilities::entityToString($this->B)
);
}
/**
* Gets the value of A
*
* @return mixed
*/
public function getA(): mixed
{
return $this->A;
}
/**
* Sets the value of A
*
* @param mixed $A
* @throws InstructionException
*/
public function setA(mixed $A): void
{
$this->A = InstructionBuilder::fromRaw($A);
}
/**
* Gets the value of B
*
* @return mixed
*/
public function getB(): mixed
{
return $this->B;
}
/**
* Sets the value of B
*
* @param mixed $B
* @throws InstructionException
*/
public function setB(mixed $B): void
{
$this->B = InstructionBuilder::fromRaw($B);
}
}

View file

@ -0,0 +1,141 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Instructions\Comparators;
use RTEX\Abstracts\InstructionType;
use RTEX\Classes\InstructionBuilder;
use RTEX\Classes\Utilities;
use RTEX\Engine;
use RTEX\Exceptions\EvaluationException;
use RTEX\Exceptions\InstructionException;
use RTEX\Exceptions\Runtime\TypeException;
use RTEX\Interfaces\InstructionInterface;
class LessThanOrEqual implements InstructionInterface
{
/**
* @var mixed
*/
private $A;
/**
* @var mixed
*/
private $B;
/**
* Returns the type of instruction
*
* @return string
*/
public function getType(): string
{
return InstructionType::LessThanOrEqual;
}
/**
* Returns an array representation of the instruction
*
* @return array
*/
public function toArray(): array
{
return InstructionBuilder::toRaw(self::getType(), [
'a' => $this->A,
'b' => $this->B
]);
}
/**
* Constructs a new instance of this class from an array representation
*
* @param array $data
* @return InstructionInterface
* @throws InstructionException
*/
public static function fromArray(array $data): InstructionInterface
{
$instruction = new self();
$instruction->setA($data['a'] ?? null);
$instruction->setB($data['b'] ?? null);
return $instruction;
}
/**
* @param Engine $engine
* @return bool
* @throws EvaluationException
* @throws TypeException
*/
public function eval(Engine $engine): bool
{
/** @noinspection DuplicatedCode */
$a = $engine->eval($this->A);
$b = $engine->eval($this->B);
if (!(is_int($a) || is_float($a)) || is_double($a))
throw new TypeException(sprintf('Cannot compare a non-numeric value \'A\' of type \'%s\'', Utilities::getType($a, true)));
if (!(is_int($b) || is_float($b)) || is_double($b))
throw new TypeException(sprintf('Cannot compare a non-numeric value \'B\' of type \'%s\'', Utilities::getType($b, true)));
return ($a <= $b);
}
/**
* Returns the string representation of the instruction
*
* @return string
*/
public function __toString(): string
{
return sprintf(
self::getType() . ' %s <= %s',
Utilities::entityToString($this->A),
Utilities::entityToString($this->B)
);
}
/**
* Gets the value of A
*
* @return mixed
*/
public function getA(): mixed
{
return $this->A;
}
/**
* Sets the value of A
*
* @param mixed $A
* @throws InstructionException
*/
public function setA(mixed $A): void
{
$this->A = InstructionBuilder::fromRaw($A);
}
/**
* Gets the value of B
*
* @return mixed
*/
public function getB(): mixed
{
return $this->B;
}
/**
* Sets the value of B
*
* @param mixed $B
* @throws InstructionException
*/
public function setB(mixed $B): void
{
$this->B = InstructionBuilder::fromRaw($B);
}
}

View file

@ -0,0 +1,133 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Instructions\Comparators;
use RTEX\Abstracts\InstructionType;
use RTEX\Classes\InstructionBuilder;
use RTEX\Classes\Utilities;
use RTEX\Engine;
use RTEX\Exceptions\EvaluationException;
use RTEX\Exceptions\InstructionException;
use RTEX\Interfaces\InstructionInterface;
class NotEquals implements InstructionInterface
{
/**
* @var mixed
*/
private $A;
/**
* @var mixed
*/
private $B;
/**
* Returns the type of instruction
*
* @return string
*/
public function getType(): string
{
return InstructionType::NotEquals;
}
/**
* Returns an array representation of the instruction
*
* @return array
*/
public function toArray(): array
{
return InstructionBuilder::toRaw(self::getType(), [
'a' => $this->A,
'b' => $this->B
]);
}
/**
* Constructs a new instance of this class from an array representation
*
* @param array $data
* @return InstructionInterface
* @throws InstructionException
*/
public static function fromArray(array $data): InstructionInterface
{
$instruction = new self();
$instruction->setA($data['a'] ?? null);
$instruction->setB($data['b'] ?? null);
return $instruction;
}
/**
* @param Engine $engine
* @return bool
* @throws EvaluationException
*/
public function eval(Engine $engine): bool
{
$a = $engine->eval($this->A);
$b = $engine->eval($this->B);
return ($a !== $b);
}
/**
* Returns the string representation of the instruction
*
* @return string
*/
public function __toString(): string
{
return sprintf(
self::getType() . ' %s !== %s',
Utilities::entityToString($this->A),
Utilities::entityToString($this->B)
);
}
/**
* Gets the value of A
*
* @return mixed
*/
public function getA(): mixed
{
return $this->A;
}
/**
* Sets the value of A
*
* @param mixed $A
* @throws InstructionException
*/
public function setA(mixed $A): void
{
$this->A = InstructionBuilder::fromRaw($A);
}
/**
* Gets the value of B
*
* @return mixed
*/
public function getB(): mixed
{
return $this->B;
}
/**
* Sets the value of B
*
* @param mixed $B
* @throws InstructionException
*/
public function setB(mixed $B): void
{
$this->B = InstructionBuilder::fromRaw($B);
}
}

View file

@ -0,0 +1,79 @@
<?php
namespace RTEX\Objects;
use RTEX\Objects\Program\Script;
class Program
{
/**
* The main script of the program to execute
*
* @var Script
*/
private $Main;
/**
* Public Constructor
*/
public function __construct()
{
$this->Main = new Script();
}
/**
* Returns an array representation of the object
*
* @return array
*/
public function toArray(): array
{
return [
'main' => $this->Main->toArray()
];
}
/**
* Constructs a new program from an array representation
*
* @param array $data
* @return Program
*/
public static function fromArray(array $data): Program
{
$program = new Program();
$program->Main = Script::fromArray($data['main']);
return $program;
}
/**
* @return Script
*/
public function getMain(): Script
{
return $this->Main;
}
/**
* Saves the program to a file
*
* @param string $path
* @return void
*/
public function save(string $path): void
{
file_put_contents($path, json_encode($this->toArray()));
}
/**
* Loads a program from a file
*
* @param string $path
* @return Program
*/
public static function load(string $path): Program
{
return self::fromArray(json_decode(file_get_contents($path), true));
}
}

View file

@ -0,0 +1,164 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
namespace RTEX\Objects\Program;
use RTEX\Classes\InstructionBuilder;
use RTEX\Exceptions\InstructionException;
use RTEX\Interfaces\InstructionInterface;
class Script
{
/**
* An array of instructions to execute in order
*
* @var InstructionInterface[]
*/
private $Instructions;
/**
* Public Constructor
*/
public function __construct()
{
$this->Instructions = [];
}
/**
* Adds an instruction to the script and returns the index of the instruction
*
* @param InstructionInterface $instruction
* @return int
*/
public function addInstruction(InstructionInterface $instruction): int
{
return array_push($this->Instructions, $instruction);
}
/**
* Returns the instruction at the specified index
*
* @param int $index
* @return InstructionInterface
*/
public function getInstruction(int $index): InstructionInterface
{
return $this->Instructions[$index];
}
/**
* Returns the number of instructions in the script
*
* @return int
* @noinspection PhpUnused
*/
public function getInstructionCount(): int
{
return count($this->Instructions);
}
/**
* Deletes the instruction at the specified index
*
* @param int $index
* @return void
*/
public function deleteInstruction(int $index): void
{
unset($this->Instructions[$index]);
}
/**
* Replaces the instruction at the specified index
*
* @param int $index
* @param InstructionInterface $instruction
* @return void
* @noinspection PhpUnused
*/
public function replaceInstruction(int $index, InstructionInterface $instruction): void
{
$this->Instructions[$index] = $instruction;
}
/**
* Reorders the instructions in the script
*
* @param int $index
* @param int $newIndex
* @return void
* @noinspection PhpUnused
*/
public function reorderInstruction(int $index, int $newIndex): void
{
$instruction = $this->getInstruction($index);
$this->deleteInstruction($index);
array_splice($this->Instructions, $newIndex, 0, [$instruction]);
}
/**
* Clears all instructions from the script
*
* @return void
*/
public function clear(): void
{
$this->Instructions = [];
}
/**
* Returns an array representation of the object
*
* @return array
*/
public function toArray(): array
{
$instructions = [];
foreach ($this->Instructions as $instruction)
{
$instructions[] = $instruction->toArray();
}
return $instructions;
}
/**
* Constructs a script from an array representation
*
* @param array $data
* @return Script
* @throws InstructionException
*/
public static function fromArray(array $data): Script
{
$script = new Script();
foreach ($data as $instruction)
$script->addInstruction(InstructionBuilder::fromRaw($instruction));
return $script;
}
/**
* @return array|InstructionInterface[]
*/
public function getInstructions(): array
{
return $this->Instructions;
}
/**
* Returns a string representation of the script (for debugging)
*
* @return string
*/
public function __toString(): string
{
$results = [];
foreach ($this->Instructions as $instruction)
$results[] = $instruction->__toString();
return implode("\n", $results);
}
}

70
src/RTEX/RTEX.php Normal file
View file

@ -0,0 +1,70 @@
<?php
namespace RTEX;
use OptsLib\Parse;
class RTEX
{
/**
* The main CLI entry point for the RTEX program
*
* @return void
* @noinspection PhpNoReturnAttributeCanBeAddedInspection
*/
public static function main(): void
{
$args = Parse::getArguments();
$file = $args['path'] ?? $args['p'] ?? null;
if(($args['version'] ?? $args['v'] ?? false))
{
self::displayVersion(true);
}
if($file == null || ($args['help'] ?? $args['h'] ?? false))
{
self::displayHelp(true);
}
exit(0);
}
/**
* Prints the version of the RTEX program and optionally exits the program
*
* @param bool $exit
* @return void
*/
private static function displayVersion(bool $exit=false): void
{
print('RTEX 0.1.0' . PHP_EOL);
if($exit)
{
exit(0);
}
}
/**
* Prints the help menu and optionally exits the program
*
* @param bool $exit
* @return void
*/
private static function displayHelp(bool $exit=false): void
{
print('RTEX - Runtime Execution' . PHP_EOL);
print('Usage: rtex [options] [file]' . PHP_EOL);
print('Options:' . PHP_EOL);
print(' -h, --help Display this help message' . PHP_EOL);
print(' -p, --path Specify the path to the program file' . PHP_EOL);
print(' -v, --version Display the version of RTEX' . PHP_EOL);
if($exit)
{
exit(0);
}
}
}

14
src/RTEX/bin/main Normal file
View file

@ -0,0 +1,14 @@
<?php
require 'ncc';
import('net.nosial.rtex', 'latest');
try
{
\RTEX\RTEX::main();
}
catch(\Exception $e)
{
print($e->getMessage() . PHP_EOL);
exit(1);
}

24
tests/pure_runner.php Normal file
View file

@ -0,0 +1,24 @@
<?php
use RTEX\Classes\InstructionBuilder;
use RTEX\Engine;
use RTEX\Objects\Program;
require 'ncc';
import('net.nosial.rtex', 'latest');
$program = new Program();
$program->getMain()->addInstruction(InstructionBuilder::set('foo', 'bar'));
$program->getMain()->addInstruction(InstructionBuilder::set('bar', 500));
$program->getMain()->addInstruction(InstructionBuilder::set('results',
InstructionBuilder::sum(
500,
InstructionBuilder::get('bar')
)
));
$engine = new Engine($program);
$engine->run();

35
tests/script_builder.php Normal file
View file

@ -0,0 +1,35 @@
<?php
use RTEX\Classes\InstructionBuilder;
use RTEX\Objects\Program;
require('ncc');
import('net.nosial.rtex', 'latest');
$program = new Program();
$program->getMain()->addInstruction(InstructionBuilder::abs(-2));
$program->getMain()->addInstruction(InstructionBuilder::div(2, 2));
$program->getMain()->addInstruction(InstructionBuilder::floor(2.5));
$program->getMain()->addInstruction(InstructionBuilder::mod(2, 2));
$program->getMain()->addInstruction(InstructionBuilder::mul(2, 2));
$program->getMain()->addInstruction(InstructionBuilder::pow(2, 2));
$program->getMain()->addInstruction(InstructionBuilder::round(2.5));
$program->getMain()->addInstruction(InstructionBuilder::sqrt(2));
$program->getMain()->addInstruction(InstructionBuilder::sub(2, 2));
$program->getMain()->addInstruction(InstructionBuilder::sum(2, 2));
$program->getMain()->addInstruction(InstructionBuilder::array_set(["test"=>["foo"=>"bar"]], 'test.foo', 'baz'));
$program->getMain()->addInstruction(InstructionBuilder::array_get(["test"=>["foo"=>"bar"]], 'test.foo'));
$program->getMain()->addInstruction(InstructionBuilder::set('test', 'foo'));
$program->getMain()->addInstruction(InstructionBuilder::get('test'));
$program->getMain()->addInstruction(InstructionBuilder::eq(2, 2));
$program->getMain()->addInstruction(InstructionBuilder::gt(2, 2));
$program->getMain()->addInstruction(InstructionBuilder::gte(2, 2));
$program->getMain()->addInstruction(InstructionBuilder::lt(2, 2));
$program->getMain()->addInstruction(InstructionBuilder::lte(2, 2));
$program->getMain()->addInstruction(InstructionBuilder::neq(2, 2));
print(json_encode($program->toArray(), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL);
print((string)$program->getMain() . PHP_EOL);

72
tests/syntax_parse.php Normal file
View file

@ -0,0 +1,72 @@
<?php
function parseSyntax($syntax) {
// Initialize an empty array to hold the parsed instructions
$instructions = array();
// Split the syntax into an array of tokens
$tokens = preg_split('/[\s,()]+/', $syntax, -1, PREG_SPLIT_NO_EMPTY);
// Get the type of instruction
$type = array_shift($tokens);
$instructions['type'] = $type;
// Initialize an empty array to hold the instruction parameters
$params = array();
// Loop through the tokens
while (!empty($tokens)) {
// Get the next token
$token = array_shift($tokens);
// Check if the token is a key
if (preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $token) && !empty($tokens) && $tokens[0] == ':') {
// Remove the colon
array_shift($tokens);
// Get the value of the key-value pair
$value = array_shift($tokens);
// Check if the value is a string
if (preg_match('/^["\'].*["\']$/', $value)) {
// Strip the quotes from the string value
$value = substr($value, 1, -1);
}
// Add the key-value pair to the instruction parameters
$params[$token] = $value;
} else {
// The token is not a key-value pair.
// Check if the token is a value for the previous key.
$last_key = array_key_last($params);
if ($last_key !== NULL) {
// The token is a value for the previous key.
// Add it to the instruction parameters as an array.
$params[$last_key] = array($params[$last_key], $token);
} else {
// The token is not a value for the previous key.
// Add it as a separate element to the instruction parameters.
$params[] = $token;
}
}
}
// Add the instruction parameters to the instructions array
$instructions['_'] = $params;
// Return the parsed instructions
return $instructions;
}
$syntax = 'equals(1, 2)';
$instructions = parseSyntax($syntax);
print_r($instructions);
$syntax = 'equals(1, get("foo"))';
$instructions = parseSyntax($syntax);
print_r($instructions);
$syntax = 'invoke(namespace: "std", method: "print", continue_on_error: false, params: {"value":"Hello World","second_value":{"type":"get","_":"foo"}})';
$instructions = parseSyntax($syntax);
print_r($instructions);