name: ato-language
description: "Reference for the .ato declarative DSL: type system, connection semantics, constraint model, and standard library. Use when authoring or reviewing .ato code."
The ato language
ato is a declarative, constraint-based DSL for describing electronic circuits. There is no control flow, no mutation, and no execution order — you declare what a circuit is, and the compiler + solver resolve it into a valid design.
Quick Start
A minimal complete .ato file:
#pragma experiment("BRIDGE_CONNECT")
import Resistor
import ElectricPower
import Capacitor
module PowerFilter:
"""A simple decoupled power input with a pull-down resistor."""
power = new ElectricPower
decoupling_capacitor = new Capacitor
pulldown_resistor = new Resistor
power.hv ~> decoupling_capacitor ~> power.lv
power.hv ~> pulldown_resistor ~> power.lv
decoupling_capacitor.capacitance = 100nF +/- 20%
pulldown_resistor.resistance = 100kohm +/- 5%
assert power.voltage within 3.0V to 3.6V
Validate with ato build from the package directory.
Core Concepts
1. Everything is a Node in a Graph
Every entity (a resistor, a power rail, an I2C bus, a voltage parameter) is a node in a typed graph. Nodes relate to each other through edges: composition (parent–child), connection (same-net), and traits (behavioral metadata). The .ato language is a surface syntax for constructing this graph declaratively.
2. Three Block Types
ato has exactly three ways to define a new type:
| Keyword | Semantics | Typical Use |
|---|---|---|
module |
A design unit that contains children and connections | Circuit blocks, subsystems |
interface |
A connectable boundary; can be wired with ~ |
Buses, power rails, signals |
component |
A physical part with footprint/symbol | Vendor ICs, connectors |
All three compile to graph nodes. The distinction controls which traits the compiler attaches (is_module, is_interface) and what operations are legal (by convention, interfaces appear on both sides of ~).
Inheritance uses from:
module MyRegulator from Regulator:
pass
3. Composition — Children and Instantiation
Types contain children. Inside a block body, new instantiates a child:
module Board:
power = new ElectricPower # interface child
sensor = new BME280 # module child
caps = new Capacitor[4] # array of 4 capacitors
Children are accessed via dot-notation: sensor.power.voltage, caps[0].capacitance.
4. Connection — Declaring Electrical Identity
The wire operator ~ declares that two interfaces are the same net/bus. It is bidirectional and requires matching types:
power_3v3 ~ sensor.power # ElectricPower ~ ElectricPower
i2c_bus ~ sensor.i2c # I2C ~ I2C
The bridge operator ~> (requires #pragma experiment("BRIDGE_CONNECT")) inserts a component in series. The component must carry the can_bridge trait which defines its in/out mapping:
power_5v ~> regulator ~> power_3v3
i2c.scl.line ~> pullup ~> power.hv
5. Constraints — Physical Quantities and Assertions
Values in ato carry units and tolerances. The solver uses these to select real parts.
Assignment binds a value to a parameter:
power.voltage = 3.3V +/- 5%
resistor.resistance = 10kohm +/- 10%
i2c.frequency = 400kHz
i2c.address = 0x48
Assertions declare constraints the solver must satisfy:
assert power.voltage within 3.0V to 3.6V
assert i2c.frequency <= 400kHz
assert sensor.i2c.address is 0x50
Three value forms exist:
- Exact:
3.3V - Bilateral tolerance:
10kohm +/- 5% - Bounded range:
3.0V to 3.6V
6. Traits — Behavioral Metadata
Traits attach capabilities or metadata to nodes. They are not children — they use trait edges in the graph.
#pragma experiment("TRAITS")
import has_part_removed
import is_atomic_part
module Placeholder:
trait has_part_removed # mark as non-physical placeholder
trait is_atomic_part # user-defined part with footprint
Key built-in traits:
| Trait | Effect |
|---|---|
can_bridge |
Enables use with ~> operator (defines in/out pin mapping) |
has_part_removed |
No physical part placed (symbolic node) |
is_atomic_part |
User-defined part with manufacturer, partnumber, footprint |
has_datasheet |
Attaches a datasheet reference |
has_designator_prefix |
Sets PCB designator (R, C, U, etc.) |
7. Import System
Bare imports resolve to standard library types (1 line per import):
import ElectricPower
import I2C
import Resistor
Path imports resolve to types defined in other .ato files (1 line per import):
from "atopile/vendor-part/vendor-part.ato" import Vendor_Part
8. Pragma Feature Flags
Experimental syntax is gated behind pragmas (file top, before imports):
#pragma experiment("BRIDGE_CONNECT") # ~> operator
#pragma experiment("FOR_LOOP") # for loops
#pragma experiment("TRAITS") # trait keyword
#pragma experiment("MODULE_TEMPLATING") # new Foo<p=v>
#pragma experiment("INSTANCE_TRAITS") # traits on instances
Using gated syntax without the pragma is a compile error.
Statement Reference
Every statement inside a block body is one of:
| Statement | Syntax | Purpose |
|---|---|---|
assign |
name = value or name = new Type |
Bind a value or instantiate a child |
connect |
a ~ b |
Wire two interfaces together |
bridge |
a ~> b ~> c |
Insert bridgeable components in series |
assert |
assert expr <op> expr |
Declare a constraint |
retype |
name -> NewType |
Replace an inherited child's type |
pin |
pin VCC |
Declare a physical pin |
signal |
signal reset |
Declare an electrical signal |
trait |
trait TraitName |
Attach a trait |
import |
import Type |
Import a type |
for |
for x in arr: |
Iterate over an array (pragma-gated) |
string |
"""...""" |
Documentation string |
pass |
pass |
Empty placeholder |
Statements within a block are order-independent — the compiler resolves the full graph, not a sequence of operations.
Type System
Interfaces (connectable with ~ or ~>)
| Type | Children / Parameters | Purpose |
|---|---|---|
Electrical |
(single node) | Raw electrical connection point |
ElectricPower |
.hv, .lv (Electrical); .voltage, .max_current |
Power rails |
ElectricLogic |
.line (Electrical), .reference (ElectricPower) |
Digital signals with voltage context |
ElectricSignal |
.line (Electrical), .reference (ElectricPower) |
Analog signals |
I2C |
.scl, .sda (ElectricLogic); .frequency, .address |
I2C bus |
SPI |
.sclk, .mosi, .miso (ElectricLogic); .frequency |
SPI bus |
UART / UART_Base |
.tx, .rx (ElectricLogic); flow control lines |
Serial |
I2S |
audio data bus lines | Digital audio |
DifferentialPair |
.p, .n |
Differential signals |
USB2_0 / USB3 / USB2_0_IF |
USB data + power | USB interfaces |
CAN_TTL |
CAN bus lines | CAN bus |
SWD / JTAG |
debug lines | Debug interfaces |
Ethernet / HDMI / RS232 / PDM / XtalIF / MultiSPI |
protocol-specific | Other protocols |
Modules (instantiable with new)
| Type | Children / Parameters | Designator |
|---|---|---|
Resistor |
.unnamed[0..1]; .resistance, .max_power |
R |
Capacitor |
.unnamed[0..1], .power; .capacitance, .max_voltage, .temperature_coefficient |
C |
CapacitorPolarized |
polarized variant of Capacitor | C |
Inductor |
.unnamed[0..1]; .inductance |
L |
Fuse |
.unnamed[0..1]; .trip_current, .fuse_type |
F |
Diode |
.anode, .cathode; .forward_voltage, .current |
D |
LED |
.diode; .brightness, .color |
D |
MOSFET |
.source, .gate, .drain; .channel_type, .gate_source_threshold_voltage |
Q |
BJT |
.emitter, .base, .collector; .doping_type |
Q |
Regulator / AdjustableRegulator |
.power_in, .power_out |
— |
Crystal |
.unnamed[0..1], .gnd; .frequency, .load_capacitance |
XTAL |
Crystal_Oscillator |
oscillator module | — |
ResistorVoltageDivider |
voltage divider circuit | — |
FilterElectricalRC |
RC filter | — |
Net |
.part_of (Electrical) |
— |
TestPoint |
.contact; .pad_size, .pad_type |
TP |
MountingHole / NetTie |
mechanical | — |
SPIFlash |
SPI flash memory | — |
Traits (attachable with trait)
has_part_removed, is_atomic_part, can_bridge, can_bridge_by_name, has_datasheet, has_designator_prefix, has_doc_string, has_net_name_affix, has_net_name_suggestion, has_package_requirements, has_single_electric_reference, is_auto_generated, requires_external_usage
Units and Literals
SI-prefixed units: V, mV | A, mA | ohm, kohm, Mohm | F, uF, nF, pF | Hz, kHz, MHz, GHz | s, ms | W, mW
Number formats: decimal (3.3), scientific (1e-6), hex (0x48), binary (0b1010), underscore-separated (1_000_000)
Booleans: True, False
Invariants
- Type-safe connections:
~and~>should connect matching interface types.ElectricPower ~ I2Cis a type mismatch (enforcement is being strengthened). - Pragma gates syntax: using
~>,for,trait, or<>without the matching pragma is a compile error. - Tolerances on passives:
resistance = 10kohm(zero tolerance) matches no real parts. Always use+/- N%. - ElectricLogic needs a reference: logic signals require a power reference for voltage context. Set
signal.reference ~ power_rail. - Order independence: statements within a block are not sequentially executed. The solver resolves the full graph.
- No procedural logic: no
if,while,return, functions, classes, or exceptions.