ato-language
Reference for the `.ato` declarative DSL: type system, connection semantics, constraint model, and standard library. Use when authoring or reviewing `.ato` code.
/plugin install atopiledetails
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.
technical
- github
- atopile/atopile
- stars
- 3177
- license
- MIT
- contributors
- 41
- last commit
- 2026-04-03T20:56:37Z
- file
- .claude/skills/ato-language/SKILL.md