Syntax
Arc language syntax reference for comments, identifiers, literals, and statement structure
Comments
Single-line comments start with //. Multi-line comments use /* */.
// This is a single-line comment
/* This is a
multi-line comment */
x := 42 // Comments can follow code Identifiers
Identifiers name variables, functions, sequences, stages, and channels.
Rules:
- Start with a letter (
a-z,A-Z) or underscore (_) - Contain letters, digits (
0-9), or underscores - Case-sensitive (
ox_pt_1andOx_Pt_1are different)
valid_name
_private
sensor1
ox_pt_1 Reserved keywords cannot be used as identifiers:
Literals
Numeric Literals
Integer literals default to i64. Float literals default to f64.
42 // i64
3.14 // f64
0.5 // f64
.25 // f64 (leading dot allowed) Numeric Literals with Units
Unit suffixes attach directly to numbers (no whitespace):
100ms // 100 milliseconds (i64)
5s // 5 seconds (i64)
1min // 1 minute (i64)
2h // 2 hours (i64)
10hz // 10 Hz frequency (converts to 100ms period)
1khz // 1 kHz frequency (converts to 1ms period) String Literals
Strings are enclosed in double quotes. Escape sequences are supported.
"hello"
"line1\nline2" // newline
"tab\there" // tab
"quote: \"" // escaped quote Series Literals
Series (arrays) use square brackets:
[1, 2, 3] // series i64
[1.0, 2.0, 3.0] // series f64
[] // empty (requires type annotation) Empty series require an explicit type:
empty series f64 := [] Variables
Constants
Top-level declarations are compile-time constants. Use them for configuration values and to avoid magic numbers.
MAX_PRESSURE := 500.0 // f64 constant
SAMPLE_COUNT := 100 // i64 constant
TIMEOUT := 30s // with unit suffix
SCALE f32 := 2.5 // explicit type Constants can be used in expressions and function config parameters:
pressure > MAX_PRESSURE -> alarm{}
sensor -> scale{gain=SCALE, offset=0.1} -> output Local Variables
Local variables are declared with := inside functions and reset each invocation.
x := 42 // type inferred as i64
y f64 := 3.14 // explicit type Stateful Variables
Stateful variables are declared with $= and persist across invocations.
count $= 0 // persists between calls
total f64 $= 0.0 // explicit type Assignment
Assign to existing variables with =:
x = x + 1 Compound Assignment
count += 1 // count = count + 1
value -= 10 // value = value - 10
total *= 2 // total = total * 2
ratio /= 4 // ratio = ratio / 4
remainder %= 3 // remainder = remainder % 3 Variable Scope
Variables are visible from their declaration point to the end of their enclosing block. Nested blocks can access variables from enclosing scopes.
func example() {
x := 10 // visible for rest of function
if x > 5 {
y := x + 1 // visible only inside if block
}
// y is not visible here
} No Shadowing
Arc does not allow shadowing. A variable cannot have the same name as one in an enclosing scope:
func example() {
x i32 := 10
if x > 0 {
x i32 := 20 // Error: conflicts with outer x
}
} Use a different name or reassign the existing variable:
func example() {
x i32 := 10
if x > 0 {
inner_x i32 := 20 // different name
x = 20 // reassign existing
}
} Local variables can shadow built-in functions and constants:
func example() {
min := 10 // shadows built-in min function
} Authority Declarations
Authority declarations set the control authority
for channels written by the program. They must appear before any func, sequence, or
flow declarations.
Default Authority
Set a default authority for all channels:
authority 200 When omitted, the system default is 255 (maximum).
Per-Channel Authority
Set authority for specific channels using a grouped form:
authority (200 valve_cmd 100 vent_cmd 150) This sets a default of 200, then overrides valve_cmd to 100 and vent_cmd to 150.
You can also set per-channel authority without a default:
authority (valve_cmd 100 vent_cmd 150) Summary
Authority values are u8 integers in the range 0-255.
To change authority at runtime, use the
set_authority built-in
function inside stage bodies.
Statements
If Statements
if condition {
// body
}
if condition {
// body
} else {
// alternative
}
if condition1 {
// body
} else if condition2 {
// alternative
} else {
// fallback
} Conditions evaluate as u8: 0 is false, non-zero is true.
Return Statements
Functions with return types require explicit return statements.
func compute(x f64) f64 {
if x < 0 {
return 0.0 // early return
}
return x * 2.0 // required
} Functions without return types can use return for early exit:
func process() {
if skip {
return // early exit
}
// more work
} Arc has no loops. Use stateful variables with reactive execution for iterative patterns.
Flow Statements
Flow statements connect channels and functions in the reactive scope.
Continuous Flow (->)
Executes every cycle while active:
sensor -> filter{} -> output One-Shot Flow (=>)
Fires once when condition becomes true, then stops until reset:
pressure > 500 => next Routing Tables
Map multiple inputs to function parameters:
{ sensor1: a, sensor2: b } -> averager{} Route multiple outputs to different targets:
sensor -> split{} -> {
high: alarm{},
low: logger{}
} Expressions in Flows
Inline expressions act as implicit functions:
temperature > 100 -> alarm{}
(sensor1 + sensor2) / 2.0 -> display Blocks
Braces {} delimit blocks. Blocks contain statements (function bodies) or flow
statements (stage bodies).
func example() {
// statements in function block
}
stage pressurize {
// flow statements in stage block
} Stage bodies use commas to separate flow statements:
stage pressurize {
1 -> valve,
sensor -> controller{},
pressure > 500 => next
}