Skip to content

Commit 2ea8c2e

Browse files
committed
chore: Cleanup
- Use Alire for building examples, too - Remove accidentally committed binaries
1 parent 2b1e3e1 commit 2ea8c2e

35 files changed

+323
-3883
lines changed

.gitignore

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
/obj/
2-
/lib/
3-
/alire/
4-
/config/
5-
.claude
6-
CLAUDE.md
7-
/bin/
1+
obj/
2+
lib/
3+
alire/
4+
config/
5+
bin/

AGENTS.md

Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
# TinyAML - Ada YAML Library
2+
3+
A strict YAML subset parser for Ada 2022, inspired by [StrictYAML](https://github.com/crdoconnor/strictyaml). Designed for configuration files with a hybrid validation approach: parse to untyped tree, optionally validate with schemas.
4+
5+
## Build Commands
6+
7+
All build commands must run in a distrobox container:
8+
9+
```bash
10+
distrobox enter ubuntu -- alr build # Build library
11+
distrobox enter ubuntu -- bash -c 'cd tests && alr build' # Build tests
12+
distrobox enter ubuntu -- bash -c 'cd examples && alr build' # Build examples
13+
distrobox enter ubuntu -- ./tests/bin/test_runner # Run tests
14+
```
15+
16+
## Project Structure
17+
18+
```
19+
tinyaml_ada/
20+
├── alire.toml # Alire package manifest (crate: tinyaml)
21+
├── tinyaml.gpr # Main GPR project file
22+
├── src/
23+
│ ├── tinyaml.ads/adb # Root: exceptions, Source_Position, Source_Span
24+
│ ├── tinyaml-lexer.ads/adb # Tokenizer with indentation tracking
25+
│ ├── tinyaml-nodes.ads/adb # Abstract YAML_Node, Node_Access, type checking
26+
│ ├── tinyaml-nodes-scalar.ads/adb # Scalar_Node
27+
│ ├── tinyaml-nodes-sequence.ads/adb # Sequence_Node
28+
│ ├── tinyaml-nodes-map.ads/adb # Map_Node
29+
│ ├── tinyaml-nodes-navigation.ads/adb # Navigate, Get_String
30+
│ ├── tinyaml-nodes-prelude.ads # Convenience re-exports
31+
│ ├── tinyaml-parser.ads/adb # Recursive descent parser
32+
│ ├── tinyaml-schemas.ads/adb # Abstract Schema base
33+
│ ├── tinyaml-schemas-*.ads/adb # Concrete schema types
34+
│ ├── tinyaml-schemas-prelude.ads # Convenience re-exports
35+
│ └── tinyaml-validation.ads/adb # Validation engine
36+
├── tests/
37+
│ ├── tinyaml_tests.gpr
38+
│ ├── test_harness.ads/adb # Simple test framework
39+
│ ├── test_lexer.ads/adb
40+
│ ├── test_parser.ads/adb
41+
│ ├── test_validation.ads/adb
42+
│ └── test_runner.adb
43+
└── examples/
44+
├── tinyaml_examples.gpr
45+
├── basic_parsing.adb # Parse without validation
46+
├── with_validation.adb # Schema validation
47+
└── error_handling.adb # Error handling patterns
48+
```
49+
50+
## Design Decisions
51+
52+
- **Ada 2022** with FSF GNAT compatible subset (no user-defined literals, parallel blocks)
53+
- **StrictYAML philosophy**: No implicit typing, no flow style, no anchors/aliases, no tags
54+
- **Hybrid validation**: Parse to untyped tree, optional schema validation layer
55+
- **OOP design**: Tagged type hierarchies for nodes and schemas
56+
- **Strings only**: No file I/O - application provides content as String
57+
58+
## API Style
59+
60+
Uses idiomatic Ada with named access types and function call notation.
61+
Prelude packages provide convenient imports:
62+
63+
```ada
64+
with Tinyaml.Parser;
65+
with Tinyaml.Nodes; use Tinyaml.Nodes;
66+
with Tinyaml.Nodes.Prelude; use Tinyaml.Nodes.Prelude;
67+
with Tinyaml.Schemas.Prelude; use Tinyaml.Schemas.Prelude;
68+
69+
Doc := Tinyaml.Parser.Parse (Config);
70+
71+
-- Navigation with Node_Access
72+
Put_Line (Get_String (Doc, "database.host"));
73+
Features := Navigate (Doc, "features");
74+
75+
-- Type checking requires .all
76+
if Is_Sequence (Features.all) then ...
77+
78+
-- Get scalar value from Node_Access
79+
Put_Line (Value (Seq.Element (I)));
80+
```
81+
82+
## YAML Features
83+
84+
**Supported:**
85+
- Block scalars (literal `|`, folded `>`)
86+
- Block sequences (`-`)
87+
- Block mappings (`:`)
88+
- Comments (`#`)
89+
- Quoted strings (single and double)
90+
- Escape sequences in double-quoted strings
91+
92+
**Rejected (raises Parse_Error):**
93+
- Flow style (`{...}`, `[...]`)
94+
- Anchors and aliases (`&`, `*`)
95+
- Tags (`!`)
96+
- Duplicate keys
97+
98+
## Known Issues
99+
100+
- Style warnings for alphabetical ordering - intentionally deferred
101+
- Some internal helper functions lack specs - intentionally local
102+
103+
## Schema API (Redesigned)
104+
105+
The schema API uses class-wide types with dot notation:
106+
107+
1. **Direct instantiation with aggregates** - no factory functions where possible
108+
2. **Class-wide types** for dot-notation enabled interface
109+
3. **Hidden access types** - users work with tagged types directly
110+
4. **Procedural field addition** instead of functional chaining
111+
5. **Optional as a field modifier** instead of a wrapper type
112+
6. **Abstract Constraint hierarchy** for extensible validation rules
113+
7. **Seq_Item holder** for polymorphic sequence item storage
114+
115+
### Type Hierarchies
116+
117+
```
118+
Schema (abstract) Constraint (abstract)
119+
├── Str_Schema └── Range_Constraint
120+
├── Int_Schema (future: Length_Constraint,
121+
├── Float_Schema Pattern_Constraint, etc.)
122+
├── Bool_Schema
123+
├── Enum_Schema
124+
├── Seq_Schema
125+
├── Map_Schema
126+
└── Any_Schema
127+
```
128+
129+
### API
130+
131+
```ada
132+
package Tinyaml.Schemas is
133+
134+
-- Schema hierarchy (no access types exposed to users)
135+
type Schema is abstract tagged private;
136+
137+
function Is_Valid (S : Schema; N : Nodes.YAML_Node'Class) return Boolean is abstract;
138+
function Describe (S : Schema) return String is abstract;
139+
140+
-- Constraint hierarchy
141+
type Constraint is abstract tagged private;
142+
143+
function Check (C : Constraint; Value : String) return Boolean is abstract;
144+
function Describe (C : Constraint) return String is abstract;
145+
146+
-- Range_Constraint (first child of Constraint)
147+
type Range_Constraint is new Constraint with private;
148+
149+
---------------------------------------------------------------------------
150+
-- Seq_Item Holder (for polymorphic sequence items)
151+
---------------------------------------------------------------------------
152+
153+
type Seq_Item is tagged private;
154+
155+
function Seq_Item (S : Schema'Class) return Seq_Item;
156+
157+
---------------------------------------------------------------------------
158+
-- Concrete Schema Types (instantiate directly with aggregates)
159+
---------------------------------------------------------------------------
160+
161+
type Str_Schema is new Schema with private;
162+
type Float_Schema is new Schema with private;
163+
type Bool_Schema is new Schema with private;
164+
type Any_Schema is new Schema with private;
165+
166+
type Int_Schema is new Schema with private;
167+
-- Use aggregate: (Constraint => (Min => 1, Max => 100))
168+
169+
type Enum_Schema is new Schema with private;
170+
-- Use aggregate: (Values => String_Vectors.To_Vector(...))
171+
172+
type Seq_Schema is new Schema with private;
173+
-- Use aggregate: (Item => Seq_Item (Str_Schema'(...)))
174+
175+
type Map_Schema is new Schema with private;
176+
-- Instantiate directly, then add fields with dot notation
177+
178+
---------------------------------------------------------------------------
179+
-- Field Addition (class-wide parameters enable dot notation)
180+
---------------------------------------------------------------------------
181+
182+
procedure Str (M : in out Map_Schema'Class; Name : String;
183+
Optional : Boolean := False);
184+
procedure Int (M : in out Map_Schema'Class; Name : String;
185+
Optional : Boolean := False);
186+
procedure Int (M : in out Map_Schema'Class; Name : String;
187+
Constraint : Range_Constraint;
188+
Optional : Boolean := False);
189+
procedure Flt (M : in out Map_Schema'Class; Name : String;
190+
Optional : Boolean := False);
191+
procedure Bool (M : in out Map_Schema'Class; Name : String;
192+
Optional : Boolean := False;
193+
Default : String := "");
194+
procedure Enum (M : in out Map_Schema'Class; Name : String;
195+
Values : String_Array;
196+
Optional : Boolean := False);
197+
procedure Seq (M : in out Map_Schema'Class; Name : String;
198+
Item : Seq_Item;
199+
Optional : Boolean := False);
200+
procedure Any (M : in out Map_Schema'Class; Name : String;
201+
Optional : Boolean := False);
202+
203+
-- Nested map (returns the nested map for further configuration)
204+
function Map (M : in out Map_Schema'Class; Name : String;
205+
Optional : Boolean := False) return Map_Schema;
206+
207+
private
208+
209+
type Schema is abstract tagged null record;
210+
211+
type Constraint is abstract tagged null record;
212+
213+
type Range_Constraint is new Constraint with record
214+
Min : Integer := Integer'First;
215+
Max : Integer := Integer'Last;
216+
end record;
217+
218+
-- Access types hidden from users, used internally for storage
219+
type Schema_Access is access all Schema'Class;
220+
221+
-- Seq_Item wraps access type for clean aggregate syntax
222+
type Seq_Item is tagged record
223+
Schema : Schema_Access;
224+
end record;
225+
226+
type Str_Schema is new Schema with null record;
227+
type Float_Schema is new Schema with null record;
228+
type Bool_Schema is new Schema with null record;
229+
type Any_Schema is new Schema with null record;
230+
231+
type Int_Schema is new Schema with record
232+
Constraint : Range_Constraint := (others => <>);
233+
end record;
234+
235+
type Enum_Schema is new Schema with record
236+
Values : String_Vectors.Vector;
237+
end record;
238+
239+
type Seq_Schema is new Schema with record
240+
Item : Seq_Item;
241+
end record;
242+
243+
type Field_Info is record
244+
Field_Schema : Schema_Access;
245+
Is_Required : Boolean := True;
246+
Default_Val : Ada.Strings.Unbounded.Unbounded_String;
247+
end record;
248+
249+
type Map_Schema is new Schema with record
250+
Fields : Field_Maps.Map;
251+
end record;
252+
253+
end Tinyaml.Schemas;
254+
```
255+
256+
### Usage Example
257+
258+
```ada
259+
with Tinyaml.Schemas; use Tinyaml.Schemas;
260+
261+
procedure Define_Config_Schema is
262+
-- Direct instantiation, no factory functions
263+
M : Map_Schema;
264+
begin
265+
-- Simple fields with dot notation
266+
M.Str ("host");
267+
M.Str ("name");
268+
M.Int ("port", Constraint => (Min => 1, Max => 65535));
269+
M.Bool ("debug", Optional => True, Default => "false");
270+
271+
-- Nested map
272+
declare
273+
DB : Map_Schema := M.Map ("database");
274+
begin
275+
DB.Str ("driver");
276+
DB.Str ("connection");
277+
end;
278+
279+
-- Sequence of strings
280+
M.Seq ("features", Item => Seq_Item (Str_Schema'(others => <>)),
281+
Optional => True);
282+
283+
-- Sequence of maps (e.g., Docker Compose volumes)
284+
declare
285+
Volume_Schema : Map_Schema;
286+
begin
287+
Volume_Schema.Str ("type");
288+
Volume_Schema.Str ("source");
289+
Volume_Schema.Str ("target");
290+
M.Seq ("volumes", Item => Seq_Item (Volume_Schema));
291+
end;
292+
end Define_Config_Schema;
293+
```
294+
295+
### Key Design Features
296+
297+
- **Direct instantiation** - `M : Map_Schema;`
298+
- **Dot notation** - `M.Str ("host")` for building schemas
299+
- **Aggregates for construction** - `(Constraint => (Min => 1, Max => 100))`
300+
- **Seq_Item holder** - `To_Seq_Item (Map_Schema'(...))` for polymorphic sequences
301+
- **Class-wide interface** - users work with tagged types, not access types
302+
- **Hidden access types** - only in private part, for internal storage
303+
- **Optional as parameter** - `Optional => True` instead of wrapper type
304+
- **Abstract `Constraint` hierarchy** - extensible (start with `Range_Constraint`)

examples/alire.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
name = "tinyaml_examples"
2+
description = "Examples for TinyAML library"
3+
version = "0.2.0"
4+
5+
authors = ["Jochen Lillich"]
6+
maintainers = ["Jochen Lillich <hello@geewiz.dev>"]
7+
maintainers-logins = ["geewiz"]
8+
9+
[[depends-on]]
10+
tinyaml = "*"
11+
12+
[[pins]]
13+
tinyaml = { path = ".." }

examples/tinyaml_examples.gpr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
with "../tinyaml.gpr";
1+
with "tinyaml";
22

33
project Tinyaml_Examples is
44

tests/bin/test_runner

-3.22 MB
Binary file not shown.

0 commit comments

Comments
 (0)