Skip to content

Wiki Terlang(dev mode)

Marcos Oliveira edited this page Feb 23, 2025 · 3 revisions

Wiki Terlang(dev mode)

This wiki is for those who want to hack Ter/Terlang and implement their own implementations in the language.


Add a new built-in function

Assuming you are going to add a new built-in function named: helloworld() that when called in the script displays the message: Hello, World! in the terminal.

  1. Create a new class in the file: ./terlang/src/Builtin.hpp

Add the class (with initials in capital letters) and inherit publicly from Callable and add the member functions as shown in the example below.

class HelloWorld : public Callable {
public:
int arity() override;
std::any call(Interpreter &interpreter, std::vector<std::any> arguments) override;
std::string toString() override;
}; 
  1. Now create the execution in ./terlang/src/Builtin.cpp

In arity() return the number of arguments that your function needs to receive, in the case of helloworld() there are no arguments, therefore, return 0:

// ------ HelloWorld -----------
int HelloWorld::arity(){
return 0;
}

std::any HelloWorld::call(Interpreter &interpreter, std::vector<std::any> arguments){
if(arguments.size() > (size_t)arity() && interpreter.global != nullptr){
builtinError("exec");
}

std::string hello = "Hello, World!";

return std::any_cast<std::string>(hello); }

std::string HelloWorld::toString(){
return "<function builtin>";
}

Put the logic in call() and always return with std::any_cast, if there is no return, return empty, example: return std::any_cast<std::string>(std::string{});. The other information follows the pattern of this example.

  1. Now in the file: ./terlang/src/Interpreter.cpp add to the constructor of the class Interpreter::Interpreter() as a string the name you want to call in script.ter and define the type for the class you created:
// At the end of all that are already defined
global->define("helloworld", std::shared_ptr<HelloWorld>{}); 
  1. And finally, when executing the member function: std::any Interpreter::visitCallExpr(std::shared_ptr<Call> expr) create a new else if block before the final else, the call:
...
}else if(callee.type() == typeid(std::shared_ptr<HelloWorld>)){ // Builtin
auto builtin = std::make_shared<HelloWorld>();
return builtin->call(*this, arguments);
}else{
...

Recompile and test with the generated binary.

After creating a test file, e.g. main.ter, add this:

auto hello = helloworld()
output(hello)

And run: ter helloworld.ter you should see the phrase: Hello, World!.

Clone this wiki locally