15

Pitch: Carla, a linguagem mais baixo nivel que C?

Quem sou eu?

Meu nome é Lucas Silveira. Tenho 16 anos, e programo desde os 8.

Grande parte do meu tempo de vida, foi na frente de uma IDE. E eu sempre fui apaixonado por linguagens.

Dito isso...

O que é Carla, Morgana e Runa?

Carla, Morgana e Runa são todas "linguagens" criadas por mim. Eu venho trabalhado nisso de forma silenciosa a muito tempo, e vi recentemente projetos de linguagens sendo anunciados aqui, e notei o quão maior é o escopo do meu projeto.

Isso, de forma alguma deve diminuir a conquista dos outros, apenas aumentar um pouco a minha (talvez)

O início

Carla nasceu e foi maturada com o tempo, já usou LLVM como back-end, e até Assembly diretamente. Mas, eu sempre achava ruim isto, e queria ter um "ecosistema" real. Disto, nasceu o Morgana, uma alternativa ao LLVM no qual foi feita para o Carla. Porém com algumas diferenças do LLVM:

  • Compilação rápida (Maior problema do Rust, por exemplo)
  • Fácil acesso à comunidade (Falaremos melhor sobre isso logo)
  • Portabilidade extrema (tal como LLVM, porém oferecendo um back-end complexo)

Extensors

Extensors são "pacotes" no qual você baixa para ter seu código Morgana finalmente transformado em assembly.

E, como você pode baixar um complemento para o Morgana, o ideal era que este complemento fosse fácilmente adaptavel por você, ou por "desenvolvedores enxeridos" e interessados em melhorar a performance de seu projeto.

Para isto, eu decidi usar lua como a linguagem dos extensors. Mas, tive alguns problemas com o Lua 5.4 oficial da PUC-RJ para AARCH64, e, decidi criar o meu interpretador de lua. Com isso, nasce o Runa.

Runa

Runa, nada mais é do que um interpreatdor MINIMALISTA, contendo apenas o que eu julguei necessário para uma linguagem "Basica" como o Lua usado nos extensors. Ele tem um FFI direto com C, compartilhando do mesmo endereço virtual de memória, permitindo comunicação fina entre C e Lua.

Runa também é escrito em Rust, sendo 0 memory-leaks (se bem usado). O que torna Runa uma opção viável para programas embarcados, de hardware altamente limitado.

Além de que, fiz algumas medições básicas comparando o tempo de runtime do Runa, JavaScript e Python.

Rodei o mesmo código (Fibonacci NÃO RECURSIVA de 80) nas 3 linguagens, e obtive:

Runa:
Output: 14472334024676220
em: 0,003s

JavaScript (Node.js):
Output: 14472334024676220
em: 0,033s

Python:
Output: 14472334024676221
em: 0,013s

E, sim, eu também não sei por que o Python deu um resultado diferete, mas vida que segue.

E por que eu deveria conhecer Carla?

Além de Carla ter seu próprio ecosistema, assim como zig, ou clang, Carla tem também o objetivo de ser sério, e não um projeto de brincadeira. Uma sintaxe CONCISA, muito inspirada em C, Rust, Zig e Go.

Sendo, praticamente um wrapper de Assembly (C like), mas, com coisas de qualidade de vida. Como, um "print" de strings estáticas. (puts como statement), e coisas do tipo.

Por exemplo, um Hello, world básico em Carla (que vem quando vocês usam "carla init"), seria:

@_start
void main = () {
    puts "Hello, world";
}

E, sim. você pode baixar e testar o Carla no seu próprio pc.

No repositório oficial (https://github.com/lucasFelixSilveira/carla) vc pode baixar o "./install.sh", e rodar. Será instalado na sua máquina o Carla e o Morgana. (Runa já vem empacotado no Morgana).

Por enquanto, posso garantir o funcionamento do Carla e do Morgana APENAS no Linux. Mas, claro, traremos pro Windows e outras plataformas.

Lembrem-se que Carla é para ser mais baixo nível do que C (em alguns quesitos). Não respeito o padrão de outras linguagens nem mesmo em como estruturei meus compiladores e interpretador. Eu fiz como acho que deve ser feito.

Assim como Go tem a sintaxe que Ken Thompson acha que deve ter, Carla tem a sintaxe que eu acho que deve ter, da forma que eu idealizo uma linguagem ideal. Isto quer dizer, que sim, haverá coisas que só funcionam em X aplicação. (Tal como o puts)

Conclusão

Eu gostaria MUITO que vocês dessem uma olhada no Carla, no Morgana e até no Runa, me passasem um bom feedback do que acham e, claro, deixar uma estrelinha nos repositórios!

Agradeço a atenção!

https://github.com/lucasFelixSilveira/runa
https://github.com/lucasFelixSilveira/morgana
https://github.com/lucasFelixSilveira/carla

Carregando publicação patrocinada...
4

Cara, parabéns. Sério. Você está fazendo um mestrado/doutorado em compiladores sem formalizar. Vi que você é de Minas, então já estou torcendo para te ver no Laboratório de Compiladores do DCC da UFMG fazendo pós junto com a graduação, estilo Artur Avila da computação rs.

Gostei muito dos extensors em Lua/Runa. Isso é uma ideia muito interessante porque transforma codegen em algo hackeável pela comunidade. E me parece ser algo original. Certo? Ou "roubou" essa ideia de algum lugar?

A entrada docs parece arquivo vazio, symlink quebrado ou submodule mal configurado...

Algumas outras perguntas (não é cobrança, é curiosidade real)

  1. Quando você diz que Carla é “mais baixo nível que C”, o que isso significa exatamente? Pergunto porque C já é basicamente assembly portável com tipos e UB de brinde rs. Algo como -nostdlib e __attribute__(()) nativos?

  2. Qual é o modelo de memória da Carla? Você cita "as good as Rust" então existe algum esquema de ownership/borrow/lifetime ou a gestão é manual mesmo?

  3. Codegen via Lua compete direto com o objetivo de "compilação rápida". Tu já mediu Morgana+extensor vs QBE gerando o mesmo asm pro mesmo programa? Se Morgana ganhar, vira paper no SBLP hora. Se perder, sem problemas, ainda é muito defensável pelo ângulo da extensibilidade, mas o pitch muda.

1

Opa! Quem sabe! ksksk

Não, é algo mais original mesmo. Eu tenho mania de acordar no meio da noite com ideias, e começar a fazer. Neste caso, foi uma das raras boas ideias ksksks

Quando digo "mais baixo nível do que C", eu digo:

Carla é pensado para ser apenas um "wrapper" de assembly. Ser o mais próximo e direto possível. Sem muitas abstrações. Apenas algumas de qualidade de vida, como disse.

Sobre -nostdlib, não. Teremos libs std bem trabalhadas.

já o __attribute__, depende. Teremos sim, os atributos do C, mas, de forma mais simples. Isso vai ser consequência da "qualidade de vida do Carla", exemplo:

int32 foo = () naked {
    return 2;
}

int32 main = () {
    return foo();
}

Em relação ao modelo de memória, Carla usará Arenas de memória combado com um defer para desalocação ao pop do escopo.

E sim, também será compatvel com alocação 100% manual, assim como Rust, Zig e C++ são.

string name = arena.alloc(128);
defer arena.dump(name);

-- resto do código

Sobre a performance de compilação, o Runa não faz muitas coisas. Ele é reponsável por adaptar a sintaxe do Assembly para a arquitetura ou assembler específico. Claro, que se o usuário quiser ele pode e deve delegar mais funções ao Runa. Mas nos extensors oficiais é o mínimo possível. Grande parte das coisas processadas em tempo de compilação estão dentro do core C++ do Morgana.

Até o momento não realizei benchmarks, mas tenho absoluta certeza que se o comptime ficar pior em um projeto pequeno, em um grande nunca será pior, o que ainda sim gera vantagem.

Além de que, nos meus testes de performance do Runa (que estes sim eu realizei), o Runa chegava ser até 3x mais rápido em algumas situações do que o Lua oficial. Depois trarei mais dados sobre isto.

Muito obrigado pelo review!

Edit. Sobre as docs, eu removi. Por que ainda não tenho a sintaxe 100% estabelecida. Alguns detalhes MINIMOS ainda estão sendo decididos. Tipo:

  • Devo usar parênteses no if?
  • Devo implementar tipagem "automatica" com auto como C++ ou let?
  • Em caso de ser um let, devo implementa-lo por padrão constante e permiti-lo ser mutável com mut tal como Rust?
  • Quando o tipo é definido em tempo de compilação, devo usar := ou mantenho = ?

Estes são alguns dos exemplos.

2

Legal demais a ideia de arena + defer.

Sobre auto, tenho sentimentos mistos. Ótimo quando o tipo está evidente no RHS, perigoso quando começa a esconder informação. Então talvez isso seja algo que a própria linguagem possa restringir melhor, não só deixar para “code standart". Sobre := vs =, eu tenderia a deixar explícito.

E sobre o “mais baixo nível que C” / “as good as Rust”: eu entendi melhor agora o que você quis dizer, mas eu tomaria bastante cuidado com essas frases. Como marketing elas são fortes, mas em comunidade técnica/científica o pessoal cobra é precisão.

C já é um wrapper para assembly. Mas muita coisa para controlar o binário gerado tipo alinhamento, seções, naked, freestanding fica espalhado entre atributos específicos do compilador, flags e convenções da toolchain. Então talvez a tese da Carla seja pegar essas coisas que em C são meio "escondidas" e tornar elas primitivas de primeira classe. E deixar isso claro para defender a alegação.

Carla tenta ser “mais baixo nível que C” porque torna explícito na linguagem controle que em C fica implícito na toolchain.

Sobre “Good as Rust”, eu evitaria essa formulação. “Good” é subjetivo demais e abre uma guerra religiosa desnecessária, tem gente que nem acha Rust bom rs (yours truly). Rust só é "bom" porque entrega segurança de memória sem GC.

Carla oferece segurança de memória por arenas e escopos sem trazer toda a complexidade do modelo de ownership do Rust.

Isso é uma promessa técnica bem mais precisa e talvez até mais interessante.

E a melhor dica que posso te dar: não subestime documentação. Não deixa para documentar só quando “a sintaxe estiver pronta”, porque linguagem nunca fica pronta (C++ está aí para provar). Vai deixando a documentação evoluir junto com a implementação. Mesmo que seja provisório, escreva design docs. No mínimo vão te ajudar a pensar melhor.

1

Ótimos colamentos sobre o "auto", levarei em consideração!

E sobre o “mais baixo nível que C” / “as good as Rust”: eu entendi melhor agora o que você quis dizer, mas eu tomaria bastante cuidado com essas frases. Como marketing elas são fortes, mas em comunidade técnica/científica o pessoal cobra é precisão.

Eu pretendo ainda mudar um pouco essa proposta para deixar mais clara, você não é a primeira que comentou sobre isto. E, vocês estão certos. é muito genérico. Não diz muito sobre a proposta da linguagem, e pode soar como a nomenclatura usada por você: "Marketing forte."

C já é um wrapper para assembly. Mas muita coisa para controlar o binário gerado tipo alinhamento, seções, naked, freestanding fica espalhado entre atributos específicos do compilador. [...]

Este é apenas um dos pontos que quero mudar. Eu não vejo por que termos structs que a ordem dos campos altera a quantidade de bytes ocupados na stack. Não vejo por que termos tanta abstração em cima de estruturas de dados. Tudo deve ser "raw" em Carla.

E, claro, mantendo a tão dita "qualidade de vida do Rust/C++".

Sobre “Good as Rust”, eu evitaria essa formulação. “Good” é subjetivo demais e abre uma guerra religiosa desnecessária, tem gente que nem acha Rust bom rs (yours truly). Rust só é "bom" porque entrega segurança de memória sem GC.

Na verdade, como dito, isso será mudado. Mas, o "Good as Rust" quer dizer:

Não te deixar ser burro tal como Rust. Segurança de memória implementada de forma nativa ao máximo possível, mas que não afetará a sua responsabilidade de "assegurar" a segurança do seu código. Tal como C++, por exemplo.

A oferta de alocadores customizados em Rust, e a simplicidade da criação destes alocadores também são algo que pretendo trazer par ao Carla.

E a melhor dica que posso te dar: não subestime documentação. Não deixa para documentar só quando “a sintaxe estiver pronta”, porque linguagem nunca fica pronta (C++ está aí para provar). Vai deixando a documentação evoluir junto com a implementação. Mesmo que seja provisório, escreva design docs. No mínimo vão te ajudar a pensar melhor.

Não irei. Ainda não esta implementada pelos motivos que eu te citei acima, mas ainda há mais um: O projeto está migrando da fase "imatura", para a fase "matura", agora. E isto não foi minha prioridade agora. Eu estava focado na compatibilidade com Windows até ontem.


Ainda não consegui distinguir quais pronomes usar para você, usei o feminino, peço desculpas caso não seja uma mulher. (O username me parece mais feminino)

1

Gostei muito dos extensors em Lua/Runa. Isso é uma ideia muito interessante porque transforma codegen em algo hackeável pela comunidade.

Só de curiosidade, vale dizer que o GCC e o Clang suportam plugins:

Ah, e meio que o -nostdlib é nativo de C porque a especificação determina os ambientes freestanding e hosted, onde freestanding não tem libc. Então já é nativo da especificação da linguagem um ambiente sem libc. Eu explico melhor isso aqui:

1

Sim, tenho ciência disto, e entendo que tenha feito uma correlação entre ambos. Então, esta minha resposta nem é muito direcioanda à ti, mas sim pessoas "de fora" que lerem isto:

A enorme diferneça entre os Plugins do GCC/Clang e os Extensors do Morgana, é:

Morgana não tem "comportamente padrão" quando se trata no codegen. Tudo é customizado.

GCC/Clang tem. Mas, coisas podem ser modificadas.

1

Acho que meu comentário foi interpretado errado. Eu estava respondendo isso:

[...] porque transforma codegen em algo hackeável pela comunidade.

Os plugins do GCC/Clang tornam codegen hackeável pela comunidade, não quis dizer que eram a mesma coisa que os Extensors no seu projeto.


Não entenda como uma crítica, mas sugiro observar qual comentário responde quem. Eu não estava falando com você, mas você respondeu como se eu estivesse.

Não é uma crítica, é só que se você achar que todo comentário no seu post é para você, você vai interpretar errado o comentário.

2

Achamos que, em primeiro lugar, o projeto precisa ser um pouco mais profissional, evitando coisas assim: https://github.com/lucasFelixSilveira/carla/blob/main/src/main.crl#L4, seguido o que você mesmo disse sobre ser um projeto que não é brincadeira.

Tentamos ler a documentação, e tivemos um 404: https://github.com/lucasFelixSilveira/carla/blob/main/docs, ou https://github.com/lucasFelixSilveira/carla/blob/main/docs/carla.md. Não há exemplos de código em qualquer parte do projeto. Não há testes unitários em nenhum dos três componentes. O parser de Carla é tão pequeno que não podemos ter certeza de que funciona ou não.

Se funciona no Linux, funciona em Mac e BSD. É algo que você poderia facilmente terminar.

LLVM tem suas virtudes. Dezenas de arquiteturas de processador, sistemas operacionais, imensa interoperabilidade. São mais de 500 mil commits e mais de 5000 colaboradores. Seu projeto precisa fazer a lição de casa: ter CI/CD em cada projeto, documentação mais extensa, código curado, sem renomear arquivos indesejados pra .txt ou coisa do tipo. Temos interesse de acompanhar, mas ainda não vimos todo o diferencial prometido aqui.

2

Fala "pessoal"! (Creio que seja um grupo dono do perfil)

Seguinte, vou passar ponto à ponto para não deixar passar nada!

Achamos que, em primeiro lugar, o projeto precisa ser um pouco mais profissional, evitando coisas assim: https://github.com/lucasFelixSilveira/carla/blob/main/src/main.crl#L4, seguido o que você mesmo disse sobre ser um projeto que não é brincadeira.

Carla está migrando agora de uma etapa "Não profissional" para "Profissional". Estou adaptando o projeto em um todo. Alguns detalhes, tal como o "main.crl" acabam passando da fase de coding para o repositório. Irresponsabilidade de não revisar o diff das mudanças antes de commitar. Esse tipo de coisa acabará em breve, podem ficar tranquilos.

Tentamos ler a documentação, e tivemos um 404: https://github.com/lucasFelixSilveira/carla/blob/main/docs, ou https://github.com/lucasFelixSilveira/carla/blob/main/docs/carla.md. Não há exemplos de código em qualquer parte do projeto. Não há testes unitários em nenhum dos três componentes. [...]

Ainda não trabalhamos na documentação, e isto é sim um problema. Alguns mínimos detalhes estão sendo decididos ainda. E, eu entendo sim que o projeto deve ter uma documentação ao menos com o que já está implementado. Mas, novamente, ainda não foi a prioridade. Estava até ontem, focando na compatibilidade com Windows. Agora sim esse tipo de coisa entrará como prioridade.

Testes unitários estão sendo desenvolvidos. Estou trabalhando no "Mari", um "cmake" da vida, compatível com Carla e que também terá o papel de cuidar dos testes unitários.

[...] O parser de Carla é tão pequeno que não podemos ter certeza de que funciona ou não.

Este é mais um dos diferenciais do Carla. O Parser é realmente simples, ele é composto por 2 tipos de "nodes", Common e Block.

Mas, O parser do Carla tem uma chamada de um "pattern checker" externo ao parser.hpp.
Lá sim o parser "cresce". Ainda bem incompleto, com certeza. Mas permite maior facilidade para implementar novas keywords, statements, etc.

O core do Carla é sim pequeno ainda, pois para ele crescer, o do Morgana também deve crescer. Isso é o único "gap" que tomamos por essa escolha de abandonar o LLVM.

Se funciona no Linux, funciona em Mac e BSD. É algo que você poderia facilmente terminar.

Sim, com certeza. Mas meu objetivo é garantir uma compatibilidade mais ampla entre diferentes sistemas.

Eu entendo que eu poderia sim usar a libc internamente para me facilitar a gerar código de máquina, mas, não é um opção que vejo como plausível. Para mim, Morgana deve gerar código como cada sistema operacional espera nativamente. Respeitando ABIs, syscalls e convenções específicas.

Em vez de depender da libc como abstração comum, prefiro tratar cada plataforma de forma explícita.

Como o foco do Carla também inclui aplicações de baixo nível, essa abordagem faz sentido: reduz camadas intermediárias e tende a oferecer um comportamento mais previsível e consistente entre os sistemas, na maioria dos casos.

LLVM tem suas virtudes. Dezenas de arquiteturas de processador, sistemas operacionais, imensa interoperabilidade.

Estarei ativamente trabalhando em inovações para o Morgana. Nem por um dia o projeto ficará parado. Mesmo que não haja commit, pode ter certeza que alguma ideia estará sendo bolada.

Documentação mais extensa, código curado, sem renomear arquivos indesejados pra .txt ou coisa do tipo. Temos interesse de acompanhar, mas ainda não vimos todo o diferencial prometido aqui.

Já tocamos neste ponto, mas pretendo retomar novamente para deixar claro novamente, o projeto ainda está migrando para "a fase de maturidade". Faremos o dever de casa o mais cedo possível.

1

Opa, Lucas! Tudo bem? Primeiramente queria dizer que adorei teu post e queria te parabenizar por essas 3 linguagens, tu certamente é um programador diferenciado.

Mas analisando esse problema de diferença entre o resultado de Runa, JavaScript e Python, acredito que eu saiba qual é o problema:

Seu fibonacci(80) na verdade é um fibonacci(79) pelo que percebi (mas isso não tem nenhum problema, só depende se você considera ou não o primeiro número na implementação).

O fibonacci(79) resulta em 4472334024676221, ou seja, o Python tá certo.

Talvez o fato de que JavaScript e Runa apresentarem o mesmo resultado seja a maneira de como eles lidam com números.

No JavaScript, quando você define um valor numérico (mesmo se for inteiro) ele é um "Number", que na prática é um float64/double e quando esse valor cresce demais você não consegue mais trabalhar com ele e precisa trabalhar com BigInt.

Usando declarações de número com sufixo "n" ele entende que eles são BigInt. Ex.: const num = 88n

Já o Python funciona de uma maneira diferente. Quando tu define um número inteiro no Python ele usa uma lógica de "big integers" automática, sempre que o valor cresce ele aumenta a capacidade sozinho.

Talvez Python tenha abordado dessa forma porque a linguagem tem um foco na simplicidade e na ergonomia.

Olhando para os resultados, talvez a tua linguagem implemente isso de uma maneira semelhante ao JavaScript.

Era apenas isso. Novamente, adorei seu post e te desejo sucesso na área!

2

Sim, eu não tinha parado para pensar nisto. Entendi.

Runa trata inteiros e floats ambos como Floats durante operações, faz sentido.

Não tinha me lembrado disto.

Já sobre a fib de 79, eu não faço ideia de como se programar Python, então pedi pro GPT gerar os 3 códigos (o que até foi bom para testar a compatibilidade do Runa com o Lua conhecido). Não observei se havia problemas diretamente com o código gerado! Devia ter checado!

De qualquer forma, não cometerei mais estes deslizes.

1

Vc quer conhecer uma linguagem "baixo nível", dá uma olhada no 4th (forth). Já fiz um joguinho de pong que o executável tinha 920 bytes :-) Parabéns pelo esforço, eu comecei com 11 anos.

1
1

Que legal, muito top!
Estou fazendo curso técnico e comecei a ter contato com programação no ano passado,2025, (comecei em C). Gostaria muito de conseguir fazer coisas como essas, mas não sei exatamente o que estudar e como aplicar diretamente.
Se for possível, gostaria de uma ajuda nesse sentido :)
(Talvez uma direção)
Tenho 16 anos.
Obrigado,

1
1

Bacana, melhor maneira de testar algo é jogar pra testes e debate.

Vc parece ser mt melhor do que eu em arquitetura de linguagens de maquina. Mas uma coisa que só vem com mais idade é a capacidade de não pegar ar com as críticas. Não parece ser o seu caso, mas olhando como vc quis responder todos os comentarios (incluindo os que não eram com vc) lembrei de mim mais novo, debatendo teses apaixonadas em foruns e grupos de amigos.

A gente ama instruir maquinas a fazer as coisas da forma que queremos, mas com avanço da i.a. eu percebi que codar na mão, msm q em side projects ficou algo lento de mais. Mais e mais incerteza sobre futuro da programa me fez perceber que precisava cobrir outros gaps pra ser relevante profissionalmente...

O que quero dizer é que é mt bom que tenha algo q vc ama mt. Mas não passe a maior parte da sua vida na frente de uma ide. Vc estará limitando o potencial de vida que vc tem. Vc é mt novo... Sucesso na vida.