Transzformáció

A transzformáció alrendszer egy beágyazott mini DSL nyelv a hozzá tartozó csomópontokkal és kódgeneráló funkciókkal. Általában validációs/adatgyűjtő, A->A és A->B transzformáció típus is valósítható meg. Az egyes elemekre kulcs, minta vagy foglalat (slot) találati szabályokat lehet létrehozni. Jelenleg csomópont fa struktúrához készült, speciális gráf felépítéshez egyedi szabályok vagy többmenetes transzformációk kellenek.

Találati stratégiák

  • alapértelmezett: minden önálló objektum tesztelődik, nem kötelező a találat, több találat esetén figyelmeztetés jön létre.

  • strict: minden önálló objektumra találatnak kell létrejönni, maximum egynek.

  • enforced: minden önálló objektumra és osztály tag tesztelődik, nem kötelező a találat.

Első szintű találat

Az első elem vagy egy tároló, vagy egy elemből álló «azonosító» csomópont, ami csak egyszer fordul elő. Ezért az első szintre külön szabályok vonatkoznak. Ezeket [root] attribútummal kell megjelölni.

Találati módok

Annak kiválasztása, hogy a soron következő csomópontra melyik találatot kell alkalmazni.

Kulcs

Csomópont típusra, útvonalra vagy névre készíthető találati feltétel. Váltózók használata nem lehetséges.

Példák:

  • <%Data::String%>: a string típusra ad találatot.

  • <%:xml::#Element tag="test"%>: olyan :xml::#Element típusra ad találatot, ahol a «tag» váltózó „test” értékű.

  • <%:xml::#Element tag="main"/:xml::#Element tag="child" %>: olyan :xml::#Element típusra ad találatot, ahol a «tag» váltózó „main” értékű és az egyik tárolójában van olyan elem, ami :xml::#Element típusú és a «tag» változója „child” értékű. Itt a „van olyan útvonal, ahol..” elv érvényesül. A konkrét útvonalak megadása a *next{} mezőben lehetséges .

Minta

Egyedi teszttel dönthető el a találat kifejezések segítségével. A feltételek között «bool» típusú metódus megadása is lehetséges.

    *pattern XmlMain {
        *match <%:xml::#Element%> {
            $1.tag == "main";
            $1.container.size() == 1;
        }
    }

Slot és SlotUse

Az első hívással váltózókat hozunk létre és állítunk be, a SlotUse a változók alapján dönti el a találat tényét. Előnye például a lokális változók transzformációjakor jelentkezik, amikor a feloldott (teljes) típust tesszük a változóba, és adjuk tovább. Így csomópontonként egyszer történik típuskeresés (Slot), a további tesztelés már csak sima összehasonlítás (SlotUse).

    *slot LocalDeclare {
        *provides {
            type: Data::String;
            name: Data::String;
        }
        *match declare: Code::VariableDeclare {
        }
        *fill {
            type = transformHelper.findType(declare.variableType.@string);
            name = declare.variableName;
        }
    }

    *slotuse MyVariable: LocalDeclare {
        *match {
            type == "MyFullType";
        }
        *pre {
            System::stdout("MyVariable...\n");
        }
    }

Kód végrehajtása a találaton

Két blokk adható meg, az egyik a gyerek csomópontok feldolgozása előtt, a másik utána.

    *pre {
        // Előtte fut le a $1 csomóponton.
    }
    *post {
        // Utána fut le a $1 csomóponton.
    }

Következő elemek kiválasztása

Külön szabály megadása nélkül a példányosított objektum összes gyerek csomópontja szerepelni fog a keresési listában. Lehetőség van üres keresési lista megadására.

    *next {}

Vagy a tagokat felsorolva csak a megadott elemekből keresési listát készíteni.

    *next {
        container.@children;
    }

Vagy a kódból is meghívható egy speciális metódus (@mainlist).

    *pre {
        *foreach (#UserType data: $1.list) {
            @mainlist(data);
        }
    }
    *next {}

A találati szabály nevének használatával közvetlen találatok használhatóak.

    *pre {
        Rule1($1.member1);
        Rule2($1.member2);
    }
    *next {}

Visszatérési érték és típus megadása

Deklaráció nélkül egy státust taralmazó Data::Bool érték kerül visszaadásra. Egyedi típust az onResult() metódussal adhatunk meg.

    *method UserType onResult () {
        return UserType(value);
    };

Implementáció

Végrehajtás előtt a transzformációs adatok és szabályok egy klasszikus osztályba szerveződnek (Group::Class). Minden tag váltózó, metódus és alap osztály közös lesz. Speciális módon osztályként és funkcióként is használható.

    *entrypoint main () {
        // Tetszőleges kezdő elem.
        Node root = init();

        // Funkció hívás egyszerű transzformációhoz.
        UserType result1 = TestTransform (root);

        // Osztály példányosítás.
        TestTransform testTransform;
        // Feldolgozási értékek megadása.
        testTransform.member = "value";
        // Feldolgozás indítása a beépített main() metódussal.
        UserType result2 = testTransform.main (root);
    };

Példa

    //! Teszt transzformáció.
    [std:strict]
    *transform Test {
        //! Közös tag változó.
        Data::String member;

        //! Közös metódus.
        *method testMethod () {
        };

        //! Találati szabály csak az első elemre.
        [std:root]
        *key RootMatch: <%RootType%> {
            *next {
                container.@children;
            }
        }
        //! Találati szabály a további elemre.
        *key UserMatch <%UserType%> {
            *pre {
                // Előtte fut le a $1 csomóponton.
            }
            *post {
                // Utána fut le a $1 csomóponton.
            }
            *next {
                container.@children;
            }
        };
    };