Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deCapnKit: safe serialization for capn #205

Open
wants to merge 52 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
dfc74a0
toward capper in monte: make hello
dckc Sep 3, 2017
f4352ad
persistentSlot method seems to work
dckc Sep 3, 2017
dcfeb79
[e-lang] Announcing E 0.8.22a: Preliminary Persistence & Upgrade Support
erights Apr 4, 2003
58be1ff
[e-lang] Announcing E 0.8.22a: Preliminary Persistence & Upgrade Support
erights Apr 4, 2003
0a25987
deSubgraphKit and deps: .emaker -> .mt
dckc Sep 4, 2017
9a2d110
deSubgraphKit port: docstrings
dckc Sep 4, 2017
37de015
deSubgraphKit port: lexical fixes
dckc Sep 4, 2017
393b667
deSubgraphKit port: 1-1 name changes
dckc Sep 4, 2017
679c78a
deSubGraphKit: rewrite imports
dckc Sep 4, 2017
79007ec
deSubgraphKit port: implicit returns (to / method)
dckc Sep 4, 2017
5b4c1a7
E-style guards: Guard, NotNull, Tuple
dckc Sep 4, 2017
6853b6b
deSubGraph port: fix / postpone imports
dckc Sep 4, 2017
c3621a7
deSubgraphKit port: mute unused name warnings
dckc Sep 4, 2017
acab891
deSubgraphKit port: runtime name changes
dckc Sep 4, 2017
e567cb9
deSubGraphKit port: handle named args
dckc Sep 4, 2017
6c4554b
deSubgraphKit port: get/2 -> fetch/2
dckc Sep 4, 2017
53804bf
deSubgraphKit: DeepFrozen exports
dckc Sep 4, 2017
a1afc8a
deJSONKit builder
dckc Sep 4, 2017
facc537
deJSONKit test based on uneval.updoc
dckc Sep 4, 2017
ab0ea0b
readOnly facet for maps
dckc Sep 4, 2017
1fd75c5
o.__optUncall() -> o._uncall()
dckc Sep 4, 2017
1437b0f
Monte generic guards use .get() rather than .run()
dckc Sep 4, 2017
1b87fbb
list guards: g[] -> List[g] (cont)
dckc Sep 4, 2017
c02325f
bail on Tuple, for now
dckc Sep 4, 2017
8faaf0a
Merge elib/serial port
dckc Sep 5, 2017
7315228
start porting deMNodeKit, deSrcKit
dckc Sep 9, 2017
bf7612d
deSrcKit builder works in one case
dckc Sep 9, 2017
0a27e87
deMNodeKit: E -> Monte API
dckc Sep 9, 2017
ece921f
deMNodeKit: 1/1 tests
dckc Sep 9, 2017
2d86089
deJSONKit: use static Tuple guard
dckc Sep 9, 2017
e9e7e5e
markupKit works in several cases
dckc Sep 11, 2017
5f2432b
markupKit: fix Element._uncall()
dckc Sep 12, 2017
d3c5b8e
markupKit: handle <link />
dckc Sep 12, 2017
90cfacd
markupKit: handle &amp; in attrs
dckc Sep 12, 2017
06ffb52
markupKit: handle - in Name
dckc Sep 12, 2017
15ff978
markupKit: comments, <!doctype>
dckc Sep 12, 2017
1ef12e4
move elib to mast/lib
dckc Mar 9, 2019
788c7f6
Merge branch 'typhon-serial'
dckc Mar 9, 2019
1ac811c
mast/lib/serial: update import paths
dckc Mar 9, 2019
2b22172
serial/guards: prune Tuple
dckc Mar 9, 2019
dd501cd
deCapnKit (WIP)
dckc Mar 9, 2019
dd3a52b
capnpc: fix a default value
dckc Mar 9, 2019
409f8d6
deCapnKit.buildRoot dumps message bytes
dckc Mar 9, 2019
4403011
deCapnKit: clean up debug traceln
dckc Mar 9, 2019
11d827b
deCapnKit: oops! noun, not import
dckc Mar 9, 2019
268adf5
uneval: send capn message to stdout
dckc Mar 9, 2019
8acce48
deSubGraphKit: to -> method
dckc Mar 11, 2019
5451259
deSubGraphKit: G(T, U) -> G[T, U]
dckc Mar 11, 2019
4c32b31
deSubGraphKit: don't auto-extend FlexList
dckc Mar 11, 2019
50e0082
Merge branch 'serial-port' into serial-re-merge
dckc Mar 11, 2019
c39d61a
deCapnKit.recognize (modulo Char, Double, bigint)
dckc Mar 11, 2019
d1bf539
deCapnKit: Int32 code for Char, digit string for big Int
dckc Mar 11, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 138 additions & 0 deletions mast/capn/deCapnKit.mt
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import "lib/capn" =~ [=> makeMessageReader :DeepFrozen]
import "lib/serial/DEBuilderOf" =~ [=> DEBuilderOf :DeepFrozen]
import "capn/montevalue" =~ [=> reader, => makeWriter]

exports (deCapnKit)


def Node :DeepFrozen := Map[Str, Any] # Named arguments to makeDataExpr
def Root :DeepFrozen := Bytes # capn message

def Int32 :DeepFrozen := -(2 ** 31)..!2 ** 31


object deCapnKit as DeepFrozen:
to makeBuilder():

def Literal := Any[Int, Double, Str, Char]

var nextTemp :Int := 0
var varReused := [].asMap().diverge()
def w := makeWriter()

def expr(nargs :Map):
return M.call(w, "makeDataExpr", [], nargs)

return object deCapnBuilder implements DEBuilderOf[Node, Root]:
method getNodeType() :Near:
Node
method getRootType() :Near:
Root

to buildRoot(root :Node) :Bytes:
return w.dump(expr(root))

to buildLiteral(it :Literal) :Node:
def lit := switch (it) {
match i :Int32 { ["int" => w.makeInteger("int32" => i)] }
match i :Int { ["int" => w.makeInteger("bigint" => `${i}`)] }
match x :Double { ["double" => x] }
match s :Str { ["str" => s] }
match ch: Char { ["char" => ch.asInteger()] }
match bs: Bytes { ["bytes" => bs] }
}
return ["literal" => lit]

to buildImport(varName :Str) :Node:
return ["noun" => varName]

to buildIbid(tempIndex :Int) :Node:
if (! (tempIndex < nextTemp)):
throw(`assertion failure: $tempIndex < $nextTemp`)
varReused[tempIndex] := true
# traceln(`buildIbid: $tempIndex marked reused.`)
return ["ibid" => tempIndex]

to buildCall(rec :Node, verb :Str, args :List[Node], nargs :Map[Str, Node]) :Node:
def message := ["verb" => verb,
"args" => args,
"namedArgs" => [for k => v in (nargs) ["key" => k, "value" => v]]
]
return ["call" => ["receiver" => expr(rec), "message" => message]]

to buildDefine(rValue :Node) :Pair[Node, Int]:
def tempIndex := nextTemp
nextTemp += 1
varReused[tempIndex] := false
def defNode := ["defExpr" => ["index" => tempIndex, "rValue" => expr(rValue)]]
return [defNode, tempIndex]

to buildPromise() :Int:
def promIndex := nextTemp
nextTemp += 2
varReused[promIndex] := false
varReused[promIndex + 1] := false
return promIndex

to buildDefrec(resIndex :Int, rValue :Node) :Node:
def promIndex := resIndex - 1
# traceln(`buildDefrec: $promIndex reused? ${varReused[promIndex]}.`)
return if (varReused[promIndex]):
# We have a cycle
["defRec" => ["promIndex" => promIndex, "rValue" => expr(rValue)]]
else:
# No cycle
["defExpr" => ["index" => promIndex, "rValue" => expr(rValue)]]

to recognize(msg :Root, builder) :(def _Root := builder.getRootType()):
def Node := builder.getNodeType()

def build(expr):
return switch (expr._which()) {
match ==0 { # literal
def lit := expr.literal()
switch (lit._which()) {
match ==0 {
def litInt := lit.int()
switch (litInt._which()) {
match ==0 { litInt.int32() }
match ==1 { _makeInt(litInt.bigint()) }
}
}
match ==1 { lit.double() }
match ==2 { lit.str() }
match ==3 { '@' - 64 + lit.char() }
match ==4 { lit.bytes() }
}
}
match ==1 {
builder.buildImport(expr.noun())
}
match ==2 {
builder.buildIbid(expr.ibid())
}
match ==3 {
def call := expr.call()
def msg := call.message()
def args := [for arg in (msg.args()) build(arg)]
def nargs := [for n => arg in (msg.namedArgs()) n => build(arg)]
builder.buildCall(build(call.receiver()), msg.verb(), args, nargs)
}
match ==4 { # defExpr
# ISSUE: we're not using the de.index() field. Is it needed?
def de := expr.defExpr()
def [val, _tempIndex] := builder.buildDefine(build(de.rValue()))
val
}
match ==5 { # defRec
# ISSUE: we're not using the dr.promIndex() field. Is it needed?
def dr := expr.defRec()
def promIndex := builder.buildPromise()
return builder.buildDefrec(promIndex + 1, build(dr.rValue()))
}
match other { throw(`not implemented: ${other}`) }
}

def expr := reader.DataExpr(makeMessageReader(msg).getRoot())

return builder.buildRoot(build(expr))
60 changes: 42 additions & 18 deletions mast/capn/montevalue.capnp
Original file line number Diff line number Diff line change
@@ -1,23 +1,47 @@
@0xe2597668ccd0fb6a;

struct MonteValue {
null @0 :Void;
bool @1 :Bool;
int @2 :Int32;
bigint @3 :Data;
double @4 :Float64;
bytes @5 :Data;
text @6 :Text;
list @7 :List(MonteValue);
}
struct DataExpr {
struct Integer {
union {
int32 @0 :Int32;
bigint @1 :Text;
}
}

struct NamedArg {
key @0 :Text;
value @1 :MonteValue;
}
struct NamedArg {
key @0 :Text;
value @1 :DataExpr;
}

union {
literal :union {
int @0 :Integer;
double @1 :Float64;
str @2 :Text;
char @3 :Int32;
bytes @4 :Data;
}

noun @5 :Text;
ibid @6 :Int32;

call :group {
receiver @7 :DataExpr;
message :group {
verb @8 :Text;
args @9 :List(DataExpr);
namedArgs @10 :List(NamedArg);
}
}

defExpr :group {
index @11 :Int32;
rValue @12 :DataExpr;
}

struct MonteMessage {
verb @0 :Text;
args @1 :List(MonteValue);
namedArgs @2 :List(NamedArg);
defRec :group {
promIndex @13 :Int32;
rValue @14 :DataExpr;
}
}
}
51 changes: 51 additions & 0 deletions mast/fun/uneval.mt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import "lib/serial/deSubgraphKit" =~ [=>deSubgraphKit :DeepFrozen]
import "lib/serial/deMNodeKit" =~ [=>deMNodeKit :DeepFrozen]
import "lib/serial/deSrcKit" =~ [=>deSrcKit :DeepFrozen]
import "capn/deCapnKit" =~ [=>deCapnKit :DeepFrozen]
exports (main)

def test(actual, expected) as DeepFrozen:
if (actual == expected):
trace(".")
else:
traceln("")
traceln(`want: $expected`)
traceln(` got: $actual`)


def main(_argv) :Vow[Int] as DeepFrozen:
def s := M.toString

def data := [null, true, false, 1, 2 ** 32 + 123,
# 2.54 messageWriter lacks writeFloat64
# https://github.com/monte-language/typhon/issues/206
"abc",'A',
# b`hello` TODO: Problem: Can't uneval <makeBytes>
]
def dataMsg := deSubgraphKit.recognize(data,
deCapnKit.makeBuilder())
def data2 := deCapnKit.recognize(dataMsg, deSubgraphKit.makeBuilder())
test(data2, data)

def x := [1, x, 3]
test(s(x), "[1, <**CYCLE**>, 3]")

test(s(deSubgraphKit.recognize(x, deSrcKit.makeBuilder())),
"def t_0 := [def t_2 := 1, t_0, def t_4 := 3]")

def ast := deSubgraphKit.recognize(x, deMNodeKit.makeBuilder()).canonical()
# TODO: def makeKernelECopyVisitor := elang_uriGetter("visitors.KernelECopyVisitor")
test(ast, m`def [t_0 :Any, t_1 :Any] := Ref.promise();$\
t_1.resolve(_makeList.run(def t_2 :Any := 1, t_0, def t_4 :Any := 3));$\
t_0`.canonical() :(astBuilder.getAstGuard()))

def output := deSubgraphKit.recognize(x, deCapnKit.makeBuilder())

def xx := deCapnKit.recognize(output, deSubgraphKit.makeBuilder())
test(s(xx), "[1, <**CYCLE**>, 3]")

test(output.size(), 472)
test(output.contains(b`_makeList`), true)
# def stdout := stdio.stdout()
# return when (stdout(output), stdout<-complete()) -> { 0 }
return 0
104 changes: 104 additions & 0 deletions mast/lib/serial/DEBuilderOf.mt
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#!/usr/bin/env rune

# Copyright 2002 Combex, Inc. under the terms of the MIT X license
# found at http://www.opensource.org/licenses/mit-license.html ................

# module "org.erights.e.elib.serial.DEBuilderOf"
import "lib/serial/guards" =~ [=>Guard :DeepFrozen]
exports (DEBuilderOf)

# /**
# * Data-E is the subset of E used for serializing a subgraph by unevaling to an
# * expression.
# *
# * @see <a hrep=
# * "http://www.erights.org/data/serial/jhu-paper/modeling.html#as-eval"
# * >Unserialization as Expression Evaluation</a>.
# * @author Mark S. Miller
# */
def DEBuilderOf.get(Node :Guard, _Root :Guard) :Guard as DeepFrozen {

interface _DEBuilder {

# /**
# * What's the actual type corresponding to the Node type parameter?
# */
to getNodeType() :Guard

# /**
# * What's the actual type corresponding to the Root type parameter?
# */
to getRootType() :Guard

# /**
# * An opportunity to do some post-optimizations, writing out trailers,
# * and closing.
# * <p>
# * [root] => buildRoot()
# * <p>
# * This must appear exactly once at the end.
# */
to buildRoot(root :Node) :Node

# /**
# * For literal values -- ints, float64s, chars, or bare Strings.
# * <p>
# * [] => buildLiteral(value) => [value]
# */
to buildLiteral(value :Any[Int, Double, Char, Str]) :Node

# /**
# * Generates a use-occurrence of a named variable.
# * <p>
# * [] => buildImport(varName) => [value]
# * <p>
# * Load the value of the named variable from the scope.
# */
to buildImport(varName :Str) :Node

# /**
# * Generates a use-occurrence of an temp variable.
# * <p>
# * [] => buildIbid(tempIndex) => [value]
# * <p>
# * Load the value of the temp variable at that index.
# */
to buildIbid(tempIndex :Int) :Node

# /**
# * Generates a call-expression.
# * <p>
# * [rec, arg0,...] => buildCall(verb,arity) => [result]
# */
to buildCall(rec :Node, verb :Str, args :List[Node]) :Node

# /**
# * Allocates the next tempIndex, defines it to hold the value of
# * rValue, and return a pair of the generated definition and the index
# * of the new temp variable.
# * <p>
# * [rValue] => buildDefine() => [rValue]
# * <p>
# * If rValue needs to use the new variable, use
# * buildPromise/buildDefrec instead.
# */
to buildDefine(rValue :Node) :Pair[Node, Int]

# /**
# * Like a forward variable declaration in E (def varName).
# * <p>
# * [] => buildPromise() => []
# * <p>
# * Allocates the next two temp variables. Defines them to hold a
# * promise and its Resolver, respectively.
# */
to buildPromise() :Int

# /**
# * Resolves a promise to the value of rValue.
# * <p>
# * [rValue] => buildDefrec(resolverIndex) => [rValue]
# */
to buildDefrec(resolverIndex :Int, rValue :Node) :Node
}
}
Loading