Pular para o conteúdo

Arquitetura do runtime

Como o interpretador funciona por dentro.

O fluxo#

text
arquivo.df → tokenize() → parse() → check_program() → Interpreter().run(ast)
             lexer.py     parser.py  typechecker.py   interpreter.py

Os componentes#

ArquivoResponsabilidadeLinhas
tokens.pyTokenType e as 81 palavras reservadas305
lexer.pytexto → tokens, INDENT/DEDENT, interpolação556
parser.pyrecursivo descendente: tokens → AST1941
ast_nodes.pynós da AST como dataclasses706
interpreter.pyinterpretador de árvore — a semântica2703
typechecker.pyanálise estática1193
formatter.pydataforge fmt280
linter.pydataforge lint394
testrunner.pydataforge test194
docgen.pydataforge doc218
project.pyforge.toml184
environment.pycadeia de escopos91
errors.pyerros, sinais de controle, stack traces167
builtins.py225 funções globais1224
repl.pyconsole interativo409
cli.pya linha de comando1055
stdlib/os 20 módulos Arcane.*7282

Despacho por nome de classe#

O interpretador não usa match nem tabela: ele monta o nome do método a partir do tipo do nó.

text
# um nó GivenBlock procura exec_GivenBlock
# uma expressão BinaryOp procura eval_BinaryOp

Isso significa que adicionar um recurso à linguagem toca cinco lugares: tokens.py (se houver palavra nova), lexer.py, ast_nodes.py + parser.py, interpreter.py e typechecker.py.

O executor preguiçoso#

Generators precisam entregar cada valor no instante em que emit o produz — inclusive dentro de um laço infinito. Um interpretador de árvore comum não consegue pausar no meio.

A solução é um executor paralelo (_lazy_block) que percorre o corpo de um stream action como gerador Python: ele desce nas estruturas onde emit pode aparecer e delega o resto ao execute() normal.

dataforge
stream action fib():
    a := 0
    b := 1
    persist yes:           # não trava: cada emit pausa
        emit a
        a, b := b, a + b

Escopos#

Cada bloco cria um Environment filho. Buscar um nome sobe a cadeia até o global. steady marca o nome no conjunto de constantes daquele escopo; shadow força a criação local.

Sem dependências#

O runtime usa apenas a biblioteca padrão do Python. Isso é uma restrição de projeto, não uma limitação temporária: garante que um programa DataForge roda em qualquer máquina com Python 3.10+.

O que ainda não existe#

É um interpretador de árvore, sem bytecode e sem otimização. Uma IR e uma VM de pilha estão no roadmap, mas nenhum usuário reclamou de desempenho ainda — e medir antes de otimizar é a regra.