Linguaggio personalizzato con markup misto e Python, analisi in Python

2

Ho bisogno di un sistema per creare sottoclassi Python in modo semplice, e stavo pensando di usare un linguaggio di configurazione (personalizzato) simile a json , xml , ecc.

Ecco la struttura iniziale che ho pensato (un file = una sottoclasse, i file sono in una cartella da cui vengono letti automaticamente), che è fondamentalmente solo un semplice linguaggio di configurazione, con i corpi delle funzioni Python come gestori di eventi:

name: Warrior
description: Excels at close combat

Item:
    name: Shield
    description: Block 10% of incoming damage, but move 10% slower

    Event defend:
        # Everything after "event <event_name>" line
        # is parsed as normal python until unindentation
        event_args['damage'] *= 0.9

    Event spawn:
        event_args['player'].speed -= 0.1

Sono aperto a qualsiasi suggerimento, quindi se è molto più semplice usare qualche altra formattazione (XML o simile), sono pronto. Tuttavia, questo sarebbe il formato ideale.

Come potrei continuare a scrivere misto Python e il linguaggio di configurazione? Ci sono progetti esistenti che potrei studiare? Ho ricercato ast un po ', che è apparentemente progettato per l'analisi di Python, ma sto solo cercando alcune indicazioni per iniziare.

L'unica soluzione che viene in mente è:

  1. legge il file riga per riga e analizza manualmente ogni riga con le funzioni di stringa di Python come .split()
  2. Se il contenuto della riga corrisponde a regex ^Event .*:$ , analizzerò come Python fino a quando non tornerò (come faccio?)

Ma anche questo sembra irrealizzabile, e sembra che ci debba essere un modo migliore.

    
posta Markus Meskanen 11.04.2017 - 15:12
fonte

1 risposta

3

Una volta ho scritto un parser basato su espressioni regolari per un simile linguaggio di configurazione, ma era un lavoro non necessario. Invece: usa un linguaggio di configurazione esistente come YAML - ha un datamodel simile a JSON e una sintassi quasi indistinguibile dal tuo esempio (devi solo usare : | invece di : per avviare le righe testuali). L'analisi è difficile da correggere, quindi lascia che sia qualcun altro a gestirlo.

Lo svantaggio di utilizzare qualsiasi linguaggio di configurazione esistente è che non è possibile creare un buon messaggio di errore. Quando uno dei frammenti di codice genera un errore, la traccia dello stack non può puntare alla riga corretta del file di configurazione.

In alternativa, potrebbe essere preferibile scrivere semplicemente come codice Python. Non è molto sintattico in più! Almeno questo ti offre l'evidenziazione della sintassi per il tuo codice e numeri di linea appropriati per le tue tracce dello stack. Puoi definire i decoratori per eseguire la convalida o per registrare i callback, ecc.

class Shield(GameObject):
  name = "Shield"
  description = "Block 10% of incoming damage, but move 10% slower"

  @event
  def event_defend(self, event_args):
    event_args['damage'] *= 0.9

  @event
  def event_spawn(self, event_args):
    event_args['player'].speed -= 0.1

class Warrior(GameObject):
  name = "Warrior"
  description = "Excels at close combat"

  items = [Shield()]

Se vuoi essere "intelligente", i decoratori, il protocollo metaclass, gli oggetti descrittore e le superbe capacità di riflessione di Python offrono molte opportunità per attirare la creazione e il comportamento della classe. A differenza di C ++ o Java, le classi di Python sono solo oggetti ordinari e, come tali, alcuni schemi di programmazione del gioco come il tipo di modello di oggetto evitare la creazione di classi extra spesso non necessarie in Python.

    
risposta data 11.04.2017 - 16:08
fonte