Extensões nativas da linguagem de script - evitando colisões de nomes e sobrecarregando o espaço de nomes de outras pessoas

8

Eu desenvolvi uma linguagem de script pequena e comecei a escrever as primeiras ligações de bibliotecas nativas. Esta é praticamente a primeira vez que escrevo uma extensão nativa para uma linguagem de script, por isso me deparei com um problema conceitual.

Gostaria de escrever um código de cola para bibliotecas populares, para que elas possam ser usadas nessa linguagem e, devido ao design do mecanismo que escrevi, isso é conseguido usando uma matriz de Cs que structdescreve o nome da função visível pelo máquina virtual, juntamente com um ponteiro de função.

Assim, uma ligação nativa é realmente apenas uma variável de matriz global, e agora devo obviamente dar a ela um nome (de preferência bom). Em C, é idiomático colocar as próprias funções em um "espaço para nome", acrescentando um prefixo personalizado aos nomes das funções, como em myscript_parse_source()ou myscript_run_bytecode(). O nome personalizado deve descrever idealmente o nome da biblioteca da qual faz parte. Aqui surge a confusão.

Digamos que estou escrevendo uma encadernação para libcURL. Nesse caso, parece razoável chamar minha biblioteca de extensões curl_myscript_binding, assim:

MYSCRIPT_API const MyScriptExtFunc curl_myscript_lib[10];

Mas agora isso colide com o curlespaço para nome. (Eu até pensei em chamá-lo, curlmyscript_libmas, infelizmente, o libcURL não usa exclusivamente o curl_prefixo - as APIs públicas contêm macros como CURLCODE_*e CURLOPT_*, portanto, presumo que isso também atrapalhe o namespace.)

Outra opção seria declarar como myscript_curl_lib, mas isso é bom apenas enquanto eu for o único que escreve as ligações (já que sei o que estou fazendo com meu espaço para nome). Assim que outros colaboradores começam a adicionar suas próprias ligações nativas, eles agora desorganizam o myscriptespaço para nome. (Eu fiz algumas pesquisas e parece que, por exemplo, a ligação Perl cURL segue esse padrão. Não tenho certeza do que devo pensar sobre isso ...)

Então, como você sugere que eu cite minhas variáveis? Existem diretrizes gerais que devem ser seguidas?

H2CO3
fonte
3
Não há necessidade de globais. Você também pode fornecer uma função em sua API para registrar uma nova extensão, por exemplo, SomeLang_register_extension("curl", "H2CO3", "000.001.000", the_extension)onde the_extensionaponta para alguma estrutura de extensão, mas não é visível globalmente. Seu idioma manteria uma estrutura de dados interna para classificar as extensões por nome, versão e autor.
7163 amon
@ amon Claro, isso também é possível.
H2CO3
Essa resposta pode ser interessante, trata de um assunto diferente, mas explica como as convenções de nomenclatura são derivadas para HTML; Se houver regras semelhantes para idiomas diferentes, pode ser útil escolher uma convenção que atenda às suas necessidades e segui-la.
Rob

Respostas:

2

Bem, realisticamente, não é necessário conter uma matriz global de funções exportadas apenas para torná-las visíveis ao seu ambiente de tempo de execução.

Uma boa pergunta é se o seu ambiente de tempo de execução salva o ponteiro da função e o nome associado a ele.

Sua noção de usar uma matriz global para exportar funções só faz sentido se o seu ambiente de tempo de execução não salvar essas informações, mas presumo que você deve salvá-las para que o ambiente de execução da VM seja executado corretamente.

Um recurso comum que é adicionado à linguagem de script como a sua é a idéia de registrar suas funções .

Essencialmente, você precisa de um meio para armazenar a função exportada ptr e o nome do ponteiro da função exportada que será usada no código do script.

Conheço duas opções que você pode implementar para isso:

  1. Um hashmap que usará o nome da função do lado do script como chave de cadeia e a função ptr como o valor associado a essa chave.

    exported_funcs["do_thing"] = &native_do_thing;

  2. Geralmente usado em linguagens de script de sistemas incorporados, como Pawn, você pode usar os dados do script para armazenar o ponteiro da função. Quando você "registra" a função, itera a tabela de funções exportadas do script e procura o nome em que a função exportada será registrada; Depois de encontrar esse nome, substitua esses dados de script (não o arquivo de script em si, mas os dados de memória de script carregados) e você basicamente armazenou o ponteiro da função nativa.

FuncPtrType **table_entry = get_script_entry_ptr(func_name); *table_entry = func_ptr;

Eu recomendo que, para a segunda opção, você dê à entrada da tabela tamanho suficiente para acomodar o tamanho dos ponteiros de todas as arquiteturas, principalmente a entrada deve ter 8 bytes.

Nergal
fonte