Skip to content

Commit feb5728

Browse files
authored
new languge syntax (#55)
1 parent ae04dfc commit feb5728

3 files changed

Lines changed: 237 additions & 132 deletions

File tree

CLAUDE.md

Lines changed: 9 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
## Project Overview
44

5-
ArchML is a text-based DSL for defining software architecture alongside code. It covers functional, behavioral, and deployment architecture domains with consistency checking, navigable web views, and native Sphinx integration. Architecture files use the `.archml` extension.
5+
ArchML is a text-based DSL for defining software architecture alongside code.
6+
It covers functional, behavioral, and deployment architecture domains with consistency checking, navigable web views, and native Sphinx integration. Architecture files use the `.archml` extension.
67

7-
The project is in early development. The DSL syntax for functional architecture is specified in `docs/LANGUAGE_SYNTAX.md`. The overall vision and landscape analysis are in `docs/PROJECT_SCOPE.md`.
88

99
## Tech Stack
1010

@@ -13,42 +13,11 @@ The project is in early development. The DSL syntax for functional architecture
1313
- **Linter/formatter**: ruff
1414
- **Type checker**: ty
1515
- **Testing**: pytest
16-
- **Documentation**: Sphinx (ArchML views will embed natively via a Sphinx extension)
16+
- **Documentation**: Sphinx
1717
- **Distribution**: PyPI
1818

19-
## Project Structure (Target)
2019

21-
```
22-
archml/
23-
├── CLAUDE.md
24-
├── README.md
25-
├── LICENSE
26-
├── pyproject.toml
27-
├── docs/
28-
│ ├── PROJECT_SCOPE.md
29-
│ ├── LANGUAGE_SYNTAX.md
30-
│ └── sphinx/ # Sphinx documentation source
31-
├── src/
32-
│ └── archml/
33-
│ ├── __init__.py
34-
│ ├── parser/ # Lexer and parser for .archml files
35-
│ ├── model/ # Semantic model (systems, components, interfaces, etc.)
36-
│ ├── validation/ # Consistency checks (dangling refs, unused interfaces)
37-
│ ├── views/ # View generation and rendering
38-
│ ├── sphinx_ext/ # Sphinx extension for embedding architecture views
39-
│ ├── lsp/ # Language server (LSP) for VS Code integration
40-
│ ├── webui/ # Dash-based web UI for interactive architecture viewing
41-
│ └── cli/ # Command-line interface
42-
└── tests/ # All tests (mirrors src/ structure)
43-
├── parser/
44-
├── model/
45-
├── validation/
46-
├── views/
47-
├── sphinx_ext/
48-
├── lsp/
49-
├── webui/
50-
└── cli/
51-
```
20+
## Project Structure (Target)
5221

5322
## Common Commands
5423

@@ -59,9 +28,6 @@ uv sync
5928
# Run all tests
6029
uv run pytest
6130

62-
# Run tests with coverage
63-
uv run pytest --cov=archml
64-
6531
# Run a specific test file or test
6632
uv run pytest tests/parser/test_lexer.py
6733
uv run pytest -k "test_parse_component"
@@ -72,12 +38,6 @@ uv run ruff format src/ tests/
7238

7339
# Type check
7440
uv run ty check src/
75-
76-
# Build the package
77-
uv build
78-
79-
# Build Sphinx docs
80-
uv run sphinx-build docs/sphinx docs/sphinx/_build
8141
```
8242

8343
## Development Methodology
@@ -90,37 +50,15 @@ Every new feature requires thorough testing before it is considered complete. Th
9050
4. Ensure all tests pass, ruff reports no issues, and ty finds no type errors using `uv run tools/ci.py`.
9151
5. Commit with a clear message describing the change.
9252

93-
Tests are not optional. A feature without tests is not done.
94-
95-
## ArchML Language Quick Reference
53+
Tests are not optional.
54+
A feature without tests is not done.
9655

97-
The DSL defines architecture through these core constructs:
9856

99-
- **`system`** — groups components or sub-systems
100-
- **`component`** — module with `requires` and `provides` interface declarations; supports nesting
101-
- **`user`** — human actor (role or persona) that interacts with the system; a leaf node
102-
- **`interface`** — typed contract between elements; supports versioning (`@v1`, `@v2`)
103-
- **`type`** — reusable data structure used within interfaces
104-
- **`enum`** — constrained set of named values
105-
- **`connect`** — data-flow edge linking a required interface to a provided interface (`connect A -> B by Interface`)
106-
- **`external`** — marks a system, component, or user as outside the development boundary
107-
- **`import` / `use`** — multi-file composition; `use` always includes the entity type (e.g., `use component X`)
108-
- **`tags`** — arbitrary labels for filtering and view generation
109-
- **`field`** — typed data element with optional `description` and `schema` annotations
110-
111-
Primitive types: `String`, `Int`, `Float`, `Decimal`, `Bool`, `Bytes`, `Timestamp`, `Datetime`
112-
Container types: `List<T>`, `Map<K, V>`, `Optional<T>`
113-
Filesystem types: `File` (with `filetype`, `schema`), `Directory` (with `schema`)
57+
## ArchML Language Quick Reference
11458

11559
Full syntax specification: `docs/LANGUAGE_SYNTAX.md`
11660

117-
## Architecture and Design Decisions
11861

119-
- The parser produces an AST which is then lowered into a semantic model. Validation runs on the semantic model, not the AST.
120-
- Views are not part of the architecture language. They will be defined in a separate view DSL that references model entities.
121-
- The Sphinx extension reads `.archml` files directly and renders views inline — it is not an export pipeline.
122-
- The CLI is the primary user entry point for parsing, validating, and generating views outside of Sphinx.
123-
- A Language Server Protocol (LSP) implementation provides IDE support (diagnostics, completion, go-to-definition) for `.archml` files, with a VS Code extension as the primary client.
12462

12563
## Coding Conventions
12664

@@ -129,6 +67,7 @@ Full syntax specification: `docs/LANGUAGE_SYNTAX.md`
12967
- Prefer dataclasses or attrs for model types.
13068
- Keep modules focused: one responsibility per module.
13169
- The test directory structure mirrors the source structure. Every module in `src/archml/<package>/` has a corresponding directory in `tests/<package>/`. Test files are prefixed with `test_`: `src/archml/parser/lexer.py` -> `tests/parser/test_lexer.py`.
70+
- Use proper docstrings for public functions.
13271
- Every Python file follows this layout:
13372

13473
```python
@@ -142,7 +81,6 @@ import ...
14281
# ###############
14382

14483
def public_function() -> None:
145-
"""Docstring describing the function."""
14684
...
14785

14886
# ################
@@ -153,4 +91,4 @@ def _private_helper() -> None:
15391
...
15492
```
15593

156-
The copyright header and imports come first. Public interface (classes, functions, constants) is separated from private implementation by section comments. All private members are prefixed with an underscore.
94+
The copyright header and imports come first. Public interface (classes, functions, constants) is separated from private implementation by section comments. All private members are prefixed with an underscore.

README.md

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,26 @@ system ECommerce {
8787
title = "Order Service"
8888
description = "Accepts, validates, and processes customer orders."
8989
90-
requires OrderRequest
91-
requires PaymentRequest
92-
requires InventoryCheck
93-
provides OrderConfirmation
90+
// Internal pipeline: Validator feeds into Processor
91+
component Validator {
92+
requires OrderRequest as input
93+
provides ValidationResult as output
94+
}
95+
96+
component Processor {
97+
requires ValidationResult as input
98+
requires PaymentRequest
99+
requires InventoryCheck
100+
provides OrderConfirmation
101+
}
102+
103+
connect Validator.output -> Processor.input
104+
105+
// Promote inner ports to the OrderService boundary
106+
expose Validator.input // requires OrderRequest
107+
expose Processor.PaymentRequest // requires PaymentRequest
108+
expose Processor.InventoryCheck // requires InventoryCheck
109+
expose Processor.OrderConfirmation // provides OrderConfirmation
94110
}
95111
96112
component PaymentGateway {
@@ -104,14 +120,15 @@ system ECommerce {
104120
component InventoryManager {
105121
title = "Inventory Manager"
106122
107-
requires InventoryCheck
123+
requires InventoryCheck as requests [1..*] // accepts requests from multiple sources
108124
provides InventoryStatus
109125
}
110126
111-
connect Customer -> OrderService by OrderRequest
112-
connect OrderService -> Customer by OrderConfirmation
113-
connect OrderService -> PaymentGateway by PaymentRequest
114-
connect OrderService -> InventoryManager by InventoryCheck {
127+
// Short form: interface is unambiguous on both sides
128+
connect Customer -> OrderService by OrderRequest
129+
connect OrderService -> Customer by OrderConfirmation
130+
connect OrderService -> PaymentGateway by PaymentRequest
131+
connect OrderService -> InventoryManager by InventoryCheck {
115132
protocol = "HTTP"
116133
}
117134
connect PaymentGateway -> StripeAPI by PaymentRequest {
@@ -125,21 +142,25 @@ Large architectures split naturally across files. A `from ... import` statement
125142

126143
## Language at a Glance
127144

128-
| Keyword | Purpose |
129-
| ----------------------- | --------------------------------------------------------------------- |
130-
| `system` | Group of components or sub-systems with a shared goal |
131-
| `component` | Module with a clear responsibility; may nest sub-components |
132-
| `user` | Human actor (role or persona) that interacts with the system |
133-
| `interface` | Named contract of typed data fields; supports `@v1`, `@v2` versioning |
134-
| `type` | Reusable data structure (used within interfaces) |
135-
| `enum` | Constrained set of named values |
136-
| `field` | Named, typed data element with optional `description` and `schema` |
137-
| `requires` / `provides` | Declare consumed and exposed interfaces on a component or user |
138-
| `connect A -> B by I` | Data-flow edge linking a required interface to a provided one |
139-
| `external` | Marks a system, component, or user as outside the development boundary |
140-
| `from … import` | Bring specific definitions from another file into scope |
141-
| `use component X` | Place an imported entity inside a system |
142-
| `tags` | Arbitrary labels for filtering and view generation |
145+
| Keyword | Purpose |
146+
| ---------------------------- | --------------------------------------------------------------------------------- |
147+
| `system` | Group of components or sub-systems with a shared goal |
148+
| `component` | Module with a clear responsibility; may nest sub-components |
149+
| `user` | Human actor (role or persona) that interacts with the system |
150+
| `interface` | Named contract of typed data fields; supports `@v1`, `@v2` versioning |
151+
| `type` | Reusable data structure (used within interfaces) |
152+
| `enum` | Constrained set of named values |
153+
| `field` | Named, typed data element with optional `description` and `schema` |
154+
| `requires` / `provides` | Declare consumed and exposed interface ports on a component or user |
155+
| `requires X as name` | Named port — required when the same interface appears more than once |
156+
| `requires X as name [1..*]` | Multi-port with cardinality — for fan-in patterns; `[N]`, `[*]`, `[M..N]` also valid |
157+
| `expose Sub.port` | Promote a nested component's port to the enclosing component's boundary |
158+
| `connect A -> B by I` | Short form: wire interface I between A and B (when I is unambiguous on both sides) |
159+
| `connect A.p -> B.p` | Long form: wire named ports directly (no `by` needed) |
160+
| `external` | Marks a system, component, or user as outside the development boundary |
161+
| `from … import` | Bring specific definitions from another file into scope |
162+
| `use component X` | Place an imported entity inside a system |
163+
| `tags` | Arbitrary labels for filtering and view generation |
143164

144165
Primitive types: `String`, `Int`, `Float`, `Decimal`, `Bool`, `Bytes`, `Timestamp`, `Datetime`
145166
Container types: `List<T>`, `Map<K, V>`, `Optional<T>`

0 commit comments

Comments
 (0)