Skip to content

Commit

Permalink
Update README.md and ExtendingElectra.md
Browse files Browse the repository at this point in the history
Rename a variable
  • Loading branch information
DolphyWind committed May 25, 2024
1 parent fcf0236 commit c4e8d7d
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 60 deletions.
78 changes: 25 additions & 53 deletions ExtendingElectra.md
Original file line number Diff line number Diff line change
@@ -1,66 +1,38 @@
## Extending Electra Using C++
You can add your own components to electra using C++ shared libraries.
When the electra interpreter loads a shared library, it looks for two functions:
- `void load(ComponentInformation&)`
- `bool work(std::vector<std::stack<double>>&, Current::Ptr, std::vector<Current::Ptr>&)`
You can add your own components to Electra using C++ shared libraries, also referred as packages.
When the Electra interpreter loads a package, it looks for a single function:
- `void load(std::vector<ComponentInformation>&)`

#### Load Function
The purpose of the `load` function is simple; It takes a reference to a ComponentInformation
object and modifies it. Let's look at an example:
The purpose of the `load` function is simple; It takes a reference to a vector of ComponentInformation
objects and populates it with custom components. Let's look at an example:
```cpp
void load(ComponentInformation& c)
void load(std::vector<ComponentInformation>& components)
{
c.symbol = U'9';
c.directions = {Direction::EAST, Direction::WEST};
c.componentType = ComponentInformation::ComponentType::CLONING;
components.push_back({
.symbol = U'9',
.directions = {Direction::EAST, Direction::WEST},
.componentType = ComponentType::CLONING,
.workFunc = work_9
});
components.push_back({
.symbol = U'η',
.directions = {Direction::EAST, Direction::WEST},
.componentType = ComponentType::CLONING,
.workFunc = work_h
});
}
```
- The `symbol` field is the unicode character representation of the component. It overwrites
- The `symbol` field is the Unicode character representation of the component. It overwrites
any component with the same symbol.
- The `directions` field is a list of supported directions.
- The `componentType` field specifies the component's type. The `componentType` can take
two values: `ComponentInformation::ComponentType::CLONING` or `ComponentInformation::ComponentType::NON_CLONING`.
`NON_CLONING` components do not clone the current after they've done their job, like portals.
And as you may guess, `CLONING` components do clone the current after they've done their job like any other component in electra.
#### Work Function
The `work` function is the function specifies the actual job of the component. It has three parameters
- The first parameter is a reference to the memory of electra.
- The second parameter is a shared pointer to the current that triggered the component
- The third parameter is a vector of currents, if you want to create new currents, you can do so
by pushing new currents to this vector.
If the `work` function returns false, the current gets killed and no cloning occurs.
(Note: If you manually push some currents to the last parameter, they'll still be created)
two values: `ComponentType::CLONING` or `ComponentType::NON_CLONING`. `NON_CLONING` components
do not clone the current after they've done their job, like portals. And as you may guess,
`CLONING` components do clone the current after they've done their job like any other component in Electra.
- The `workFunc` field is the function that gets triggered when a current touches it. If it returns false
the current dies. Its signature should be, `bool(std::vector<std::stack<var_t>>&, Current::Ptr&, std::vector<Current::Ptr>&)`
### Full Example
Let's look at an example to better understand how you can create a custom component:
```cpp
#include "ComponentInformation.hpp"
#include "Current.hpp"
#include "Direction.hpp"
#include <iostream>
//g++ helloworld.cpp -fPIC -shared -o libhelloworld.so
extern "C"
{
// We create a custom component. It supports west and east directions and '5' is its symbol.
// It also clones currents after it's done its work
void load(ComponentInformation& c)
{
c.symbol = U'5';
c.directions = {Direction::EAST, Direction::WEST};
c.componentType = ComponentInformation::ComponentType::CLONING;
}
// The component just prints hello world to the screen
bool work(std::vector<std::stack<var_t>>& stacks, Current::Ptr currentPtr, std::vector<Current::Ptr>& currentVector)
{
std::cout << "hello world\n";
return true;
}
}
```
An example program that uses packages can be found [here](https://github.com/DolphyWind/Electra-Lang/tree/master/examples/HQ9Plus_interpreter).
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,10 @@ To include other files in your code, use quotation marks.
"!foo.ec" 5:12 ? You can always do a force include ?
```

But be careful, files ending with `.dll`, `.so` or `.dylib` will be treated as dynamic components
This behavior depends on your platform, for example, on Windows only the `.dll` files will be treated as dynamic components, on Linux, it is `.so` files
But be careful, files ending with `.dll`, `.so` or `.dylib` will be treated as packages.
This behavior depends on your platform, for example, on Windows only the `.dll` files will be treated as packages, on Linux, it is `.so` files
and on Mac it is the `.dylib` files.
Dynamic components allow you to extend Electra using C++. For more info, click [here](ExtendingElectra.md).
Packages allow you to extend Electra using C++. For more info, click [here](ExtendingElectra.md).

## **Currents**
Currents are instruction pointers in Electra. They all have a direction, a position, a stack that holds visited portals and a stack pointer.
Expand Down
4 changes: 2 additions & 2 deletions examples/HQ9Plus_interpreter/hq9plus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ void load(std::vector<ComponentInformation>& components)
.symbol = U'9',
.directions = {Direction::EAST, Direction::WEST},
.componentType = ComponentType::CLONING,
.workFuncWithStacks = work_9
.workFunc = work_9
});
components.push_back({
.symbol = U'η',
.directions = {Direction::EAST, Direction::WEST},
.componentType = ComponentType::CLONING,
.workFuncWithStacks = work_h
.workFunc = work_h
});
}

Expand Down
2 changes: 1 addition & 1 deletion include/utility/ComponentInformation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,5 @@ struct ComponentInformation
char32_t symbol = U'\0';
std::vector<Direction> directions{};
ComponentType componentType{ComponentType::CLONING};
WorkFunctionWithStacksType workFuncWithStacks;
WorkFunctionWithStacksType workFunc;
};
2 changes: 1 addition & 1 deletion src/Electra.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ void Electra::loadPackage(const fs::path& path, const std::string& filename)

for(auto& ci : componentInfos)
{
auto workFunc = std::bind(ci.workFuncWithStacks, std::ref(m_stacks), std::placeholders::_1, std::placeholders::_2);
auto workFunc = std::bind(ci.workFunc, std::ref(m_stacks), std::placeholders::_1, std::placeholders::_2);

if(ci.componentType == ComponentType::NON_CLONING)
{
Expand Down

0 comments on commit c4e8d7d

Please sign in to comment.