favella1 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- favella1-1.0.0/CHANGELOG.md +1729 -0
- favella1-1.0.0/LICENSE +21 -0
- favella1-1.0.0/MANIFEST.in +9 -0
- favella1-1.0.0/PACKAGING.md +145 -0
- favella1-1.0.0/PKG-INFO +295 -0
- favella1-1.0.0/README.md +266 -0
- favella1-1.0.0/collaudo.py +610 -0
- favella1-1.0.0/compilatore.py +4591 -0
- favella1-1.0.0/favella.py +352 -0
- favella1-1.0.0/favella1/__init__.py +30 -0
- favella1-1.0.0/favella1/galleria/README.md +57 -0
- favella1-1.0.0/favella1/galleria/galleria.json +36 -0
- favella1-1.0.0/favella1/galleria/i-tre-sigilli/i-tre-sigilli.fav +93 -0
- favella1-1.0.0/favella1/galleria/il-faro/il-faro.fav +82 -0
- favella1-1.0.0/favella1/galleria/il-giardino-murato/il-giardino-murato.fav +88 -0
- favella1-1.0.0/favella1/libreria/README.md +50 -0
- favella1-1.0.0/favella1/libreria/proprieta.fav +49 -0
- favella1-1.0.0/favella1/libreria/sinonimi.fav +54 -0
- favella1-1.0.0/favella1/libreria/verbi.fav +51 -0
- favella1-1.0.0/favella1.egg-info/PKG-INFO +295 -0
- favella1-1.0.0/favella1.egg-info/SOURCES.txt +30 -0
- favella1-1.0.0/favella1.egg-info/dependency_links.txt +1 -0
- favella1-1.0.0/favella1.egg-info/entry_points.txt +2 -0
- favella1-1.0.0/favella1.egg-info/requires.txt +1 -0
- favella1-1.0.0/favella1.egg-info/top_level.txt +9 -0
- favella1-1.0.0/favella_playground.py +448 -0
- favella1-1.0.0/gioco.py +865 -0
- favella1-1.0.0/libreria_azioni.py +216 -0
- favella1-1.0.0/pyproject.toml +73 -0
- favella1-1.0.0/setup.cfg +4 -0
- favella1-1.0.0/strutture.py +1159 -0
- favella1-1.0.0/utils.py +282 -0
|
@@ -0,0 +1,1729 @@
|
|
|
1
|
+
# Registro delle Versioni (Changelog) - FAVELLA 1
|
|
2
|
+
|
|
3
|
+
Tutti i cambiamenti significativi a questo progetto saranno documentati in questo file.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## [1.0.0] - 2026-06-16
|
|
8
|
+
### 🏁 Il linguaggio è completo — versione 1.0
|
|
9
|
+
Traguardo. La **1.0.0 non introduce modifiche di grammatica** rispetto alla 0.34.0:
|
|
10
|
+
è il rilascio che **dichiara chiuso e definitivo il linguaggio FAVELLA 1**. Un solo
|
|
11
|
+
numero di versione per motore, compilatore e specifica; spec di milestone
|
|
12
|
+
`documentazione/grammatica-1.0.0.md` (identica alla 0.34.0, con la nota di traguardo).
|
|
13
|
+
|
|
14
|
+
Cosa c'è dentro la 1.0:
|
|
15
|
+
- **Livelli 1–8** della roadmap (stanze, oggetti, regole «Invece di», stati e
|
|
16
|
+
contatori, contenitori/supporti, dialoghi, capacità di trasporto, eventi e demoni).
|
|
17
|
+
- **Consolidamento 0.18.0** (regole a due oggetti col `se`, posizione del giocatore,
|
|
18
|
+
testi d'esito, copula plurale, `al massimo`/`non è`, verbi multi-parola, `non(…)`).
|
|
19
|
+
- **Asse A «Il mondo vivo» 0.19.0→0.26.0** (pronomi/anafora, ANNULLA/ANCORA/
|
|
20
|
+
trascrizione, varietà nelle descrizioni, buio e luce, movimento degli NPC,
|
|
21
|
+
sinonimi di verbo, verbi intransitivi, inventario iniziale, tick silenziosi).
|
|
22
|
+
- **Revisione totale di solidità 0.27.0→0.28.1** (correttezza, robustezza, perf).
|
|
23
|
+
- **Piano di completamento**: Cassetto A (0.30.0), **Tema 1** «i contatori si parlano»
|
|
24
|
+
(0.31.0), **Tema 2** «casualità d'autore» (0.32.0), **Tema 4** «il mondo che cambia
|
|
25
|
+
in scena» (0.33.0), **Tema 3** «lo stato che parla allo stato» (0.34.0).
|
|
26
|
+
- **Fuori per scelta**: Tema 5a (quantità con plurali) e Tema 5b (template di entità)
|
|
27
|
+
— la semplicità d'autore è una feature; una scorta è già un contatore.
|
|
28
|
+
|
|
29
|
+
Garanzie della 1.0: grammatica **LALR(1) a zero ambiguità** (guardia Earley
|
|
30
|
+
permanente), **suite verde** (681 asserzioni di linguaggio + 43 di collaudo, pytest
|
|
31
|
+
312), versioning unificato, una spec e un CHANGELOG per release. Da qui l'evoluzione
|
|
32
|
+
è di **ecosistema** (distribuzione, libreria di moduli, galleria di storie), non più
|
|
33
|
+
di linguaggio.
|
|
34
|
+
|
|
35
|
+
### 📦 Ecosistema (2026-06-16): pacchetto PyPI, libreria standard, galleria
|
|
36
|
+
Primo passo dell'**ecosistema** annunciato dalla 1.0.0. **Nessuna modifica al
|
|
37
|
+
motore** (resta `VERSIONE_MOTORE = 1.0.0`, suite 681+43 verde): solo confezione e
|
|
38
|
+
contenuti attorno al linguaggio.
|
|
39
|
+
|
|
40
|
+
- **Pacchetto installabile (`pip install favella1`).** Aggiunti
|
|
41
|
+
`pyproject.toml` (layout piatto: i moduli del motore restano alla radice e si
|
|
42
|
+
installano insieme — `esporta` li rilegge da lì a runtime — più il package
|
|
43
|
+
`favella1` coi dati), `LICENSE` (**MIT**) e `MANIFEST.in`. La versione del
|
|
44
|
+
pacchetto è derivata automaticamente da `strutture.VERSIONE_MOTORE`. Verificato
|
|
45
|
+
con `python -m build` + `twine check` (wheel e sdist) e con un'installazione
|
|
46
|
+
pulita in venv (CLI completa, **`esporta` incluso**, funzionante).
|
|
47
|
+
- **Libreria standard di moduli `Includi`-bili** in `favella1/libreria/`:
|
|
48
|
+
`sinonimi.fav` (sinonimi dei verbi), `proprieta.fav` (coppie di proprietà
|
|
49
|
+
opposte comuni), `verbi.fav` (verbi d'azione pronti). Vocabolario riusabile,
|
|
50
|
+
sicuro da includere per intero (nessun avviso del linter).
|
|
51
|
+
- **Galleria di storie** in `favella1/galleria/`: tre avventure brevi, complete e
|
|
52
|
+
**vincibili** col sorgente commentato — «Il Faro Spento», «Il Giardino Murato»,
|
|
53
|
+
«Il Forziere dei Tre Sigilli» — più l'indice `galleria.json`. Ognuna passa il
|
|
54
|
+
`collaudo` statico ed è stata giocata end-to-end fino alla vittoria.
|
|
55
|
+
- **Nuovi sottocomandi della CLI** (`favella.py`, lo strato sottile — motore
|
|
56
|
+
intatto): `favella1 libreria [elenca|copia]` e
|
|
57
|
+
`favella1 galleria [elenca|gioca|copia]`.
|
|
58
|
+
|
|
59
|
+
## [0.34.0] - 2026-06-16
|
|
60
|
+
### Tema 3: lo stato che parla allo stato 🔗
|
|
61
|
+
Quinta sessione del **piano di completamento del linguaggio**
|
|
62
|
+
(`documentazione/espansione-oltre-0.29.md`): il **Tema 3**, l'**indirezione fra
|
|
63
|
+
stati**. Fino a ieri uno «stato» si assegnava/confrontava solo contro un valore
|
|
64
|
+
**letterale** (`il corteggiato è Anna`); ora può farlo contro il **contenuto di un
|
|
65
|
+
altro stato**. Costrutto piccolo e mirato, pesato con prudenza (l'indirezione è
|
|
66
|
+
mezzo passo verso le variabili dei linguaggi veri) e tenuto minimo. Richiedente
|
|
67
|
+
reale: il tester Pietro («La Talpa», impersonare un personaggio). **Additivo** (le
|
|
68
|
+
4 demo e tutte le storie esistenti compilano e si comportano identiche). Modifica di
|
|
69
|
+
grammatica → bump **minor**; spec nuova `documentazione/grammatica-0.34.0.md` (§17).
|
|
70
|
+
|
|
71
|
+
- **Copia stato↔stato** (`ConseguenzaVariabileCopia`): `e adesso il corteggiato
|
|
72
|
+
diventa il preferito.` copia il valore corrente di uno stato in un altro. Forma
|
|
73
|
+
**nuda**, 0-ambigua (nessun `diventa PROPRIETA` compete dopo `diventa`).
|
|
74
|
+
- **Confronto stato↔stato** (`CondizioneVariabileUguali`): `se il corteggiato è
|
|
75
|
+
come il preferito: …` (anche `non è come`). Il marcatore **`come`** è obbligatorio:
|
|
76
|
+
senza, `VARIABILE è VARIABILE` collide con `VARIABILE è PROPRIETA` (confronto con
|
|
77
|
+
un letterale) — un nome di stato è anche una parola-valore lecita. `come` separa i
|
|
78
|
+
due casi in modo strutturale → LALR(1) 0-ambiguo (guardia Earley estesa). Si legge
|
|
79
|
+
come italiano corrente («è come il preferito» = ha lo stesso valore).
|
|
80
|
+
- **Riservato agli stati; diagnostica gentile.** La forma nuda vale solo fra due
|
|
81
|
+
**stati**: la copia/confronto fra **contatori** usa già il valore fra parentesi
|
|
82
|
+
`[nome]` (Tema 1, più espressivo). Un mismatch stato↔contatore — o l'uso della
|
|
83
|
+
forma nuda fra due contatori — è un errore d'autore localizzato che indirizza alla
|
|
84
|
+
forma corretta. Validazione **differita** (lo stato a destra può essere dichiarato
|
|
85
|
+
dopo). **ANNULLA-safe** (muta `Mondo.variabili`, già nelle istantanee; niente RNG).
|
|
86
|
+
- **Tema 5a (quantità/scorte): NO-GO.** Pesato e non realizzato: la «versione ridotta
|
|
87
|
+
sui contatori» non richiede codice (una scorta è già un contatore col Tema 1); la
|
|
88
|
+
versione piena apre plurali/concordanza, fuori dallo spirito di FAVELLA. Resta un
|
|
89
|
+
idioma documentato, non una primitiva. Tema 5b (template): sconsigliato.
|
|
90
|
+
- **Demo non retrofittate.** Nessuna delle 4 demo ha due stati simbolici fra cui
|
|
91
|
+
l'indirezione sia naturale (i pretendenti del dating sono entità/contatori):
|
|
92
|
+
forzarla sarebbe contrived e rischierebbe l'additività. Il costrutto è coperto da
|
|
93
|
+
8 test dedicati. (Stessa scelta della 4a in 0.33.0.)
|
|
94
|
+
- **Suite:** 681 asserzioni di linguaggio (+15) + 43 di collaudo, pytest 312, LALR(1)
|
|
95
|
+
0-ambiguo. Le 4 demo restano vincibili/perdibili end-to-end identiche.
|
|
96
|
+
|
|
97
|
+
## [0.33.0] - 2026-06-16
|
|
98
|
+
### Tema 4: il mondo che cambia in scena 🌒
|
|
99
|
+
Quarta sessione del **piano di completamento del linguaggio**
|
|
100
|
+
(`documentazione/espansione-oltre-0.29.md`): il **Tema 4**, due «non si può» dal
|
|
101
|
+
lato della *messa in scena*, indipendenti e a riuso alto. **Additivo** (le 4 demo
|
|
102
|
+
e tutte le storie esistenti compilano e si comportano identiche). Modifica di
|
|
103
|
+
grammatica → bump **minor**; spec nuova `documentazione/grammatica-0.33.0.md`.
|
|
104
|
+
|
|
105
|
+
- **4a — buio commutabile.** Una conseguenza nuova (`ConseguenzaBuioStanza`):
|
|
106
|
+
`e adesso la radura diventa buia.` spegne la luce di una stanza e
|
|
107
|
+
`… diventa illuminata.` (o `chiara`) la riaccende. Fino a ieri il buio di stanza
|
|
108
|
+
(`è buia`) era **statico** — solo all'avvio; ora il ciclo giorno/notte può calare
|
|
109
|
+
il buio in scena. La proprietà è classificata per **radice** riusando il folding
|
|
110
|
+
di concordanza (`bui-` → buio; `illuminat-`/`chiar-` → luce). **ANNULLA-safe**
|
|
111
|
+
senza RNG (è stato del mondo). Diagnostica gentile: cambiare il buio a un oggetto,
|
|
112
|
+
o con una proprietà non di luce, è un errore localizzato.
|
|
113
|
+
- **4b — battuta di nodo condizionale.** La regola della battuta guadagna una
|
|
114
|
+
clausola `se` opzionale, per parità con le descrizioni:
|
|
115
|
+
`Anna al nodo "x" dice "Ciao." se il doppiogioco è palese.` convive con la battuta
|
|
116
|
+
incondizionata (fallback). Le varianti si **accumulano** e a render-time vince la
|
|
117
|
+
prima la cui condizione è vera — riuso diretto del meccanismo «prima vera vince»
|
|
118
|
+
delle descrizioni.
|
|
119
|
+
- **4c — creazione di oggetti: pesata e rimandata.** Creare un oggetto *non
|
|
120
|
+
dichiarato* sfida il terminale chiuso `ENTITA`; il pattern «dichiara nel nulla e
|
|
121
|
+
rivela» resta sufficiente. Non entra in 0.33.0 (annotato in
|
|
122
|
+
`debiti-motore-da-integrare`).
|
|
123
|
+
- **Grammatica LALR(1) 0-ambigua.** 4a: dopo `ENTITA` il lookahead `"diventa"` è
|
|
124
|
+
disgiunto da `_copula`/`"va"`/`"cambia"`, ed `ENTITA` è disgiunto da `VARIABILE`
|
|
125
|
+
(niente collisione con `VARIABILE "diventa" …`). 4b: dopo il 2° testo il lookahead
|
|
126
|
+
`"se"` vs `"."` è disgiunto. **Nessun** terminale o parola riservata nuovi. Guardia
|
|
127
|
+
anti-ambiguità estesa a entrambi.
|
|
128
|
+
- **Demo.** Il saluto di Anna in `cuori-al-caffe.fav` ora si **scalda** quando
|
|
129
|
+
l'affinità è alta (battuta condizionale 4b): risolve l'attrito annotato nel demo.
|
|
130
|
+
Il 4a (buio commutabile) non è stato retrofittato nelle demo: la notte
|
|
131
|
+
*all'aperto* del survival non è buio pesto (stelle + uscite visibili), e
|
|
132
|
+
sostituirla regredirebbe le descrizioni notturne d'autore — il costrutto è
|
|
133
|
+
comunque pienamente coperto dai test.
|
|
134
|
+
- **Test.** +10 test (4a: spegne/riaccende/sinonimo-chiara/ANNULLA/2 diagnostiche;
|
|
135
|
+
4b: prima-vera-vince/runtime/segnaposto/retro-compatibilità). Suite **666
|
|
136
|
+
linguaggio + 43 collaudo** (pytest **304**), LALR(1) 0-ambiguo.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## [0.32.0] - 2026-06-16
|
|
141
|
+
### Tema 2 (resto): casualità d'autore non-numerica 🎲
|
|
142
|
+
Terza sessione del **piano di completamento del linguaggio**
|
|
143
|
+
(`documentazione/espansione-oltre-0.29.md`): il **resto del Tema 2**. L'estrazione
|
|
144
|
+
*numerica* (`un numero fra A e B`) era già entrata in 0.31.0; ora arrivano i due
|
|
145
|
+
costrutti casuali **non numerici**. Entrambi riusano `Mondo.rng` — il generatore
|
|
146
|
+
**seedato** e **ANNULLA-safe** già usato da A2/A5 e dall'estrazione numerica — quindi
|
|
147
|
+
le partite restano riproducibili e disfare un turno riavvolge anche il caso.
|
|
148
|
+
**Additivo** (le 4 demo e tutte le storie esistenti compilano e si comportano
|
|
149
|
+
identiche). Modifica di grammatica → bump **minor**; spec nuova
|
|
150
|
+
`documentazione/grammatica-0.32.0.md`.
|
|
151
|
+
|
|
152
|
+
- **2b — scelta casuale fra valori di stato.** Una conseguenza nuova
|
|
153
|
+
(`ConseguenzaSceltaStato`): `e adesso il meteo diventa uno fra sereno, pioggia,
|
|
154
|
+
nebbia.` assegna allo «stato» un valore *simbolico* pescato a caso dall'elenco.
|
|
155
|
+
È la casualità simbolica, distinta dall'estrazione numerica (i valori sono
|
|
156
|
+
parole-stato, non interi). Con un solo valore la scelta è deterministica.
|
|
157
|
+
- **2c — condizione probabilistica.** Un atomo-condizione nuovo
|
|
158
|
+
(`CondizioneProbabilita`): `Ogni turno se càpita (1 su 4): …` è vero con
|
|
159
|
+
probabilità N/M (`M su M` sempre, `0 su M` mai). È l'unico `cond_base` senza un
|
|
160
|
+
operando a sinistra (keyword dedicata `càpita`); componibile con
|
|
161
|
+
`e`/`oppure`/`non` e usabile in regole, demoni, opzioni e descrizioni.
|
|
162
|
+
- **Grammatica LALR(1) 0-ambigua.** 2b condivide il prefisso `VARIABILE "diventa"`
|
|
163
|
+
con `cons_contatore_set` ma se ne stacca al token dopo (`"uno"` vs
|
|
164
|
+
`{NUMERO,"[","un"}` dell'operando; `uno ≠ un`). 2c parte da `càpita`, disgiunto
|
|
165
|
+
da ogni altro FIRST di `cond_base`. Guardia anti-ambiguità estesa a entrambi.
|
|
166
|
+
Riservata aggiunta: **`càpita`**.
|
|
167
|
+
- **Diagnostica e IDE.** Uno stato assegnato *solo* via `diventa uno fra …` non è
|
|
168
|
+
più segnalato «dichiarato ma mai usato». Serializzazione JSON: `{op:"pick",…}`
|
|
169
|
+
(scelta) e `{op:"chance",num,den}` (probabilità).
|
|
170
|
+
- **Demo.** La guida `notte-di-gara.fav` ora ha un **meteo davvero imprevedibile**
|
|
171
|
+
(era sceneggiato su turni fissi): risolto l'attrito **D1** del suo stress-test.
|
|
172
|
+
- **Test.** +11 test (2b: pesca/riproducibilità/ANNULLA/valore-singolo/non-collisione/
|
|
173
|
+
lint; 2c: frequenza/estremi/ANNULLA/in-regola/serializzazione). Suite **642
|
|
174
|
+
linguaggio + 43 collaudo**, LALR(1) 0-ambiguo.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## [0.31.0] - 2026-06-16
|
|
179
|
+
### Tema 1: i contatori si parlano (operando-quantità + confronti) 🔢
|
|
180
|
+
Seconda sessione del **piano di completamento del linguaggio**
|
|
181
|
+
(`documentazione/espansione-oltre-0.29.md`): il **Tema 1**, il limite strutturale
|
|
182
|
+
n°1 emerso in TUTTE e quattro le demo di stress-test. Fino a ieri un contatore era
|
|
183
|
+
una **cella isolata** — aritmetica e confronti solo contro **costanti letterali**,
|
|
184
|
+
mai fra celle. Ora i contatori si parlano. **Additivo** (le 4 demo e tutte le
|
|
185
|
+
storie esistenti compilano e si comportano identiche; i numeri letterali restano
|
|
186
|
+
nudi e invariati). Modifica di grammatica → bump **minor**; spec nuova
|
|
187
|
+
`documentazione/grammatica-0.31.0.md`.
|
|
188
|
+
|
|
189
|
+
- **Operando-quantità.** Un solo concetto nuovo, ciò che produce un intero al
|
|
190
|
+
momento dell'uso, in tre forme: un **NUMERO** letterale (`di 3`, storico), il
|
|
191
|
+
**valore di un contatore** fra parentesi quadre (`di [forza]` — come
|
|
192
|
+
l'interpolazione `[nome]` dei testi: `[x]` = «il valore corrente di x»), e
|
|
193
|
+
un'**estrazione casuale** (`un numero fra 2 e 6`). Le quadre marcano il «valore
|
|
194
|
+
dinamico»: il letterale resta nudo, il riferimento è fra parentesi.
|
|
195
|
+
- **Tema 1a — contatore come quantità.** `aumenta/diminuisci X di [Y]` e
|
|
196
|
+
`X diventa [Y]`: il danno scala con una statistica, il consumo con la velocità,
|
|
197
|
+
l'affinità con un'altra affinità. `diminuisci la vita del lich di [forza].`
|
|
198
|
+
- **Tema 1b — confronto grandezza↔grandezza.** I sei confronti (`è N`, `non è N`,
|
|
199
|
+
`almeno`, `più di`, `meno di`, `al massimo`) accettano ora un `[contatore]` come
|
|
200
|
+
termine destro: `se la vita del troll è meno di [la mia vita]: …`. Il confronto è
|
|
201
|
+
**dinamico** (risolto a ogni valutazione): abilita le soglie *relative* (gelosie,
|
|
202
|
+
difficoltà mobile) prima possibili solo con batterie di demoni.
|
|
203
|
+
- **Casualità d'autore (accorpata).** `il dado diventa un numero fra 1 e 6.`,
|
|
204
|
+
`diminuisci la vita di un numero fra 2 e 6.`. Riusa l'RNG **seedato** del mondo
|
|
205
|
+
(`Mondo.rng`, infrastruttura già esistente per A2/A5): le partite restano
|
|
206
|
+
**riproducibili** e **ANNULLA riavvolge** anche l'estrazione. Solo l'estrazione
|
|
207
|
+
numerica entra ora (è un operando-quantità della stessa famiglia); `diventa uno
|
|
208
|
+
fra X, Y, Z` e `càpita (1 su N)` restano per una sessione futura.
|
|
209
|
+
- **Grammatica LALR(1) 0-ambigua.** Le tre forme partono da token disgiunti
|
|
210
|
+
(`NUMERO | "[" | "un"`): `è più di 3` e `è più di [forza]` convivono con un solo
|
|
211
|
+
token di lookahead. Le quadre `[` `]`, prima viste solo dentro le stringhe,
|
|
212
|
+
diventano token letterali che non collidono con nulla. Guardia anti-ambiguità del
|
|
213
|
+
corpus estesa a tutti i nuovi costrutti.
|
|
214
|
+
- **Diagnostica e IDE.** Un contatore citato **solo** come operando non è più un
|
|
215
|
+
falso «dichiarato ma mai usato». Il serializzatore JSON dell'IDE espone il
|
|
216
|
+
letterale come int (retrocompatibile) e le forme dinamiche come
|
|
217
|
+
`{kind:"var",…}` / `{kind:"rand",…}`.
|
|
218
|
+
- **Scartato — 1c «valore successivo».** Il cambio di marcia (`sali di una
|
|
219
|
+
marcia`) avrebbe richiesto un concetto di «scala ordinata»: le N regole esplicite
|
|
220
|
+
restano più leggibili. Non fatto, per il principio «la semplicità è una feature».
|
|
221
|
+
- **Prova sul campo.** Una porzione della demo GDR (`esempi/demo/ruolo/`) è stata
|
|
222
|
+
riscritta idiomatica col nuovo costrutto al posto del workaround a soglie.
|
|
223
|
+
- 9 nuovi test di regressione (linguaggio), guardia anti-ambiguità estesa. Suite:
|
|
224
|
+
**623 + 43 di collaudo**, tutta verde (pytest e runner nativo).
|
|
225
|
+
|
|
226
|
+
## [0.30.0] - 2026-06-16
|
|
227
|
+
### Cassetto A: robustezza, diagnostica e due piccole simmetrie 🧰
|
|
228
|
+
Prima sessione del **piano di completamento del linguaggio** (`documentazione/espansione-oltre-0.29.md`):
|
|
229
|
+
quattro rifiniture a basso rischio, **additive** (le 4 demo di stress-test e tutte
|
|
230
|
+
le storie esistenti compilano e si comportano identiche). Una sola modifica di
|
|
231
|
+
grammatica (A3) → bump **minor**; spec nuova `documentazione/grammatica-0.30.0.md`.
|
|
232
|
+
|
|
233
|
+
- **A1 — Diagnostica dei nomi non validi.** Un carattere come `/` in un nome di
|
|
234
|
+
entità/stato/contatore chiudeva in anticipo il letterale regex del terminale
|
|
235
|
+
generato per-file, facendo fallire la costruzione del parser con un
|
|
236
|
+
`GrammarError` interno e incomprensibile (riprodotto da un tester reale). Ora la
|
|
237
|
+
Passata 1 (`valida_nomi_dichiarati`) lo intercetta **prima** del parser con un
|
|
238
|
+
errore d'autore **localizzato** (riga, colonna, carattere) e codice
|
|
239
|
+
`nome-non-valido`. Alfabeto ammesso nei nomi: lettere (anche accentate), cifre,
|
|
240
|
+
spazi e l'apostrofo — lo stesso del terminale `WORD`.
|
|
241
|
+
- **A3 — `dire` opzionale nelle regole.** Per simmetria con i «tick silenziosi»
|
|
242
|
+
di eventi e demoni (A9), una regola che muta solo lo stato può ora **omettere il
|
|
243
|
+
testo**: `Invece di riposa: aumenta la forza.`. `def_regola` riusa lo stesso
|
|
244
|
+
inline `_esito_temporale` di eventi/demoni; a runtime una regola con risposta
|
|
245
|
+
vuota **non** stampa una riga vuota. **LALR(1) 0-ambiguo** (guardia anti-ambiguità
|
|
246
|
+
del corpus estesa al nuovo costrutto).
|
|
247
|
+
- **A4 — Idioma di direzione.** `"sinistra" è come est.` non funziona: `è come`
|
|
248
|
+
rimappa **solo i verbi**. Si mantiene l'idioma esistente — più pulito —
|
|
249
|
+
`Sinistra e destra sono direzioni opposte.`, e si **migliora l'avviso**: quando
|
|
250
|
+
il bersaglio di `è come` è una direzione, il warning lo dice e indica l'idioma
|
|
251
|
+
corretto, invece del generico «non è un verbo noto».
|
|
252
|
+
- **A2 — Punto dentro le virgolette: RIMANDATO.** Indagine svolta: una diagnostica
|
|
253
|
+
proattiva in Passata 1 non è perseguibile senza falsi positivi (la continuazione
|
|
254
|
+
legittima `dire "X."` a capo seguita da `e adesso …` è indistinguibile dall'errore
|
|
255
|
+
senza il parser, che la Passata 1 deliberatamente non è). La regola d'autore «il
|
|
256
|
+
punto va fuori dalle virgolette» resta nel manuale. Decisione documentata nella spec.
|
|
257
|
+
- **Test.** Suite **601** asserzioni di linguaggio (era 585) + **43** collaudo, tutte
|
|
258
|
+
verdi (pytest e runner nativo). Versioni allineate a **0.30.0**; puntatore
|
|
259
|
+
anti-drift della spec aggiornato.
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## [0.29.1] - 2026-06-16
|
|
264
|
+
### Robustezza: niente più crash sui caratteri fuori da Windows-1252 🛡️
|
|
265
|
+
Patch di **sola robustezza runtime**: la grammatica è **invariata** (la spec EBNF
|
|
266
|
+
resta valida), nessun cambio di semantica delle storie. Emersa da uno
|
|
267
|
+
**stress-test di genere a tappeto** (quattro demo di generi non nativi — guida,
|
|
268
|
+
sopravvivenza, dating, GDR — in `esempi/demo/`; vedi `documentazione/espansione-oltre-0.29.md`).
|
|
269
|
+
|
|
270
|
+
- **Fix del crash cp1252.** Un carattere non rappresentabile in Windows-1252
|
|
271
|
+
(es. `★`, `─`, frecce, emoji) **dentro un testo mostrato al giocatore** faceva
|
|
272
|
+
terminare il gioco con un `UnicodeEncodeError` fatale sulla console Windows —
|
|
273
|
+
la logica era corretta, a cadere era solo la stampa. Ora la console viene
|
|
274
|
+
riconfigurata a UTF-8 con `errors="replace"`: il carattere degrada invece di
|
|
275
|
+
far crashare la partita. (I caratteri nei **commenti** `#` erano e restano
|
|
276
|
+
innocui: non vengono mai stampati.)
|
|
277
|
+
- **Fonte unica.** Nuova `utils.assicura_console_utf8()`, condivisa dalla CLI
|
|
278
|
+
`favella1` (`favella.py`) e dall'avvio del ciclo interattivo (`gioco.py::gioca`),
|
|
279
|
+
così il fix copre **ogni** modo di lanciare una storia (`python gioco.py`
|
|
280
|
+
incluso, che prima non riconfigurava nulla). Idempotente.
|
|
281
|
+
- **Bug della trascrizione.** Avviare/chiudere la `TRASCRIZIONE` ripristinava
|
|
282
|
+
`sys.__stdout__` (il flusso grezzo cp1252), **annullando** la riconfigurazione
|
|
283
|
+
e facendo riaffiorare il crash. Ora si torna al flusso console già riconfigurato.
|
|
284
|
+
- **Test.** Aggiunta una guardia di regressione deterministica (finta console
|
|
285
|
+
cp1252) in `test_linguaggio.py`. Suite **585** asserzioni di linguaggio (era
|
|
286
|
+
582) + 43 collaudo, tutte verdi. Versioni allineate a **0.29.1**.
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## [Manuale] - 2026-06-14
|
|
291
|
+
### Rifinitura editoriale per la stampa (Amazon KDP) 📖
|
|
292
|
+
Lavoro **solo sul manuale** (`documentazione/manuale/`): nessun cambio al motore né
|
|
293
|
+
alla grammatica, suite invariate (**582** linguaggio + **43** collaudo). Gli esempi
|
|
294
|
+
`.fav` restano byte-corretti. Manuale allineato al motore **v0.29.0**.
|
|
295
|
+
|
|
296
|
+
- **Seconda edizione.** Etichetta «Seconda edizione · 2026» uniforme su copertina,
|
|
297
|
+
frontespizio e colophon (prima l'edizione era indicata solo nel frontespizio).
|
|
298
|
+
«Edizione» e «versione del motore» tenute distinte (lockstep su v0.29.0).
|
|
299
|
+
- **Doppia dedica.** Accanto a Bonaventura Di Bello, una dedica a **Pietro Bernasconi**,
|
|
300
|
+
i cui stress-test di genere hanno ispirato le primitive A7–A9. Due strofe nella stessa
|
|
301
|
+
pagina, separate da un filetto di marca.
|
|
302
|
+
- **Crismi tipografici di stampa.** Trim portato al formato **standard KDP 6,69×9,61″**
|
|
303
|
+
(169,93×244,09 mm; prima 170×240, non standard). Capitoli che aprono su **pagina
|
|
304
|
+
dispari** (recto, `pagebreak(to: "odd")`). Margine di cucitura interno 23 mm, ben
|
|
305
|
+
oltre il minimo KDP. Interno **84 pagine**, 0 warning.
|
|
306
|
+
- **Doppia tiratura da sorgente unica.** `manuale.pdf` (digitale, con copertina navy a
|
|
307
|
+
pagina intera) e `manuale-interno-kdp.pdf` (interno di stampa, senza copertina —
|
|
308
|
+
`typst compile --input kdp=1`).
|
|
309
|
+
- **Copertina KDP integrale** (`copertina-kdp.typ` → `copertina-kdp.pdf`): wrap
|
|
310
|
+
fronte-retro **351,0×250,4 mm** con bleed 3,175 mm e dorso 4,80 mm (84 pp., carta
|
|
311
|
+
bianca). Quarta di copertina, marchio, area riservata al codice a barre/ISBN (KDP).
|
|
312
|
+
Dorso in navy pieno senza testo (sotto 100 pp. KDP non ammette testo sul dorso).
|
|
313
|
+
- **Revisione linguistica integrale** dei 20 capitoli (prosa-italiana + humanizer): la
|
|
314
|
+
prosa era già di livello, corretti i refusi reali rimasti (`servono`→`valgono`,
|
|
315
|
+
`dà`→`dài`, `la dita`→`il dito`); nessun pattern LLM da rimuovere.
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## [0.29.0] - 2026-06-14
|
|
320
|
+
### Distribuzione multipiattaforma — installer + CLI unica + playground offline 📦
|
|
321
|
+
Prima release **distribuibile**: un autore (anche non tecnico) installa FAVELLA e la
|
|
322
|
+
usa **senza clonare il repo né installare Python**. **Nessun cambio al motore**: la
|
|
323
|
+
grammatica resta `grammatica-0.28.0.md`, le suite invariate (**582** linguaggio + **43**
|
|
324
|
+
collaudo, tutte verdi). Tutto il nuovo codice è additivo e fuori dal motore.
|
|
325
|
+
|
|
326
|
+
- **Entry-point unico `favella1`** (`favella.py`): strato sottile (argparse) sopra i
|
|
327
|
+
moduli esistenti, con sottocomandi `gioca` / `compila` / `collaudo` / `playground` /
|
|
328
|
+
`esporta` / `versione` (alias inglesi: `play`/`check`/`test`/`export`/`version`).
|
|
329
|
+
Console riconfigurata a UTF-8 per sicurezza sulle console legacy.
|
|
330
|
+
- **Playground locale offline** (`favella_playground.py`): `favella1 playground` avvia
|
|
331
|
+
un mini-server (sola libreria standard, nessuna dipendenza nuova) su `127.0.0.1` e
|
|
332
|
+
apre un editor + terminale nel browser, collegato al **motore nativo** — completamente
|
|
333
|
+
offline, con la diagnostica reale del compilatore. (Diverso da `esporta`, che usa
|
|
334
|
+
Pyodide e richiede la rete.)
|
|
335
|
+
- **Freeze PyInstaller** (`favella1.spec`, build *one-dir*): `--collect-all lark`, i 5
|
|
336
|
+
moduli del motore inclusi anche come sorgente (servono a `esporta` via `sys._MEIPASS`),
|
|
337
|
+
demo ufficiali nel bundle, icona di marca.
|
|
338
|
+
- **CI multipiattaforma** (`.github/workflows/release.yml`): build matrix
|
|
339
|
+
Windows/macOS/Linux con PyInstaller; impacchettamento per-OS in **installer NSIS**
|
|
340
|
+
(`.exe`), **`.dmg`** (Apple Silicon) e **AppImage**; smoke su ogni bundle; al push di
|
|
341
|
+
un tag `v*` pubblica una **GitHub Release** con i tre installer. La suite del motore
|
|
342
|
+
gira in CI e blocca eventuali regressioni.
|
|
343
|
+
- **Doc**: `PACKAGING.md` (architettura del pacchetto + procedura di rilascio
|
|
344
|
+
tag→Release); `packaging/` con script NSIS e file AppImage.
|
|
345
|
+
- Versioni in lockstep su **0.29.0** (`VERSIONE_MOTORE` fonte di verità). La firma del
|
|
346
|
+
codice è assente per ora: al primo avvio Gatekeeper/SmartScreen mostrano un avviso atteso.
|
|
347
|
+
- **Manuale tipografico aggiornato a 0.29.0** (Typst, da 17 a **20 capitoli**, 72 pp.):
|
|
348
|
+
copre tutta l'evoluzione dalla v0.18.0 a oggi. Tre capitoli nuovi — «Installare e
|
|
349
|
+
avviare FAVELLA» (installer/CLI/playground), «Buio e luce» (`è buia`/`illumina`),
|
|
350
|
+
«I comandi del giocatore» (pronomi/anafora, ANNULLA/ANCORA/TRASCRIZIONE) — e inserti
|
|
351
|
+
nei capitoli esistenti: descrizioni a varietà (`è una di`/`è in sequenza`), inventario
|
|
352
|
+
iniziale (`Il giocatore ha …`), copula plurale su stati/contatori (`Le vite sono un
|
|
353
|
+
contatore`/`partono da`), verbi intransitivi (`comando senza oggetto`) e sinonimi di
|
|
354
|
+
verbo (`… è come prendi`), tick silenziosi, movimento NPC (`va`/`cambia stanza`),
|
|
355
|
+
aggettivi con prefisso-preposizione (`è incisa`). Riepilogo e parole riservate estesi.
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## [0.28.1] - 2026-06-14
|
|
360
|
+
### Revisione totale del linguaggio — Lotto 3 (performance, documentazione, pulizia) 🧹
|
|
361
|
+
Patch di chiusura della revisione: nessun cambio di grammatica (la spec EBNF resta
|
|
362
|
+
`grammatica-0.28.0.md`), nessuna nuova feature. Suite invariate (**582** linguaggio
|
|
363
|
+
+ **43** collaudo).
|
|
364
|
+
|
|
365
|
+
- **Perf — cache dei parser LALR.** Costruire la tabella LALR costa ~40 ms;
|
|
366
|
+
`costruisci_parser` ora riusa i parser già costruiti, indicizzati per
|
|
367
|
+
(grammatica, propagate_positions). Una ricostruzione identica passa da ~44 ms a
|
|
368
|
+
~0,1 ms (utile a CLI e IDE che rianalizzano lo stesso file più volte). Sicuro: un
|
|
369
|
+
parser Lark è riusabile e senza stato fra le `.parse()`; un `GrammarError` non
|
|
370
|
+
viene cachato (la guardia anti-ambiguità resta valida).
|
|
371
|
+
- **Dedup `guarda` / ingresso in stanza.** `guarda_logica_default` ora delega a
|
|
372
|
+
`gioco.mostra_stanza` (fonte unica): prima ne duplicava la logica ma **ometteva
|
|
373
|
+
le uscite**; ora `guarda` mostra anche le uscite, coerente con l'ingresso.
|
|
374
|
+
- **cp1252-safety.** Sostituito l'unico `…` (U+2026) in un `print` di runtime
|
|
375
|
+
(l'aiuto) con `...`: non più a rischio `UnicodeEncodeError` su console Windows
|
|
376
|
+
legacy.
|
|
377
|
+
- **README allineato a 0.28.1** (stato, tabella versioni, conteggi test, roadmap;
|
|
378
|
+
era fermo a v0.18.0). **Commenti datati ripuliti**: «PARSING v0.2», conteggi-test
|
|
379
|
+
fissi nei commenti del compilatore, riferimenti al «robot dinamico B1.2 — sessione
|
|
380
|
+
successiva» (accantonato) in `collaudo.py` e banner di stato in
|
|
381
|
+
`documentazione/progettazione-collaudo.md`.
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## [0.28.0] - 2026-06-14
|
|
386
|
+
### Revisione totale del linguaggio — Lotto 2 (robustezza) 🧱
|
|
387
|
+
Secondo lotto della revisione di solidità. Una sola modifica di grammatica (D) +
|
|
388
|
+
due rafforzamenti del runtime + rinforzo della rete di test. Tutto verificato
|
|
389
|
+
eseguendo il motore; nessuna regressione (la suite collaudo ha intercettato in
|
|
390
|
+
corsa una regressione su `nello`, poi corretta — vedi sotto).
|
|
391
|
+
|
|
392
|
+
- **D — Aggettivi-proprietà che iniziano con una preposizione.** `La lapide è
|
|
393
|
+
incisa.` veniva rifiutato con un errore fuorviante («entità sconosciuta «cisa»»)
|
|
394
|
+
perché il lexer staccava `in` (PREP_LUOGO) dall'inizio dell'aggettivo. Ora
|
|
395
|
+
**`PREP_LUOGO` è una regex con confine destro** (`(?![a-zA-ZÀ-ÿ0-9'])`) sulle
|
|
396
|
+
forme semplici; le forme con apostrofo (`nell'`/`sull'`) ne sono esenti. Poiché
|
|
397
|
+
`nel` non si scompone più in `nel`+`lo`, l'insieme articolato è ora elencato per
|
|
398
|
+
intero (`nello`, `nei`, …). `è incisa`/`sulfurea`/`insanguinata`/`informe` ora
|
|
399
|
+
compilano; le posizioni (`in cella`, `nell'atrio`, `nello scriptorium`, `sullo
|
|
400
|
+
scaffale`) restano invariate. **Regressione intercettata dal collaudatore**: la
|
|
401
|
+
prima versione del confine rompeva `è nello scriptorium` (demo «Il Relitto») →
|
|
402
|
+
corretta completando l'insieme articolato.
|
|
403
|
+
- **E — Turno atomico.** Un'eccezione a metà di una conseguenza veniva inghiottita
|
|
404
|
+
e il turno avanzava su uno stato mutato a metà (con tanto di istantanea ANNULLA).
|
|
405
|
+
Ora l'eccezione risale a `elabora_comando`, che **ripristina l'istantanea
|
|
406
|
+
pre-turno** (rollback) e tratta il turno come no-op: niente stato incoerente,
|
|
407
|
+
niente avanzamento di turno/eventi/demoni, niente passo di ANNULLA spurio.
|
|
408
|
+
- **D-dialogo — Conversazione annullabile come unità.** Le conseguenze `e adesso …`
|
|
409
|
+
nelle opzioni di dialogo mutavano il mondo ma non erano annullabili (l'ingresso in
|
|
410
|
+
dialogo scartava l'istantanea). Ora l'istantanea pre-dialogo è messa da parte
|
|
411
|
+
all'ingresso (`Mondo._snap_dialogo`) e registrata all'uscita: **un solo ANNULLA
|
|
412
|
+
riporta a prima di `parla con …`**, con tutte le conseguenze delle scelte.
|
|
413
|
+
- **G — Rete di test rinforzata.** (1) L'anti-drift della spec EBNF ora verifica che
|
|
414
|
+
ogni regola sia **DEFINITA nei blocchi ```ebnf** della spec, non solo citata in
|
|
415
|
+
prosa (prima era un match per sottostringa sull'intero file). (2) Il collaudatore
|
|
416
|
+
ha ora test dedicati per la **vittoria via evento** (`Al turno N: … vinci`) e
|
|
417
|
+
**via demone** (`Quando … vinci`), rami prima coperti solo dalle demo.
|
|
418
|
+
- **Test**: linguaggio **+28 asserzioni** (D, E, D-dialogo, anti-drift più forte) →
|
|
419
|
+
**582** (era 549 a inizio revisione); collaudo **+10** → **43** (era 33). Demo
|
|
420
|
+
`vincibile-staticamente`. Spec EBNF **`grammatica-0.28.0.md`** (§13); puntatore
|
|
421
|
+
`_SPEC_EBNF` 0.27.0 → 0.28.0. Versioni allineate a **0.28.0**.
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
## [0.27.0] - 2026-06-14
|
|
426
|
+
### Revisione totale del linguaggio — Lotto 1 (correttezza) 🛡️
|
|
427
|
+
Sessione di **revisione di solidità** prima del manuale (caccia a difetti/debiti, non
|
|
428
|
+
nuove feature). Quattro correzioni di correttezza, ciascuna verificata eseguendo il
|
|
429
|
+
motore e coperta da un test dedicato. Nessuna regressione.
|
|
430
|
+
|
|
431
|
+
- **A — Copula plurale `sono` su stati e contatori.** Prima `Le vite sono un
|
|
432
|
+
contatore.` / `Le luci sono uno stato.` venivano **rifiutati** (scanner e
|
|
433
|
+
grammatica accettavano solo `è`), benché i nomi di stato/contatore siano spesso
|
|
434
|
+
plurali (`le vite`, `i punti`, `le munizioni`) — un'asimmetria con stanze/oggetti,
|
|
435
|
+
che la copula plurale la accettano dalla 0.18.0. Ora `def_stato`,
|
|
436
|
+
`def_stato_valore` e `def_contatore` usano `_copula`; il valore iniziale accetta
|
|
437
|
+
`partono` oltre a `parte` (`Le vite partono da 3.`). Aggiornati i due `_RE_DEF_*`
|
|
438
|
+
dello scanner. **Unica modifica di grammatica**; LALR(1) 0-ambiguo (VARIABILE
|
|
439
|
+
resta disgiunto da ENTITA). Riservata aggiunta: `partono`.
|
|
440
|
+
- **B — `accesa`↔`spenta` opposte di default.** Il motore le trattava già come
|
|
441
|
+
coppia per la luce (`c_e_luce`/fonte di luce, confronto per radice), ma senza la
|
|
442
|
+
coppia precaricata in `Mondo.opposti` una conseguenza `e adesso la torcia è
|
|
443
|
+
spenta` lasciava l'oggetto **sia `accesa` sia `spenta`** → `se la torcia è accesa`
|
|
444
|
+
restava vera a luce spenta. Precaricata accanto ad `aperta↔chiusa`.
|
|
445
|
+
- **C — `lascia` bloccato al buio.** Al buio `prendi`/`metti`/`esamina` erano
|
|
446
|
+
bloccati ma `lascia` no (asimmetria fra canali). Ora `lascia_logica_default`
|
|
447
|
+
rispetta `c_e_luce()`; una fonte di luce accesa in mano rende comunque la stanza
|
|
448
|
+
illuminata, quindi posarla per fare luce resta possibile.
|
|
449
|
+
- **M4 — Iniziale maiuscola senza rovinare i nomi propri.** `str.capitalize()`
|
|
450
|
+
minuscolava il resto del nome (`La Guardia Reale` → `La guardia reale`) in
|
|
451
|
+
intestazioni di stanza, nomi NPC, uscite e annunci di movimento. Nuovo helper
|
|
452
|
+
`utils.prima_maiuscola` (maiuscola solo sull'iniziale); sostituite tutte e 7 le
|
|
453
|
+
occorrenze di `.capitalize()` su `nome_visualizzato`.
|
|
454
|
+
- **Test**: **+13 asserzioni** (5 test nuovi: copula plurale stati/contatori,
|
|
455
|
+
`partono`, opposte accesa/spenta, `lascia` al buio, `prima_maiuscola`); corpus
|
|
456
|
+
della guardia anti-ambiguità esteso con le forme plurali. Suite del linguaggio a
|
|
457
|
+
**562** (era 549); collaudatore invariato a **33**; demo `vincibile-staticamente`.
|
|
458
|
+
Spec EBNF **`grammatica-0.27.0.md`** (§10); puntatore `_SPEC_EBNF` 0.26.0 → 0.27.0.
|
|
459
|
+
Versioni allineate a **0.27.0** (incluso l'header di `libreria_azioni.py`, rimasto
|
|
460
|
+
indietro a 0.24.0).
|
|
461
|
+
|
|
462
|
+
> **Nota.** Questa release apre la revisione totale post-Asse-A. I lotti successivi
|
|
463
|
+
> (robustezza del turno atomico, aggettivi con prefisso-preposizione `è incisa`,
|
|
464
|
+
> rete di test/anti-drift, README a v0.27.0, performance) sono in valutazione con
|
|
465
|
+
> l'autore.
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
## [0.26.0] - 2026-06-14
|
|
470
|
+
### Sinonimi di verbo (Asse A — A6) 🗣️
|
|
471
|
+
Sesta e ultima voce dell'**Asse A** di `progettazione-oltre-0.18.md`: con questa il
|
|
472
|
+
linguaggio chiude il gruppo «Il mondo vivo» (A4+A5+A6).
|
|
473
|
+
|
|
474
|
+
- **Sinonimo di verbo**: `"ghermisci" è come prendi.` (`def_sinonimo`,
|
|
475
|
+
`TESTO_QUOTATO "è" "come" VERBO "."`) — rimappa una parola-nuova (quotata, come
|
|
476
|
+
i verbi custom e gli alias) a un **verbo di libreria**. A differenza di un verbo
|
|
477
|
+
personalizzato (che richiede una regola `Invece di` per ogni oggetto), il
|
|
478
|
+
sinonimo eredita tutto il comportamento del bersaglio: il parser dei comandi lo
|
|
479
|
+
**riscrive nel canonico** prima di ogni trattamento, così funzionano regole
|
|
480
|
+
`Invece di prendi …`, anafora e logica di default.
|
|
481
|
+
- **Modello**: `Mondo.sinonimi_verbo` (parola → verbo canonico). Serve l'input del
|
|
482
|
+
giocatore; nelle regole d'autore vale il canonico (come per gli alias di oggetto).
|
|
483
|
+
Il bersaglio dev'essere un verbo noto (`VERBI_VALIDI`): altrimenti il sinonimo è
|
|
484
|
+
morto e si emette un **warning non bloccante** (e non viene registrato).
|
|
485
|
+
- **LALR(1) 0-ambiguo**: `def_sinonimo` è distinta da `def_verbo` sul lookahead
|
|
486
|
+
`come` vs `un` (dopo `"…" è`). Riservata aggiunta: `come`.
|
|
487
|
+
- **Test**: **+12 asserzioni** (6 test: registrazione, comportamento identico al
|
|
488
|
+
verbo bersaglio, attivazione delle regole del canonico, coesistenza col verbo
|
|
489
|
+
originale, warning su bersaglio ignoto, più sinonimi). Suite del linguaggio a
|
|
490
|
+
**549** (era 537); collaudatore invariato a **33**; demo `vincibile-staticamente`.
|
|
491
|
+
Spec EBNF **`grammatica-0.26.0.md`** (§12); puntatore `_SPEC_EBNF` 0.25.0 → 0.26.0.
|
|
492
|
+
Versioni allineate a **0.26.0**.
|
|
493
|
+
|
|
494
|
+
> **Asse A completato.** Con A6 il linguaggio FAVELLA chiude l'Asse A di
|
|
495
|
+
> `progettazione-oltre-0.18.md` (A1–A9). Prossimo passo della roadmap: il
|
|
496
|
+
> **manuale completo** rigenerato sul linguaggio finale.
|
|
497
|
+
|
|
498
|
+
---
|
|
499
|
+
|
|
500
|
+
## [0.25.0] - 2026-06-14
|
|
501
|
+
### Movimento degli NPC (Asse A — A5) 🚶
|
|
502
|
+
Quinta voce dell'**Asse A** di `progettazione-oltre-0.18.md`. I personaggi erano
|
|
503
|
+
statici: il mondo sembrava un museo. I demoni (Livello 8) fornivano già il
|
|
504
|
+
*quando*; mancava la conseguenza di *movimento*.
|
|
505
|
+
|
|
506
|
+
- **Due conseguenze nuove** (classe `ConseguenzaMovimentoPNG`), usabili in regole,
|
|
507
|
+
eventi, demoni e opzioni di dialogo:
|
|
508
|
+
- **Deterministica**: `la guardia va nel corridoio` (`cons_png_va`,
|
|
509
|
+
`ENTITA "va" PREP_LUOGO ENTITA`) — destinazione fissa, validata come stanza
|
|
510
|
+
esistente a compile-time.
|
|
511
|
+
- **Casuale**: `il gatto cambia stanza` (`cons_png_cambia`,
|
|
512
|
+
`ENTITA "cambia" "stanza"`) — una stanza **adiacente** a caso fra le uscite,
|
|
513
|
+
pescata da `mondo.rng` (riproducibile e ANNULLA-safe, come le varianti A2).
|
|
514
|
+
Senza uscite, l'NPC resta dov'è.
|
|
515
|
+
- **Annunci**: se la mossa coinvolge la stanza del giocatore, il motore lo segnala
|
|
516
|
+
— uscita «La guardia se ne va verso nord.» (con la direzione se la destinazione
|
|
517
|
+
è adiacente) / ingresso «Il gatto arriva.». Le conseguenze restano **pure**:
|
|
518
|
+
accodano in `Mondo.annunci`, e il loop di gioco (`_stampa_annunci`) svuota la
|
|
519
|
+
coda dopo ogni blocco di conseguenze (eventi/demoni a fine turno, regole del
|
|
520
|
+
giocatore, scelte di dialogo). `annunci` è stato di sessione (escluso da ANNULLA).
|
|
521
|
+
- **Scelta di design LALR-safe**: la forma casuale **non** usa `va in una stanza
|
|
522
|
+
adiacente` (collide col lessico su `PREP_LUOGO` `in`, romperebbe l'invariante
|
|
523
|
+
0-conflitti); `cambia stanza` è l'equivalente naturale e privo di collisioni.
|
|
524
|
+
Riservate aggiunte: `va`, `cambia`. **LALR(1) 0-ambiguo** (dopo ENTITA il
|
|
525
|
+
lookahead `va`/`cambia` vs `_copula`).
|
|
526
|
+
- **Linter**: `_lint_oggetti_orfani` riconosce un NPC introdotto da un movimento
|
|
527
|
+
deterministico (niente falso «mai collocato»).
|
|
528
|
+
- **Test**: **+17 asserzioni** (10 test: parsing delle due forme, movimento
|
|
529
|
+
deterministico e casuale-riproducibile, annunci di uscita/ingresso, nessun
|
|
530
|
+
annuncio fuori scena, movimento via evento e via regola del giocatore, no-op
|
|
531
|
+
senza uscite, destinazione non-stanza = errore). Suite del linguaggio a **537**
|
|
532
|
+
(era 520); collaudatore invariato a **33**; le demo restano `vincibile-
|
|
533
|
+
staticamente`. Spec EBNF **`grammatica-0.25.0.md`** (§11); puntatore `_SPEC_EBNF`
|
|
534
|
+
0.24.0 → 0.25.0. Versioni allineate a **0.25.0**.
|
|
535
|
+
|
|
536
|
+
---
|
|
537
|
+
|
|
538
|
+
## [0.24.0] - 2026-06-14
|
|
539
|
+
### Buio e luce come primitiva (Asse A — A4) 🔦
|
|
540
|
+
Quarta voce dell'**Asse A** di `progettazione-oltre-0.18.md` (la prima del gruppo
|
|
541
|
+
«Il mondo vivo»). Il pattern «stanza buia finché non hai una luce», universale
|
|
542
|
+
nell'interactive fiction, diventa una primitiva del motore invece di un esercizio
|
|
543
|
+
di regole.
|
|
544
|
+
|
|
545
|
+
- **Stanza al buio**: `La cantina è buia.` — `buia` è una **proprietà speciale**
|
|
546
|
+
della stanza (come `prendibile`), riconosciuta nel transformer per **radice**
|
|
547
|
+
(`bui-` → buia/buio/buie), che imposta `Stanza.buia`. **Nessuna nuova regola di
|
|
548
|
+
grammatica** per questa forma.
|
|
549
|
+
- **Fonte di luce**: `La torcia illumina.` — nuova regola di capacità
|
|
550
|
+
**`def_illumina`** (`ENTITA "illumina" "."`), additiva e order-independent
|
|
551
|
+
(crea-su-riferimento), che imposta `Oggetto.illumina`. Riservate aggiunte:
|
|
552
|
+
`buia`, `buio`, `illumina`.
|
|
553
|
+
- **Visibilità centralizzata**: `Mondo.c_e_luce()` — vero se la stanza non è buia
|
|
554
|
+
**oppure** è raggiungibile una fonte `illumina` **accesa** (`illumina` e non
|
|
555
|
+
«spenta», folding per radice `spent-`: l'interazione con le opposte accesa/spenta
|
|
556
|
+
è automatica; una torcia senza stato illumina sempre). Riusa
|
|
557
|
+
`oggetti_raggiungibili()`: una fonte in un **contenitore chiuso** non illumina;
|
|
558
|
+
una in mano o che brilla a terra sì.
|
|
559
|
+
- **Runtime**: in una stanza buia senza luce, `guarda`/`mostra_stanza` stampano
|
|
560
|
+
«È buio pesto.» (niente descrizione/oggetti/uscite) ed `esamina`/`prendi`/`metti`
|
|
561
|
+
rispondono «È troppo buio per vederci.». Le **uscite restano percorribili** (si
|
|
562
|
+
cammina alla cieca). Le regole d'autore (`Invece di esamina X`) mantengono la
|
|
563
|
+
precedenza sulla logica di default: si può rendere qualcosa percepibile al buio.
|
|
564
|
+
- **LALR(1) 0-ambiguo** per costruzione (`def_illumina` distinta dopo ENTITA sul
|
|
565
|
+
lookahead `illumina`). Spec EBNF aggiornata: **`grammatica-0.24.0.md`** (§10);
|
|
566
|
+
puntatore test `_SPEC_EBNF` da 0.22.0 → 0.24.0.
|
|
567
|
+
- **Test**: **+28 asserzioni** (15 test dedicati: buio blocca esamina/prendi,
|
|
568
|
+
luce in mano / a terra rischiara, spenta non illumina, contenitore chiuso vs
|
|
569
|
+
aperto, demone che spegne la luce, uscite percorribili, regola d'autore
|
|
570
|
+
prioritaria, concordanza `buio`/`buia`, order-independence). Suite del linguaggio
|
|
571
|
+
a **520** (era 492); collaudatore invariato a **33**; le demo restano
|
|
572
|
+
`vincibile-staticamente`. Versioni allineate a **0.24.0** (header core, suite,
|
|
573
|
+
`Mondo.__str__`, sidecar `VERSIONE_MOTORE`).
|
|
574
|
+
|
|
575
|
+
---
|
|
576
|
+
|
|
577
|
+
## [0.23.0] - 2026-06-13
|
|
578
|
+
### Il collaudatore automatico di storie — `collaudo.py` (B1.1) 🤖
|
|
579
|
+
Prima voce dell'**Asse B** di `progettazione-oltre-0.18.md`: «il differenziatore».
|
|
580
|
+
Verificare che una storia sia **vincibile** e che il contenuto sia
|
|
581
|
+
**raggiungibile** senza playthrough manuali. Questa release implementa il
|
|
582
|
+
**Livello 1 — analisi statica** (la «catena della vittoria»); il robot dinamico
|
|
583
|
+
(BFS sullo spazio degli stati) è la fase B1.2, successiva. Spec completa in
|
|
584
|
+
`documentazione/progettazione-collaudo.md`.
|
|
585
|
+
|
|
586
|
+
- **Nuovo modulo `collaudo.py`**, *consumatore* del Mondo compilato: **non tocca
|
|
587
|
+
la grammatica né il loop di gioco** (la grammatica resta `grammatica-0.22.0.md`).
|
|
588
|
+
- `analizza_vincibilita(mondo)` → report **strutturato (dict)** riusabile dal
|
|
589
|
+
sidecar/IDE; `rendi_report_testuale(report)` → resa leggibile per la CLI.
|
|
590
|
+
- CLI: `python collaudo.py storia.fav`.
|
|
591
|
+
- **Catena della vittoria (a ritroso)**: raccoglie ogni conseguenza «vinci»
|
|
592
|
+
(in regole, eventi, demoni, opzioni di dialogo) e risale i prerequisiti fino
|
|
593
|
+
allo stato iniziale, scomponendo le condizioni in atomi (possesso, proprietà,
|
|
594
|
+
stato, contatore, posizione) e trovando, per ciascuno, **quale conseguenza —
|
|
595
|
+
o quale azione standard (`prendi`) o movimento (`collega`) — lo rende vero**.
|
|
596
|
+
Esito: `vincibile-staticamente` / `ostruzione-possibile` / `nessuna-vittoria`.
|
|
597
|
+
- **Diagnostica**: riusa il **linter del compilatore** (`analisi_statica`) per
|
|
598
|
+
stanze isolate, oggetti orfani, regole morte e stati/contatori inutilizzati —
|
|
599
|
+
niente reinvenzione; aggiunge le **regole potenzialmente irraggiungibili**
|
|
600
|
+
(condizione mai soddisfacibile), controllo distinto dal «regola morta».
|
|
601
|
+
- **Limite onesto dichiarato nel report**: l'analisi dà condizioni *necessarie*
|
|
602
|
+
ed *euristiche* (le strutture e/oppure/non sono appiattite, l'aritmetica dei
|
|
603
|
+
contatori è approssimata), **non una prova** di vincibilità: quella spetta al
|
|
604
|
+
robot della fase B1.2.
|
|
605
|
+
- **Test**: nuova suite **`test_collaudo.py`** (33 asserzioni) — catena su una
|
|
606
|
+
storia vincibile, rilevamenti su una storia rotta, ostruzione su una vittoria
|
|
607
|
+
irraggiungibile, e verifica end-to-end sulle tre demo reali (La Casa, Il
|
|
608
|
+
Relitto Silente, Salerno-Reggio), tutte `vincibile-staticamente`.
|
|
609
|
+
|
|
610
|
+
Suite del linguaggio invariata a **492 asserzioni** verdi (nessuna regressione:
|
|
611
|
+
collaudo è additivo). Versione-ombrello del progetto a **0.23.0**; la grammatica
|
|
612
|
+
del sorgente resta `grammatica-0.22.0.md`.
|
|
613
|
+
|
|
614
|
+
---
|
|
615
|
+
|
|
616
|
+
## [0.22.0] - 2026-06-13
|
|
617
|
+
### Varietà nelle risposte: descrizioni alternate 🎲
|
|
618
|
+
Una descrizione può ora avere **più varianti**, così il mondo non si ripete
|
|
619
|
+
identico a ogni sguardo — la cosa che più «data» un gioco testuale. Terza voce
|
|
620
|
+
dell'Asse A di `progettazione-oltre-0.18.md`. Suite del linguaggio: **492
|
|
621
|
+
asserzioni** (era 484), tutte verdi; invariante LALR(1) 0-ambiguo intatto.
|
|
622
|
+
|
|
623
|
+
- **Due politiche dichiarabili**:
|
|
624
|
+
- `La descrizione del mare è una di: "…", "…", "…".` — **casuale**, senza
|
|
625
|
+
ripetere mai due volte di fila la stessa variante.
|
|
626
|
+
- `La descrizione del faro è in sequenza: "…", "…".` — **rotazione**: le
|
|
627
|
+
varianti si susseguono e l'ultima resta (descrizioni che «si consumano»).
|
|
628
|
+
- Vale sia per la descrizione di base sia per le varianti condizionali (`se …`),
|
|
629
|
+
e i segnaposto `[var]` continuano a funzionare dentro ogni variante.
|
|
630
|
+
- **Casualità riproducibile**: il mondo ha un generatore con **seme fisso**
|
|
631
|
+
(`Mondo.rng`, `SEME_CASUALE_DEFAULT`). Le partite sono deterministiche e —
|
|
632
|
+
punto chiave — **ANNULLA riavvolge anche la casualità** (il generatore e gli
|
|
633
|
+
indici delle varianti sono catturati dalle istantanee di stato). Pronto per il
|
|
634
|
+
futuro giocatore-robot (B1).
|
|
635
|
+
|
|
636
|
+
**Modifica di grammatica** (la prima dalla 0.19.0; 0.20.0 e 0.21.0 erano solo
|
|
637
|
+
runtime): `def_descrizione` delega a `descr_valore`
|
|
638
|
+
(`descr_singola`/`descr_casuale`/`descr_sequenza`). Nuova classe
|
|
639
|
+
`strutture.VariantiDescrizione`. Riservata aggiunta: `sequenza`. Spec EBNF
|
|
640
|
+
**`grammatica-0.22.0.md`** (puntatore test 0.19.0→0.22.0). Validazione segnaposto,
|
|
641
|
+
linter e serializzazione IDE aggiornati per ispezionare ogni variante.
|
|
642
|
+
|
|
643
|
+
---
|
|
644
|
+
|
|
645
|
+
## [0.21.0] - 2026-06-13
|
|
646
|
+
### Comandi di servizio: ANNULLA, ANCORA, TRASCRIZIONE ↩️
|
|
647
|
+
Le tre comodità standard dell'interactive fiction dal 1985 (Infocom). Seconda
|
|
648
|
+
voce dell'Asse A di `progettazione-oltre-0.18.md`. **Solo runtime: grammatica
|
|
649
|
+
del sorgente invariata** (spec EBNF resta `grammatica-0.19.0.md`). Suite del
|
|
650
|
+
linguaggio: **484 asserzioni** (era 474), tutte verdi.
|
|
651
|
+
|
|
652
|
+
- **ANNULLA** (anche `disfa`): disfa l'ultimo turno. Implementato con istantanee
|
|
653
|
+
profonde dello stato del mondo prima di ogni turno (`Mondo.cattura_stato` /
|
|
654
|
+
`ripristina_stato`): un «time-machine» fedele che riavvolge posizioni,
|
|
655
|
+
inventario, stati, contatori, turni ed eventi/demoni — niente replay. Pila
|
|
656
|
+
fino a `_MAX_ANNULLA` (100) turni. «Non c'è niente da annullare.» quando vuota.
|
|
657
|
+
- **ANCORA** (anche `ripeti`, `g`): ripete l'ultimo comando che ha consumato un
|
|
658
|
+
turno (`Mondo.ultimo_comando`).
|
|
659
|
+
- **TRASCRIZIONE**: avvia/ferma il salvataggio della partita su
|
|
660
|
+
`trascrizione-favella.txt` (comandi del giocatore + output del motore). È una
|
|
661
|
+
funzione della sessione da riga di comando (un `_Tee` su `sys.stdout` nel loop
|
|
662
|
+
di `gioca`); non disponibile nei driver headless/web.
|
|
663
|
+
|
|
664
|
+
I comandi di servizio NON consumano un turno. `aiuto` ora li elenca, insieme ai
|
|
665
|
+
pronomi (0.20.0). Versioni core e suite a **0.21.0**.
|
|
666
|
+
|
|
667
|
+
---
|
|
668
|
+
|
|
669
|
+
## [0.20.0] - 2026-06-13
|
|
670
|
+
### Pronomi e anafora 🗣️
|
|
671
|
+
Il giocatore può ora usare i **pronomi** per riferirsi all'ultimo oggetto
|
|
672
|
+
nominato — la singola cosa che più fa sembrare «sveglio» un parser italiano.
|
|
673
|
+
Prima voce dell'Asse A del documento `progettazione-oltre-0.18.md` (era marcata
|
|
674
|
+
⭐ priorità massima). **Solo runtime: la grammatica del sorgente NON cambia**
|
|
675
|
+
(la spec EBNF resta `grammatica-0.19.0.md`), quindi l'invariante LALR(1) non è
|
|
676
|
+
nemmeno sfiorato. Suite del linguaggio: **474 asserzioni** (era 467), tutte verdi.
|
|
677
|
+
|
|
678
|
+
- **Clitici suffissi**: `esamina la torcia` → `prendila`; `aprilo`, `esaminale`,
|
|
679
|
+
`usali`. Il clitico si stacca dal verbo se il resto è un comando noto.
|
|
680
|
+
- **Pronomi tonici / nudi**: `prendi quella`, `apri quello`, `usa lo`.
|
|
681
|
+
- **Concordanza di genere e numero**: il riferito è indicizzato per
|
|
682
|
+
`m_sing`/`f_sing`/`m_plur`/`f_plur` (dedotto dall'articolo del nome). Un
|
|
683
|
+
pronome del genere sbagliato non trova riferente: «Cosa vorresti prendere?».
|
|
684
|
+
- **Riferito = ultima azione *o* ultimo nominato**: vale sia l'oggetto su cui hai
|
|
685
|
+
appena agito (`esamina la torcia`), sia un oggetto elencato dalla stanza
|
|
686
|
+
(`entri… → prendila`).
|
|
687
|
+
- **Riferito non più raggiungibile**: se l'oggetto è stato preso da altri o
|
|
688
|
+
lasciato indietro, «Non la vedi più.».
|
|
689
|
+
|
|
690
|
+
Implementazione in `gioco.py` (`_risolvi_anafora`) + `strutture.Mondo`
|
|
691
|
+
(`ultimo_riferito`, `registra_riferito`/`registra_riferiti_da_stanza`) +
|
|
692
|
+
`utils.chiave_genere_numero`. Versioni core e suite a **0.20.0**.
|
|
693
|
+
|
|
694
|
+
---
|
|
695
|
+
|
|
696
|
+
## [0.19.0] - 2026-06-13
|
|
697
|
+
### Lezioni dallo stress-test di genere 🚗
|
|
698
|
+
Tre integrazioni al linguaggio nate costruendo un genere fuori dall'asse del
|
|
699
|
+
design originale — un **simulatore di guida testuale** («Salerno-Reggio
|
|
700
|
+
Calabria», in `esempi/demo/salerno-reggio/`). I punti d'attrito incontrati sono
|
|
701
|
+
diventati primitive. Suite del linguaggio: **467 asserzioni** (era 446), tutte
|
|
702
|
+
verdi; invariante LALR(1) 0-ambiguo intatto (guardia estesa ai tre costrutti);
|
|
703
|
+
`analizza_file` invariata.
|
|
704
|
+
|
|
705
|
+
- **A7 — Verbi intransitivi.** `"accelera" è un comando senza oggetto.` dichiara
|
|
706
|
+
un comando che il giocatore digita da solo, gestito da una regola GLOBALE
|
|
707
|
+
`Invece di accelera: …` (con condizioni e conseguenze, incluso `vinci`/`perdi`;
|
|
708
|
+
vale anche multi-parola). La dichiarazione si sdoppia in `verbo_con_oggetto`
|
|
709
|
+
(storico) e `verbo_senza_oggetto`; in `carica_azioni` i verbi custom si dividono
|
|
710
|
+
fra `_personalizzata` (transitivi) e `_personalizzata_intransitiva`.
|
|
711
|
+
- **A8 — Inventario iniziale.** `Il giocatore ha la torcia.` mette l'oggetto in
|
|
712
|
+
inventario all'avvio (`def_giocatore_inventario`, applicato in `valida_post`,
|
|
713
|
+
order-independent). Un oggetto per frase; oggetto inesistente = errore bloccante.
|
|
714
|
+
- **A9 — «Tick» silenziosi.** La battuta `dire "…"` di eventi e demoni è ora
|
|
715
|
+
**opzionale**, purché ci sia almeno una conseguenza:
|
|
716
|
+
`Ogni 3 turni: diminuisci il carburante.` muta lo stato senza stampare nulla
|
|
717
|
+
(regola inline `_esito_temporale`).
|
|
718
|
+
|
|
719
|
+
Nuove riservate: `senza`, `oggetto`. Spec EBNF `documentazione/grammatica-0.19.0.md`.
|
|
720
|
+
Versioni allineate a **0.19.0** (header core, suite, `VERSIONE_MOTORE`). La demo
|
|
721
|
+
di guida è inclusa in due tempi: la sfida (fattibilità sul motore 0.18.0) e la
|
|
722
|
+
riscrittura idiomatica resa possibile da A7/A8/A9.
|
|
723
|
+
|
|
724
|
+
---
|
|
725
|
+
|
|
726
|
+
## [Manutenzione] - 2026-06-11
|
|
727
|
+
### Pulizia interna del motore 🧹
|
|
728
|
+
Nessun cambiamento al linguaggio. Suite sempre a **446 test** verdi.
|
|
729
|
+
- **Versione in un punto solo:** nuova costante `VERSIONE_MOTORE` in
|
|
730
|
+
`strutture.py`; il sidecar e il report di compilazione (`Mondo.__str__`) la
|
|
731
|
+
importano invece di cablare il numero in proprio.
|
|
732
|
+
- **Deduplicato il preprocessore:** `espandi_inclusioni` ora accetta un
|
|
733
|
+
`sorgente_radice` opzionale (il buffer in memoria dell'IDE) e la copia
|
|
734
|
+
parallela `_espandi_inclusioni_seedable` è diventata un semplice alias.
|
|
735
|
+
- **Diagnostica dei crash:** un errore interno del compilatore ora stampa lo
|
|
736
|
+
stack trace completo (prima solo il messaggio), per individuare il punto
|
|
737
|
+
esatto del bug.
|
|
738
|
+
|
|
739
|
+
---
|
|
740
|
+
|
|
741
|
+
## [Export HTML] - 2026-06-05
|
|
742
|
+
### Esporta il gioco come pagina HTML autoportante 📦
|
|
743
|
+
Nuova funzione `esporta_html` nel compilatore (op `game.exportHtml` del
|
|
744
|
+
sidecar): impacchetta una storia `.fav` in **un singolo file HTML giocabile nel
|
|
745
|
+
browser**, con il motore Python eseguito via **Pyodide** (nessuna installazione
|
|
746
|
+
per chi gioca).
|
|
747
|
+
- Sorgente espanso (inclusioni risolte) e moduli del motore incapsulati nel
|
|
748
|
+
JSON dei dati; il driver Python vive nel JSON, non in un template literal
|
|
749
|
+
(robusto rispetto a backtick e `${}` nei testi delle storie).
|
|
750
|
+
- Robusto al bundle congelato di PyInstaller (`_MEIPASS`): i sorgenti del
|
|
751
|
+
motore vengono letti dal bundle quando il sidecar gira impacchettato.
|
|
752
|
+
|
|
753
|
+
---
|
|
754
|
+
|
|
755
|
+
## [Manuale] - 2026-06-04
|
|
756
|
+
### Manuale d'autore completo — PDF tipografico 📖
|
|
757
|
+
Riscritto da zero il **Manuale di Programmazione** (`documentazione/manuale/`),
|
|
758
|
+
allineato alla **v0.18.0** e focalizzato esclusivamente sul linguaggio. 17
|
|
759
|
+
capitoli (dalle stanze ai personaggi, ai demoni, ai moduli) più appendici, con
|
|
760
|
+
**ogni costrutto illustrato da esempi reali** presi parola per parola da «La Casa
|
|
761
|
+
di Via Stradivari» (`esempi/materiale-didattico/`).
|
|
762
|
+
- Composto con **Typst**: copertina di marca, dedica, indice, colophon, e un
|
|
763
|
+
evidenziatore di sintassi `.fav` dedicato. Sorgente modulare (un file per
|
|
764
|
+
capitolo) + `build.ps1` + `README`.
|
|
765
|
+
- Font di marca (Sora, Source Code Pro) inclusi sotto licenza SIL OFL 1.1.
|
|
766
|
+
- Sostituisce il vecchio `manuale.md` (datato ≈0.0.9.2), ora rimosso.
|
|
767
|
+
|
|
768
|
+
---
|
|
769
|
+
|
|
770
|
+
## [0.18.0] - 2026-06-03
|
|
771
|
+
### Consolidamento del linguaggio — «linguaggio al massimo» 🏁
|
|
772
|
+
Sessione dedicata a **colmare ogni buco e asimmetria** emersi scrivendo le demo,
|
|
773
|
+
senza più workaround: il linguaggio è ora completo ed eccellente allo stato
|
|
774
|
+
attuale delle conoscenze. Grammatica sempre **LALR(1) 0-ambigua**. Suite da 386 a
|
|
775
|
+
**446 test** verdi.
|
|
776
|
+
|
|
777
|
+
**Correzioni di limiti/asimmetrie (A):**
|
|
778
|
+
- **A1 — Le regole a DUE oggetti valutano il `se`.** `usa X PREP Y` ora sceglie,
|
|
779
|
+
fra le regole che combaciano, la prima **condizionale soddisfatta**, poi la
|
|
780
|
+
prima **semplice** (esatto come le regole a un oggetto), con fallback
|
|
781
|
+
prep-tollerante. Prima il `se` era ignorato: vinceva sempre la prima dichiarata.
|
|
782
|
+
- **A2 — Genitivo `dei`** nelle descrizioni: `La descrizione dei pilastri è "…"`.
|
|
783
|
+
- **A3 — Accenti NFC.** Sorgente e input del giocatore sono normalizzati in forma
|
|
784
|
+
NFC: i nomi accentati (`comò`) si risolvono in modo affidabile anche se digitati
|
|
785
|
+
in forma decomposta. Cade la convenzione «niente accenti nei nomi».
|
|
786
|
+
- **A4 — Preposizioni d'azione articolate.** `usa la batteria sul pannello`,
|
|
787
|
+
`metti la spada nella teca`: niente più la stonatura `su il`/`su la`.
|
|
788
|
+
- **A5 — Copula plurale `sono`.** `Le tacche sono una cosa`, `Le tacche sono
|
|
789
|
+
vergini`, `se le tacche sono segnate`: l'italiano corretto sui nomi plurali (era
|
|
790
|
+
obbligatorio scrivere `Le tacche È una cosa`).
|
|
791
|
+
|
|
792
|
+
**Nuovi costrutti di design (B):**
|
|
793
|
+
- **B1 — `se il giocatore è in [stanza]`** (+ negazione).
|
|
794
|
+
- **B2 — Teletrasporto:** `e adesso il giocatore è in [stanza]` (mostra la nuova
|
|
795
|
+
stanza; destinazione validata a compile-time).
|
|
796
|
+
- **B3 — Testo d'esito personalizzato:** `… e adesso vinci "Sei libero!"` (anche
|
|
797
|
+
`perdi`/`termina`), al posto del banner fisso.
|
|
798
|
+
- **B4 — Confronto `al massimo N`** (≤) sui contatori, simmetrico ad `almeno` (≥).
|
|
799
|
+
- **B5 — Disuguaglianza numerica `non è N`** (≠) sui contatori.
|
|
800
|
+
- **B6 — Verbi personalizzati multi-parola:** `"fai scattare" è un comando.`
|
|
801
|
+
(terminale chiuso `VERBO_MULTI` + longest-match a runtime).
|
|
802
|
+
- **B7 — Negazione di un gruppo:** `non ( A e B )`.
|
|
803
|
+
|
|
804
|
+
**Consolidamento:** versioni allineate a **0.18.0** (moduli core, suite, sidecar,
|
|
805
|
+
`Mondo.__str__`); spec EBNF `documentazione/grammatica-0.18.0.md`; demo
|
|
806
|
+
naturalizzate (`su il`→`sul`). Sidecar `VERSIONE_MOTORE` → 0.18.0. Dettaglio in
|
|
807
|
+
`documentazione/0.18.0.md`.
|
|
808
|
+
|
|
809
|
+
## [0.17.0] - 2026-06-03
|
|
810
|
+
### Robustezza d'ordine + audit dei Livelli 1-8 🧱
|
|
811
|
+
Due lavori della sequenza «linguaggio al massimo»: rendere il linguaggio
|
|
812
|
+
**indipendente dall'ordine** delle frasi e una **rassegna** dei livelli 1-8.
|
|
813
|
+
|
|
814
|
+
**Robustezza d'ordine.** Finora una frase che *usa* un'entità doveva venire DOPO
|
|
815
|
+
la sua definizione: `La gemma è nella scatola.` falliva se `La scatola è un
|
|
816
|
+
contenitore.` arrivava dopo. Ora la risoluzione delle entità per nome è
|
|
817
|
+
**differita a fine compilazione** (`valida_post`, a mondo completo), così l'ordine
|
|
818
|
+
non conta più. Vale per:
|
|
819
|
+
- **posizioni** (`X è in/nella/sul Y`), incluse le collocazioni in contenitori/supporti;
|
|
820
|
+
- **proprietà** (`X è chiusa`);
|
|
821
|
+
- **descrizioni** (`La descrizione di X è "…"`);
|
|
822
|
+
- **conseguenze** (`… e adesso la chiave è in inventario`) che citano entità definite dopo;
|
|
823
|
+
- **bersaglio delle regole** (`Invece di apri la porta: …` con `la porta` dichiarata dopo).
|
|
824
|
+
|
|
825
|
+
Gli errori veri restano: una destinazione/bersaglio **mai** definito fallisce
|
|
826
|
+
ancora la compilazione (solo il *momento* del controllo è cambiato, non l'esito).
|
|
827
|
+
È una modifica **semantica**: la grammatica è invariata (spec
|
|
828
|
+
`documentazione/grammatica-0.16.0.md` resta valida).
|
|
829
|
+
|
|
830
|
+
**Audit — due bug corretti:**
|
|
831
|
+
1. **No-op a partita conclusa.** Dopo `vinci`/`perdi`/`termina`, un ulteriore
|
|
832
|
+
comando non avanza più il turno né fa scattare eventi/demoni (prima, un
|
|
833
|
+
chiamante che ignorava il valore di ritorno poteva far ripartire gli eventi).
|
|
834
|
+
2. **Linter cieco ai demoni.** Le analisi statiche «variabile inutilizzata» e
|
|
835
|
+
«oggetto orfano» non guardavano dentro i demoni (Livello 8): una variabile o un
|
|
836
|
+
oggetto usati *solo* in un demone venivano falsamente segnalati. Ora
|
|
837
|
+
`_tutte_le_condizioni`/`_tutte_le_conseguenze`/`_tutti_i_testi` includono i demoni.
|
|
838
|
+
|
|
839
|
+
- Suite linguaggio: **386 asserzioni** (era 364), tutte verdi; 11 nuovi test
|
|
840
|
+
(8 di robustezza d'ordine, 1 no-op fine partita, 2 linter+demoni). `analizza_file`
|
|
841
|
+
invariata. Sidecar `VERSIONE_MOTORE` → 0.17.0. Dettaglio in
|
|
842
|
+
`documentazione/0.17.0.md`.
|
|
843
|
+
|
|
844
|
+
## [0.16.0] - 2026-06-03
|
|
845
|
+
### Valore iniziale configurabile dei contatori 🔢
|
|
846
|
+
Finora un contatore partiva **sempre da 0**: per dargli un valore di partenza
|
|
847
|
+
(forza, vita, mana iniziali per una storia in stile GDR) bisognava alzarlo a mano
|
|
848
|
+
con una conseguenza. Da questa versione basta una frase:
|
|
849
|
+
|
|
850
|
+
La forza è un contatore.
|
|
851
|
+
La forza parte da 3.
|
|
852
|
+
|
|
853
|
+
- **Additivo e order-independent.** La frase `parte da N` imposta il valore; può
|
|
854
|
+
comparire prima o dopo `è un contatore.` (la dichiarazione usa `setdefault` e non
|
|
855
|
+
sovrascrive). Richiede comunque che il contatore sia dichiarato nel file.
|
|
856
|
+
- **Grammatica.** Nuova produzione `def_contatore_iniziale` (`VARIABILE "parte"
|
|
857
|
+
"da" NUMERO "."`): inizia con VARIABILE, il lookahead `parte` vs `è` la distingue
|
|
858
|
+
dagli altri costrutti su variabile → **LALR(1) 0-ambiguo**. Nuova riservata: `da`.
|
|
859
|
+
- **Capacità di trasporto invariata.** Conferma del modello "moltiplicatore" del
|
|
860
|
+
Livello 7 (`Il giocatore può portare N oggetti.` + `Lo zaino dà N spazi.`):
|
|
861
|
+
inventario piatto, nessun contenitore-zaino, nessuno slot "indossato".
|
|
862
|
+
- Suite linguaggio: **364 asserzioni** (era 360), tutte verdi; guardia
|
|
863
|
+
anti-ambiguità estesa. Spec EBNF `documentazione/grammatica-0.16.0.md`. Sidecar
|
|
864
|
+
`VERSIONE_MOTORE` → 0.16.0. Dettaglio in `documentazione/0.16.0.md`.
|
|
865
|
+
|
|
866
|
+
## [0.15.0] - 2026-06-03
|
|
867
|
+
### Roadmap del Linguaggio — Livello 8: REATTIVITÀ / DEMONI 👁️
|
|
868
|
+
L'ultima capacità mancante del linguaggio: gli **eventi condizionali** (i
|
|
869
|
+
«demoni»). Finora un *if-then* in FAVELLA era sempre ancorato a qualcosa — a un
|
|
870
|
+
verbo del giocatore (`Invece di …`) o a un turno fisso (`Al turno N` / `Ogni N
|
|
871
|
+
turni`, timer **senza** `se`). Mancava la sentinella **autonoma**: qualcosa che
|
|
872
|
+
sorveglia una condizione a ogni turno e scatta da sola quando si avvera.
|
|
873
|
+
|
|
874
|
+
Due forme nuove, entrambe **additive** e **LALR(1) 0-ambigue** per costruzione:
|
|
875
|
+
|
|
876
|
+
- **A livello** — `Ogni turno se [condizione]: dire "…" e adesso […].`
|
|
877
|
+
Scatta a **ogni** turno in cui la condizione è vera (effetti continui: veleno,
|
|
878
|
+
fame, un allarme che pulsa). Si distingue da `Ogni N turni` sul primo token dopo
|
|
879
|
+
«Ogni» (un numero = timer, la parola «turno» = demone).
|
|
880
|
+
- **Sul fronte di salita** — `Quando [condizione] (diventa vera)?: dire "…" e adesso […].`
|
|
881
|
+
Scatta **una sola volta**, nel turno in cui la condizione passa da falsa a vera
|
|
882
|
+
(soglie, scadenze, punti di non ritorno). La chiusura `diventa vera` è
|
|
883
|
+
**opzionale**: `Quando X:` e `Quando X diventa vera:` sono sinonimi.
|
|
884
|
+
|
|
885
|
+
L'esempio prima impossibile, ora nativo:
|
|
886
|
+
|
|
887
|
+
La tensione è un contatore.
|
|
888
|
+
Ogni 1 turno: dire "La tensione cresce." e adesso aumenta la tensione di 2.
|
|
889
|
+
Quando la tensione è almeno 8: dire "Il portale ti risucchia." e adesso perdi.
|
|
890
|
+
|
|
891
|
+
- **Riusano tutto il già esistente**: l'albero `condizione` completo
|
|
892
|
+
(proprietà/stati/contatori + AND/OR/NOT/parentesi) e la coda di conseguenze
|
|
893
|
+
`e adesso …`.
|
|
894
|
+
- **Anti-loop per costruzione**: i demoni sono valutati **una volta per turno**,
|
|
895
|
+
in un solo passaggio in ordine di dichiarazione, **dopo** gli eventi a tempo. Un
|
|
896
|
+
demone può innescare a cascata i demoni *successivi* nello stesso passaggio, ma
|
|
897
|
+
nessuno viene ri-valutato → loop infiniti impossibili.
|
|
898
|
+
- **Fronte di salita corretto**: ogni demone `Quando` ricorda il valore precedente
|
|
899
|
+
(`Demone.era_vera`), inizializzato a fine compilazione sul mondo iniziale → una
|
|
900
|
+
condizione già vera alla partenza non genera un falso fronte.
|
|
901
|
+
- **Byte-stabile**: classe `Demone` e lista `Mondo.demoni` distinte dagli eventi a
|
|
902
|
+
tempo (la serializzazione degli eventi resta intatta). Nuove riservate: `quando`,
|
|
903
|
+
`vera` (`diventa` era già riservata). `analizza_file` invariata.
|
|
904
|
+
- Suite linguaggio: **360 asserzioni** (era 344), tutte verdi; guardia
|
|
905
|
+
anti-ambiguità estesa a entrambe le forme. Spec EBNF
|
|
906
|
+
`documentazione/grammatica-0.15.0.md`. Sidecar `VERSIONE_MOTORE` → 0.15.0.
|
|
907
|
+
Dettaglio in `documentazione/0.15.0.md`.
|
|
908
|
+
|
|
909
|
+
## [0.14.0] - 2026-06-03
|
|
910
|
+
### Concordanza di genere/numero sulle proprietà di stato 🇮🇹
|
|
911
|
+
In un linguaggio d'autore italiano, `aperto` e `aperta` devono valere uguale.
|
|
912
|
+
Finora le proprietà erano confrontate **alla lettera**: `il portale è aperto` NON
|
|
913
|
+
rimuoveva `chiusa`, così il contenitore restava chiuso pur dicendo «si apre».
|
|
914
|
+
|
|
915
|
+
Da questa versione il motore confronta le proprietà di stato per **RADICE**,
|
|
916
|
+
ignorando la desinenza regolare `-o/-a/-i/-e`:
|
|
917
|
+
|
|
918
|
+
aperto = aperta = aperti = aperte -> apert
|
|
919
|
+
chiuso = chiusa -> chius
|
|
920
|
+
spento = spenta -> spent
|
|
921
|
+
bloccato = bloccata -> bloccat
|
|
922
|
+
|
|
923
|
+
Il folding (nuova `utils.radice_proprieta`) si applica nei **quattro punti** che
|
|
924
|
+
contano: condizioni (`se X è aperto` combacia con `aperta`), conseguenze opposte
|
|
925
|
+
(`è aperto` rimuove `chiusa`/`chiuso`), apertura dei contenitori
|
|
926
|
+
(`Mondo.contenitore_aperto`) e il linter dei refusi. Le coppie opposte dichiarate
|
|
927
|
+
al maschile valgono anche al femminile e viceversa (`acceso/spento` ⇄ `accesa/spenta`).
|
|
928
|
+
|
|
929
|
+
- **Le proprietà restano scritte come le ha messe l'autore** (display/IDE/serializzazione
|
|
930
|
+
invariati): la normalizzazione è solo interna al confronto.
|
|
931
|
+
- **I refusi veri restano segnalati**: cambiano la radice (`chuisa` ≠ `chiusa`), quindi
|
|
932
|
+
il linter li intercetta ancora.
|
|
933
|
+
- Pochi termini invariabili (colori come `rosa`, `viola`, `blu`) sono esclusi dal troncamento.
|
|
934
|
+
- **Grammatica invariata** rispetto a 0.13.0 (modifica solo semantica): la spec EBNF
|
|
935
|
+
`documentazione/grammatica-0.13.0.md` resta valida.
|
|
936
|
+
- Suite linguaggio: **344 asserzioni** (era 334), tutte verdi. `analizza_file` invariata.
|
|
937
|
+
- Sidecar `VERSIONE_MOTORE` → 0.14.0. Dettaglio in `documentazione/0.14.0.md`.
|
|
938
|
+
|
|
939
|
+
## [0.13.0] - 2026-06-02
|
|
940
|
+
### Roadmap del Linguaggio — Livello 7: CAPACITÀ DI TRASPORTO 🎒
|
|
941
|
+
Primo costrutto del **Livello 7**. Aggiunge un limite **opzionale** di oggetti
|
|
942
|
+
trasportabili, configurabile dall'autore e **additivo**:
|
|
943
|
+
|
|
944
|
+
Il giocatore può portare 5 oggetti. # capacità base
|
|
945
|
+
Lo zaino dà 15 spazi. # bonus mentre lo zaino è nell'inventario
|
|
946
|
+
|
|
947
|
+
La capacità attuale è `base + somma dei bonus degli oggetti portati`
|
|
948
|
+
(`Mondo.capacita_attuale()`); l'azione `prendi` rifiuta un oggetto se
|
|
949
|
+
l'inventario è pieno («Hai le mani troppo piene…»). **Senza dichiarazione
|
|
950
|
+
l'inventario resta illimitato** (default storico invariato): la feature non è
|
|
951
|
+
vincolante. L'azione `inventario` mostra «(usati/max)» quando una capacità è
|
|
952
|
+
dichiarata.
|
|
953
|
+
|
|
954
|
+
**Grammatica** (LALR(1) 0-ambiguo, per costruzione): due regole nuove —
|
|
955
|
+
`def_giocatore_capacita` (`"Il giocatore può portare" NUMERO "oggetti"`,
|
|
956
|
+
distinta da `def_giocatore` sul lookahead `può` vs `comincia/inizia/parte`) e
|
|
957
|
+
`def_capacita_oggetto` (`ENTITA "dà" NUMERO "spazi"`, unico costrutto `ENTITA "dà"`).
|
|
958
|
+
Nuove parole riservate: `può`, `portare`, `oggetti`, `dà`, `spazi`.
|
|
959
|
+
|
|
960
|
+
**Modello**: `Mondo.capacita_base` (None = illimitata), `Oggetto.bonus_capacita`.
|
|
961
|
+
L'IDE espone `carryUsed`/`carryMax` nello snapshot (`world.snapshot`); l'inspector
|
|
962
|
+
mostra «Inventario (n/max)».
|
|
963
|
+
|
|
964
|
+
Suite: **334 asserzioni** (era 321), tutte verdi; la guardia anti-ambiguità copre
|
|
965
|
+
i nuovi costrutti (1 albero / 0 conflitti LALR). Spec EBNF aggiornata in
|
|
966
|
+
**`documentazione/grammatica-0.13.0.md`**. Header core (compilatore/strutture/gioco/
|
|
967
|
+
libreria_azioni/suite) + `Mondo.__str__` a **v0.13.0**. Doc: `documentazione/0.13.0.md`.
|
|
968
|
+
|
|
969
|
+
---
|
|
970
|
+
|
|
971
|
+
## [0.11.3] - 2026-05-31
|
|
972
|
+
### Roadmap del Linguaggio — Livello 6: SPEC EBNF FORMALE VERSIONATA 📐
|
|
973
|
+
Terza patch del Livello 6 (verso `0.12.0`). Aggiunge il documento tecnico
|
|
974
|
+
**`documentazione/grammatica-0.12.0.md`**: la specifica formale versionata della
|
|
975
|
+
grammatica di FAVELLA 1 — scheletro statico in EBNF (Lark) + modello dei
|
|
976
|
+
**terminali chiusi generati per-file** (`ENTITA`/`VARIABILE`/`DIREZIONE`),
|
|
977
|
+
priorità lessicali (`PROPRIETA`, `NUMERO`, `_PREP_DESCR`) e invariante LALR(1).
|
|
978
|
+
Non è il manuale d'autore: descrive il linguaggio dal lato compilatore.
|
|
979
|
+
|
|
980
|
+
**Guardia anti-drift**: nuovi test verificano che la spec citi tutte le regole
|
|
981
|
+
`def_/cond_/cons_` della grammatica reale (`_GRAMMAR_TEMPLATE`) e documenti i
|
|
982
|
+
terminali chiusi — così la spec non potrà divergere dal codice senza far fallire
|
|
983
|
+
la suite.
|
|
984
|
+
|
|
985
|
+
Suite: **321 asserzioni** (era 314), tutte verdi. Header `test_linguaggio.py` a
|
|
986
|
+
**v0.11.3** (il compilatore non cambia in questa patch).
|
|
987
|
+
|
|
988
|
+
---
|
|
989
|
+
|
|
990
|
+
## [0.11.2] - 2026-05-31
|
|
991
|
+
### Roadmap del Linguaggio — Livello 6: MODULI / IMPORT MULTI-.FAV 📦
|
|
992
|
+
Seconda patch del Livello 6 (verso `0.12.0`). Introduce gli **import multi-file**
|
|
993
|
+
come **preprocessore (Passata 0)** testuale: la direttiva
|
|
994
|
+
|
|
995
|
+
Includi "file.fav".
|
|
996
|
+
|
|
997
|
+
viene espansa in un unico sorgente **prima** delle due passate, quindi **non
|
|
998
|
+
raggiunge mai il parser** → invariante LALR(1) 0-ambiguo intatto per costruzione.
|
|
999
|
+
|
|
1000
|
+
Il preprocessore (`compilatore.espandi_inclusioni`) gestisce:
|
|
1001
|
+
- **Path relativi** al file che include (anche in sottocartelle).
|
|
1002
|
+
- **Deduplica** — lo stesso file incluso più volte (diamanti) è espanso una sola volta.
|
|
1003
|
+
- **Rilevamento dei cicli** — un'inclusione circolare è un **errore bloccante**.
|
|
1004
|
+
- **File incluso mancante** — errore bloccante con il nome del file.
|
|
1005
|
+
- **Source map** riga-espansa → (file, riga): gli errori di sintassi e le
|
|
1006
|
+
diagnosi d'entità sono **attribuiti al file e alla riga originali**.
|
|
1007
|
+
- Il path quotato è *vocabolario nuovo tra virgolette* (come alias/verbi); le
|
|
1008
|
+
direttive dentro stringhe/commenti non vengono interpretate.
|
|
1009
|
+
|
|
1010
|
+
Suite: **314 asserzioni** (era 302), tutte verdi; guardia anti-ambiguità
|
|
1011
|
+
invariata. Superficie pubblica `analizza_file()` intatta. Header `compilatore.py`
|
|
1012
|
+
e `test_linguaggio.py` a **v0.11.2**.
|
|
1013
|
+
|
|
1014
|
+
---
|
|
1015
|
+
|
|
1016
|
+
## [0.11.1] - 2026-05-31
|
|
1017
|
+
### Roadmap del Linguaggio — Livello 6 «Maturità toolchain»: LINTER SEMANTICO 🔍
|
|
1018
|
+
Prima patch del Livello 6 (verso la release `0.12.0`). Introduce un **linter
|
|
1019
|
+
semantico** nel compilatore: analisi statica **non bloccante** sul mondo
|
|
1020
|
+
compilato, che emette avvisi sul canale `warnings` già esistente. **Nessuna
|
|
1021
|
+
modifica alla grammatica** → invariante LALR(1) 0-ambiguo intatto per costruzione.
|
|
1022
|
+
|
|
1023
|
+
Quattro controlli (in `FavellaTransformer.analisi_statica`, eseguita in coda a
|
|
1024
|
+
`valida_post`):
|
|
1025
|
+
- **Stanze irraggiungibili** — reachability (BFS) dal punto di partenza sulle
|
|
1026
|
+
uscite (`collega`); una stanza non raggiunta è segnalata.
|
|
1027
|
+
- **Oggetti orfani** — oggetti (NPC/contenitori/supporti inclusi) mai collocati
|
|
1028
|
+
e mai introdotti da una conseguenza di spostamento.
|
|
1029
|
+
- **Regole morte** — regole oscurate da una precedente con identica firma
|
|
1030
|
+
(verbo, bersaglio, secondario, preposizione) che scatta sempre; criterio
|
|
1031
|
+
conservativo allineato all'ordine delle fasi del runtime (zero falsi positivi).
|
|
1032
|
+
- **Stati/contatori inutilizzati** — variabili dichiarate ma mai lette in una
|
|
1033
|
+
condizione, conseguenza o interpolazione `[var]`.
|
|
1034
|
+
|
|
1035
|
+
Suite: **302 asserzioni** (era 287), tutte verdi; guardia anti-ambiguità
|
|
1036
|
+
invariata. Superficie pubblica `analizza_file()` intatta. Header `compilatore.py`
|
|
1037
|
+
e `test_linguaggio.py` a **v0.11.1**.
|
|
1038
|
+
|
|
1039
|
+
---
|
|
1040
|
+
|
|
1041
|
+
## [0.11.0] - 2026-05-31
|
|
1042
|
+
### Roadmap del Linguaggio — Livello 5b «NPC e dialoghi ramificati» COMPLETATO 🗣️
|
|
1043
|
+
Release minore che consolida le patch `0.10.1` → `0.10.4` e aggiunge al linguaggio
|
|
1044
|
+
un **sistema di dialogo completo da interactive fiction**. In sintesi (dettaglio
|
|
1045
|
+
per-patch sotto e nel documento tecnico `documentazione/0.11.0.md`):
|
|
1046
|
+
|
|
1047
|
+
- **NPC** (`0.10.1`): `Il mercante è un personaggio.`, `parla con X`, conversazione
|
|
1048
|
+
modale con battute e opzioni numerate (scelta per numero o testo).
|
|
1049
|
+
- **Ramificazione** (`0.10.2`): `l'opzione "…" conduce al nodo "…"` — alberi di
|
|
1050
|
+
dialogo con cicli e ritorni.
|
|
1051
|
+
- **Conseguenze sulle scelte** (`0.10.3`): `… e adesso …` — una scelta dà oggetti,
|
|
1052
|
+
muta stati/contatori, può vincere/perdere la partita.
|
|
1053
|
+
- **Opzioni condizionali** (`0.10.4`): `l'opzione "…" se [condizione] …` — scelte
|
|
1054
|
+
che compaiono solo a requisiti soddisfatti.
|
|
1055
|
+
|
|
1056
|
+
Le battute e le opzioni passano per l'interpolazione `[var]` (Livello 5); le
|
|
1057
|
+
interazioni di dialogo non consumano un turno di gioco.
|
|
1058
|
+
|
|
1059
|
+
**Principio LALR-safe del livello**: etichette dei nodi e testi delle opzioni sono
|
|
1060
|
+
*sempre quotati* (vocabolario nuovo, come alias/verbi del Livello 4), quindi non
|
|
1061
|
+
entrano in contesa con i terminali chiusi; si sono evitati di proposito `porta` e
|
|
1062
|
+
`parla` come keyword (collidono con nomi-oggetto comuni). Vincoli mantenuti:
|
|
1063
|
+
grammatica **LALR(1) non ambigua per costruzione**, guardia permanente (1 albero /
|
|
1064
|
+
0 conflitti) estesa a ogni costrutto di dialogo, superficie pubblica
|
|
1065
|
+
`analizza_file()` invariata. Suite del linguaggio: **287 asserzioni**, tutte verdi
|
|
1066
|
+
(erano 247 a inizio livello). Header core e `Mondo.__str__` a **v0.11.0**.
|
|
1067
|
+
|
|
1068
|
+
> **Prossimo**: Livello 6 (Maturità linguaggio/toolchain) verso **v0.12.0** —
|
|
1069
|
+
> linter semantico, moduli/import multi-`.fav`, spec EBNF formale versionata.
|
|
1070
|
+
|
|
1071
|
+
---
|
|
1072
|
+
|
|
1073
|
+
## [0.10.4] - 2026-05-31
|
|
1074
|
+
### Aggiunto (Roadmap Livello 5b «NPC e dialoghi ramificati» — verso 0.11.0)
|
|
1075
|
+
- **Opzioni di dialogo condizionali** (`[Livello 5b]`). Una scelta può essere
|
|
1076
|
+
subordinata a una condizione e comparire **solo se è vera**:
|
|
1077
|
+
- `Al nodo "saluto" l'opzione "Ecco la chiave!" se il giocatore ha la chiave
|
|
1078
|
+
conduce al nodo "grazie".`
|
|
1079
|
+
- Le condizioni sono quelle complete del linguaggio (possesso, proprietà, stati,
|
|
1080
|
+
contatori, `e`/`oppure`/`non`). Una scelta non disponibile non viene mostrata
|
|
1081
|
+
né numerata; la numerazione segue sempre le sole opzioni disponibili.
|
|
1082
|
+
- **Grammatica**: clausola `( "se" condizione )?` tra il testo dell'opzione e
|
|
1083
|
+
l'esito in `def_opzione`. Dopo il testo, il lookahead `se` la distingue da
|
|
1084
|
+
`conduce`/`chiude` → **LALR(1) 0-ambiguo**. Il transformer estrae per-tipo
|
|
1085
|
+
condizione, esito e conseguenze (tutti opzionali e in qualsiasi combinazione).
|
|
1086
|
+
Guardia anti-ambiguità estesa con un'opzione che combina `se` + `conduce` +
|
|
1087
|
+
conseguenza nello stesso costrutto.
|
|
1088
|
+
- **Suite del linguaggio**: **287 asserzioni** (erano 281). Header core a **v0.10.4**.
|
|
1089
|
+
- Con questa patch il sistema di dialogo è **completo** (ramificazione +
|
|
1090
|
+
conseguenze + condizioni): pronto per la release **v0.11.0**.
|
|
1091
|
+
|
|
1092
|
+
---
|
|
1093
|
+
|
|
1094
|
+
## [0.10.3] - 2026-05-31
|
|
1095
|
+
### Aggiunto (Roadmap Livello 5b «NPC e dialoghi ramificati» — verso 0.11.0)
|
|
1096
|
+
- **Conseguenze sulle scelte di dialogo** (`[Livello 5b]`). Un'opzione può ora
|
|
1097
|
+
cambiare lo stato del mondo, con la clausola `e adesso …` riusata da regole ed
|
|
1098
|
+
eventi (Livello 3):
|
|
1099
|
+
- `Al nodo "saluto" l'opzione "Sì!" conduce al nodo "fine" e adesso la gemma è
|
|
1100
|
+
in inventario e adesso aumenta l'oro di 5.`
|
|
1101
|
+
- `Al nodo "fine" l'opzione "Addio." chiude il dialogo e adesso vinci.`
|
|
1102
|
+
- Le conseguenze valgono sia con `conduce` sia con `chiude`; una scelta può dare
|
|
1103
|
+
oggetti, mutare stati/contatori e perfino **vincere/perdere** la partita.
|
|
1104
|
+
Vengono eseguite *prima* della transizione, così la battuta del nodo d'arrivo
|
|
1105
|
+
riflette già il nuovo stato (interpolazione `[var]`).
|
|
1106
|
+
- **Grammatica**: coda `( "e" "adesso" conseguenza … )?` in `def_opzione`,
|
|
1107
|
+
identica a quella di regole/eventi. Nessun nuovo terminale → **LALR(1)
|
|
1108
|
+
0-ambiguo**. Le conseguenze sono validate a compile-time come le altre. Guardia
|
|
1109
|
+
estesa con conseguenze su un'opzione (mutazione + fine partita).
|
|
1110
|
+
- **Suite del linguaggio**: **281 asserzioni** (erano 274). Header core a **v0.10.3**.
|
|
1111
|
+
|
|
1112
|
+
---
|
|
1113
|
+
|
|
1114
|
+
## [0.10.2] - 2026-05-31
|
|
1115
|
+
### Aggiunto (Roadmap Livello 5b «NPC e dialoghi ramificati» — verso 0.11.0)
|
|
1116
|
+
- **Ramificazione dei dialoghi** (`[Livello 5b]`). Un'opzione può ora **condurre a
|
|
1117
|
+
un altro nodo**, non solo chiudere la conversazione:
|
|
1118
|
+
- `Al nodo "saluto" l'opzione "Chi sei?" conduce al nodo "presentazione".`
|
|
1119
|
+
- `Al nodo "saluto" l'opzione "Addio." chiude il dialogo.`
|
|
1120
|
+
- A runtime, scegliere un'opzione con transizione mostra la battuta e le opzioni
|
|
1121
|
+
del nodo di arrivo; si possono creare cicli (tornare a un nodo precedente).
|
|
1122
|
+
- **Grammatica**: l'opzione ha un **esito** (`opzione_esito`): `conduce al nodo
|
|
1123
|
+
"X"` oppure `chiude il dialogo`. Dopo il testo dell'opzione il lookahead
|
|
1124
|
+
`conduce` vs `chiude` distingue le alternative → **LALR(1) 0-ambiguo**. Nuova
|
|
1125
|
+
parola riservata `conduce` (si evita `porta`, che è un nome-oggetto comune).
|
|
1126
|
+
- **Validazione**: un'opzione che conduce a un nodo **inesistente** genera un
|
|
1127
|
+
avviso non bloccante (ramificazione morta). Guardia anti-ambiguità estesa con
|
|
1128
|
+
un dialogo a più nodi e una transizione.
|
|
1129
|
+
- **Suite del linguaggio**: **274 asserzioni** (erano 267). Header core a **v0.10.2**.
|
|
1130
|
+
|
|
1131
|
+
---
|
|
1132
|
+
|
|
1133
|
+
## [0.10.1] - 2026-05-31
|
|
1134
|
+
### Aggiunto (Roadmap Livello 5b «NPC e dialoghi ramificati» — verso 0.11.0)
|
|
1135
|
+
- **NPC e dialoghi, fondazione** (`[Livello 5b]`). Prima patch del sistema di
|
|
1136
|
+
dialogo: personaggi e conversazione modale minima.
|
|
1137
|
+
- **Personaggi**: `Il mercante è un personaggio.` introduce un NPC (un oggetto
|
|
1138
|
+
speciale che vive in una stanza ed è raggiungibile).
|
|
1139
|
+
- **Nodo d'ingresso**: `Il dialogo del mercante comincia con "saluto".`
|
|
1140
|
+
- **Battuta**: `Il mercante al nodo "saluto" dice "Benvenuto, viaggiatore!".`
|
|
1141
|
+
- **Opzione di uscita**: `Al nodo "saluto" l'opzione "Addio." chiude il dialogo.`
|
|
1142
|
+
- **Runtime**: `parla con X` avvia una conversazione modale; la battuta dell'NPC
|
|
1143
|
+
e le opzioni numerate vengono mostrate; il giocatore sceglie per **numero** o
|
|
1144
|
+
per **testo**; `esci`/`addio`/`basta` chiudono la conversazione (non il gioco).
|
|
1145
|
+
Le interazioni di dialogo **non consumano un turno** di gioco. Le battute e le
|
|
1146
|
+
opzioni passano per l'interpolazione `[var]` (Livello 5).
|
|
1147
|
+
- **Principio LALR-safe**: etichette dei nodi e testi delle opzioni sono *sempre
|
|
1148
|
+
quotati* (vocabolario nuovo, come alias/verbi del Livello 4) → non entrano in
|
|
1149
|
+
contesa con i terminali chiusi. Si evitano di proposito `porta`/`parla` come
|
|
1150
|
+
keyword di grammatica (collidono con nomi-oggetto comuni: «la porta»). Guardia
|
|
1151
|
+
anti-ambiguità estesa con un NPC e un dialogo completo: **1 albero / 0 conflitti**.
|
|
1152
|
+
- **Suite del linguaggio**: **267 asserzioni** (erano 247). Header core a **v0.10.1**.
|
|
1153
|
+
|
|
1154
|
+
---
|
|
1155
|
+
|
|
1156
|
+
## [0.10.0] - 2026-05-31
|
|
1157
|
+
### Roadmap del Linguaggio — Livello 5 «Espressività narrativa» COMPLETATO
|
|
1158
|
+
Release minore che consolida le patch `0.9.1` → `0.9.4` e porta a compimento la
|
|
1159
|
+
promessa di copertina del progetto — *«il codice è prosa»* — sul versante della
|
|
1160
|
+
resa narrativa. In sintesi (dettaglio per-patch sotto e nel documento tecnico
|
|
1161
|
+
`documentazione/0.10.0.md`):
|
|
1162
|
+
|
|
1163
|
+
- **Interpolazione di testo dinamico** (`0.9.1`): segnaposto `[punteggio]`,
|
|
1164
|
+
`[semaforo]`, `[chiave]` nelle stringhe d'autore, risolti a render-time.
|
|
1165
|
+
- **Regole globali senza oggetto** (`0.9.2`): `Invece di guarda se il punteggio è
|
|
1166
|
+
almeno 3: …` — risolve il limite noto del Livello 3, sbloccando verifiche
|
|
1167
|
+
globali su stati e contatori.
|
|
1168
|
+
- **Descrizioni condizionali** (`0.9.3`): `La descrizione della torcia se il
|
|
1169
|
+
semaforo è verde è "…".`, con varianti in ordine e fallback alla base.
|
|
1170
|
+
- **Concordanza grammaticale italiana minima** (`0.9.4`): genere/numero inferiti
|
|
1171
|
+
dall'articolo del nome; articoli concordati negli elenchi di output.
|
|
1172
|
+
|
|
1173
|
+
Vincoli mantenuti per tutto il livello: grammatica **LALR(1) non ambigua per
|
|
1174
|
+
costruzione** (guardia permanente 1 albero / 0 conflitti, estesa a ogni nuovo
|
|
1175
|
+
costrutto) e superficie pubblica `analizza_file()` invariata. La 0.9.3 ha inoltre
|
|
1176
|
+
**corretto un'ambiguità latente preesistente** di `def_descrizione` (terminale
|
|
1177
|
+
unico filtrato `_PREP_DESCR`), rendendo le descrizioni *genuinamente* 0-ambigue.
|
|
1178
|
+
Suite del linguaggio: **247 asserzioni**, tutte verdi (erano 192 a inizio livello).
|
|
1179
|
+
Header dei moduli core e `Mondo.__str__` allineati a **v0.10.0**.
|
|
1180
|
+
|
|
1181
|
+
> **Ambito della release**: NPC e dialoghi ramificati — la seconda metà del
|
|
1182
|
+
> Livello 5 — sono volutamente rinviati a una **v0.11.0** dedicata (Livello 5b),
|
|
1183
|
+
> dove l'alta complessità della macchina a stati dei dialoghi potrà essere
|
|
1184
|
+
> affrontata con il margine per rinviare i costrutti che non superano puliti il
|
|
1185
|
+
> gate anti-ambiguità.
|
|
1186
|
+
|
|
1187
|
+
---
|
|
1188
|
+
|
|
1189
|
+
## [0.9.4] - 2026-05-31
|
|
1190
|
+
### Aggiunto (Roadmap Livello 5 «Espressività narrativa» — verso 0.10.0)
|
|
1191
|
+
- **Concordanza grammaticale italiana (minima)** (`[Livello 5]`). Genere e numero
|
|
1192
|
+
vengono **inferiti dall'articolo che l'autore già scrive** nel nome (`La torcia`
|
|
1193
|
+
→ femminile singolare, `Il tavolo` → maschile singolare, `Le chiavi` → femminile
|
|
1194
|
+
plurale): nessuna nuova sintassi.
|
|
1195
|
+
- L'elenco degli oggetti in una stanza usa ora l'**articolo indeterminativo
|
|
1196
|
+
concordato** (o il partitivo al plurale): *«Puoi vedere qui: una torcia, un
|
|
1197
|
+
tavolo, uno specchio, delle chiavi.»* — al posto del nome grezzo con l'articolo
|
|
1198
|
+
determinativo maiuscolo.
|
|
1199
|
+
- Gestiti i casi della fonologia italiana: `uno`/`gli` davanti a *s* impura, *z*,
|
|
1200
|
+
*gn*, *ps*…; `un'` femminile davanti a vocale; partitivi `dei`/`degli`/`delle`.
|
|
1201
|
+
- Nuovi helper `utils.genere_numero()` / `utils.frase_indeterminativa()` e
|
|
1202
|
+
`Oggetto.concordanza()`. Un nome senza articolo riconoscibile resta invariato
|
|
1203
|
+
(non si inventano articoli: meglio nessuno che uno sbagliato); `l'…` è ambiguo
|
|
1204
|
+
nel genere e ripiega sul maschile.
|
|
1205
|
+
- **Grammatica invariata**: è tutta logica di *render* + inferenza dai metadati,
|
|
1206
|
+
nessun impatto su parsing o ambiguità.
|
|
1207
|
+
- **Suite del linguaggio**: **247 asserzioni** (erano 225). Header core a **v0.9.4**.
|
|
1208
|
+
|
|
1209
|
+
---
|
|
1210
|
+
|
|
1211
|
+
## [0.9.3] - 2026-05-31
|
|
1212
|
+
### Aggiunto (Roadmap Livello 5 «Espressività narrativa» — verso 0.10.0)
|
|
1213
|
+
- **Descrizioni condizionali** (`[Livello 5]`). La descrizione di una stanza o di
|
|
1214
|
+
un oggetto può ora variare in base allo stato del mondo, con una clausola `se`:
|
|
1215
|
+
- `La descrizione della torcia è "Una torcia spenta.".` (base/fallback)
|
|
1216
|
+
- `La descrizione della torcia se il semaforo è verde è "Una torcia che brilla.".`
|
|
1217
|
+
- Più varianti per la stessa entità sono valutate **in ordine di dichiarazione**:
|
|
1218
|
+
vince la prima la cui condizione è vera; se nessuna lo è, vale la descrizione
|
|
1219
|
+
di base. Le condizioni sono quelle complete del linguaggio (stati, contatori,
|
|
1220
|
+
proprietà, possesso, `e`/`oppure`/`non`).
|
|
1221
|
+
- Si combinano con l'interpolazione `[var]` (0.9.1): una variante può contenere
|
|
1222
|
+
segnaposto.
|
|
1223
|
+
- **Grammatica**: `def_descrizione` accetta una clausola `( "se" condizione )?`
|
|
1224
|
+
opzionale tra l'entità e `"è"` (lookahead netto `se` vs `è` → LALR(1) 0-ambiguo).
|
|
1225
|
+
Nuovi `Stanza.descrizione_attuale(mondo)` / `Oggetto.descrizione_attuale(mondo)`.
|
|
1226
|
+
|
|
1227
|
+
### Corretto
|
|
1228
|
+
- **Ambiguità latente preesistente di `def_descrizione`** (`[Livello 5]`). Le
|
|
1229
|
+
preposizioni articolate (`del`/`della`/…) erano terminali anonimi inline: il
|
|
1230
|
+
lexer dinamico poteva spezzare `della` in `del` + `la` (con `la` assorbito
|
|
1231
|
+
dall'articolo opzionale di `ENTITA`), rendendo `def_descrizione` formalmente
|
|
1232
|
+
ambiguo (mascherato finora dal determinismo di LALR e mai esercitato dalla
|
|
1233
|
+
guardia). Ora sono un **terminale unico filtrato** `_PREP_DESCR` (maximal-munch,
|
|
1234
|
+
come già `PREP_LUOGO`): la grammatica delle descrizioni è **genuinamente
|
|
1235
|
+
0-ambigua**. La guardia anti-ambiguità include ora una descrizione condizionale.
|
|
1236
|
+
|
|
1237
|
+
### Note
|
|
1238
|
+
- **Suite del linguaggio**: **225 asserzioni** (erano 216). Header core a **v0.9.3**.
|
|
1239
|
+
|
|
1240
|
+
---
|
|
1241
|
+
|
|
1242
|
+
## [0.9.2] - 2026-05-31
|
|
1243
|
+
### Aggiunto (Roadmap Livello 5 «Espressività narrativa» — verso 0.10.0)
|
|
1244
|
+
- **Regole globali senza oggetto** (`[Livello 5]`) — risolve il limite noto del
|
|
1245
|
+
Livello 3. Una regola `Invece di` può ora **omettere il bersaglio** e scattare
|
|
1246
|
+
sul solo verbo, valutando la sua condizione:
|
|
1247
|
+
- `Invece di guarda se il punteggio è almeno 3: dire "Una luce pulsa.".`
|
|
1248
|
+
- Sblocca le **verifiche globali su stati e contatori**, finora agganciabili
|
|
1249
|
+
solo a regole su oggetto o agli eventi a turni.
|
|
1250
|
+
- **Precedenza**: una regola specifica (con bersaglio) vince sempre su una
|
|
1251
|
+
globale; le globali scattano solo se nessuna specifica si è attivata, e
|
|
1252
|
+
valgono anche per le azioni senza oggetto (`guarda`, `aiuto`, `inventario`).
|
|
1253
|
+
- Una globale senza condizione scatta sempre (sostituisce il comportamento di
|
|
1254
|
+
default del verbo).
|
|
1255
|
+
- **Grammatica**: il bersaglio di `def_regola` è ora opzionale, incapsulato nella
|
|
1256
|
+
sottoregola `regola_target`. Questo mantiene la grammatica **LALR(1) 0-ambigua**
|
|
1257
|
+
(dopo `VERBO` il lookahead distingue nettamente `ENTITA`/`DIREZIONE` dal `se`/`:`)
|
|
1258
|
+
e permette al transformer di non confondere il bersaglio con la risposta quando
|
|
1259
|
+
il primo manca. Guardia anti-ambiguità estesa con una regola globale.
|
|
1260
|
+
- **Limite residuo** (minore): per un verbo che richiede un oggetto, una regola
|
|
1261
|
+
globale non scatta se il giocatore digita il verbo *senza* oggetto (l'azione
|
|
1262
|
+
chiede prima l'oggetto). Le globali danno il meglio con verbi senza oggetto.
|
|
1263
|
+
- **Suite del linguaggio**: **216 asserzioni** (erano 204). Header core a **v0.9.2**.
|
|
1264
|
+
|
|
1265
|
+
---
|
|
1266
|
+
|
|
1267
|
+
## [0.9.1] - 2026-05-31
|
|
1268
|
+
### Aggiunto (Roadmap Livello 5 «Espressività narrativa» — verso 0.10.0)
|
|
1269
|
+
- **Interpolazione di testo dinamico** (`[Livello 5]`) — *prima patch del livello*.
|
|
1270
|
+
Le stringhe d'autore possono ora contenere **segnaposto** `[nome]` che vengono
|
|
1271
|
+
sostituiti, al momento della stampa, con il valore corrente del mondo:
|
|
1272
|
+
- **Stati e contatori**: `dire "Hai [punteggio] punti."` → il numero corrente;
|
|
1273
|
+
`"Il semaforo è [semaforo]."` → la parola-stato attuale (uno stato non ancora
|
|
1274
|
+
impostato rende stringa vuota).
|
|
1275
|
+
- **Oggetti**: `[chiave]` → il nome visualizzato dell'oggetto.
|
|
1276
|
+
- Vale per **descrizioni** (di stanze e oggetti), **risposte delle regole** e
|
|
1277
|
+
**messaggi degli eventi a turni**: ogni testo d'autore passa per
|
|
1278
|
+
`utils.rendi_testo(mondo, testo)`.
|
|
1279
|
+
- Un segnaposto che non corrisponde a nessuno stato/contatore/oggetto resta
|
|
1280
|
+
**invariato** a runtime (letterale `[nome]`) e genera un **avviso non
|
|
1281
|
+
bloccante** a compile-time (possibile refuso).
|
|
1282
|
+
- **Vincoli invariati**: l'interpolazione vive *dentro* le virgolette
|
|
1283
|
+
(`TESTO_QUOTATO`), quindi è del tutto invisibile alla grammatica: **nessun
|
|
1284
|
+
rischio di ambiguità**. Guardia LALR (1 albero / 0 conflitti) estesa con un
|
|
1285
|
+
costrutto che usa segnaposto. Superficie pubblica `analizza_file()` invariata.
|
|
1286
|
+
- **Suite del linguaggio**: **204 asserzioni** (erano 192), tutte verdi. Header dei
|
|
1287
|
+
moduli core allineati a **v0.9.1**.
|
|
1288
|
+
|
|
1289
|
+
---
|
|
1290
|
+
|
|
1291
|
+
## [0.9.0] - 2026-05-31
|
|
1292
|
+
### Roadmap del Linguaggio — Livello 4 «Estendibilità vocabolario e topologia» COMPLETATO
|
|
1293
|
+
Release minore che consolida le patch 0.8.1 → 0.8.5. L'autore può ora **estendere
|
|
1294
|
+
il vocabolario e la topologia** del mondo, finora in parte cablati nel motore. In
|
|
1295
|
+
sintesi (dettaglio per-patch sotto e in `documentazione/0.9.0.md`):
|
|
1296
|
+
- **Alias/sinonimi di oggetti** (`0.8.1`): `La torcia si chiama anche "lanterna".`
|
|
1297
|
+
- **Verbi personalizzati** (`M1`, `0.8.2`): `"spingi" è un comando.`
|
|
1298
|
+
- **Direzioni estese data-driven** (`L1`, `0.8.3`): `Alto e basso sono direzioni
|
|
1299
|
+
opposte.` con fonte unica per le direzioni (prima cablate in 4 punti).
|
|
1300
|
+
- **Contenitori e supporti** (`M1`, `0.8.4`–`0.8.5`): `La scatola è un
|
|
1301
|
+
contenitore.`, `La gemma è nella scatola.`, verbo `metti`, visibilità a catena.
|
|
1302
|
+
|
|
1303
|
+
Vincoli mantenuti per tutto il livello: grammatica **LALR(1) non ambigua per
|
|
1304
|
+
costruzione** (guardia permanente: 1 albero / 0 conflitti, estesa a ogni nuovo
|
|
1305
|
+
costrutto) e superficie pubblica `analizza_file()` invariata. Header dei moduli
|
|
1306
|
+
core allineati a **v0.9.0** (`compilatore`, `strutture`, `gioco`,
|
|
1307
|
+
`libreria_azioni`, suite). Suite del linguaggio: **192 asserzioni**, tutte verdi
|
|
1308
|
+
(erano 133 a inizio livello).
|
|
1309
|
+
|
|
1310
|
+
> Nota di design: il *vocabolario nuovo* (alias e verbi) si introduce **tra
|
|
1311
|
+
> virgolette**, perché non è ancora un token noto e così non intacca l'invariante
|
|
1312
|
+
> dei nomi come simboli chiusi (Livello 2.5). Le direzioni custom usano invece un
|
|
1313
|
+
> terminale `DIREZIONE` generato per-file (regex con `\b`, priorità alta) per
|
|
1314
|
+
> vincere il prefix-clash con le keyword, senza toccare la disambiguazione `e`=est.
|
|
1315
|
+
|
|
1316
|
+
---
|
|
1317
|
+
|
|
1318
|
+
## [0.8.5] - 2026-05-31
|
|
1319
|
+
### Aggiunto (Roadmap Livello 4 — verso 0.9.0)
|
|
1320
|
+
- **Contenitori e supporti** (`[M1]`) — *runtime*. La meccanica di gioco completa
|
|
1321
|
+
il modello introdotto in 0.8.4:
|
|
1322
|
+
- **Visibilità a catena**: un oggetto è raggiungibile se è nella stanza,
|
|
1323
|
+
nell'inventario, o dentro/sopra un contenitore/supporto a sua volta
|
|
1324
|
+
raggiungibile. Un **contenitore chiuso** (`è chiusa`) nasconde il contenuto;
|
|
1325
|
+
aprirlo lo rivela. I supporti sono sempre accessibili.
|
|
1326
|
+
- **Nuovo verbo `metti`** (`metti`, `poni`, `inserisci`, `infila`, `appoggia`…):
|
|
1327
|
+
`metti la gemma in la scatola`, `metti la tazza sul tavolo`. Rifiuta i
|
|
1328
|
+
contenitori chiusi e gli oggetti che non sono contenitori/supporti.
|
|
1329
|
+
- **`esamina`** di un contenitore aperto/supporto ne elenca il contenuto
|
|
1330
|
+
(`Dentro vedi: …` / `Sopra vedi: …`); chiuso, dice «È chiuso.».
|
|
1331
|
+
- **`prendi`** funziona anche su oggetti dentro contenitori aperti / sui supporti.
|
|
1332
|
+
- Le **conseguenze di spostamento** accettano ora un contenitore/supporto come
|
|
1333
|
+
destinazione: `… e adesso la gemma è nella scatola.`
|
|
1334
|
+
- `strutture.py`: `Mondo.oggetto_raggiungibile()`, `oggetti_raggiungibili()`,
|
|
1335
|
+
`contenitore_aperto()`, `rimuovi_da_posizione()` (centralizza la rimozione da
|
|
1336
|
+
stanza/inventario/contenitore); `ConseguenzaSpostamento` gestisce le
|
|
1337
|
+
destinazioni contenitore/supporto.
|
|
1338
|
+
- `libreria_azioni.py`: `esamina`/`prendi` riscritte sulla raggiungibilità; nuova
|
|
1339
|
+
azione `mettere` con la sua logica di default; helper `_elenca_contenuto`.
|
|
1340
|
+
- `compilatore.py`: `_valida_conseguenze` accetta destinazioni contenitore/supporto.
|
|
1341
|
+
- `gioco.py`: lo scope di `risolvi_nome_oggetto` usa `oggetti_raggiungibili()`;
|
|
1342
|
+
`mettere` escluso dalla ristampa automatica della stanza.
|
|
1343
|
+
- `test_linguaggio.py`: sei nuovi test runtime (scope contenitore aperto,
|
|
1344
|
+
chiuso↔apertura, metti in contenitore/su supporto, rifiuto chiuso, conseguenza
|
|
1345
|
+
di spostamento in contenitore). Suite a **192 asserzioni** (era 174).
|
|
1346
|
+
|
|
1347
|
+
---
|
|
1348
|
+
|
|
1349
|
+
## [0.8.4] - 2026-05-31
|
|
1350
|
+
### Aggiunto (Roadmap Livello 4 — verso 0.9.0)
|
|
1351
|
+
- **Contenitori e supporti** (`[M1]`) — *modello e grammatica* (il runtime arriva
|
|
1352
|
+
in 0.8.5). Si dichiarano oggetti capaci di contenere o reggere altri oggetti, e
|
|
1353
|
+
si possono collocare oggetti al loro interno/sopra fin dalla definizione:
|
|
1354
|
+
```
|
|
1355
|
+
Una scatola è un contenitore.
|
|
1356
|
+
La scatola è in cella.
|
|
1357
|
+
Una gemma è una cosa.
|
|
1358
|
+
La gemma è nella scatola.
|
|
1359
|
+
|
|
1360
|
+
Un tavolo è un supporto.
|
|
1361
|
+
La tazza è sul tavolo.
|
|
1362
|
+
```
|
|
1363
|
+
Un contenitore tiene gli oggetti *dentro* (visibili solo se aperto, semantica a
|
|
1364
|
+
runtime in 0.8.5); un supporto li regge *sopra* (sempre visibili). Collocare un
|
|
1365
|
+
oggetto dentro qualcosa che non è né contenitore né supporto è un **errore
|
|
1366
|
+
bloccante** chiaro.
|
|
1367
|
+
- `strutture.py`: `Oggetto.is_contenitore`, `Oggetto.is_supporto`,
|
|
1368
|
+
`Oggetto.contenuto: Set[str]`. L'oggetto collocato ha `posizione` = id del
|
|
1369
|
+
contenitore/supporto (la catena fino alla stanza sarà risolta dal runtime).
|
|
1370
|
+
- `compilatore.py`: scanner `_RE_DEF_CONTENITORE`/`_RE_DEF_SUPPORTO` (un
|
|
1371
|
+
contenitore/supporto è a tutti gli effetti un oggetto); regole `def_contenitore`
|
|
1372
|
+
e `def_supporto` (distinte da `def_proprieta` sul token `un`, come
|
|
1373
|
+
`def_contatore`); `def_posizione` accetta come luogo anche un contenitore/
|
|
1374
|
+
supporto; parole riservate `contenitore`, `supporto`.
|
|
1375
|
+
- `test_linguaggio.py`: sei nuovi test (dichiarazione contenitore/supporto,
|
|
1376
|
+
collocazione dentro/sopra, errore su non-contenitore, scanner); corpus della
|
|
1377
|
+
guardia esteso con contenitore, supporto e una collocazione. Suite a **174
|
|
1378
|
+
asserzioni** (era 162).
|
|
1379
|
+
|
|
1380
|
+
---
|
|
1381
|
+
|
|
1382
|
+
## [0.8.3] - 2026-05-31
|
|
1383
|
+
### Aggiunto / Modificato (Roadmap Livello 4 — verso 0.9.0)
|
|
1384
|
+
- **Direzioni estese, data-driven** (`[L1]`). Le direzioni del mondo (finora
|
|
1385
|
+
cablate in 4 punti del codice) hanno ora un'**unica fonte di verità** e sono
|
|
1386
|
+
**estendibili dall'autore**:
|
|
1387
|
+
```
|
|
1388
|
+
Alto e basso sono direzioni opposte.
|
|
1389
|
+
La torre collega basso a cantina.
|
|
1390
|
+
```
|
|
1391
|
+
Le direzioni personalizzate si dichiarano sempre **in coppia opposta**, così
|
|
1392
|
+
l'auto-ritorno della connessione è garantito (qui `cantina` torna a `torre` con
|
|
1393
|
+
`alto`). Funzionano sia nelle connessioni sia come comando di movimento a
|
|
1394
|
+
runtime. Il nome di una direzione non può coincidere con una parola riservata o
|
|
1395
|
+
un'entità: è un **errore bloccante** con messaggio chiaro.
|
|
1396
|
+
- Miglioria collaterale: nelle regole il bersaglio-direzione è ora
|
|
1397
|
+
**canonicalizzato** (`Invece di vai n` equivale a `vai nord`); le direzioni
|
|
1398
|
+
sono riconosciute **case-insensitive**.
|
|
1399
|
+
- `utils.py`: `DIREZIONI_BASE` e `DIREZIONI_OPPOSTE_BASE` come **fonte unica**.
|
|
1400
|
+
- `strutture.py`: `Mondo.direzioni` (forma → canonica) e `opposte_direzioni`
|
|
1401
|
+
(canonica → opposta), precaricate dalle basi; `dichiara_direzione_opposta()`,
|
|
1402
|
+
`direzione_canonica()`, `opposta_di()`.
|
|
1403
|
+
- `compilatore.py`: scanner Passata 1 `_RE_DEF_DIREZIONI`
|
|
1404
|
+
(`TabellaSimboli.coppie_direzioni`); regola `def_direzioni`; il terminale
|
|
1405
|
+
**`DIREZIONE` è generato per-file** (base + custom) come regex con `\b` e
|
|
1406
|
+
priorità `.2` — vince il longest-match contro le keyword di cui una direzione
|
|
1407
|
+
custom condivide il prefisso (es. `alto` vs `al` di «Al turno»), senza intaccare
|
|
1408
|
+
l'invariante `e`=est / congiunzione (il lexer contestuale non le mette mai nello
|
|
1409
|
+
stesso stato). `def_connessione` e `def_regola` consultano le mappe del mondo
|
|
1410
|
+
invece dei dict cablati. `valida_direzioni_dichiarate()` blocca i conflitti.
|
|
1411
|
+
Parola riservata `direzioni`.
|
|
1412
|
+
- `gioco.py`: rimosso il dict cablato `DIREZIONI_VALIDI`; movimento e
|
|
1413
|
+
`risolvi_nome_oggetto` usano `mondo.direzioni`.
|
|
1414
|
+
- `test_linguaggio.py`: cinque nuovi test (connessione+auto-ritorno custom,
|
|
1415
|
+
movimento runtime, canonicalizzazione abbreviazione, conflitto bloccante,
|
|
1416
|
+
scanner); corpus della guardia esteso con una `def_direzioni` e una connessione
|
|
1417
|
+
che la usa; le chiamate della guardia passano ora le direzioni dichiarate. Suite
|
|
1418
|
+
a **162 asserzioni** (era 151).
|
|
1419
|
+
|
|
1420
|
+
---
|
|
1421
|
+
|
|
1422
|
+
## [0.8.2] - 2026-05-31
|
|
1423
|
+
### Aggiunto (Roadmap Livello 4 — verso 0.9.0)
|
|
1424
|
+
- **Verbi personalizzati** (`[M1]`): l'autore può introdurre nuove parole-comando
|
|
1425
|
+
che il giocatore potrà digitare e usare nelle regole `Invece di`.
|
|
1426
|
+
```
|
|
1427
|
+
"spingi" è un comando.
|
|
1428
|
+
Invece di spingi la pietra: dire "La pietra rotola via.".
|
|
1429
|
+
```
|
|
1430
|
+
Il verbo è una **stringa quotata** monoparola (coerente con gli alias: il
|
|
1431
|
+
vocabolario nuovo si introduce tra virgolette). Una regola che usa un verbo
|
|
1432
|
+
dichiarato non è più segnalata come "morta". A runtime il comando attiva la
|
|
1433
|
+
regola corrispondente; se nessuna regola si applica, il motore risponde con un
|
|
1434
|
+
messaggio neutro (`Non succede nulla di particolare.`) anziché "Non capisco
|
|
1435
|
+
questo verbo.". Come gli altri verbi, un comando custom agisce su un oggetto.
|
|
1436
|
+
- `strutture.py`: `Mondo.verbi_personalizzati: Set[str]` + `dichiara_verbo()`;
|
|
1437
|
+
`carica_azioni()` instrada i verbi custom a un'azione generica `_personalizzata`
|
|
1438
|
+
(priva di logica di default; `setdefault` → non scavalca i verbi di libreria).
|
|
1439
|
+
- `compilatore.py`: regola `def_verbo` (`TESTO_QUOTATO "è" "un" "comando" "."`),
|
|
1440
|
+
unica dichiarazione che inizia con `TESTO_QUOTATO` → 0 conflitti LALR; parola
|
|
1441
|
+
riservata `comando`; un comando multiparola genera un *warning* ed è ignorato;
|
|
1442
|
+
il check dei verbi delle regole ora accetta anche i verbi personalizzati.
|
|
1443
|
+
- `gioco.py`: un'azione con `logica_di_default is None` (verbo custom senza regola)
|
|
1444
|
+
stampa il messaggio neutro; `_personalizzata` escluso dalla ristampa stanza.
|
|
1445
|
+
- `test_linguaggio.py`: quattro nuovi test (dichiarazione+niente warning, runtime
|
|
1446
|
+
con regola, runtime senza regola, multiparola); corpus della guardia esteso con
|
|
1447
|
+
un `def_verbo` e una regola che lo usa. Suite a **151 asserzioni** (era 142).
|
|
1448
|
+
|
|
1449
|
+
---
|
|
1450
|
+
|
|
1451
|
+
## [0.8.1] - 2026-05-31
|
|
1452
|
+
### Aggiunto (Roadmap Livello 4 — verso 0.9.0)
|
|
1453
|
+
- **Alias/sinonimi di oggetti**: l'autore può dare a un oggetto un nome
|
|
1454
|
+
alternativo con cui il giocatore potrà riferirlo.
|
|
1455
|
+
```
|
|
1456
|
+
La torcia si chiama anche "lanterna".
|
|
1457
|
+
```
|
|
1458
|
+
Il sinonimo è una **stringa quotata** (può essere multiparola, es.
|
|
1459
|
+
`"vecchia lanterna"`); a runtime il parser dei comandi lo risolve all'oggetto
|
|
1460
|
+
canonico (corrispondenza esatta e parziale). Il nome proprio dell'oggetto ha
|
|
1461
|
+
sempre la precedenza. Gli alias servono l'input del **giocatore**: nelle regole
|
|
1462
|
+
d'autore (`Invece di …`) vale il nome canonico.
|
|
1463
|
+
- `strutture.py`: `Mondo.alias: Dict[str, str]` (alias normalizzato → id canonico)
|
|
1464
|
+
+ `dichiara_alias()`. Header e report a v0.8.1.
|
|
1465
|
+
- `compilatore.py`: regola `def_alias`
|
|
1466
|
+
(`ENTITA "si" "chiama" "anche" TESTO_QUOTATO "."`); si distingue dalle altre
|
|
1467
|
+
dichiarazioni che iniziano con `ENTITA` grazie al keyword `si`, senza conflitti
|
|
1468
|
+
LALR. Parole riservate `si`/`chiama`/`anche`. Validazione non bloccante: alias
|
|
1469
|
+
verso oggetto inesistente o verso una non-entità-oggetto → *warning*.
|
|
1470
|
+
- `gioco.py`: `risolvi_nome_oggetto` consulta `mondo.alias` (esatto e parziale).
|
|
1471
|
+
- `test_linguaggio.py`: quattro nuovi test (risoluzione esatta, multiparola,
|
|
1472
|
+
parziale, warning su bersaglio non-oggetto); corpus della guardia esteso con
|
|
1473
|
+
una `def_alias`. Suite a **142 asserzioni** (era 133); guardia anti-ambiguità
|
|
1474
|
+
(1 albero / 0 conflitti LALR) verde.
|
|
1475
|
+
|
|
1476
|
+
---
|
|
1477
|
+
|
|
1478
|
+
## [0.8.0] - 2026-05-31
|
|
1479
|
+
### Roadmap del Linguaggio — Livello 3 «Stato di gioco e meccaniche» COMPLETATO
|
|
1480
|
+
Release minore che consolida le patch 0.7.1 → 0.7.5. Il linguaggio FAVELLA passa
|
|
1481
|
+
da descrittore di mondi statici a motore di **avventure complete**, con stato
|
|
1482
|
+
astratto e meccaniche temporali. In sintesi (dettaglio per-patch sotto e in
|
|
1483
|
+
`documentazione/0.8.0.md`):
|
|
1484
|
+
- **Proprietà opposte dichiarabili** (`M5`): `Accesa e spenta sono opposte.`
|
|
1485
|
+
- **Fine partita**: conseguenze `vinci` / `perdi` / `termina`.
|
|
1486
|
+
- **Stato astratto** (`G3`): **stati** enum-like (`Il semaforo è uno stato.` →
|
|
1487
|
+
`… è rosso`, `se … è verde`) e **contatori** numerici (`Il punteggio è un
|
|
1488
|
+
contatore.`, `aumenta … di N`, `diventa N`, confronti `almeno`/`più di`/`meno di`).
|
|
1489
|
+
- **Eventi a turni**: `Al turno N: …`, `Ogni N turni: …`.
|
|
1490
|
+
|
|
1491
|
+
Vincoli mantenuti per tutto il livello: grammatica **LALR(1) non ambigua per
|
|
1492
|
+
costruzione** (guardia permanente: 1 albero / 0 conflitti) e superficie pubblica
|
|
1493
|
+
`analizza_file()` invariata. Header dei moduli core allineati a **v0.8.0**
|
|
1494
|
+
(`compilatore`, `strutture`, `gioco`, `libreria_azioni`, suite). Suite del
|
|
1495
|
+
linguaggio: **133 asserzioni**, tutte verdi (erano 65 a inizio livello).
|
|
1496
|
+
|
|
1497
|
+
> Nota architetturale chiave: stati e contatori sono una **terza classe di
|
|
1498
|
+
> simboli chiusi** (terminale `VARIABILE`) disgiunta da `ENTITA`/`PROPRIETA`,
|
|
1499
|
+
> raccolta in Passata 1. È questa separazione a garantire **zero ambiguità** tra
|
|
1500
|
+
> i costrutti su variabili e quelli su oggetti.
|
|
1501
|
+
|
|
1502
|
+
---
|
|
1503
|
+
|
|
1504
|
+
## [0.7.5] - 2026-05-31
|
|
1505
|
+
### Aggiunto (Roadmap Livello 3 — verso 0.8.0)
|
|
1506
|
+
- **Eventi a turni**: costrutti temporali a livello di mondo.
|
|
1507
|
+
- `Al turno 3: dire "..." e adesso ...` — scatta **una sola volta** al turno N.
|
|
1508
|
+
- `Ogni 5 turni: dire "..." e adesso ...` — scatta a **ogni multiplo** di N.
|
|
1509
|
+
Riusano la stessa coda di conseguenze delle regole (incluse fine partita,
|
|
1510
|
+
stati e contatori), così si può far perdere allo scadere del tempo o
|
|
1511
|
+
incrementare un contatore a ogni turno.
|
|
1512
|
+
- `strutture.py`: classe `Evento` (`scatta_a()`, `esegui_conseguenze()`),
|
|
1513
|
+
`Mondo.eventi` + `turno_corrente` + `aggiungi_evento()`.
|
|
1514
|
+
- `gioco.py`: contatore dei turni nel loop. `elabora_comando` è ora un wrapper
|
|
1515
|
+
che, dopo un comando reale, chiama `avanza_turno_e_processa(mondo)` (avanza il
|
|
1516
|
+
turno e attiva gli eventi scattati, terminando se un evento chiude la partita);
|
|
1517
|
+
la logica del comando è in `_esegui_comando`. Header allineato a v0.7.5.
|
|
1518
|
+
Policy: ogni comando non vuoto e diverso da `esci` conta come un turno.
|
|
1519
|
+
- `compilatore.py`: regola `def_evento` (forme `evento_al`/`evento_ogni`), parole
|
|
1520
|
+
riservate `al`/`turno`/`turni`/`ogni`; validazione conseguenze condivisa
|
|
1521
|
+
(`_valida_conseguenze`, usata anche da `def_regola`); un numero di turni < 1 è
|
|
1522
|
+
un warning e l'evento è ignorato. Suite a **133 asserzioni** (era 119), con
|
|
1523
|
+
test d'integrazione del loop e guardia anti-ambiguità estesa agli eventi.
|
|
1524
|
+
|
|
1525
|
+
---
|
|
1526
|
+
|
|
1527
|
+
## [0.7.4] - 2026-05-31
|
|
1528
|
+
### Aggiunto (Roadmap Livello 3 — verso 0.8.0)
|
|
1529
|
+
- **Contatori numerici** (completano `[G3]`), sulla stessa classe di simboli
|
|
1530
|
+
degli stati (`VARIABILE`):
|
|
1531
|
+
- dichiarazione: `Il punteggio è un contatore.` (valore iniziale 0)
|
|
1532
|
+
- mutazioni: `e adesso aumenta il punteggio` (+1), `... aumenta il punteggio di 5`,
|
|
1533
|
+
`... diminuisci il punteggio (di N)`, `... il punteggio diventa 10`
|
|
1534
|
+
- confronti: `se il punteggio è almeno 3` (≥), `... è più di 2` (>),
|
|
1535
|
+
`... è meno di 5` (<), `... è 0` (=)
|
|
1536
|
+
- `strutture.py`: `CondizioneContatore` (operatori `==`/`>=`/`>`/`<`),
|
|
1537
|
+
`ConseguenzaContatore` (modi `aumenta`/`diminuisci`/`diventa`),
|
|
1538
|
+
`Mondo.dichiara_contatore()`. `compilatore.py`: scanner `è un contatore`,
|
|
1539
|
+
terminale `NUMERO` (priorità alta su `PROPRIETA`, che include le cifre),
|
|
1540
|
+
regole `def_contatore`, `cond_contatore_*`, `cons_aumenta`/`cons_diminuisci`/
|
|
1541
|
+
`cons_contatore_set`; parole riservate `contatore`/`almeno`/`più`/`meno`/
|
|
1542
|
+
`aumenta`/`diminuisci`/`diventa`. I confronti dopo `VARIABILE è` si
|
|
1543
|
+
distinguono dal valore-stato per il lookahead (NUMERO/`almeno`/`più`/`meno`
|
|
1544
|
+
vs PROPRIETA) → nessuna ambiguità. Suite a **119 asserzioni** (era 102).
|
|
1545
|
+
|
|
1546
|
+
> **Limite noto** (non risolto in questo livello): una regola `Invece di [verbo] …`
|
|
1547
|
+
> richiede sempre un **oggetto bersaglio**; non esistono ancora regole senza
|
|
1548
|
+
> oggetto del tipo `Invece di guarda se il punteggio è almeno 3: …`. Le verifiche
|
|
1549
|
+
> globali su contatori/stati vanno per ora agganciate a una regola su oggetto
|
|
1550
|
+
> (o agli eventi a turni, 0.7.5).
|
|
1551
|
+
|
|
1552
|
+
---
|
|
1553
|
+
|
|
1554
|
+
## [0.7.3] - 2026-05-31
|
|
1555
|
+
### Aggiunto (Roadmap Livello 3 — verso 0.8.0)
|
|
1556
|
+
- **Stato astratto del mondo** (criticità `[G3]`): gli **stati**, variabili globali
|
|
1557
|
+
con nome non legate ad alcun oggetto. Uno stato contiene una *parola-stato*
|
|
1558
|
+
(modello enum-like, più potente di un booleano):
|
|
1559
|
+
- dichiarazione: `Il semaforo è uno stato.`
|
|
1560
|
+
- valore iniziale: `Il semaforo è rosso.`
|
|
1561
|
+
- condizione: `... se il semaforo è verde` (e negazione `... non è verde`)
|
|
1562
|
+
- conseguenza: `... e adesso il semaforo è verde.`
|
|
1563
|
+
- Architettura: gli stati sono una **terza classe di simboli chiusi** (terminale
|
|
1564
|
+
`VARIABILE`), raccolta in Passata 1 e **disgiunta** da `ENTITA`/`PROPRIETA`.
|
|
1565
|
+
LALR distingue i costrutti su stato da quelli su oggetto al primo token →
|
|
1566
|
+
**zero ambiguità** anche con parole-stato omonime a proprietà di oggetti.
|
|
1567
|
+
- `strutture.py`: `CondizioneVariabile`, `ConseguenzaVariabile`, `Mondo.variabili`
|
|
1568
|
+
+ `dichiara_variabile()`. `compilatore.py`: scanner `è uno stato`, terminale
|
|
1569
|
+
`VARIABILE` iniettato per-file, regole `def_stato`/`def_stato_valore`/
|
|
1570
|
+
`cond_variabile(_neg)`/`cons_variabile`; parola riservata `stato`. Corretto un
|
|
1571
|
+
bug latente: il terminale "vuoto" ora è `[^\s\S]` (larghezza 1) invece di `(?!)`
|
|
1572
|
+
(zero-width, rifiutato da Lark). Suite a **102 asserzioni** (era 84), guardia
|
|
1573
|
+
anti-ambiguità estesa agli stati.
|
|
1574
|
+
|
|
1575
|
+
---
|
|
1576
|
+
|
|
1577
|
+
## [0.7.2] - 2026-05-31
|
|
1578
|
+
### Aggiunto (Roadmap Livello 3 — verso 0.8.0)
|
|
1579
|
+
- **Condizioni di fine partita**: nuove conseguenze `vinci` / `perdi` / `termina`,
|
|
1580
|
+
usabili in coda a una regola (`... dire "..." e adesso vinci.`). Impostano lo
|
|
1581
|
+
stato globale della partita; il messaggio narrativo è quello della clausola
|
|
1582
|
+
`dire`. Combinabili con altre conseguenze nella stessa regola
|
|
1583
|
+
(es. `... e adesso la porta è aperta e adesso vinci.`).
|
|
1584
|
+
- `strutture.py`: nuova `ConseguenzaFinePartita` (esiti `vinta`/`persa`/`terminata`)
|
|
1585
|
+
e `Mondo.stato_partita` (default `in_corso`).
|
|
1586
|
+
- `gioco.py`: il loop interattivo controlla `partita_finita(mondo)` dopo ogni
|
|
1587
|
+
conseguenza e termina con il banner di esito. Header allineato a v0.7.2.
|
|
1588
|
+
- Grammatica: tre nuove alternative di `conseguenza`, parole riservate
|
|
1589
|
+
`vinci`/`perdi`/`termina`. Validazione conseguenze resa robusta alle
|
|
1590
|
+
conseguenze prive di oggetto. Guardia anti-ambiguità estesa (corpus con
|
|
1591
|
+
`vinci`). Suite a **84 asserzioni** (era 72).
|
|
1592
|
+
|
|
1593
|
+
---
|
|
1594
|
+
|
|
1595
|
+
## [0.7.1] - 2026-05-31
|
|
1596
|
+
### Aggiunto (Roadmap Livello 3 — Stato di gioco e meccaniche, in lavorazione verso 0.8.0)
|
|
1597
|
+
- **Proprietà opposte dichiarabili** (generalizza la criticità `[M5]`): l'autore può
|
|
1598
|
+
dichiarare coppie di proprietà mutuamente esclusive con la frase
|
|
1599
|
+
`Accesa e spenta sono opposte.`. Assegnare una proprietà a un oggetto rimuove
|
|
1600
|
+
automaticamente tutte le sue opposte. La coppia `aperta`↔`chiusa`, prima
|
|
1601
|
+
cablata in `ConseguenzaProprieta.esegui`, è ora una semplice **coppia
|
|
1602
|
+
precaricata di default** (retro-compatibilità totale con le storie esistenti).
|
|
1603
|
+
- Nuova regola di grammatica `def_opposti` (`PROPRIETA "e" PROPRIETA "sono" "opposte" "."`),
|
|
1604
|
+
nuove parole riservate `sono`/`opposte`. La guardia anti-ambiguità (1 albero / 0
|
|
1605
|
+
conflitti LALR) copre il nuovo costrutto. Suite a **72 asserzioni** (era 65).
|
|
1606
|
+
|
|
1607
|
+
Dettaglio tecnico cumulativo del livello: `documentazione/0.8.0.md`.
|
|
1608
|
+
|
|
1609
|
+
---
|
|
1610
|
+
|
|
1611
|
+
## [0.2.1] - 2026-05-21
|
|
1612
|
+
### Risolto (Criticità Gravissime)
|
|
1613
|
+
- **Normalizzazione dell'input dell'utente:** Risolto il bug gravissimo che impediva la risoluzione degli oggetti in scope quando digitati con articoli (es. `prendi la keycard` falliva mentre `prendi keycard` funzionava). Ora l'input dell'utente viene normalizzato tramite `normalizza_nome` prima del confronto in `risolvi_nome_oggetto`.
|
|
1614
|
+
- **Risoluzione movimenti con direzioni abbreviate:**
|
|
1615
|
+
- Risolto il blocco della navigazione quando le connessioni erano definite con abbreviazioni nel file `.fav` (es. `collega n a il corridoio`). Ora vengono normalizzate a compile-time a nomi interi (`nord`, `sud`, etc.).
|
|
1616
|
+
- Abilitato il supporto per direzioni abbreviate inserite con il verbo `vai` (es. `vai n` o `vai s` ora si risolvono correttamente a `nord` e `sud`).
|
|
1617
|
+
|
|
1618
|
+
---
|
|
1619
|
+
|
|
1620
|
+
## [0.3.0] - 2026-05-21
|
|
1621
|
+
### Risolto (Criticità Gravi)
|
|
1622
|
+
- **Conservazione del nome visualizzato originale:** Ristrutturazione delle classi `Oggetto` e `Stanza` in `strutture.py` e della logica del transformer in `compilatore.py` per preservare la capitalizzazione e gli articoli originali scritti dall'autore (es. `"Una keycard magnetica"`, `"La cella di contenimento"`), mantenendo gli ID normalizzati in minuscolo solo per la logica interna del gioco. Aggiornato l'interprete in `gioco.py` e le azioni in `libreria_azioni.py` per visualizzare questi bellissimi nomi originali.
|
|
1623
|
+
- **Corrispondenza flessibile delle preposizioni nelle regole a due oggetti:** Implementazione di una logica di tolleranza e fallback in `gioco.py` (`elabora_comando`, FASE 0): se non si trova una corrispondenza esatta con la preposizione specificata nella regola (es. `usa chiave su porta`), il motore tenta un fallback tollerante ignorando la preposizione (es. accettando `usa chiave con porta`) a patto che i due oggetti coincidano univocamente con la regola.
|
|
1624
|
+
|
|
1625
|
+
---
|
|
1626
|
+
|
|
1627
|
+
## [0.4.0] - 2026-05-21
|
|
1628
|
+
### Aggiunto & Ottimizzato (Criticità Medie)
|
|
1629
|
+
- **Rendering asincrono e ottimizzato della mappa:** Spostato il calcolo pesante delle posizioni dei nodi del grafo (`nx.spring_layout`) all'interno di un thread secondario dedicato (`LayoutWorker` ereditato da `QThread`) in `favella_studio.py`. In questo modo si previene efficacemente il congelamento (UI freeze) dell'intera interfaccia utente di PySide6 durante la compilazione di storie di grandi dimensioni. Lo sfondo della figura Matplotlib si armonizza ora con la Dark Mode.
|
|
1630
|
+
- **Design System Premium "Cyber-Scrittore" (Dark Mode):** Sviluppato e applicato un foglio di stile QSS completo, scuro e moderno (`CYBER_STYLESHEET`) per tutta l'interfaccia dell'IDE. Coinvolge menu, toolbar, splitter, schede (tab), barre di scorrimento, bottoni e dialoghi `QMessageBox`, curando la tipografia monospazio e i feedback di hover.
|
|
1631
|
+
- **Marker visivi degli errori di sintassi nell'editor:** Integrato un sistema dinamico che, al fallimento della compilazione di Lark, estrae tramite regex la riga d'errore dal log, evidenzia con uno sfondo rosso scuro soffuso (`#4a1515`) la riga esatta nell'editor sfruttando `QTextEdit.ExtraSelection` e posiziona automaticamente il cursore per agevolare il debug.
|
|
1632
|
+
|
|
1633
|
+
### Risolto (Criticità Lievi)
|
|
1634
|
+
- **Generazione di righe vuote superflue nella console:** Ottimizzato l'intercettore di standard output in `GameSession` filtrando le stringhe che, dopo la rimozione dei caratteri di spaziatura finali (`.rstrip()`), risultano vuote, risolvendo il problema dei doppi a capo fastidiosi nella console dell'IDE.
|
|
1635
|
+
- **Feedback visivo se il gioco non è avviato:** Aggiornata la gestione dell'input in `on_console_input` di `FavellaStudio` per visualizzare un messaggio informativo elegante e colorato direttamente nella console di gioco se l'utente tenta di inviare comandi quando non c'è una sessione attiva.
|
|
1636
|
+
|
|
1637
|
+
---
|
|
1638
|
+
|
|
1639
|
+
## [0.5.0] - 2026-05-31
|
|
1640
|
+
### Roadmap del Linguaggio — Livello 1: Consolidamento e Robustezza
|
|
1641
|
+
Primo passo della roadmap evolutiva del linguaggio FAVELLA: mettere in sicurezza
|
|
1642
|
+
i costrutti esistenti prima di estenderli. L'obiettivo è impedire all'autore di
|
|
1643
|
+
scrivere una storia "rotta" senza ricevere alcun feedback. Nessuna funzionalità
|
|
1644
|
+
narrativa nuova, ma fondamenta molto più solide e diagnostica d'autore.
|
|
1645
|
+
|
|
1646
|
+
### Risolto (Criticità Gravissime)
|
|
1647
|
+
- **[GG1] Posizione iniziale esplicita del giocatore.** Introdotta la primitiva di linguaggio `Il giocatore comincia in [stanza].` (accetta anche *inizia* / *parte*). Prima la stanza di partenza era implicitamente la prima nell'ordine di parsing (`list(stanze.keys())[0]`), fragile e non controllabile dall'autore. Ora `Mondo.posizione_iniziale` è dichiarabile; in sua assenza resta il fallback alla prima stanza. Una stanza di partenza inesistente è un **errore bloccante**.
|
|
1648
|
+
- **[GG2] Rilevamento refusi nelle proprietà.** Una condizione `se [oggetto] è [proprietà]` che controlla una proprietà mai assegnata a quell'oggetto (né come stato iniziale né tramite conseguenza) emette ora un **avviso di possibile refuso** (es. `chuisa` per `chiusa`), invece di fallire silenziosamente lasciando il puzzle morto.
|
|
1649
|
+
- **[GG3] Validazione dei verbi delle regole.** Il verbo di ogni regola `Invece di` viene confrontato a compile-time con il vocabolario noto al motore (`VERBI_VALIDI`). Un verbo sconosciuto (regola che non si attiverebbe mai) genera ora un **avviso esplicito**.
|
|
1650
|
+
|
|
1651
|
+
### Aggiunto & Migliorato
|
|
1652
|
+
- **[G1] Disambiguazione esplicita della grammatica.** Aggiunte priorità di regola (`def_*.2` vs `def_proprieta.1`): la scelta del parser Earley sulle frasi formalmente ambigue (`X è una cosa` vs proprietà) è ora deterministica e documentata, non più affidata al tie-break interno di Lark.
|
|
1653
|
+
- **Suite di test del linguaggio (`test_linguaggio.py`).** 12 test / 28 asserzioni che "congelano" disambiguazione, posizione iniziale, validazioni e parsing della storia di esempio. Garanzia anti-regressione (`python test_linguaggio.py`).
|
|
1654
|
+
- **[M6] Escape nelle stringhe.** `TESTO_QUOTATO` supporta ora `\"` e `\\`: è finalmente possibile inserire virgolette dentro le battute (`dire "Lui disse \"ciao\"."`).
|
|
1655
|
+
- **Avvisi non bloccanti.** Nuovo canale diagnostico: gli avvisi (`[FAVELLA 1] Avvisi`) informano l'autore senza interrompere la compilazione, distinti dagli errori fatali.
|
|
1656
|
+
|
|
1657
|
+
### Risolto (Criticità Lievi)
|
|
1658
|
+
- **[L2] Normalizzazione tipografica.** Apostrofi e virgolette "curve" (`'` `'` `"` `"`), tipiche del copia-incolla da editor di testo, vengono convertite nelle versioni dritte attese dalla grammatica, evitando errori di sintassi oscuri.
|
|
1659
|
+
- **[L5] Rimosso il refuso di versione "v0.8"** nel report di `Mondo.__str__`; allineati gli header di versione di tutti i moduli core a `v0.5.0`.
|
|
1660
|
+
|
|
1661
|
+
---
|
|
1662
|
+
|
|
1663
|
+
## [0.6.0] - 2026-05-31
|
|
1664
|
+
### Roadmap del Linguaggio — Livello 2: Logica Composita
|
|
1665
|
+
Le regole `Invece di` passano da un singolo trigger a vere espressioni logiche.
|
|
1666
|
+
Questo sblocca i puzzle multi-stato senza dover duplicare le regole.
|
|
1667
|
+
|
|
1668
|
+
### Aggiunto (Criticità Gravi)
|
|
1669
|
+
- **[G2] Condizioni booleane composite.** Le condizioni supportano ora `e` (AND) e `oppure` (OR), con precedenza `OR < AND < atomo` e raggruppamento tramite parentesi. Esempio: `se la porta è chiusa e il giocatore ha la chiave`. (Si usa `oppure` e non `o`, che resta l'abbreviazione di *ovest*.)
|
|
1670
|
+
- **[M3] Negazione infissa.** Nuove forme negate, idiomatiche in italiano: `se il giocatore non ha [oggetto]` e `se [oggetto] non è [proprietà]`. Internamente generano una `CondizioneNot`.
|
|
1671
|
+
- **[G2] Conseguenze multiple.** Una regola può applicare più conseguenze in sequenza: `... e adesso la porta è aperta e adesso la chiave è nel nulla` (accettata anche la forma breve `e adesso X e Y`). `Regola.conseguenza` (singola) diventa `Regola.conseguenze` (lista) con il nuovo metodo `esegui_conseguenze()`.
|
|
1672
|
+
|
|
1673
|
+
### Modifiche Architetturali
|
|
1674
|
+
- Nuove classi in `strutture.py`: `CondizioneAnd`, `CondizioneOr`, `CondizioneNot` (gerarchia `Condizione` polimorfica, valutazione ricorsiva).
|
|
1675
|
+
- Grammatica delle condizioni stratificata (`cond_or` / `cond_and` / `cond_base`) con priorità di regola: le forme negate (`.2`) battono quelle affermative, impedendo che il token `non` venga assorbito dentro `entita` invertendo la semantica.
|
|
1676
|
+
- Il rilevamento refusi `[GG2]` ora attraversa ricorsivamente le condizioni composite (`_atomi_proprieta`) per trovare i refusi annidati dentro AND/OR/NOT.
|
|
1677
|
+
- Suite `test_linguaggio.py` estesa: **44 asserzioni** (era 28), inclusi AND/OR, negazioni, conseguenze multiple ed end-to-end.
|
|
1678
|
+
|
|
1679
|
+
---
|
|
1680
|
+
|
|
1681
|
+
## [0.6.1] - 2026-05-31
|
|
1682
|
+
### Roadmap del Linguaggio — Livello 2.5 (Disambiguazione strutturale): Fondamenta
|
|
1683
|
+
Primo commit incrementale verso la **risoluzione definitiva dell'ambiguità grammaticale [G1]** (target `v0.7.0`). La causa radice è il terminale aperto `entita: WORD+`, che rende la grammatica formalmente ambigua: oggi ogni dichiarazione genera più alberi di parsing (misurato: da 1 a 7 nodi `_ambig` per frase) e il parser Earley "indovina" tramite priorità di regola — deterministico ma fragile. La cura, decisa al massimo livello di robustezza, è un compilatore a **due passate** con `ENTITA` come token *chiuso* risolto da una symbol-table + parser **LALR(1)**, unambiguo per costruzione.
|
|
1684
|
+
|
|
1685
|
+
Questo commit introduce le **fondamenta isolate** (ancora non cablate nel parsing, che cambierà in `0.6.2`):
|
|
1686
|
+
|
|
1687
|
+
### Aggiunto
|
|
1688
|
+
- **Passata 1 — scanner della symbol-table** (`costruisci_symbol_table` in `compilatore.py`). Estrae dal sorgente i nomi di tutte le stanze e gli oggetti *dichiarati* (`è una stanza`, `è una cosa`, `collega … a …`) senza eseguire il parsing completo; robusto ai punti dentro le stringhe e ai commenti. Restituisce una `TabellaSimboli` con i nomi già normalizzati (supporta i nomi multiparola, es. `cella di contenimento`).
|
|
1689
|
+
- **Set di parole riservate esplicito** (`PAROLE_RISERVATE`): vocabolario strutturale del linguaggio, base per la futura risoluzione delle entità e per la documentazione d'autore.
|
|
1690
|
+
- **`utils.normalizza_tipografia`**: estratta la normalizzazione di apostrofi/virgolette tipografiche `[L2]` in un helper condiviso (usato sia da `analizza_file` sia dallo scanner). `utils.ARTICOLI`: lista unica degli articoli, ora condivisa con `normalizza_nome` (eliminata la duplicazione).
|
|
1691
|
+
- Suite `test_linguaggio.py`: **54 asserzioni** (era 44), con 10 nuovi controlli su scanner e parole riservate.
|
|
1692
|
+
|
|
1693
|
+
---
|
|
1694
|
+
|
|
1695
|
+
## [0.6.2] - 2026-05-31
|
|
1696
|
+
### Roadmap del Linguaggio — Livello 2.5 (Disambiguazione strutturale): Il refactor del cuore
|
|
1697
|
+
Il compilatore passa da single-pass **Earley** (grammatica formalmente ambigua, salvata solo da priorità di regola) a **due passate + LALR(1)**, unambiguo per costruzione. L'ambiguità `[G1]` è eliminata **alla radice**, non più mitigata.
|
|
1698
|
+
|
|
1699
|
+
### Modifiche Architetturali
|
|
1700
|
+
- **Terminale `ENTITA` chiuso, generato per-file.** Sparisce `entita: WORD+` (la causa radice). Le entità sono ora un terminale risolto per **longest-match** contro la symbol-table della Passata 1 (con articolo iniziale opzionale, nomi multiparola come `cella di contenimento`). Le parole-chiave non possono più collidere coi nomi.
|
|
1701
|
+
- **Migrazione a `parser='lalr'`.** Il parser si costruisce per-file da `costruisci_parser(simboli)`; un'eventuale ambiguità emergerebbe come `GrammarError` a build-time anziché come scelta silenziosa a runtime. Più veloce di Earley.
|
|
1702
|
+
- **Proprietà coniate = terminale `PROPRIETA` separato**, di **una sola parola** e a priorità lessicale bassa: non può inghiottire i keyword che la seguono (`e`, `oppure`, `:`). *Conseguenza author-facing:* le proprietà di stato sono ora monoparola (i nomi multiparola restano supportati per le entità). Nessuna storia/test esistente ne è impattato.
|
|
1703
|
+
- **`è prendibile` unificato in `def_proprieta`** come proprietà speciale: rimossa la regola `def_prendibile`, che era l'unica collisione lessicale residua. La grammatica è ora **0-ambigua** anche sotto Earley, non solo risolta da LALR.
|
|
1704
|
+
- **Rimosse tutte le priorità-cerotto `.2`/`.1`**: con i nomi come token chiusi non servono più (né per le definizioni base né per le forme negate delle condizioni).
|
|
1705
|
+
|
|
1706
|
+
### Aggiunto
|
|
1707
|
+
- **Guardia anti-ambiguità permanente** in `test_linguaggio.py`: un corpus che in `v0.6.0` generava da 1 a 7 alberi per frase ora ne produce **esattamente uno** (0 nodi `_ambig`), e si verifica che **LALR(1) si costruisca senza conflitti**. Rete di sicurezza definitiva contro le regressioni di `[G1]`.
|
|
1708
|
+
- Suite a **58 asserzioni** (era 54).
|
|
1709
|
+
|
|
1710
|
+
---
|
|
1711
|
+
|
|
1712
|
+
## [0.7.0] - 2026-05-31
|
|
1713
|
+
### Roadmap del Linguaggio — Livello 2.5: Disambiguazione strutturale COMPLETATA
|
|
1714
|
+
Rilascio che chiude il Livello 2.5: la grammatica di FAVELLA è ora **non ambigua per costruzione** (parser LALR(1), nomi come token chiusi). La criticità `[G1]` — la grammatica formalmente ambigua salvata solo dal tie-break di Earley — è **risolta in via definitiva**, non più mitigata. Questo rilascio raccoglie le fondamenta (`0.6.1`) e il refactor del cuore (`0.6.2`) e vi aggiunge la rifinitura della diagnostica d'autore.
|
|
1715
|
+
|
|
1716
|
+
### Aggiunto
|
|
1717
|
+
- **Errori d'autore mirati per le entità non dichiarate.** Sfruttando i nomi come token chiusi, un riferimento a un'entità mai dichiarata non produce più un parse error criptico ma un messaggio chiaro: *«Entità sconosciuta: "porta" non è mai stata dichiarata. Dichiarala prima dell'uso…»*. In caso di refuso vicino a un nome noto, viene proposta la **correzione** (es. `chave` → *«Forse intendevi: chiave?»*) tramite `difflib`. Un vero errore di sintassi (es. punto mancante) continua a ricevere il messaggio generico, senza falsi positivi.
|
|
1718
|
+
|
|
1719
|
+
### Documentazione
|
|
1720
|
+
- Nuova sezione **«Parole riservate»** e nota sulle **proprietà monoparola** nel manuale autore (`documentazione/manuale/manuale.md`).
|
|
1721
|
+
- `documentazione/0.7.0.md`: dettaglio tecnico del Livello 2.5 (due passate, ENTITA chiuso, LALR, guardia).
|
|
1722
|
+
|
|
1723
|
+
### Riepilogo del Livello 2.5 (0.6.1 → 0.6.2 → 0.7.0)
|
|
1724
|
+
- Compilatore a **due passate**: Passata 1 = symbol-table dei nomi; Passata 2 = parsing LALR(1) con `ENTITA` chiuso (longest-match).
|
|
1725
|
+
- Eliminato `entita: WORD+` e **tutte** le priorità-cerotto `.2`/`.1`.
|
|
1726
|
+
- Proprietà coniate = terminale `PROPRIETA` separato, **monoparola** (i nomi multiparola restano per le entità).
|
|
1727
|
+
- **Guardia anti-ambiguità permanente**: corpus a 1 albero (0 `_ambig`) + LALR senza conflitti.
|
|
1728
|
+
- Suite del linguaggio a **65 asserzioni** (era 44 a inizio livello), tutte verdi.
|
|
1729
|
+
- Allineati a `v0.7.0` gli header dei moduli core del linguaggio (`compilatore`, `strutture`, `test_linguaggio`) e il report di `Mondo.__str__`.
|