Todo programador tem um sonho - criar sua própria linguagem de programação. O melhor e o mais conveniente, é claro - não como os existentes. Para mim, pessoalmente, a idéia da correção era criar uma linguagem na qual não houvesse absolutamente nenhum clichê, o mais curto possível, mas extremamente eloquente. Por dois anos, tenho tentado alcançar o resultado desejado, mas onde quer que comece, no final, depois de cortar tudo o que era supérfluo, sempre recebi o Lisp. E então um pensamento engenhoso me ocorreu - tomar Lisp e melhorá-lo de acordo com minhas idéias. Em homenagem à primeira coisa que chamou minha atenção, o projeto foi nomeado Sova.
Para tornar o idioma pronto para uso no servidor, na web e nas plataformas móveis, decidi compilá-lo em Javascript, que, na minha opinião, é apenas uma das linguagens mais bem projetadas de nossa época e, mais importante, possui um poderoso ecossistema npm, Node.js, React e React Native.
E antes de iniciar nossa jornada, para despertar interesse imediato em ler mais o artigo, aqui está um exemplo de um arquivo de aplicativo Express no Sova:
=-> './database' database =-> 'express' express = application express () application.get '/' -> (request response) (response.sendStatus 200) application.get '/user/:id' -> (request response) (response.send (database.getUserById request.params.id)) application.listen 8080 -> () (console.log 'Application is listening on port 8080')
Bem, vamos começar ...
Etapa 1: retirar parênteses do Lisp usando recuo do Python

Embora essa história em quadrinhos me faça sorrir toda vez que a olho, discordo completamente de sua afirmação principal. Os suportes não são elegantes; os suportes são padronizados.
Portanto, a primeira coisa na minha maravilhosa linguagem que decidi me livrar dos colchetes. A melhor solução foi o recuo relevante, assim como no Python. Tomemos, por exemplo, uma parte do código lisp:
(* 2 (+ 1 2) (- 4 (/ 2 1)))
É claro que essa expressão pode se espalhar em linhas diferentes, mas isso não nos livra da palhaçada dos olhos entupidos.
(* 2 (+ 1 2) (- 4 (/ 2 1)))
Agora vamos ver o quão elegante e arejada é possível escrever a mesma expressão em Sova com a ajuda de um recuo significativo:
* 2 + 1 2 - 4 (/ 2 1)
Ou seja, em Sova, a expressão a (bc) (d (ef))
equivalente à expressão:
a bc d ef
Etapa 2: tornar o idioma conciso
O que eu não gostei na maioria das linguagens de programação foi o entupimento da sintaxe sem nada significativo, mas ocupando um lugar na tela com um clichê - palavras-chave extras, sinais de pontuação sem sentido e muitos outros. Mesmo no lisp comum, em vez de caracteres simples e compreensíveis, as palavras são frequentemente usadas para denotar operações simples, como a mesma defn
.
Declaração de Constantes
Tomemos, por exemplo, a declaração de uma constante em Javascript:
const a = 1
O Sova é uma linguagem extremamente funcional e todas as variáveis são imutáveis, portanto, você não precisa especificar uma palavra-chave adicional const, mas tudo é escrito simplesmente:
= a 1
Funções
O elemento central de qualquer linguagem é a função. Tão minimalistas que parecem em Sova:
= addOne -> number + number 1 = doubleAndAddOne -> number = doubled (* number 2) addOne doubled console.log (doubleAndAddOne 2)
Como em qualquer linguagem funcional, a última expressão no corpo da função é retornável. Ou seja, o código acima no JavaScript compilado será semelhante a:
const addOne = number => { return number + 1 } const doubleAndAddOne = number => { const doubled = number * 2 return addOne(doubled) } console.log(doubleAndAddOne(2))
Comparações e condições
Uma expressão condicional no Sova pode ter dois ou um argumento.
Aqui estão exemplos de condições que possuem dois argumentos:
console.log ? true 1 0 console.log ? (> 2 1) 'Greater' 'Less' console.log ? (> 2 1) ? (> 1 2) 'x' 'y' 'z'
E aqui, por exemplo, na função checkNumber, retornamos valores por condição:
= checkNumber -> number ? (=== number 1) (<- 'One') ? (=== number 2) (<- 'Two') ? (<= number 9) (<- 'From three to nine') 'Ten or more' console.log (checkNumber 1) console.log (checkNumber 4) console.log (checkNumber 11)
No JavaScipt compilado, ele se parece com:
const checkNumber = number => { if (number === 1) return 'One' if (number === 2) return 'Two' if (number <= 9) return 'From three to nine' return 'Ten or more' } console.log(checkNumber(1)) console.log(checkNumber(4)) console.log(checkNumber(11))
Colecções
Matriz
A coleção principal de qualquer idioma é uma matriz. É assim que a declaração e a desconstrução da matriz são exibidas no Sova:
= list | 1 2 3 4 console.log list console.log list.map (-> x (+ x 1)) = (| first second) list console.log first console.log second
No JavaScript compilado, será semelhante a:
const list = [1, 2, 3, 4] console.log(list) console.log(list.map(x => x + 1)) const [first, second] = list console.log(first) console.log(second)
Object
A segunda coleção mais importante é o hashmap. Em Sova, o anúncio e a desconstrução do mapa são assim:
= map : a 1 b 2 c : d 3 e 4 f 'Hello' console.log map = (: a (c (: de))) map console.log a console.log d console.log e
No JavaScript compilado, fica assim:
const map = { a: 1, b: 2, c: { d: 3, e: 4 }, f: 'Hello' } console.log(map) const { a, c: { d, e }} = map console.log(a) console.log(d) console.log(e)
Se queremos chamar um método em um objeto, existem duas maneiras de fazer isso. Podemos chamá-lo como object.method parameter1 parameter2
ou como .method object parameter1 parameter2
. O segundo método nos permite criar uma cadeia de chamadas de método.
Módulos de importação e exportação
Importar
Você pode importar módulos para o código Sova de outros arquivos .sv
e de arquivos .js
. Por exemplo, neste exemplo, dois módulos são importados - data/index.js
e handler/index.sv
:
=-> './data' (: greeting name) =-> './handler' handle handle greeting name
No JavaScript compilado, fica assim:
const { greeting, name } = require('./data') const handle = require('./handler') handle(greeting, name)
A importação dos módulos JavaScript e Sova torna possível integrar levemente o Sova em um projeto Javascript existente.
Exportar
Neste exemplo, a função é exportada do módulo:
<-= -> (greeting name) console.log greeting console.log name
No JavaScript compilado, fica assim:
module.exports = (greeting, name) => { console.log(greeting) console.log(name) }
Exemplos de uso
Para ver toda a beleza, leveza e concisão de Sova, você precisa observar um programa mais ou menos grande. Por exemplo, aqui está um programa que calcula a idade média das pessoas e localiza o nome da pessoa cuja idade é a mais próxima da idade média.
=-> 'lodash' _ = people | : (name 'Alice') (age 24) : (name 'Bob') (age 15) : (name 'Chris') (age 46) : (name 'Daniel') (age 35) : (name 'Elisabeth') (age 29) : (name 'Fred') (age 52) = averageAge / .reduce (.map people (-> man man.age)) -> (xy) (+ xy) 0 .length people = manWithClosestToAverageAge _.minBy .map people (-> man (: (name man.name) (distance (Math.abs (- averageAge man.age))))) 'distance' console.log averageAge console.log manWithClosestToAverageAge.name
Devido ao fato de a linguagem ser compilada em JavaScript, o desenvolvimento para qualquer plataforma se torna possível. Por exemplo, aqui está um pequeno exemplo de um aplicativo React para navegadores da web:
=-> 'react' React =-> 'react-dom' ReactDOM =-> './styles' styles = (: createElement:e) React = App -> ((: name)) e 'div' (: (style styles.container)) e 'div' (: (style styles.hello)) 'Hello' e 'div' (: (style styles.name)) name ReactDOM.render (e App (: (name 'John'))) (document.getElementById 'root')
Também no repositório há exemplos de servidor Express e aplicativos React Native para plataformas móveis.
Conclusão
Assim, o Sova incorpora o melhor de várias outras línguas:
- a simplicidade e poder do Lisp
- Recuo do Python limpo
- ecossistema de tempo de execução e JavaScript
O código do compilador com exemplos de uso da linguagem está aqui https://github.com/sergeyshpadyrev/sova . Ficarei feliz em ver as estrelas no repositório de todos aqueles que gostaram do conceito da linguagem e que gostariam de continuar trabalhando nele. Mas avisarei imediatamente que, por enquanto, isso é apenas uma prova de conceito, e até brincar com o idioma por causa da falta de documentação e de alguns recursos é extremamente difícil. Por exemplo, o idioma ainda não possui tratamento de exceção, classes e outras coisas necessárias. E é improvável que executar o Windows seja bem-sucedido.
Nas etapas a seguir, planejo suplementar e estabilizar a sintaxe, reescrever o analisador, escrever testes para o analisador e tradutor, escrever documentação. Enquanto isso, obrigado por sua atenção e até breve.