🎮 Le Features di Pangea - Guida Dettagliata per Ragazzi e Ragazze

Scopri come funziona veramente questo linguaggio di programmazione unico!

🚀 Cosa Rende Pangea Speciale?

Pangea non è un linguaggio di programmazione ordinario. È un esperimento affascinante su come scrivere codice in modo completamente diverso. In questa guida scoprirai 7 feature straordinarie che lo rendono unico e come funzionano dietro le quinte!

1️⃣ Notazione Prefissa (Polish Notation)

Quando usi la maggior parte dei linguaggi di programmazione, scrivi operatore in mezzo agli operandi (notazione infissa):

5 + 6 ← standard (infissa)

In Pangea, scrivi l'operatore prima degli operandi:

add 5 6 ← Pangea (prefissa)

💡 Perché è Utile?

Confronto: Infix vs Prefix

Cosa Vuoi Fare Standard (Infix) Pangea (Prefix) Risultato
Somma semplice 5 + 6 add 5 6 11
Moltiplicazione 3 * 4 multiply 3 4 12
Operazioni miste (2 + 3) * 4 multiply add 2 3 4 20
Operazioni complesse ((5+6)*(7-2)) multiply add 5 6 subtract 7 2 55
🔍 Come funziona nel codice Lua:

Nel file main.lua, la funzione phrase_length() calcola quanti token un operatore consuma:

function phrase_length(word_index)
  local word = words[word_index]
  local length = 1
  local word_definition = word_definitions[word]
  if word_definition == nil then
    return 1
  end

  local argument_length = word_definition[1] -- Quanti argomenti?
  for _ = 1, argument_length do
    length = length + phrase_length(word_index + length)
  end
  return length
end

Esempio: add ha arity=2 (prende 2 argomenti), quindi phrase_length calcola quanti token occupano gli ultimi 2 valori da valutare.

2️⃣ Literali Quotati con Escape Support

In Pangea, le stringhe (testi) sono semplicemente parole tra virgolette. Dentro le virgolette puoi scrivere qualsiasi cosa, inclusi spazi e caratteri speciali.

Sintassi Base

"Ciao Mondo"       ← Una stringa semplice con spazi
"nome"             ← Un nome di variabile
"Hello, World!"    ← Con punteggiatura

Sequenze di Escape

All'interno di una stringa tra virgolette, puoi usare caratteri speciali con il backslash (\):

Sequenza Cosa Rappresenta Esempio
\" Una virgoletta dentro la stringa "Lui ha detto \"Ciao\"" → Lui ha detto "Ciao"
\\ Un backslash letterale "C:\\Users" → C:\Users
\n Vai a capo (newline) "Riga 1\nRiga 2" → due righe
\t Una tabulazione (spazi allineati) "Nome\tEtà" → colonne allineate

Esempi Pratici

1 Stampare una frase
print "Benvenuto in Pangea!"

Output: Benvenuto in Pangea!

2 Usare una stringa come nome variabile
set "nome" "Mario"
print get "nome"

Output: Mario

3 Escape per testo multi-riga
print "Riga 1\nRiga 2\nRiga 3"

Output: tre righe separate

🔍 Come funziona nel codice Lua:

Nel file main.lua, la funzione program_words() analizza il testo carattere per carattere e gestisce le stringhe quotate:

function program_words(pn_program)
  local in_string = false
  local escaping = false
  local quoted = {}

  for i = 1, #pn_program do
    local char = pn_program:sub(i, i)

    if in_string then
      if escaping then
        if    char == '"' then table.insert(quoted, '"')
        elseif char == 'n' then table.insert(quoted, "\n")
        end
        escaping = false
      elseif char == '"' then
        in_string = false -- Fine stringa
      end
    elseif char == '"' then
      in_string = true -- Inizio stringa
    end
  end
end

Il token viene marcato nella tabella string_literals in modo che l'evaluatore sappia che è un letterale e non una parola da cercare nei word_definitions.

⚠️ Attenzione: Se scrivi una sequenza di escape non valida (tipo \q), Pangea ti mostrerà un errore!

3️⃣ Input Testuale e Conversione Numerica

Pangea include due parole utili per i programmi interattivi: read_text / leggi_testo per leggere una riga da console e to_number / numero_da_testo per convertirla in numero.

Lettura da Console

set "nome" read_text
print get "nome"

Comportamento: legge una singola riga da input standard e la restituisce come testo.

Conversione da Testo a Numero

print to_number "42"
print add to_number "7" 5

Risultato: il testo numerico viene convertito in numero e puo essere usato direttamente con add, multiply, modulus, ecc.

Comportamento su Input Non Valido

print to_number "abc"   ← stampa nil
add to_number "abc" 5   ← errore Lua: aritmetica su nil

Nota: la semantica corrente non forza errore in to_number/numero_da_testo; in caso di testo non numerico ritorna nil.

EOF su leggi_testo/read_text: se non ci sono piu righe disponibili in input, viene restituita una stringa vuota ("").

🔍 Come funziona nel codice Lua:
function read_text_function()
  local text = io.read()
  if text == nil then
    return ""
  end
  return text
end

function to_number_function(arguments)
  local value = evaluate_word(arguments[1])
  return tonumber(value)
end

4️⃣ Scoping Lessicale (Variabili Locali)

Scope significa "area di validità". In Pangea, le variabili vivono solo dentro la funzione in cui sono dichiarate. Questo si chiama scoping lessicale.

Il Concetto di Call Stack

Immagina una pila di scatole (call stack). Ogni volta che chiami una funzione, una nuova scatola viene messa sopra. Le variabili dentro quella scatola esistono solo in quella funzione. Quando la funzione finisce, la scatola viene tolta e le variabili spariscono.

Come funziona il Call Stack

Programma:

set "x" 10 ← x va nello scope globale
define_word "miaFunzione" 0
  set "x" 20 ← x va nello scope locale della funzione
miaFunzione
print get "x" ← Stampa x globale (10)

Visualizzazione del Call Stack:

Stato 1: Prima di chiamare la funzione
Global
x = 10
Stato 2: Durante l'esecuzione della funzione
Global
x = 10
miaFunzione
x = 20

Nota: la x nella funzione è diversa da quella globale!

Stato 3: Dopo la funzione
Global
x = 10

Output: 10 (la x della funzione è sparita)

Perché è Importante?

🔍 Come funziona nel codice Lua:

In Pangea, c'è una variabile globale call_stack che è una lista di tabelle:

local call_stack = {{}} -- Inizia con uno scope vuoto

function get_function(arguments)
  local variables = call_stack[#call_stack] -- Leggi dall'ultimo scope (il corrente)
  local variable_name = evaluate_word(arguments[1])
  return variables[variable_name]
end

function define_word_function(arguments)
  local word_function = function(word_arguments)
    -- CREA UN NUOVO SCOPE
    table.insert(call_stack, {})

    -- Esegui il corpo della funzione
    local returned = evaluate_word(arguments[3])

    -- ELIMINA LO SCOPE
    table.remove(call_stack)

    return returned
  end
end
📝 Nota tecnica: call_stack[#call_stack] significa "l'ultimo elemento della lista", che è sempre lo scope corrente.

4️⃣ Recursive Descent (Valutazione Ricorsiva)

Recursive descent è il modo in cui Pangea legge e valuta quello che scrivi. È un processo ricorsivo: ogni funzione chiama altre funzioni per valutare i suoi argomenti.

Il Meccanismo Fondamentale

La funzione centrale è evaluate_word(word_index). Ecco cosa fa:

1 Leggi il token

Prende il token all'indice word_index

2 Decidi cosa fare
  • Se è un numero → restituisci il numero
  • Se è una stringa quotata → restituisci la stringa
  • Se è una parola registrata → cercala in word_definitions
3 Calcola quanti argomenti servono

Usa phrase_length() per sapere quanti token occupano gli argomenti

4 Chiama ricorsivamente gli argomenti

Per ogni argomento, chiama di nuovo evaluate_word()

5 Esegui la funzione

Ora che hai i valori, esegui la vera operazione (add, print, ecc.)

Esempio Pratico: Traccia di Esecuzione

Programma: print add 5 6

Tokens: [1: print, 2: add, 3: 5, 4: 6]

Traccia:

evaluate_word(1) ← Valuta "print"
├─ "print" ha arity=1 ← Ha bisogno di 1 argomento
├─ Argomento 1: evaluate_word(2) ← Valuta "add"
│  ├─ "add" ha arity=2 ← Ha bisogno di 2 argomenti
│  ├─ Argomento 1: evaluate_word(3) ← Valuta "5" → 5
│  ├─ Argomento 2: evaluate_word(4) ← Valuta "6" → 6
│  └─ Restituisce: 5 + 6 = 11
└─ print(11)
   └─ Output: 11
🔍 Come funziona nel codice Lua:
function evaluate_word(word_index)
  local word = words[word_index]

  -- Caso 1: È un numero?
  local returned_value = tonumber(word)
  if returned_value ~= nil then
    return returned_value
  end

  -- Caso 2: È una stringa quotata?
  if string_literals[word_index] then
    return word
  end

  -- Caso 3: È una parola registrata?
  local word_definition = word_definitions[word]
  if word_definition == nil then
    return
  end

  -- Calcola argomenti ricorsivamente
  local arguments = {}
  local arity = word_definition[1]
  local argument_word_index = word_index + 1

  for _ = 1, arity do
    table.insert(arguments, argument_word_index)
    argument_word_index = argument_word_index + phrase_length(argument_word_index)
  end

  -- Esegui la funzione
  return word_definition[2](arguments)
end

Perché "Recursive Descent"?

Si chiama così perché:

5️⃣ Modularità - Includere File Esterni

Non vuoi scrivere tutto in un solo file? In Pangea puoi dividere il tuo programma in più file e includerli uno dentro l'altro. Questo si chiama modularità.

La Parola Chiave: "!"

Per includere un file, usa il simbolo ! seguito dal nome del file tra virgolette:

! "file-esterno.words"

Esempio Pratico

File 1: funzioni-comuni.words

define_word "doppio" 1
  multiply argument 1 2

File 2: programma-principale.words

! "funzioni-comuni.words"

print doppio 5 ← Usa la funzione da file-esterno

Output: 10

Path Relativi e Assoluti

Pangea supporta sia percorsi relativi che assoluti:

! "utils/helper.words"    ← Relativo: cerca in subdirectory
! "/home/user/file.words" ← Assoluto: percorso completo
🔍 Come funziona nel codice Lua:

Nel file main.lua, c'è il concetto di file_directory_stack:

local file_directory_stack = {}

function execute_words_file(file_name)
  local file = io.open(resolved_file_name, "r")

  -- Metti la directory del file sullo stack
  table.insert(file_directory_stack, path_dirname(resolved_file_name))

  -- Esegui il programma
  execute_program(program)

  -- Togli la directory dallo stack
  table.remove(file_directory_stack)
end

In questo modo Pangea sa dove cercare i file relativi, anche quando includi file che a loro volta includono altri file (nesting).

Vantaggi della Modularità

📝 Convention: In Pangea, i file in inglese finiscono con .words e quelli in italiano finiscono con .parole.

6️⃣ Bilingual - Italiano e Inglese

Pangea supporta sia l'italiano che l'inglese come linguaggio di programmazione. Puoi scrivere il tuo codice nella lingua che preferisci!

Come Attivare la Modalità Italiana

Quando lanci Pangea, passa italian come primo argomento:

lua src/pangea1/main.lua          ← Modalità Inglese (default)
lua src/pangea1/main.lua italian  ← Modalità Italiana

Parole Traducibili

Ecco un confronto tra inglese e italiano per le parole chiave:

Funzione Inglese Italiano
Stampa output print stampa
Addizione add somma
Moltiplicazione multiply moltiplica
Assegna variabile set metti
Leggi variabile get prendi
Condizione if se
Ciclo while mentre
Uguaglianza equal uguale
Maggiore di greater maggiore
Definifico funzione define_word definisci_parola

Esempio Comparativo

Lo stesso programma in inglese e italiano:

English (words)

print add 5 6
set "x" 10
print get "x"

Italiano (parole)

stampa somma 5 6
metti "x" 10
stampa prendi "x"
🔍 Come funziona nel codice Lua:

Nel file main.lua, c'è una tabella di traduzione e una funzione tr():

local translate_italian = {
  ["print"]    = "stampa",
  ["add"]      = "somma",
  ["multiply"] = "moltiplica",
  -- ... e altri 20+ termini
}

function tr(string)
  if language == "italian" then
    local traduced = translate_italian[string]
    return traduced
  end
  return string
end

Quando definisci le parole, usano tr() come chiave:

word_definitions[tr("print")] = {1, print_function}
word_definitions[tr("add")]   = {2, add_function}

Se la lingua è italiana, tr("print") restituisce "stampa", quindi la parola viene registrata come "stampa" e funziona!

💡 Idea geniale: Puoi anche mescolare inglese e italiano nello stesso programma se vuoi. Basta che usi la sintassi corretta per la modalità in cui stai eseguendo il programma!

7️⃣ REPL & Script Modes (Interattivo e Batch)

Pangea può funzionare in due modalità diverse: interattiva (REPL) dove scrivi comandi uno per uno, e script mode dove esegui un intero file.

Modalità REPL (Interattiva)

REPL significa "Read-Eval-Print Loop" (Leggi-Valuta-Stampa in Loop). È come avere una conversazione con il computer:

$ lua src/pangea1/main.lua
pang version: 028  ? for help

print "Ciao"    ← Scrivi qui il tuo comando
Ciao

add 5 6
11

exit
bye

Script Mode

Passa il nome di un file e Pangea esegue il file intero:

$ lua src/pangea1/main.lua mio-programma.words  ← Il programma si esegue automaticamente
Risultato...
bye

Script Mode Ibrido: File + REPL

Se aggiungi un trattino - dopo il nome del file, Pangea esegue il file E POI entra nella modalità interattiva:

$ lua src/pangea1/main.lua mio-programma.words -  ← Esegue il file
                                                   ← Poi entra in REPL

print "Posso scrivere altri comandi!"
Posso scrivere altri comandi!

Confronto delle Modalità

Modalità Comando Uso Principale Vantaggio
REPL lua src/pangea1/main.lua Sperimentare e imparare Feedback immediato
Script lua src/pangea1/main.lua file.words Eseguire programmi Automatizzazione
Ibrido lua src/pangea1/main.lua file.words - Carica dati poi sperimenta Entrambi i vantaggi

Caso d'Uso Pratico

Immagina di avere un file setup.words che inizializza le tue variabili:

set "nome"          "Mario"
set "numero_magico" 42

Poi esegui:

$ lua src/pangea1/main.lua setup.words -  ← Ora entra in REPL con le variabili già caricate

print get "nome"          ← "Mario" è già disponibile!
Mario

add get "numero_magico" 8
50
🔍 Come funziona nel codice Lua:

Nel main.lua, la funzione main() gestisce tutte e tre le modalità:

function main()
  local filename = arg[1]

  if filename ~= nil then
    if filename == "-" then
      -- Solo REPL
      read_execute_loop()
    else
      -- Esegui file
      execute_words_file(filename)

      -- Se arg[2] == "-", entra anche in REPL
      if arg[2] == "-" then
        read_execute_loop()
      end
    end
  else
    -- Nessun file: REPL diretto
    read_execute_loop()
  end
end

La funzione read_execute_loop() legge linea per linea finché non premi exit:

function read_execute_loop()
  while true do
    local program = io.read()
    if program == nil or program == tr("exit") then
      break
    end
    execute_program(program)
  end
end

🎉 Riassunto: Le 7 Features di Pangea

--- ⭐ ---

🧠 Prossimi Passi

Ora che conosci le features in dettaglio, prova:

💪 Sfida: Crea un gioco semplice in Pangea usando un ciclo while e variabili!