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, falseReserved keywords (package.archspace files only)
use, from, as, export, dependenciesname, 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
- Appendix B: Keywords — what each reserved word does
- Appendix C: Stdlib kinds — built-in module and interface kinds
- Chapter 1: Setup — for getting started