Ich versuche eine SQL-ähnliche Abstraktion zu erstellen und habe ein Problem gefunden.
Dies ist eine vereinfachte "Datenbanktabelle":
%Vor%Dies ist meine Abfrage Abstraktion:
%Vor%Dies ist meine Makroimplementierung:
%Vor%Und das ist mein Beispielcode:
%Vor%Es kompiliert und läuft gut, aber die Ausgabe ist:
%Vor% Grundsätzlich scheint result
leer zu sein. Ich erwartete, dass es die angesammelten Stränge der Bäume halten würde.
Wie kann ich meine Daten von der Macro-Compile-Phase zur nächsten Phase übertragen, sodass sie zur Laufzeit angezeigt wird? Ich könnte natürlich die aktuelle Zeichenfolge explizit an die nächste Methode übergeben, aber das möchte ich vermeiden.
Grundsätzlich müssen Sie eine Queryable
-Abstraktion haben, die: 1) die Sammlungs-API ( from
, select
, usw.) bereitstellt, 2) sich die aufgerufenen Methoden merkt, indem sie die Aufrufe verdichtet und akkumuliert innen.
Dieses Konzept ist in unseren ScalaDays Folien [1] etwas erklärt und wird in Slick (Open Source) implementiert [2]. Übrigens machen sie in LINQ ungefähr das gleiche mit den Methoden auf Queryable
, die die Aufrufe vereinheitlichen und sie Ihrem Objekt zuführen, das IQueryable
implementiert, z. wie in [3] beschrieben.
Links:
Das Problem besteht nicht darin, die Informationen von einem Makroaufruf an den nächsten zu übergeben. All das geschieht zur Kompilierzeit, das sollte funktionieren. Das Problem ist mit dem Makro, das zuletzt aufgerufen wird. Da c.universe.reify(new Where(result.toString))
zurückgegeben wird, wird new Where(result.toString)
zur Laufzeit aufgerufen. Und dann wird result
leer sein. Was Sie tun können, ist c.Expr(tree)
zurückzugeben, wobei tree
den Konstruktor von Where
auf ein String
literal anwendet, das result.toString
enthält.
Sie sollten auch beachten, dass Ihr Code von der Reihenfolge abhängt, in der die Makroaufrufe kompiliert werden. Wenn Sie in mehreren Codedateien mehrere Aufrufe dieser Makros ausführen, enthält result
möglicherweise Informationen aus früheren Aufrufen. Es wäre wahrscheinlich am besten, den gesamten Ansatz zu überdenken.
Wie @Kim darauf hinweist, dass die Aggregation der Informationen nicht das Problem ist, sondern dass die Makroerweiterung Code generiert, der result.toString
zur Laufzeit auswertet, wenn er tatsächlich leer ist. Ich hatte ein ähnliches Problem wie Sie und tat das Äquivalent, indem ich result.toString
durch resultExpr(c).splice
(Wie @Kim auch darauf hinweist, wird dies die aufgelaufenen Ergebnisse aller Makroaufrufe an die Laufzeit zurückgeben, also Vorsicht!)
Tags und Links sql scala macros compilation