Referência da Linguagem Nyl
Nyl é uma linguagem de programação moderna, estaticamente tipada (com inferência de tipos), segura e eficiente, projetada para versatilidade e facilidade de uso. Ela apresenta uma sintaxe única que combina o melhor das linguagens de estilo C com recursos modernos de script e funcionais.
Execução e CLI
Executando um Script
Para executar um arquivo .nyl:
nyl main.nyl
REPL (Read-Eval-Print Loop)
Para iniciar o shell interativo:
nyl
Pacote Autossuficiente Distribuível
O Nyl pode empacotar um script junto ao executável do runtime host:
nyl -build main.nyl
Compilação Nativa
Para gerar binários nativos de máquina ultra-pequenos e de alta performance utilizando a compilação nativa com suporte a cross-compilação (zig cc, clang ou gcc):
# Compilação nativa para o sistema atual
nyl compile main.nyl -o build/
# Compilação cruzada (cross-compile) para binário estático Linux x86_64
nyl compile main.nyl -target x86_64-linux-musl -o distrib/
Variáveis e Declarações
O Nyl usa inferência de tipo automática por padrão. Você não precisa de palavras-chave como var ou let para declarar variáveis, embora elas sejam suportadas por compatibilidade.
Declaração Implícita (Padrão)
nome = "Nyl" // string
versao = 1.0 // number
estaAtivo = true // bool
Tipagem Explícita
Variáveis podem ser tipadas explicitamente, embora isso seja usado principalmente para requisitos internos específicos e não seja recomendado para o código geral do usuário.
int idade = 25
number preco = 19.99
string nome = "Nyl"
bool estaAtivo = true
Strings e Interpolação
Interpolação
O comportamento padrão usa {} para injetar variáveis em strings.
nome = "Mundo"
println("Olá {nome}") // Olá Mundo
println('Texto Raw') // Usando aspas simples
Desativando a Interpolação (Raw Strings)
Use um # no final (dentro ou fora da string) para escapar o motor de interpolação.
println("Não {interpolado}"#)
Verbatim e Multiline
Strings verbatim ignoram caracteres de escape (como \), e as aspas triplas permitem blocos de múltiplas linhas.
caminho = @"C:\Users\Nyl"
texto = """
Múltiplas
Linhas
"""
️ Maps (Dicionários)
Maps armazenam pares chave-valor e suportam tanto inferência dinâmica quanto tipagem explícita.
Literais e Acesso
pessoa = { "nome": "Alice", "idade": 29, } // Vírgula final suportada
println(pessoa["nome"])
println(pessoa.nome) // Atalho estilo propriedade
Tipagem Explícita
map<string, int> pontos = { "jogador1": 100, "jogador2": 150 }
Sintaxe Básica
Comentários
- Linha única:
// comentário - Documentação:
/// comentário de doc - Múltiplas linhas:
/ comentário em bloco /
Ponto e Vírgula e Vírgulas
- Ponto e Vírgula: Opcional e serve principalmente para separar múltiplas instruções em uma única linha.
- Vírgulas: Opcionais entre campos em definições de tipo. Vírgulas finais (trailing commas) são suportadas em listas (arrays, maps, parâmetros, etc.).
Tipos de Dados
int,long: Inteiros.number: Ponto flutuante.string: Texto Unicode.bool:trueoufalse.byte: Inteiro sem sinal de 8 bits (0-255).datetime: Datas e horas.nil: Ausência de valor.any: Tipo universal.ptr: Ponteiro nativo (FFI).
Sufixos Numerais (Nativos)
Por padrão, o Nyl avalia as casas decimais como number (precisão double subjacente) e números inteiros como int ou long. Para ignorar o fallback ou não depender das conversões de base usando .parse, o desenvolvedor pode forçar a tipagem exata anexando os sufixos padrão C# diretamente no número:
fouF: Força para Ponto flutuante de 32-bits (tipofloat). Exemplo:3.14FmouM: Força a alta precisão extrema de 128-bits ideal para lida financeira (tipodecimal). Exemplo:10.5mnouN: Força para Ponto flutuante de 64-bits (tiponumber). Exemplo:99nlouL: Força explicitamente para Inteiro de 64-bits (tipolong). Exemplo:100L
Bytes e Operações Bitwise
O Nyl fornece suporte robusto para manipulação em nível de byte.
Literais de Byte
b1 = 42 // Decimal
b2 = 0x2A // Hex
b3 = 0b101010 // Binário
b4 = 'A' // Literal de caractere
Operadores Bitwise
&(AND),|(OR),^(XOR),~(NOT)<<(Deslocamento à Esquerda),>>(Deslocamento à Direita)- Atribuições:
&=,|=,^=,<<=,>>=
Conversão de Tipo
Usando .parse()
n = int.parse("123")
d = number.parse("3.14")
b = byte.parse("255")
x = parse(int, val)
Usando Sufixos Literais
Para tipos numéricos, você pode pular o .parse() inteiramente e usar sufixos diretamente no literal:
preco = 19.99M // decimal
velocidade = 3.14F // float
contagem = 100L // long
valor = 42n // number (double)
Sistema de Importação
Básico e Alias
import "math.nyl"
import "utils.nyl" as utils
Fallback e Módulos
import "local.nyl" fallback "default.nyl"
import os.windows as win
Fluxo de Controle
If / Else
if x > 10 { ... } else { ... }
res = condicao ? "Sim" : "Não"
Loops For (Unificados)
for i < 10 { ... } // Estilo while
for { ... } // Infinito
for item in lista { ... } // Foreach
for i, val in lista { ... } // Foreach com índice
for i in 1..10 { ... } // Intervalo (inclusivo)
Match
match x {
1 => println("Um")
2, 3 => println("Dois/Três")
_ => println("Outro")
}
Intervalos (Ranges)
Intervalos representam um intervalo inclusivo entre dois valores. Eles suportam números, caracteres, datas e enums.
Sintaxe e Tipos
r1 = 1..5 // Números: 1, 2, 3, 4, 5
r2 = "a".."c" // Caracteres: "a", "b", "c"
r3 = inicio..fim // Datas: dia a dia
r4 = Norte..Sul // Enums: variantes na ordem definida
Propriedades e Indexação
r = 1..10
print(r.count()) // 10
print(r[2]) // 3
️ Sistema de Tipos Unificado (Structs & Unions)
O Nyl apresenta um sistema de tipos poderoso com herança e tipos de união.
Structs/Classes
type Usuario {
string nome = "Anônimo", // Vírgula opcional
int idade, // Vírgula final
fn ehAdulto() => self.idade >= 18
}
u = Usuario(nome = "Bob", idade = 20)
Herança e Genéricos
type Caixa<T> { T valor }
type Admin : Usuario { ... }
Tipos de União e Enums
Uniões permitem que uma variável contenha um de vários tipos ou variantes específicas (Enums).
type Resultado = string | int
type Direcao = Norte | Sul | Leste | Oeste
fn mover(Direcao d) {
match d {
case Norte => println("Cima")
case _ => println("Outro")
}
}
Atualizações Imutáveis (with)
Cria uma cópia com campos modificados.
p2 = p1 with { nome = "Novo Nome", idade = 21 }
️ Tratamento de Erros
O Nyl usa a construção try/or para avaliação segura de expressões.
resultado = try (10 / 0) or {
println("Erro: {err.message}")
return 0
}
Dentro do bloco or, o objeto err está automaticamente disponível com err.type e err.message.
Arrays (arrayList)
lista = [1, 2, 3]
lista.push(4)
println(lista.len())
️ Funções & Defers
Funções
As funções podem ser definidas de várias maneiras, desde funções de seta concisas até corpos de bloco detalhados com tipos explícitos.
Corpo de Expressão (Arrow Function)
fn somar(a, b) => a + b
Corpo de Bloco
A última expressão em um corpo de bloco é retornada automaticamente.
fn calcular(x, y) {
resultado = x * y
resultado + 10 // Retorna este valor
}
Tipagem Explícita
Você pode especificar tipos de parâmetros e tipos de retorno.
fn multiplicar(int a, int b) int {
return a * b
}
Múltiplos Valores de Retorno (Tuplas)
O Nyl suporta o retorno de múltiplos valores, que podem ser desempacotados durante a atribuição.
fn obterInfoJogador() string, int {
return "Alice", 25
}
nome, idade = obterInfoJogador()
Funções Anônimas (Expressões)
As funções são cidadãs de primeira classe e podem ser atribuídas a variáveis ou passadas como argumentos.
// Atribuição
somador = fn(x) => x + 5
println(somador(10)) // 15
// Como argumento
aplicar(fn(x) => x * 2, 7)
Sobrecarga e Tipos de União
As funções podem ser sobrecarregadas por tipo ou aceitar múltiplos tipos usando uniões.
fn descrever(int v) => "Inteiro: {v}"
fn descrever(string v) => "String: {v}"
fn processar(int | string entrada) {
if entrada is int { /* ... */ }
}
Defers (Limpeza)
Blocos defer são executados quando a função termina (ordem LIFO).
fn trabalho() {
arquivo = abrir("dados.txt")
defer fechar(arquivo)
// ...
}
️ Decoradores
Decoradores fornecem metadados e modificação de comportamento para funções e parâmetros.
decorator log(msg) { ... }
[log("Use novaFunc no lugar")]
fn funcAntiga() { ... }
Decoradores Nativos
O Nyl inclui vários decoradores integrados para tarefas comuns:
[auth]: Usado para marcar funções que exigem autenticação (ex: noNylWeb).[obsolete("mensagem")]: Marca uma função como obsoleta e emite um aviso em tempo de compilação.
- Exemplo: [obsolete("Use melhorFunc")]
[test]: Marca uma função como um teste unitário ou teoria.
- Teste simples: [test]
- Teoria com dados: [test(1, 2)]
⏳ Async e Await
O Nyl suporta programação assíncrona orientada a tarefas (Tasks) por meio de async e await. Isso permite executar funções em background de maneira não-bloqueante na VM.
Executando em Background
Você adiciona a palavra-chave async logo antes da chamada à função.
fn buscar_dados() {
os.sleep(100)
return "Dados"
}
tarefa = async buscar_dados()
// Faça outras coisas enquanto carrega...
resultado = await tarefa
Cancelando Tarefas
Uma NylTask em execução (retornada pelo async) pode ser interrompida via token de cancelamento.
tarefa = async buscar_dados()
tarefa.cancel()
println(tarefa.isCanceled()) // true
println(tarefa.isCompleted()) // true
Nota: Recomenda-se tratar possíveis erros de cancelamento (Task was canceled.) usandotry/or.
task.all e task.any
Você pode agrupar e conciliar arrays de tasks utilizando os métodos nativos globais task:
tarefas = [async req1(), async req2()]
// Espera finalizarem todas juntas:
resultados = await task.all(tarefas)
println(resultados[0])
// Retorna apenas a primeira que finalizar, interrompendo a espera:
primeiro_resultado = await task.any(tarefas)
Servidor Web e Redes (NylWeb)
O Nyl inclui uma pilha de rede leve e integrada utilizando o Microsoft Kestrel. Ele suporta roteamento HTTP padrão, fornecimento de arquivos estáticos e WebSockets de alta performance.
Iniciando um Servidor
Existem duas maneiras de gerenciar um servidor: um loop "singleton" global ou uma instância dedicada.
1. Loop Global (Início Rápido)
nylweb.runLoop(8080)
get("/ping", fn() => "pong")
2. Servidor baseado em Instância (Recomendado)
O uso de uma instância permite melhor gerenciamento de estado e servidores paralelos.
server = nylweb.createServer(8080)
server.getRouter("/api/v1", fn() => { "versao": 1.0 })
server.runLoop() // Inicia o listener
Roteamento HTTP
Você pode definir rotas usando os verbos HTTP padrão (get, post, put, delete, patch).
server.post("/usuario", fn(corpo) {
usuario = json.parse(corpo)
return { "id": usuario.id, "status": "criado" }
})
// Parâmetros de caminho (começam com :)
server.get("/itens/:id", fn(id) {
return "Buscando item {id}"
})
WebSockets (Tempo Real)
O NylWeb oferece uma API de WebSocket simples e orientada a eventos, tanto para servidores quanto para clientes.
Push do Lado do Servidor
server = nylweb.createServer(8080)
server.onConnect(fn(clientId) {
println("Cliente {clientId} conectado!")
server.sendMessage(clientId, "Bem-vindo!")
})
server.onMessage(fn(msg) {
// Transmitir mensagem para todos os clientes
for client in server.getClients() {
server.sendMessage(client, msg)
}
})
server.runLoop()
Lado do Cliente (NylClient)
Conecte-se a qualquer servidor WebSocket (Nyl ou de terceiros).
cliente = nylweb.createClient("ws://localhost:8080", true) // true = auto-reconexão
cliente.onConnect(fn(info) {
println("Conectado ao servidor!")
cliente.sendMessage("Olá Servidor!")
})
cliente.onMessageClient(fn(dados) {
println("Resposta: {dados}")
})
cliente.connect()
Rotas Protegidas (Autenticação)
Marque qualquer rota com o decorador [auth] para exigir uma sessão válida. Você pode gerenciar usuários no banco Key-Value (KV) e customizar a rota de login.
import nylweb as web
// 1. Criar o servidor
server = web.createServer(8080)
// 2. Adicionar usuários ao KV (rode no bootstrap)
// Senha em texto plano (para dev/testes):
auth.addUser(server, "admin", "senha123", "Admin")
// ou use addOrUpdateUser para garantir que o usuário sempre exista:
auth.addOrUpdateUser(server, "joao", "SK-abc123def456...", "User", true)
// 3. Rota protegida usando o login padrão ("auth/loginservice")
[auth]
server.get("/painel", fn() => "Bem-vindo ao Painel")
// 4. Rota protegida com login customizado
[auth("minha/rota")]
server.get("/dashboard", fn() => "Dashboard Privado")
// 5. Handler de login customizado
server.post("minha/rota", fn(credentials) {
// credentials.user e credentials.pass já vêm decodificados
// auth.approve retorna uma tupla: (sucesso, jsonResponse)
sucesso, jsonRes = auth.approve(server, credentials, "/dashboard")
return jsonRes
})
// Dica: Você também pode usar auth.updateUser, auth.addOrUpdateUser e auth.removeUser
// auth.removeUser(server, "joao")
server.runLoop()
Fornecimento de Arquivos Estáticos
Para habilitar o fornecimento de arquivos HTML, CSS e JS de um diretório:
// Porta, Host, Caminho do WebRoot
server = nylweb.createServer(8080, "localhost", "./wwwroot")
server.runLoop()
Arquivos em ./wwwroot serão servidos automaticamente no caminho raiz /.
Interface de Função Estrangeira (FFI)
sys = link "user32.dll" {
fn MessageBoxA(ptr, string, string, int) int
}
Assert
assert condicao, "Mensagem de sucesso"
Meta-Programação
Execução Dinâmica (eval)
Avalia strings de código Nyl assincronamente em tempo de execução. O builtin @eval retorna uma NylTask que deve aguardada usando await. Definir o segundo argumento como false permite que o script compartilhe/modifique o escopo atual.
t = @eval("os.sleep(100); return 'Olá do Eval'") // Isolado
res = await t
println(res)
Verificação de Existência
if fnExists("minhaFuncao") ? minhaFuncao()
️ Referência de Funções Integradas (Built-ins)
Core & Meta
print(),println(),input(),pause().clock(),getTime(): Timestamps.fnExists(name): Verifica se a função existe.@eval(script, isolado): Execução dinâmica assíncrona (retornaNylTask).formatToStr(obj, delimitador, camelCase, delimitadorCamel, usarMarkup): Formata qualquer objeto para string. Também pode ser usado como método de extensão:obj.formatToStr(...).
Sistema de Arquivos e SO (módulo os)
os.name(),os.arch(),os.getEnvVar(),os.getUptime().os.watchProcesses(names, onStart, onStop, intervalMs?): Monitora uma lista de nomes de processos e invoca os callbacks fornecidos automaticamente na VM sem bloqueá-la. Retorna um handle.os.stopWatchProcesses(handle): Para um monitor de processos. Você também pode chamarhandle.stop().os.fileExists(),os.fileReadText(),os.fileWriteText(),os.fileDelete().os.findFilesInFolder(path, filter).ptr.nil(),ptr.isNil(),ptr.add().
Exemplos Práticos de JSON
1. Serializando para JSON
jsonStr = json.stringify({ "id": 1, "ativo": true })
2. Analisando para um Objeto Tipado
type Config { string host, int port }
cfg = json.parse(jsonStr, Config)
3. Analisando como Mapa Dinâmico
mapa = json.parse(jsonStr)
println(mapa.id)
️ Roadmap
- Estruturas nativas para FFI.
- Gerenciamento de pacotes aprimorado.