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:

bash
nyl main.nyl

REPL (Read-Eval-Print Loop)

Para iniciar o shell interativo:

bash
nyl

Pacote Autossuficiente Distribuível

O Nyl pode empacotar um script junto ao executável do runtime host:

bash
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):

bash
# 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)

nyl
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.

nyl
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.

nyl
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.

nyl
println("Não {interpolado}"#)

Verbatim e Multiline

Strings verbatim ignoram caracteres de escape (como \), e as aspas triplas permitem blocos de múltiplas linhas.

nyl
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

nyl
pessoa = { "nome": "Alice", "idade": 29, } // Vírgula final suportada
println(pessoa["nome"])
println(pessoa.nome) // Atalho estilo propriedade

Tipagem Explícita

nyl
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: true ou false.
  • 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:

  • f ou F: Força para Ponto flutuante de 32-bits (tipo float). Exemplo: 3.14F
  • m ou M: Força a alta precisão extrema de 128-bits ideal para lida financeira (tipo decimal). Exemplo: 10.5m
  • n ou N: Força para Ponto flutuante de 64-bits (tipo number). Exemplo: 99n
  • l ou L: Força explicitamente para Inteiro de 64-bits (tipo long). Exemplo: 100L

Bytes e Operações Bitwise

O Nyl fornece suporte robusto para manipulação em nível de byte.

Literais de Byte

nyl
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()

nyl
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:

nyl
preco = 19.99M    // decimal
velocidade = 3.14F // float
contagem = 100L    // long
valor = 42n        // number (double)

Sistema de Importação

Básico e Alias

nyl
import "math.nyl"
import "utils.nyl" as utils

Fallback e Módulos

nyl
import "local.nyl" fallback "default.nyl"
import os.windows as win

Fluxo de Controle

If / Else

nyl
if x > 10 { ... } else { ... }
res = condicao ? "Sim" : "Não"

Loops For (Unificados)

nyl
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

nyl
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

nyl
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

nyl
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

nyl
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

nyl
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).

nyl
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.

nyl
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.

nyl
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)

nyl
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)

nyl
fn somar(a, b) => a + b

Corpo de Bloco

A última expressão em um corpo de bloco é retornada automaticamente.

nyl
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.

nyl
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.

nyl
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.

nyl
// 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.

nyl
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).

nyl
fn trabalho() {
    arquivo = abrir("dados.txt")
    defer fechar(arquivo)
    // ...
}

️ Decoradores

Decoradores fornecem metadados e modificação de comportamento para funções e parâmetros.

nyl
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: no NylWeb).
  • [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.

nyl
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.

nyl
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.) usando try/or.

task.all e task.any

Você pode agrupar e conciliar arrays de tasks utilizando os métodos nativos globais task:

nyl
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)

nyl
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.

nyl
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).

nyl
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

nyl
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).

nyl
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.

nyl
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:

nyl
// 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)

nyl
sys = link "user32.dll" {
    fn MessageBoxA(ptr, string, string, int) int
}

Assert

nyl
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.

nyl
t = @eval("os.sleep(100); return 'Olá do Eval'") // Isolado
res = await t
println(res)

Verificação de Existência

nyl
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 (retorna NylTask).
  • 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 chamar handle.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

nyl
jsonStr = json.stringify({ "id": 1, "ativo": true })

2. Analisando para um Objeto Tipado

nyl
type Config { string host, int port }
cfg = json.parse(jsonStr, Config)

3. Analisando como Mapa Dinâmico

nyl
mapa = json.parse(jsonStr)
println(mapa.id)

️ Roadmap

  • Estruturas nativas para FFI.
  • Gerenciamento de pacotes aprimorado.