Skip to content

Appendix A: Grammar

This appendix is dense lookup. For learning the language, read the book starting at the Foreword.

Lexical elements

Comments

// single-line
/* multi-line
comment */

Identifiers

identifier = letter (letter | digit | "_")*
stable_id = "#" alphanumeric+
qualified_name = identifier ("." identifier)*
quoted_string = '"' (any_char - '"' | '\"')* '"'

Reserved keywords (.arch files)

type, in,
labels, required, cascade, append,
override, drop, subscribes,
process, view, subprocess, do,
if, else, switch, each, try, catch,
parallel, fail, finish,
focus, group, by, layout, include, exclude,
true, false

Reserved keywords (package.archspace files only)

use, from, as, export, dependencies

name, version, and widgets are recognized as field names in the manifest grammar but are not reserved words — they don’t shadow identifiers anywhere else.

Kinds are not keywords

Module kinds (service, database, system, …), facet kinds, and interface kinds (command, query, event, …) are not reserved keywords — they’re user-defined identifiers introduced by type module …, type facet …, type interface … declarations.

Base kinds. module, facet, interface are pre-registered base kinds; they’re identifiers, not keywords. process and view are pre-registered base kinds and reserved keywords because their bodies have specialized grammar productions.

Operators and punctuation

{ } ( ) [ ] : , . > =>

The process arrow is > (single GT). The grammar fragments below reflect this.

Grammar (EBNF)

Top-level

program = declaration* ;
declaration = type_decl
| module_decl
| process_decl
| view_decl
| subprocess_decl
;

Type declarations

type_decl = "export"? "type" stable_id? parent_kind identifier type_body? ;
parent_kind = identifier ; (* validator rejects 'process' and 'view' *)
type_body = "{" type_member* "}" ;
type_member = type_field_decl
| type_label_block
| type_subdecl
;
type_field_decl = field_modifier* ( "required" field_path
| field_path ":" value field_body?
) ;
field_modifier = ( "cascade" "*"? ) | "append" ;
field_body = "{" field_body_member* "}" ;
field_body_member = ( "required" | "cascade" | "append" )*
field_path ( ":" value field_body? )? ;
field_path = identifier ("." identifier)* ;
type_label_block = "labels" "{" type_label_member* "}" ;
type_label_member = ( "required" identifier ("." identifier)*
| identifier ("." identifier)* ":" value
| drop_stmt
) ;
type_subdecl = "required"? ( facet_decl | interface_decl | module_decl ) ;
value = identifier | quoted_string | number | "true" | "false" ;

Module declarations

module_decl = kind_name stable_id? identifier in_clause? module_body? ;
kind_name = identifier ; (* registered module kind *)
in_clause = "in" qualified_name ;
module_body = "{" module_member* "}" ;
module_member = field_assignment
| description
| labels_block
| facet_decl
| interface_decl
| module_decl (* nested submodules *)
| process_decl (* module-scoped process *)
| subprocess_decl (* reusable helper *)
| drop_stmt
| override_decl
;
description = quoted_string ;
field_assignment = field_path ":" value ;
labels_block = "labels" "{" label_entry* "}" ;
label_entry = label_key ":" value
| "drop" label_key
;
label_key = identifier ("." identifier)* ;
drop_stmt = "drop" qualified_name ;
override_decl = "override" ( facet_decl | interface_decl | module_decl ) ;

Facet declarations

facet_decl = facet_kind identifier facet_body? ;
facet_kind = "facet" | identifier ; (* "facet" or user-defined *)
facet_body = "{" facet_member* "}" ;
facet_member = field_assignment
| description
| labels_block
| facet_decl (* nested facets *)
| interface_decl
| drop_stmt
| override_decl
;

Interface declarations

interface_decl = kind_name identifier interface_body? ;
kind_name = identifier ; (* registered interface kind *)
interface_body = "{" interface_member* "}" ;
interface_member = field_assignment
| description
| labels_block
| subscription
| drop_stmt
;
subscription = "subscribes" ":" qualified_name ;

Process declarations

process_decl = "process" stable_id? identifier in_clause? "{" process_body "}" ;
process_body = process_member* ;
process_member = process_step
| description
| subprocess_decl
;
process_step = step_simple
| step_if
| step_switch
| step_parallel
| step_each
| step_try
| step_do
| step_fail
| step_finish
;
step_simple = module_ref ">" interface_ref step_label? ;
module_ref = qualified_name ; (* resolves to module or actor *)
interface_ref = qualified_name ; (* resolves to interface leaf *)
step_label = ":" quoted_string ;
step_if = "if" condition step_body ("else" "if" condition step_body)* ("else" step_body)? ;
condition = identifier | quoted_string ;
step_switch = "switch" condition? "{" switch_case+ "}" ;
switch_case = case_label step_body ;
case_label = identifier | quoted_string ;
step_parallel = "parallel" "{" parallel_branch+ "}" ;
parallel_branch = ":" process_step | "{" process_step* "}" ;
step_each = "each" identifier "in" qualified_name step_body ;
step_try = "try" step_body ("catch" catch_label? step_body)* ;
catch_label = identifier | quoted_string ;
step_body = "{" process_step* "}" | ":" process_step ;
step_do = "do" identifier arg_list? ;
arg_list = "(" arg ("," arg)* ")" ;
arg = identifier | quoted_string ;
step_fail = "fail" quoted_string? ;
step_finish = "finish" quoted_string? ;
subprocess_decl = "subprocess" stable_id? identifier param_list? "{" process_body "}" ;
param_list = "(" identifier ("," identifier)* ")" ;

View declarations

view_decl = "view" stable_id? identifier "{" view_body "}" ;
view_body = view_member* ;
view_member = view_focus
| view_group
| view_layout
| view_include
| view_exclude
| description
;
view_focus = "focus" label_key ":" value ;
view_group = "group" "by" label_key ;
view_layout = "layout" ("elk" | "dagre" | "force" | "manual") ;
view_include = "include" pattern_list ;
view_exclude = "exclude" pattern_list ;
pattern_list = quoted_string ("," quoted_string)* ;

package.archspace grammar

manifest = manifest_field* ;
manifest_field = name_field
| version_field
| widgets_field
| dependencies_block
| use_decl
;
name_field = "name" ":" dotted_name ;
version_field = "version" ":" quoted_string ;
widgets_field = "widgets" ":" quoted_string ;
dependencies_block = "dependencies" "{" dep_entry* "}" ;
dep_entry = dotted_name ":" quoted_string ","? ;
use_decl = "export"? "use" use_targets "from" dotted_name ;
use_targets = "*" | use_import ("," use_import)* ;
use_import = identifier ("as" identifier)? ;
dotted_name = identifier ("." identifier)+ ;

File extension

.arch for source files. package.archspace for the manifest.

Encoding

UTF-8.

Whitespace

Not syntactically significant outside quoted strings and comments. Indentation is recommended for readability; stdlib uses 4 spaces.

Multi-line strings

A quoted string may span multiple lines. The lexer auto-dedents: a leading whitespace-only line and the minimum shared indent on remaining lines are stripped. Only recognized escape: \".

Triple-quoted strings ("""…""") are raw — no escapes, no interpolation.

See also