Sintaxe Concreta (formas e exemplos)
Status: Stable · Evidência: aura/parser/to_ast.py, docs/language-reference/grammar.md, tests/test_parser_statements.py, tests/test_parser_expressions.py
Este documento mostra a forma concreta de cada construção com exemplos mínimos. As regras formais estão em grammar.md; os tokens estão em lexical-structure.md; o significado está nos documentos de domínio. Ele não repete — referencia.
Todo exemplo abaixo é a forma que o parser aceita (verificada por probe). Um programa executado com
aura rundeve declarar umdef main()de nível superior; um arquivo de módulo não precisa de nenhum. Exemplos que parecem válidos mas não compilam estão listados em Anti-formas.
Programa mínimo
Um arquivo de entrada declara main. O runtime o invoca; nunca escreva uma chamada main() à direita (grammar.md §2; syntax.md).
def main() {
print("Hello, world")
}
main não recebe parâmetros ou recebe um único parâmetro args; qualquer outra assinatura é E311, e a ausência de main em um arquivo de entrada é E310.
Variáveis e constantes
let name = "Alice" // immutable
let mut counter = 0 // mutable
counter += 1
const PI = 3.14159 // must be initialised; never reassigned
const MAX: int = 100
let age: int = 30
let items: [int] = [1, 2, 3]
Desestruturação e atribuição múltipla usam padrões de tupla/lista, com um elemento rest opcional ...name:
let (a, b) = (1, 2)
let [first, ...rest] = [1, 2, 3, 4]
let x, y = 1, 2
Modificadores (public, private, protected, static, volatile, abstract) aparecem antes da keyword de declaração: private let x = 1, nunca let private x (grammar.md §3).
Tipos
int float str bool bytes none // primitives
[int] // list
{str: int} // dict
{int} // set
int | str // union
str? // optional
(int, int) -> int // function
{x: float, y: float} // structural
Box[int] // type argument (brackets only)
Tipos são parseados para checagem/documentação e apagados em tempo de execução. A forma de colchete [T] é canônica; <T> foi removida (grammar.md §4).
Parâmetros e restrições de tipo:
class Box[T] {
private let value: T
public def get() -> T {
return self.value
}
}
def smallest[T: Comparable](items: [T]) -> T {
return items[0]
}
Funções
def greet(name) -> str {
return "Hello, " + name + "!"
}
def add(a: int, b: int) -> int {
return a + b
}
def square(x: int) -> int = x * x // expression body
def noop() { } // no return type
def configure(level, prefix = "[log]") { } // default parameter
def sum_all(*numbers) -> int { return 0 } // variadic positional
def log(level, **context) { } // variadic keyword
O corpo é sempre um bloco com chaves ou um único = expr. def é a única keyword de função; fn, fun, function não existem. async def declara uma função async (grammar.md §3.2).
Lambdas
let double = x => x * 2
let square = (x) => x * x
let add = (a, b) => a + b
let none_ = () => 42
let block = (x) => {
let doubled = x * 2
return doubled + 1
}
Um parâmetro de lambda pode ser anotado: (x: int) => x * 2 (grammar.md §6.4).
Controle de fluxo
if temperature > 100 {
print("Boiling!")
} else if temperature > 50 {
print("Warm")
} else {
print("Cold")
}
unless authenticated { redirect("/login") }
guard data != none else {
print("No data")
return
}
let label = condition ? "yes" : "no" // ternary; `if` is also an expression
Loops
for i in range(10) { print(i) }
for item in items { print(item) }
for i in 0..<10 step 2 { print(i) } // range with step
while count < 5 { count += 1 }
until ready { wait(100) }
loop { if quit() { break } }
outer: for i in range(10) {
inner: for j in range(10) {
if i * j > 20 { break outer }
}
}
for usa a keyword in e um padrão. Labels funcionam com for, while, until e loop; break label / continue label onde tal loop não está em escopo é E318 (grammar.md §5.2; syntax.md1).
Pattern matching
match status {
case 0 { print("inactive") }
case 1 { print("active") }
case n if n > 100 { print("overflow") }
case _ { print("unknown") }
}
let text = match x { // match as an expression
case 1 -> "one"
case _ -> "other"
}
Padrões incluem literais, bindings, wildcard _, membros de enum pontuados (Color.RED), desestruturação de tupla/lista com *rest, padrões de construtor (Some(x)) e or-patterns (1 | 2). Um match sem case _ sobre um domínio finito avisa E109 (grammar.md §5.4; syntax.md2).
Enums
Membros são separados por vírgula (vírgula à direita é permitida). Valores são opcionais e autonumeram a partir do valor inteiro anterior.
enum Color { RED, GREEN, BLUE }
enum Status { Pending = "pending", Active = "active" }
let c = Color.RED // access via dotted member
if status == Status.Active { process() }
Membros em linhas separadas sem vírgulas não parseiam:
enum E { A B }→Expected '}' but got 'B'(probe). Use vírgulas.
Classes
Header fields geram o construtor, um getter e (para mut) um setter. A visibilidade padrão é private; cada header field precisa de um tipo ou um default.
class User(name: str, mut age: int = 0, public id: int = 0) {
public def greet() -> str {
return "hi " + self.get_name()
}
}
let u = User("ana", 30) // Aura constructs with Type(args), no `new`
print(u.get_name())
u.set_age(31)
Campos de corpo e um construtor manual (não misture com um header):
class Point {
public let x: int = 0
public let y: int = 0
public def new(x: int, y: int) {
self.x = x
self.y = y
}
public def distance() -> float {
return (self.x ** 2 + self.y ** 2) ** 0.5
}
}
Regras: todo membro precisa de uma visibilidade explícita (E307); membros devem ser únicos (E301); def new mapeia para __init__ do Python; uma classe tem exatamente um estilo de construtor. A herança usa apenas extends:
class Animal {
protected let name: str = ""
public def speak() -> str { return "..." }
}
class Dog extends Animal {
public def speak() -> str { return self.name + " says woof" }
}
class Model extends django.db.models.Model { } // dotted base allowed
class C extends A, B { } // multiple bases
class Dog(Animal) e implements não são Aura. A sobrescrita é implícita — não há override (grammar.md §3.3; classes.md).
Classes abstratas
abstract class Shape {
public let name: str = "shape"
public def describe() -> str { return "a " + self.name }
public abstract def area() -> float
}
class Square extends Shape {
public let side: float = 2.0
public def area() -> float { return self.side * self.side }
}
abstract def não tem corpo; abstract antes de def dentro de um trait é erro de sintaxe (to_ast.py:1923-1928; classes.md).
Traits
trait Drawable {
public def draw() -> void
public def get_bounds() -> float
}
class Circle extends Drawable {
private let radius: float = 0.0
public def draw() -> void { print("circle") }
public def get_bounds() -> float { return self.radius * 2 }
}
Um método de trait sem corpo já é abstrato — sem keyword abstract. Traits estendem com extends (grammar.md §3.4; classes.md (traits)).
Decorators
Decorators se anexam a um def ou a uma classe; um decorator em um campo é E320.
@staticmethod
public def max(a, b) -> int { return a }
class Rect {
public @property
def area() -> int { return 4 }
public @classmethod
def create(cls) { return cls() }
}
Modificadores de membro e decorators podem aparecer em qualquer ordem (@staticmethod public def f ≡ public @staticmethod def f).
Coleções
let list = [1, 2, 3]
let set = {1, 2, 3}
let dict = {name: "Alice", age: 30}
let pair = (1, "hello")
let single = (1,)
let empty = ()
print(list[0]) // index
print(list[-1]) // negative index
print(list[1:3]) // slice
print(list[::2]) // slice with step
let squares = [x * x for x in range(10)]
let evens = [x for x in range(20) if x % 2 == 0]
let lengths = {w: len(w) for w in words}
let gen = (x for x in xs)
Spread de lista e de dict:
let combined = [*list1, *list2, extra]
let merged = {**defaults, **overrides}
Chamadas e argumentos
f(a, b) // positional
f(name: "Alice", age: 30) // keyword
f(*args) // positional spread
f(**kwargs) // keyword spread
f(a, *rest, **kw) // mixed
Struct init é açúcar para uma chamada de construtor: um { após um identificador maiúsculo é um literal struct.
let p = Point{x: 1, y: 2}
Operadores
Precedência (menor para maior — grammar.md §6.1, correspondendo à tabela do parser to_ast.py:465-488):
| Nível | Operadores |
|---|---|
| 1 | =, +=, -=, *=, /=, %=, **=, &=, |=, ^=, <<=, >>=, ??=, |> |
| 2 | ? : (ternário) |
| 3 | or |
| 4 | and |
| 5 | == != < > <= >= in not in is is not |
| 6 | | |
| 7 | ^ |
| 8 | & |
| 9 | << >> |
| 10 | .. ..< |
| 11 | ?? ?: |
| 12 | + - |
| 13 | * / % as |
| 14 | ** |
| 15 | unário - + ~ not await ... |
| 16 | call, index, slice, member, safe-nav, struct-init |
let q = total / count // true division (never truncates)
let n = int(total / count) // integer result via cast
let r = value as int // cast
let b = a ?? fallback // coalesce on none
let e = a ?: fallback // fallback on falsy
let c = user?.address?.city // safe navigation
let i = list?[index] // safe index
let x = xs |> filter(f) |> map(g) // pipe, left to right
let rng = 0..10 // inclusive range
let rng2 = 0..<10 // exclusive range
let open = 1.. // infinite range
is / is not testam identidade; x is none é a checagem de nulo. Comparar um literal com is é rejeitado (to_ast.py:2567-2577).
Statements
return value
throw ValueError("bad")
break
continue
break outer
continue outer
yield
yield x + 1
spawn work()
assert x == 1, "message"
yield é em nível de statement, não parte de expression; yield x + 1 produz a soma inteira (grammar.md §6.1).
Blocos, with, erros
with open("f") as f {
print(f)
}
async with client() as c { } // __aenter__/__aexit__; only in async def
try {
risky()
} catch TypeError {
print("type")
} catch IOError as e {
print(e)
} finally {
cleanup()
}
let result = try { parse_int(s) } catch Error as e { 0 } // try as expression
Uma cláusula catch tem exatamente um significado por grafia (syntax.md5):
| Forma | Significado |
|---|---|
catch { } | captura toda exceção (sem binding) |
catch Type { } | captura apenas Type |
catch Type as e { } | captura apenas Type, vincula a e |
catch as e { } | captura toda exceção, vincula a e |
Um try exige pelo menos um catch ou um finally.
Imports
import stdlib.math // module; reach members by path
import stdlib.math as m // alias
from stdlib.math import sqrt, PI // names
from stdlib.math import sqrt as root // name alias
import stdlib.math { sqrt, PI } // brace form ≡ from ... import ...
from stdlib.math import * // wildcard
A forma com chaves não pode ser combinada com as (syntax.md6).
Interop com Python
Um prefixo py. marca um módulo Python hospedeiro (_split_python_prefix, to_ast.py:494-505). O prefixo é removido antes da geração de código; o nome ligado é o último segmento do caminho.
import py.re // binds `re`
import py.os.path // binds `path`
from py.math import sqrt, pi as PI // binds `sqrt` and `PI`
Um nome Python que colide com uma keyword de Aura deve ser aliasado; uma colisão nua é rejeitada (_reject_python_keyword_binding, to_ast.py:1832-1844):
from py.re import type as re_type // ok: aliased
// from py.re import type // error: 'type' is a reserved Aura keyword
Aliases de tipo e módulos
type UserId = int
type Point = {x: float, y: float}
type Pair[T] = [T]
module App.Services {
export def public_function() -> int { return 42 }
export const VERSION = "1.0.0"
let mut cache = 0 // private to the file
}
module Facade {
export Components, Utils // re-export from sibling files
}
Membros de módulo são privados ao arquivo declarante a menos que marcados export; export precede uma declaração nomeada ou introduz um re-export (grammar.md §3.7; modules.md).
Anti-formas (NÃO compila)
Cada grafia rejeitada, com o erro apontado do parser e sua substituição canônica:
fn f() { } // ❌ 'fn' is not part of Aura; use 'def' instead
fun f() { } // ❌ 'fun' is not part of Aura; use 'def'
function f() { } // ❌ 'function' is not part of Aura; use 'def'
let f = lambda x: x // ❌ 'lambda' is not part of Aura; use '(x) => expr'
let c = new C() // ❌ 'new' is not part of Aura; construct with 'Type(args)'
var x = 1 // ❌ 'var' is not part of Aura; use 'let mut' or 'let'
foreach x in xs { } // ❌ 'foreach' is not part of Aura; use 'for x in xs'
repeat { } // ❌ 'repeat' is not part of Aura; use 'loop { }' or 'until'
do { } // ❌ 'do' is not part of Aura; use 'loop { }' with 'break'
switch x { } // ❌ 'switch' is not part of Aura; use 'match x { case ... }'
if a { } elif b { } // ❌ 'elif' is not part of Aura; write 'else if'
if a { } elsif b { } // ❌ 'elsif' is not part of Aura; write 'else if'
let x = null // ❌ 'null' is not part of Aura; use 'none'
let x = !y // ❌ '!' is not part of Aura; use 'not'
let x = a && b // ❌ '&&' is not part of Aura; use 'and'
let x = a || b // ❌ '||' is not part of Aura; use 'or'
match x { case 1: f() } // ❌ ':' is not Aura case syntax; write 'case 1 -> ...'
match x { case 1 => 1 } // ❌ '=>' is not Aura case syntax; write 'case 1 -> ...'
class C(A) { } // ❌ parenthesised base; write 'class C extends A'
class C implements D { } // ❌ 'implements' is not Aura; use 'extends'
class Box<T> { } // ❌ type parameters use brackets: 'Box[T]'
if x is "a" { } // ❌ 'is' compares identity; use '=='
enum E { A B } // ❌ members are comma-separated: 'enum E { A, B }'
Anti-formas de outras linguagens (NÃO existe)
| NÃO escreva | Escreva em vez disso | Evidência |
|---|---|---|
fn, fun, function | def | to_ast.py:816-818, 2647-2649 |
elif, elsif | else if | to_ast.py:819-822 |
var (statement) | let mut / let | to_ast.py:791, 801-804 |
foreach | for x in xs | to_ast.py:792 |
lambda | (x) => expr | to_ast.py:795, 2650-2653 |
new | Type(args) | to_ast.py:796, 2640-2646 |
repeat | loop { } / until | to_ast.py:797 |
switch | match x { case ... -> ... } | to_ast.py:798 |
do | loop { } with break | to_ast.py:799 |
null | none | to_ast.py:2637-2639 |
True / False / None | true / false / none | to_ast.py:533-537 |
!x | not x | to_ast.py:2435-2437 |
&& / || | and / or | to_ast.py:2497-2502 |
case x: / case x => | case x -> | to_ast.py:2310-2317 |
class C(A) | class C extends A | to_ast.py:1270 |
implements | extends | to_ast.py:1887-1891 |
Box<T> | Box[T] | to_ast.py:1112 |
volatily | volatile | to_ast.py:281-284 |
a ? b : c is valid; x is <literal> | == / != | to_ast.py:2567-2577 |