Приложение A: Грамматика
Это приложение — плотный справочник. Для изучения языка читайте книгу, начиная с Предисловия.
Лексические элементы
Заголовок раздела «Лексические элементы»Комментарии
Заголовок раздела «Комментарии»// однострочный
/* многострочный комментарий */Идентификаторы
Заголовок раздела «Идентификаторы»identifier = letter (letter | digit | "_")*stable_id = "#" alphanumeric+qualified_name = identifier ("." identifier)*quoted_string = '"' (any_char - '"' | '\"')* '"' | '"""' (any_char* - '"""') '"""' (* triple-quoted: no escapes *)Зарезервированные ключевые слова (файлы .arch)
Заголовок раздела «Зарезервированные ключевые слова (файлы .arch)»type, in, export, use, from,aspect, aspects, required, cascade, append,override, drop,process, subprocess, view,each, if, else, select, one, try, catch, parallel, branch,join, race, out, await, reversible, unwind, on, do, go, as, dist, fail, finish,focus, group, by, layout, include, exclude,true, falseaspect — жёсткое ключевое слово, открывающее каждую форму членства/классификации (aspect k: v, aspect { … }, aspect k for …). aspects по-прежнему лексируется как ключевое слово, но зарезервировано-с-ошибкой: старые формы aspects { … } / aspects.x всё ещё парсятся (для восстановления после ошибки), но поднимают диагностику 'labels' was renamed to 'aspect'; ни один тип, интерфейс или модуль не может называться aspects.
focus теперь — клауза акцента проекции (§Декларации проекций) — она подсвечивает совпадающие элементы и никогда не меняет, какие узлы выбирает проекция. layout, include и exclude остаются зарезервированными, но являются устаревшими: каждое всё ещё парсится, но лишь для того, чтобы поднять целевую диагностику, указывающую на замену (layout → закрепить позицию через style; include/exclude → выбирать через show/hide).
export, use, from и as допустимы как в файле .arch (импорты use … from с файловой областью видимости — as переименовывает локально — и export type / export interface / export subprocess), так и в манифесте package.archspace.
package, name, version, widgets, repo, commit и dependencies распознаются как имена полей/блоков в грамматике манифеста, но не являются зарезервированными словами — они нигде не затеняют идентификаторы.
Типы не являются ключевыми словами
Заголовок раздела «Типы не являются ключевыми словами»Типы модулей (service, database, system, …), типы поверхностей и типы интерфейсов (rest_create, rest_read, kafka, …) не являются зарезервированными ключевыми словами — это пользовательские идентификаторы, вводимые декларациями type module …, type surface …, type interface ….
Базовые типы. module, surface, interface — предзарегистрированные базовые типы; это идентификаторы, не ключевые слова. process и view — предзарегистрированные базовые типы и зарезервированные ключевые слова, потому что их тела имеют специализированные грамматические правила.
Операторы и пунктуация
Заголовок раздела «Операторы и пунктуация»{ } ( ) [ ] : , ; . * > = | \Стрелка шага процесса — > (одиночный «больше»); = привязывает результат шага (order = Customer > Orders.CreateOrder); * — маркер каскад-группы (cascade *); ; разделяет шаги в строку внутри блока/тела; | (веер) и \ (змейка) — ведущие строчные глифы в теле процесса: | пишет шаг против головы предыдущего соседа, \ — против его хвоста. Фрагменты грамматики ниже это отражают.
Грамматика (EBNF)
Заголовок раздела «Грамматика (EBNF)»Верхний уровень
Заголовок раздела «Верхний уровень»program = declaration* ;
declaration = use_decl | type_decl | module_decl | process_decl | view_decl | subprocess_decl | process_step (* v0.7: a bare step at root — an anonymous single-step process; caller is explicit at root, no enclosing module *) ;
(* `use` is valid at the top of a `.arch` file (file-scoped) and in a `package.archspace` manifest (package- or space-scoped). *)use_decl = "export"? "use" use_targets "from" dotted_name ;use_targets = "*" | use_import ("," use_import)* ;use_import = identifier ("as" identifier)? ;dotted_name = identifier ("." identifier)* ;Декларации типов
Заголовок раздела «Декларации типов»type_decl = "export"? "type" stable_id? parent_type identifier type_body? ;
parent_type = qualified_name ; (* validator rejects 'process' and 'view'; may be space-qualified *)
type_body = "{" type_member* "}" ;
type_member = type_field_decl | aspect_decl (* replaces type_label_block *) | type_aspect_blank | 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)* ;
(* `required aspect <key>` — a mandatory aspect blank on a type body. `cascade`/`append` are rejected on aspects; aspects always cascade with override semantics (Spec §4.4). *)type_aspect_blank = "required" "aspect" aspect_key ( ":" aspect_value_list )? ;
type_subdecl = "required"? ( surface_decl | interface_decl | module_decl ) ;
value = identifier | quoted_string | number | "true" | "false" ;Декларации модулей
Заголовок раздела «Декларации модулей»module_decl = type_name stable_id? identifier? in_clause? module_body? ;
(* v0.7: the name (identifier) may be OMITTED for a CUSTOM-typed nested module — it auto-takes its type name, snake_case→UpperCamelCase (type `database` → `Database`). Validator constraints not in the EBNF: base `module` does not qualify; the applied type must be used exactly ONCE in the parent; no stable_id until promoted; it is NOT a TODO (fully resolved). *)type_name = identifier ; (* registered module type *)
in_clause = "in" qualified_name ;
module_body = "{" module_member* "}" ;
module_member = field_assignment | description | aspect_decl (* replaces labels_block *) | surface_decl | interface_decl | module_decl (* nested submodules *) | process_decl (* module-scoped process *) | subprocess_decl (* reusable helper *) | process_step (* v0.7: bare step — anonymous single-step process; implicit caller = this module *) | drop_stmt | override_decl ;
description = quoted_string ;
field_assignment = field_path ":" value ;
(* ASPECT — the keyword takes no dot after it (`aspect deployment.zone`, not `aspect.deployment.zone`). An inline entry's value is OPTIONAL (a bare `aspect domain` is a valueless blank). A bare STRING value is a classification (a shared group identity); a bare MODULE-REF value is a membership — the ref must resolve to a real module, which becomes a *place* on that key's plane (Spec §4.4). Block entries are separated by `;` or a newline — NEVER a comma; `aspect { a: "x", b: "y" }` is a parse error, write `aspect { a: "x"; b: "y" }` or one entry per line. *)aspect_decl = "aspect" ( aspect_inline | aspect_block ) ;aspect_inline = aspect_key ( ":" aspect_value_list )? ;aspect_key = identifier ("." identifier)* ;aspect_block = "{" aspect_entry* "}" ; (* SINGULAR keyword — one block, many keys; entries separated by `;` or a newline *)aspect_entry = "drop" aspect_key | "required" aspect_key ( ":" aspect_value_list )? | aspect_key ":" aspect_value_list ;
(* Aspect VALUES accept a scalar, a bracketed multi-value list (multi- membership — `tag: ["edge", "public"]` joins both), OR a module reference (dotted — places nest, e.g. `Euro.DC1`) with an optional `as <instance>` naming the member's instance at that place. `as` is legal ONLY in an aspect value — in a general field value it is a parse error. Multiple bare values on one line are comma-separated (`Euro as active, Euro as standby`); trailing `,` is a parse error. *)aspect_value_list = aspect_value ( "," aspect_value )* ;aspect_value = quoted_string | number | "true" | "false" | bracket_array | qualified_name ( "as" identifier )? ;bracket_array = "[" ( aspect_value ( ","? aspect_value )* ","? )? "]" ;
drop_stmt = "drop" qualified_name ;
override_decl = "override" ( surface_decl | interface_decl | module_decl ) ;Декларации поверхностей
Заголовок раздела «Декларации поверхностей»surface_decl = surface_type identifier surface_body? ;
surface_type = "surface" | identifier ; (* "surface" or user-defined *)
surface_body = "{" surface_member* "}" ;
surface_member = field_assignment | description | aspect_decl (* classification/required/drop forms only — a surface confers no membership presence *) | surface_decl (* nested surfaces *) | interface_decl | drop_stmt | override_decl ;Декларации интерфейсов
Заголовок раздела «Декларации интерфейсов»interface_decl = "export"? type_name identifier interface_body? ;
type_name = identifier ; (* registered interface type *)
interface_body = "{" interface_member* "}" ;
interface_member = field_assignment | description | aspect_decl (* classification/required/drop forms only — an interface confers no membership presence *) | drop_stmt ;
(* v0.7 removed the `subscribes:` member. An event is an async-kind interface (e.g. `kafka`) reached by an ordinary `>` process edge — no subscription wiring on the interface. *)Декларации процессов
Заголовок раздела «Декларации процессов»process_decl = "process" stable_id? identifier in_clause? "{" process_body "}" ;
process_body = ( description | process_step )* ;
process_step = ( simple_step step_name? ) | note_step | each_step | if_step | select_step | try_step | parallel_step | reversible_step | await_step | do_step | go_step | owner_block | fail_step | finish_step ;
(* OWNER — who performs the node. A qualified name (module / actor / earlier-bound name), `|` (fan = the previous sibling's head), or `dist` (distributed / emergent — no coordinator). Omitted = inherit from the nearest enclosing owner, else a TODO. `dist` is control-only (a call always has a caller) and does NOT propagate. Resolution: explicit → `|` → nearest non-dist enclosing → TODO. *)owner = qualified_name | "|" | "dist" ;caller = qualified_name | "|" ; (* note / `do` / unwind-call owner: never `dist`, never `\` *)call_caller = caller | "\\" ; (* `\\` (snake) is call-only *)
(* OWNER BLOCK — set the owner (or `dist`) for a run of steps. *)owner_block = ( qualified_name | "|" | "dist" ) block ;
(* CALL — caller (= owner) left of `>`, may be omitted (anonymous head / bare) or `|` (fan) / `\` (snake, call-only). Hops CHAIN: `A > B > C` desugars to `A > B ; B > C`, each hop's caller being the top module of the previous callee; binding captures the final hop; linear only. A call_target resolving to a MODULE synthesizes an anonymous interface (a TODO); a trailing "." marks an unspecified interface (a TODO). *)simple_step = ( identifier "=" )? call_caller? ( ">" call_target arg_list? )+ ;step_name = "as" identifier ; (* name a step for `go` / diff *)
(* A path. A single "." is the sole separator. A TRAILING "." marks the terminal interface as unspecified/anonymous (a TODO). A reserved keyword is legal in member position after "." (`Worker.process`) — never as the first segment. *)call_target = identifier ( "." member_seg )* "."? ;member_seg = identifier | keyword ;
arg_list = "(" ( arg ("," arg)* )? ")" ;arg = identifier ; (* bare intent names; not type-checked *)
(* NOTE — owner-anchored free-form string, no edge. The owner is REQUIRED (`Orders "…"`); a bare string is a description, not a note. *)note_step = caller quoted_string ;
(* All heads / conditions / labels / await targets below are FREE-FORM: rendered, not resolved or validated. A body is a brace block or a single `:`-step. *)
(* BRANCH — exclusive choice. A condition with no body = a draft branch. *)if_step = owner? "if" condition? body? ( "else" "if" condition? body? )* ( "else" body? )? ;condition = identifier | quoted_string ;
(* SELECT — multi-way, INCLUSIVE (every matching case runs). `one` = first match, N = first N matching in order, bare = all matching. *)select_step = owner? "select" select_count? select_head? "{" select_case+ "}" ;select_count = "one" | number ;select_head = identifier | quoted_string ;select_case = case_label body ;case_label = identifier | quoted_string ;
(* LOOP / RETRY. `each` iterates. `each <bound> try { } catch { } else { }` = the retry form (catch = restoration + retry; success exits; bound exhausted → else). A `try` *nested* in a plain `each` body is a per-iteration guard. *)each_step = owner? "each" each_head? ( retry_tail | body ) ;each_head = ( ( identifier | quoted_string ) ( "in" ( qualified_name | quoted_string ) )? ) | number ;retry_tail = "try" block ( "catch" catch_label? body )* ( "else" body )? ;catch_label = identifier | quoted_string ;
(* GUARD — plain try/catch: handle the failure, continue forward (no retry). *)try_step = owner? "try" body ( "catch" catch_label? body )* ;
(* PARALLEL — concurrent branches with a PREFIX merge clause. `out` = detach (no wait); `join N` = proceed at N, keep losers (N omitted = all); `race N` = proceed at N, cancel losers (N omitted = 1). The merge may be a boolean over branch names. `select` = concurrent inclusive; `each` = fan-out. *)parallel_step = owner? "parallel" "out"? merge_clause? parallel_body ;parallel_body = ( "each" each_head block ) (* fan-out: a loop body *) | ( "select" select_count? "{" branch+ "}" ) (* concurrent inclusive *) | ( "{" branch+ "}" ) ; (* plain branches *)merge_clause = ( "join" | "race" ) merge_spec? ;merge_spec = number | bool_join ;bool_join = bool_and ( "or" bool_and )* ; (* `or`/`and` case-insensitive; no `not` *)bool_and = bool_atom ( "and" bool_atom )* ;bool_atom = identifier | "(" bool_join ")" ; (* branch names only *)
(* BRANCH — a parallel branch: optionally NAMED (the name a boolean merge refers to), then a one-liner, a block, or a nested control node. *)branch = "branch" branch_name? ( ( ":" process_step ) | block | control_step ) ;branch_name = identifier ;control_step = if_step | select_step | each_step | try_step | parallel_step | reversible_step | await_step ;
(* AWAIT — timed / event wait, owned by the waiter; target free-form. *)await_step = owner? "await" await_target ;await_target = quoted_string | ( identifier | number )+ ;
(* REVERSIBLE — saga span; trigger defaults to `on error`. Each forward step or block may carry an `unwind` (inline catch-and-rethrow). `unwind` may NOT nest inside control — wrap the control in a block and put `unwind` on the block. A line may be reversal-only (`unwind` with no forward action). *)reversible_step = owner? "reversible" trigger? "{" reversible_item* "}" ;trigger = "on" ( identifier | quoted_string ) ;reversible_item = description | ( ( simple_step | block ) unwind_clause? step_name? ) | ( unwind_clause step_name? ) (* reversal-only line *) | note_step | do_step | go_step | fail_step | finish_step | control_step ;unwind_clause = "unwind" unwind_action ;unwind_call = ( identifier "=" )? caller? ( ">" call_target arg_list? )+ ;unwind_action = unwind_call | fail_step | finish_step | do_step | block ;
(* RE-ENTRY / REUSE — structural ops, OWNERLESS. `go` re-enters a step named with `as` and resumes forward. `do` splices a subprocess; an optional caller prefix is the TEMPLATE default-caller for the subprocess's owner-omitted steps (bound to `subprocess X on Caller`), NOT an owner of the `do`. *)go_step = "go" identifier ;do_step = caller? "do" qualified_name arg_list? ;
fail_step = "fail" quoted_string? ; (* terminate: failure *)finish_step = "finish" quoted_string? ; (* terminate: success *)
(* Steps in a block / body are separated by newline OR `;` (inline). *)block = "{" ( process_step ( ";" process_step )* )? "}" ;body = block | ( ":" process_step ( ";" process_step )* ) ;
subprocess_decl = "export"? "subprocess" stable_id? identifier on_caller? param_list? "{" process_body "}" ;on_caller = "on" identifier ; (* template default-caller param, bound at the `do` site *)param_list = "(" ( identifier ("," identifier)* )? ")" ; (* intent-only, not bound *)Декларации проекций (v0.10)
Заголовок раздела «Декларации проекций (v0.10)»Тело view — это тело УПОРЯДОЧЕННЫХ КЛАУЗ (как process/policy): зона
заголовка (описание / поле / knob), за которой следует последовательность
упорядоченных клауз. Проекция несёт не более одной клаузы представления
(table / matrix / flow) — доска — это отсутствие такой клаузы.
view_decl = "view" stable_id? view_head "{" view_body "}" ; (* views are never `export`ed. Declares at file top level or in a module body; `in <Module> view … { }` is the placed twin of the body form. A module-scoped view resolves selector names from its module context first. *)
view_head = identifier identifier? ; (* <Name> | <ParentView> <Name> — the two-identifier form is a VIEW INSTANCE: its clauses append to the referenced (parent) view. *)
view_body = view_header_member* view_clause* ;
view_header_member = description | knob_decl (* a view parameter, four shapes below *) | field_assignment (* base view only *) | knob_binding ; (* instance only — binds a parent-view knob *)knob_binding = identifier ":" signed_value ;
view_clause = show_clause | hide_clause | focus_clause | group_by_clause | on_clause | style_clause | flow_clause | table_clause | matrix_clause | grid_clause | lens_clause | story_clause ;
show_clause = "show" selector ; (* union matching nodes/edges into the view *)hide_clause = "hide" selector ; (* subtract *)focus_clause = "focus" selector ; (* emphasis; never changes the node selection *)group_by_clause = "group" "by" ( getter | "in" selector ) ; (* nest by repetition; the getter is sigiled (`@@team`) and groups by VALUE, the `in` form groups by CONTAINMENT — its selector names the containers, one frame each *)on_clause = "on" plane_name ("," plane_name)* ; (* one = plane board, many = weave; an `on` in a `flow` view diagnoses — a process carries its own plane *)style_clause = "style" selector "{" style_member* "}" ; (* the universal rewrite rule; the subject may be `violating <Policy>` *)
flow_clause = "flow" ( qualified_name | knob_ref ) [ "sequence" | "bpmn" ] flow_body? ; (* the process representation; plain `flow X` is the swimlane walkthrough, `sequence` a UML lifeline diagram, `bpmn` a lane/pool BPMN. `flow $knob` parameterizes the subject. A `flow_body` is `bpmn`-only. *)flow_body = "{" ( lane_entry | pool_entry )* "}" ;lane_entry = "lane" "by" getter (* one lane per getter value *) | "lane" quoted_string ":" selector (* named lane merging a query *) | "lane" selector ; (* expand one callee's steps *)pool_entry = "pool" "by" getter (* one pool per getter value *) | "pool" quoted_string ":" selector (* named pool merging a query *) | "pool" ( qualified_name | knob_ref ) ; (* one pool for an element ref *)
table_clause = "table" "{" ( table_column | table_sort )* "}" ;table_column = "column" getter quoted_string? (* getter form — editable *) | "column" quoted_string ":" expression ; (* calc form — read-only *)table_sort = "sort" "by" getter ;
matrix_clause = "matrix" ( "{" matrix_entry* "}" )? ;matrix_entry = "axis" getter | "rows" getter | "cols" getter | "order" "by" matrix_order | "cluster" ;matrix_order = "cluster" | "layer" | getter ; (* DSM: `axis` groups the shared SQUARE axis; `rows`/`cols` diverge only for a rectangular matrix (no `order`/`cluster` there). `order by cluster`/`layer` runs SCC + topological analysis; `cluster` boxes cycles on the diagonal and implies `order by cluster`. *)grid_clause = "grid" ( "{" ( "rows" getter | "cols" getter | "color" getter )* "}" )? ; (* cross-tab: cells LIST the modules at each (row, col) label intersection; `color` tints members by a third field. *)
lens_clause = "lens" "{" lens_entry* "}" ; (* computed inspector values *)lens_entry = identifier quoted_string? ":" expression ; (* name ["Title"]: <expr> *)
story_clause = "story" "{" story_chapter+ "}" ; (* an ordered walk; at most 5 chapters *)story_chapter = "chapter" quoted_string "{" quoted_string? story_node_list "}" ; (* the LEADING string is the chapter's note, the same law module and view descriptions obey; the nodes follow, and their WRITTEN ORDER is the narration's order *)story_node_list = selector ( ("," | logical_line_break) selector )* ;
plane_name = qualified_name ; (* dotted, open-world; no `plane` keyword *)В story_node_list logical_line_break — это перевод строки, разделяющий два
селектора: единственное место в теле проекции, где перенос строки несёт смысл,
чтобы узлы главы можно было писать по одному на строку, а не через запятую.
Тело style. Тело клаузы style (общее с декларацией верхнего уровня
style bundle) — это набор переопределений полей, вложенных ГРУПП полей без
двоеточия, директив rename / pin и use <Bundle>.
style_member = style_rewrite | style_group | rename_directive | pin_directive | style_use ;style_rewrite = qualified_name ":" expression ; (* RHS is the one expression grammar *)style_group = qualified_name "{" style_member* "}" ; (* colon-less nested field group *)rename_directive = "rename" quoted_string ; (* a display label *)pin_directive = "pin" signed_number "," signed_number ; (* WYSIWYG position; drag writes it *)style_use = "use" identifier ; (* apply a named style bundle *)signed_number = "-"? number ;Ручки (knob). knob — это параметр проекции в одной из ЧЕТЫРЁХ форм.
Голова снимает неоднозначность: knob { открывает блок записей
перечисления; иначе, после имени ручки, : → литеральное значение по
умолчанию (число/слайдер), from → выпадающий список значений, а второй
идентификатор → выбор элемента по типу.
knob_decl = "knob" ( knob_block | knob_number | knob_from | knob_element ) ;
knob_block = "{" knob_enum_entry* "}" ;knob_enum_entry = identifier ( "one" | "any" ) "of" ":" atomic_value ("," atomic_value)* ; (* single | multi; each element is ATOMIC — string / identifier / number ONLY (no boolean, no array) *)atomic_value = identifier | quoted_string | number ;
knob_number = identifier ":" signed_value knob_restrictions? ; (* literal default ⇒ slider *)knob_restrictions = "{" ( ("min" | "max" | "step") ":" signed_number )* "}" ;
knob_from = identifier "from" getter ; (* a dropdown over a plane/aspect's values *)knob_element = identifier identifier ; (* `knob <type> <name>` — a kind-led element picker *)
(* A kind-determined value slot (knob default / binding) is a `scalar` — string, identifier, number, or boolean — with an optional leading `-` on a numeric literal (drag writes negatives). It is NOT an array. *)signed_value = "-" number | scalar ;Декларации селекторов (v0.10)
Заголовок раздела «Декларации селекторов (v0.10)»Селектор выбирает набор элементов модели ИЛИ набор рёбер — его сорт
определяется по тексту (стрелка делает его edge-сортом, иначе node-сортом).
Селекторы — общее ядро под view (show/hide/focus/style), policy
и violating. Приоритет (от слабого к сильному): or < and < not <
стрелка/терм.
selector = sel_or ;sel_or = sel_and ("or" sel_and)* ;sel_and = sel_not ("and" sel_not)* ;sel_not = "not" sel_not | sel_term ;sel_term = sel_arrow | sel_primary ;
(* Edge patterns. A chain (A > B > C) is a single edge-sort term — the union of its hops. `>` = direct adjacency, `>>` = directed reachability cone, `<>` = undirected (symmetrized). `within N` is a suffix after a hop's right side (`A <> B within 2`); on a chain it binds — and distributes — per hop. *)sel_arrow = sel_primary ( arrow_op sel_primary within_bound? )+ ;arrow_op = ">" | ">>" | "<>" ;within_bound = "within" ( NUMBER | knob_ref ) ;
sel_primary = "*" (* universal — every element *) | "this" (* the bound subject (predicates/policies) *) | "outside" (* elements not selected in this view *) | knob_ref (* $name — a view knob *) | aspect_atom (* @@key[:"value" | :$knob] *) | "violating" qualified_name (* a policy's active findings; sort follows it *) | extraction | predicate | "(" selector ")" | qualified_name ; (* a built-in kind, a user type (incl. subtypes), or an element reference *)
extraction = ("sources" | "targets" | "nodes" | "owners") "of" "(" selector ")" ;predicate = "in" sel_primary (* structural containment / process participation *) | "on" plane_name (* plane membership *) | "where" "(" expression ")" ; (* a boolean expression per candidate *)
aspect_atom = "@@" qualified_name (":" (value | knob_ref))? ; (* glued: @@team, @@zone:"pci", @@zone:$zone *)knob_ref = "$" identifier ;Выражения (v0.10)
Заголовок раздела «Выражения (v0.10)»Грамматика выражений — это язык значений: геттеры с сигилами над
элементом, операторы, агрегаты и функции. Селекторы и выражения встречаются
ТОЛЬКО в скобочных ключевых порталах (where (…), exists (…),
count (…), <agg> <getter> of (…)).
expression = expr_or ;expr_or = expr_and ("or" expr_and)* ;expr_and = expr_not ("and" expr_not)* ;expr_not = "not" expr_not | expr_compare ;expr_compare = expr_add ( compare_op expr_add )? ;compare_op = "=" | "!=" | "<" | "<=" | ">" | ">=" ;expr_add = expr_mul ( ("+" | "-") expr_mul )* ;expr_mul = expr_unary ( ("*" | "/") expr_unary )* ;expr_unary = "-" expr_unary | expr_primary ;expr_primary = literal | "this" | getter | aggregate | exists | function_call | "(" expression ")" ;
(* Getters. `@field` reads a field, `@@aspect` reads an aspect; builtins include @name @type @kind @connections @todos @dist @reversible @compensated. A `(…)` suffix is a capability getter with raw argument text (e.g. @ver.changes(...)). *)getter = ("@" | "@@") getter_path ( "(" raw_args ")" )? ;getter_path = word ("." word)* ; (* word may be a reserved keyword after a sigil *)
aggregate = "count" "(" selector ")" | "count" "distinct" getter "of" "(" selector ")" | ("sum" | "min" | "max") getter "of" "(" selector ")" ;exists = "exists" "(" selector ")" ;function_call = identifier "(" ( expression ("," expression)* )? ")" ; (* colorize / heat / css *)
literal = quoted_string | number | "true" | "false" | identifier ; (* a bare identifier is an identifier-VALUE (a bareword, like an unquoted string). The reserved expression words `this` / `exists` / `count` / `sum` / `min` / `max`, and an identifier glued to `(` (a function_call), are matched by earlier expr_primary alternatives — none fall through to this identifier-as-literal case. *)Декларации политик (v0.10)
Заголовок раздела «Декларации политик (v0.10)»policy — это запрос над моделью, выдающий находки (узел или ребро,
нарушающие правило), обеспечиваемый archlang check, всплывающий как
диагностика LSP и выбираемый через violating <Policy>. Политика
объявляется на верхнем уровне файла или в теле модуля; in <Module> policy … { } — размещённый двойник формы с телом. Область видимости политики,
привязанной к модулю, — это поддерево этого модуля: находки по узлам —
по членству в поддереве, находки по рёбрам — по их исходной конечной точке.
policy_decl = "export"? "policy" stable_id? identifier "{" policy_body "}" ;policy_body = ( header_field | policy_rule )* ;header_field = qualified_name ":" value ; (* e.g. severity: error | warning | advisory *)
policy_rule = forbid_rule | require_rule | except_rule | escalate_rule | when_gate ;
forbid_rule = "forbid" selector ; (* a finding per matching node/edge *)require_rule = "require" selector ":" selector ; (* subject : obligation — a finding when unmet *)except_rule = "except" selector quoted_string field_body? ; (* a waiver; reason mandatory *)escalate_rule = "escalate" qualified_name "to" identifier ; (* raise-only severity override *)
(* Change gate — evaluated over a base→head diff (the accept-gate). The `changed(<getter>)` portal narrows to elements whose getter value differs; it is legal on `changed` ONLY — `added`/`removed` take no portal. An edge subject (arrow / `violating`) takes `added`/`removed` only. *)when_gate = "when" selector change_verb "{" review_req* "}" ;change_verb = "added" | "removed" | "changed" ( "(" getter ")" )? ;review_req = "require" "review" "from" ( NUMBER "of" )? ( getter | identifier ) ;Декларации запросов, пакетов стилей и линз (v0.10)
Заголовок раздела «Декларации запросов, пакетов стилей и линз (v0.10)»Четыре декларации управления/словаря, переиспользующие ядро
селекторов/выражений. Все они диспетчеризуются по заголовку члена: заголовок,
за которым следует : / ., — это поле, а не одна из этих деклараций.
Стабильный id, если присутствует, стоит сразу после ключевого слова. view,
policy, query и lens объявляются на верхнем уровне файла или внутри
тела модуля; view и policy дополнительно размещаются через
in <Module> …. style bundle и use policy остаются только верхнего
уровня.
query_decl = "export"? "query" stable_id? identifier ":" selector ; (* a named, reusable selector; `export` publishes it across the package boundary *)
style_bundle_decl = "style" "bundle" stable_id? identifier "{" style_member* "}" ; (* a reusable style body (style_member, above), applied elsewhere via `use <Bundle>`. Not `export`able. *)
lens_decl = "lens" "{" lens_entry* "}" ; (* a computed-inspector block at top level or in a module body; reuses lens_entry (above). Unnamed — no name, no stable_id (dispatched on `lens` immediately followed by `{`). *)
use_policy_stmt = "use" "policy" identifier "from" dotted_name policy_use_body? ;policy_use_body = "{" ( except_rule | escalate_rule )* "}" ; (* governance INSTANTIATION, not a type import: pulls a published `policy` from a package, then may locally waive (`except`) or raise (`escalate`) it. *)Контекстные ключевые слова
Заголовок раздела «Контекстные ключевые слова»Заголовки view/policy/селекторов ниже — это контекстные идентификаторы —
распознаются по позиции (заголовок клаузы / заголовок члена / слот после
сигила), а не жёсткие зарезервированные слова; каждый остаётся допустимым
идентификатором везде в остальных местах. Исключение — focus, group,
by, on и one: они ЯВЛЯЮТСЯ жёсткими лексерными ключевыми словами
(§Зарезервированные ключевые слова), переиспользуемыми в позиции
view/селектора. Обратите внимание на асимметрию one / any — one
жёсткое ключевое слово, any контекстное.
show, hide, style, flow, table, matrix, lens, story, chapter, knob, column,sort, rename, pin, rows, cols, any, of, bundle, sequence, bpmn, lane, pool,policy, query, forbid, require, except, escalate, when, review, severity,violating, sources, targets, nodes, owners, this, outside, where, exists,count, sum, min, max, distinct, and, or, not, withinГрамматика package.archspace
Заголовок раздела «Грамматика package.archspace»Манифест объявляет ровно одно из: package: (корень пакета — непрозрачная единица разрешения) или name: (пространство внутри объемлющего пакета). Полную модель видимости см. в PACKAGE-ARCHSPACE.
manifest = manifest_field* ;
manifest_field = package_field | space_field | version_field | widgets_field | description | evidence_pin | dependencies_block | policy_packs_block | use_decl ;
package_field = "package" ":" dotted_name ; (* package root — opaque unit *)space_field = "name" ":" dotted_name ; (* a space within a package *)version_field = "version" ":" quoted_string ;widgets_field = "widgets" ":" quoted_string ;description = quoted_string ;
evidence_pin = ( "repo" ":" quoted_string ) | ( "commit" ":" quoted_string ) ; (* `package.archspace` ONLY: the code repository this package's `sources:` bindings are checked against, and the revision they are true of. `commit` is required whenever `repo` is set — an unpinned path attests that a file existed once, not that the model is true of a commit. The bindings themselves are ordinary fields (`sources: "src/a.ts:12-88", "src/b.ts"`), so they need no production of their own. *)
dependencies_block = "dependencies" "{" dep_entry* "}" ;dep_entry = dotted_name ":" quoted_string ","? ;
policy_packs_block = "policies" "{" ( dotted_name ":" quoted_string )* "}" ; (* `package.archspace` ONLY (peer of `dependencies { }`): the governance PACKS this package adopts, each pinned to the version the pack declares. Adoption is what makes a pack un-droppable — the gate fails if a pinned pack stops resolving, ships a different version, or has one of its exported policies no longer imported. *)
(* `use_decl` as defined under Top-level; package-scoped at the package root, space-scoped in a space manifest. *)
dotted_name = identifier ("." identifier)* ;Расширение файла
Заголовок раздела «Расширение файла».arch для исходных файлов. package.archspace для манифеста.
Кодировка
Заголовок раздела «Кодировка»UTF-8.
Пробельные символы
Заголовок раздела «Пробельные символы»Синтаксически не значимы вне строк в кавычках и комментариев. Отступы рекомендованы для читаемости; стандартная библиотека использует 4 пробела.
Многострочные строки
Заголовок раздела «Многострочные строки»Строка в кавычках может занимать несколько строк. Лексер автоматически снимает отступ: ведущая строка из одних пробелов и минимальный общий отступ на остальных строках срезаются. Распознаются экранирования \" и \\.
Строки в тройных кавычках ("""…""") — сырые: без экранирований, без интерполяции.
См. также
Заголовок раздела «См. также»- Приложение B: Ключевые слова — что делает каждое зарезервированное слово
- Приложение C: Типы стандартной библиотеки — встроенные типы модулей и интерфейсов
- Глава 1: Установка — для начала работы