Como 'hackear' a linguagem de programação Ter/Terlang

🚀 Incorporar suas próprias funções diretamente via código-fonte com C++


Como 'hackear' a linguagem de programação Ter/Terlang


Quando eu criei a linguagem de programação Ter/Terlang uma das coisas que eu queria que ela tivesse era justamente: a facilidade de poder hackear a linguagem e incorporar funções embutidas pelo programador.

Ou seja, você pode criar suas próprias funções nativas. Isso vai ser interessante quando eu começar a incorporar bibliotecas, principalmente de GameDev, como: SFML, SDL, Raylib e entre outras para ser utilizada pela Ter/Terlang.

Nesse exemplo vamos criar a função nativa: helloworld(), ou seja, ao imprimir essa função, deve exibir a mensagem: Hello, World!.

No momento se você criar um arquivo helloworld.ter e tentar fazer isso:

output(helloworld())

Após rodar: ter helloworld.ter, a saída será um erro:

[line 1] Error: Undefined variable: 'helloworld'.

Então, vamos modificar o código-fonte para que isso funcione!


Procedimento

Basta seguirmos 3 passos básicos para esse feito.

01. Antes de mais nada você precisa clonar

E entrar no projeto:

git clone https://github.com/terroo/terlang
cd terlang

02. Agora vamos editar o arquivo: ./src/Builtin.hpp

E adicionar ao final do arquivo o código abaixo:

class HelloWorld : public Callable {
    public:
        int arity() override;
        std::any call(Interpreter &interpreter, std::vector<std::any> arguments) override;
        std::string toString() override;
}; 

Todas as funções precisam herdar Callable de forma pública. As funções-membro: arity(), call() e toString() são o modelo para todas as funções que serão embutidas e precisam ser públicas.

03. Depois precisamos criar a execução para as funções-membro da classe HelloWorld que adicionamos.

Edite o arquivo ./src/Builtin.cpp e insira ao final do arquivo o conteúdo abaixo:

// ------ 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("helloworld");
    }

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

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

std::string HelloWorld::toString(){
    return "<function builtin>";
}
  • A função-membro arity() precisa retornar a quantidade de argumentos que ela recebe, como a função helloworld() não recebe nenhum argumento, retornamos zero, se fosse, por exemplo, uma função de nome add(x, y) recebe 2 argumentos, logo, precisaríamos retornar return 2;

  • A função-membro call() precisa sempre haver esse if inicial para verificar a quantidade de argumentos. Todos os retornos precisam ser transformados em std::any com std::any_cast, como queremos que retorne uma string então convertemos para std::string que será a frase que será exibida.

  • E por final toString() sempre deve possuir esse conteúdo para mapearmos o tipo de erro e saber que a falha na verdade é nesse tipo de função.

04. Adicionar helloworld ao mapa da Terlang

Agora vamos editar o arquivo: ./src/BuiltinFactory.cpp e adicionar AO FINAL DOS MAPAS builtinFactory e builtinNames o contexto. Com a sintaxe abaixo informe o nome da classe da sua função embutida, nesse caso: HelloWorld:

Lembre que na linha acima dela, precisa ADICIONAR UMA VÍRGULA: , ao final da linha para mostrar que possuímos um novo elemento.

{typeid(std::shared_ptr<HelloWorld>), [](){ return std::make_shared<HelloWorld>(); }}

E fazer o mesmo em builtinNames, o primeiro elemento desse mapa é o nome que você deseja chamar no seu arquivo .ter, nesse caso chamamos ela de "helloworld" mesmo:

{"helloworld", typeid(std::shared_ptr<HelloWorld>)}

Tudo certo agora basta compilar e testar:

# rm -rf build/ se já tiver construído uma vez, pois o CMake pode usar o cache
cmake -B build .
cmake --build build

Crie o arquivo de teste: helloworld.ter:

auto hello = helloworld()
output(hello)

Nesse caso, fizemos diferente do arquivo acima, armazenamos o retorno de helloworld() na variável hello, mas você também pode imprimir diretamente caso queira: output(helloworld())

E rode:

./build/ter helloworld.ter

A saída será: Hello, World!

Se quiser que fique disponível para seu sistema é só instalar: sudo cmake --install build/.


Bem simples, né?! Esse procedimento está disponível na Wiki.

Para mais informações acesse o repositório: https://github.com/terroo/terlang/.

Aprenda a criar sua própria linguagem de programação com nosso Curso:

https://terminalroot.com.br/mylang


ter terlang programacao


Compartilhe


Nosso canal no Youtube

Inscreva-se


Marcos Oliveira

Marcos Oliveira

Desenvolvedor de software
https://github.com/terroo


Crie Aplicativos Gráficos para Linux e Windows com C++

Aprenda C++ Moderno e crie Games, Programas CLI, GUI e TUI de forma fácil.

Saiba Mais

Receba as novidades no seu e-mail!

Após cadastro e confirmação do e-mail, enviaremos semanalmente resumos e também sempre que houver novidades por aqui para que você mantenha-se atualizado!