1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
|
/** -*-C-*-ish
Kaya standard library
Copyright (C) 2004, 2005, 2006 Edwin Brady
This file is distributed under the terms of the GNU Lesser General
Public Licence. See COPYING for licence.
*/
"<summary>Inspect Kaya data values directly</summary>
<prose>This module allows you to convert primitive Kaya data types to a representation which may be inspected and edited directly within Kaya, and then convert this representation back again. This capability can then be used to save Kaya values persistently as the <moduleref>Pickle</moduleref> does, or to allow arbitrary Kaya values to be interactively constructed by the application user.</prose>"
module Reflect;
import Prelude;
"<summary>Data value, reflected as a kaya data structure.</summary>
<prose>A Data value, reflected as a kaya data structure.
Any cycles or shared values in the structure will also be shared in the
reflected structure. Note that the <code>fnid</code> in the <code>DClosure</code>
constructor may change if the program is recompiled, but is guaranteed to
be the same if the binary is unchanged.</prose>"
public data Data
= DInt(Int int)
| DFloat(Float float)
| DString(String string)
| DArray([Data] array)
| DUnion(Int tag, [Data] fields)
| DClosure(Int fnid, [Data] args);
foreign "stdfuns.o" {
pure Data doReflect(Ptr vm, a x) = funtable_reflect;
pure val reifyUnion(Int tag, Int arity) = reifyUnion;
pure val reifyClosure(Int fnid, Int arity) = reifyClosure;
pure Void reifyUnionArgs(a union, [a] flds) = reifyUnionArgs;
pure Void reifyClosureArgs(a clos, [a] args) = reifyClosureArgs;
}
"<argument name='value'>A value</argument>
<summary>Convert a value into a data representation of that value.</summary>
<prose>Convert a value into a data representation of that value.</prose>
<related><dataref>Data</dataref></related>
<related><functionref>reify</functionref></related>"
public Data reflect(a value) {
return doReflect(getVM, value);
}
"<argument name='value'>A data representation</argument>
<summary>Convert a data representation back to the represented value.</summary>
<prose>Convert a data representation back to the represented value.</prose>
<related><dataref>Data</dataref></related>
<related><functionref>reflect</functionref></related>"
public a reify(Data val) {
return reifyAux([], val);
}
private a reifyAux(var [(Data,a)] done, Data val) {
for xs in done {
if (identical(val,xs.fst)) {
return xs.snd;
}
}
case val of {
DInt(i) -> rv = subvert(i); push(done, (val,rv));
| DString(str) -> rv = subvert(str); push(done, (val,rv));
| DFloat(f) -> rv = subvert(f); push(done, (val,rv));
| DArray(arr) -> rv = subvert(map(reify,arr));
| DUnion(tag,arr) -> rv = reifyUnion(tag,size(arr));
push(done, (val,rv));
reifyUnionArgs(rv, map(reifyAux@(done), arr));
| DClosure(fn,arr) ->
rv = reifyClosure(fn,size(arr));
push(done, (val,rv));
reifyClosureArgs(rv, map(reifyAux@(done), arr));
}
return rv;
}
"<argument name='val'>A value</argument>
<summary>Print any value as a string</summary>
<prose>Prints any value as a string, including arrays, unions and closures. Note that what is printed is the run-time representation of the value, so <code>dump(just(5));</code> will print <samp>Tag1(5)</samp>, not <samp>just(5)</samp>.</prose>"
public Void dump(a val) {
dumpAux(reflect(val));
putStr("\n");
}
private Void dumpAux(Data val) {
case val of {
DInt(i) -> putStr(String(i));
| DString(str) -> putStr(str);
| DFloat(f) -> putStr(String(f));
| DArray(arr) -> putStr("["); dumpArray(arr); putStr("]");
| DUnion(tag,arr) -> putStr("Tag"+tag+"("); dumpArray(arr); putStr(")");
| DClosure(fn,arr) -> putStr("FN"+fn+"("); dumpArray(arr); putStr(")");
}
}
private Void dumpArray([Data] vals) {
for x@i in vals {
dumpAux(x);
if (i<size(vals)-1) putStr(", ");
}
}
|