From f4cc377b11dfa7a2919a297a2f7086261bf15408 Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 5 Apr 2023 20:45:43 +0200 Subject: [PATCH 01/62] start incremental --- eyg/src/node_ffi.js | 5 ++ eyg/test/incremental_test.gleam | 112 ++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 eyg/src/node_ffi.js create mode 100644 eyg/test/incremental_test.gleam diff --git a/eyg/src/node_ffi.js b/eyg/src/node_ffi.js new file mode 100644 index 000000000..5eb020f4d --- /dev/null +++ b/eyg/src/node_ffi.js @@ -0,0 +1,5 @@ +import * as crypto from "node:crypto"; + +export function hash(array) { + return crypto.createHash("sha1").update(array.buffer).digest("hex"); +} diff --git a/eyg/test/incremental_test.gleam b/eyg/test/incremental_test.gleam new file mode 100644 index 000000000..20537a9a8 --- /dev/null +++ b/eyg/test/incremental_test.gleam @@ -0,0 +1,112 @@ +import gleam/bit_string +import gleam/io +import gleam/result +import eygir/expression as e +import gleeunit/should + +pub fn encode_string(label) { + let binary = bit_string.from_string(label) + <> +} + +pub fn linear(source) { + case source { + e.Variable(label) -> <<1, encode_string(label):bit_string>> + e.Lambda(label, body) -> << + 2, + encode_string(label):bit_string, + linear(body):bit_string, + >> + e.Apply(func, arg) -> <<3, linear(func):bit_string, linear(arg):bit_string>> + e.Let(label, value, then) -> << + 4, + encode_string(label):bit_string, + linear(value):bit_string, + linear(then):bit_string, + >> + e.Integer(value) -> <<5, value:32>> + _ -> todo + } +} + +fn decode_label(x, rest) { + use label <- result.then(bit_string.slice(rest, 0, x)) + use rest <- result.then(bit_string.slice( + rest, + x, + bit_string.byte_size(rest) - x, + )) + use label <- result.then(bit_string.to_string(label)) + Ok(#(label, rest)) +} + +pub fn decode(bytes) { + case bytes { + <<1, x, rest:binary>> -> { + use #(label, rest) <- result.then(decode_label(x, rest)) + Ok(#(e.Variable(label), rest)) + } + <<4, x, rest:binary>> -> { + io.debug("matched") + use #(label, rest) <- result.then(decode_label(x, rest)) + use #(value, rest) <- result.then(decode(rest)) + use #(then, rest) <- result.then(decode(rest)) + Ok(#(e.Let(label, value, then), rest)) + } + <<5, value:32, rest:binary>> -> Ok(#(e.Integer(value), rest)) + _ -> { + io.debug(bytes) + todo("some bytes") + } + } +} + +external fn log(a) -> Nil = + "" "console.log" + +// hash and digest +external fn hash(BitString) -> String = + "./node_ffi.js" "hash" + +fn gather_hash(source) { + case source { + <<1, x, rest:binary>> -> { + use part <- result.then(bit_string.slice(rest, 0, x)) + Ok(log(hash(<<1, x, part:bit_string>>))) + } + // TODO need a pop function that doesn't turn to string, i.e.utf16 on JS + + <<4, x, rest:binary>> -> { + io.debug("matched") + use #(label, rest) <- result.then(decode_label(x, rest)) + use #(value, rest) <- result.then(decode(rest)) + use #(then, rest) <- result.then(decode(rest)) + Ok(#(e.Let(label, value, then), rest)) + } + } + // Ok(#(e.Variable(label), rest)) + + // <<4, x, rest:binary>> -> { + // io.debug("matched") + // use #(label, rest) <- result.then(decode_label(x, rest)) + // use #(value, rest) <- result.then(decode(rest)) + // use #(then, rest) <- result.then(decode(rest)) + // Ok(#(e.Let(label, value, then), rest)) + // } + // <<5, value:32, rest:binary>> -> Ok(#(e.Integer(value), rest)) + // _ -> { + // io.debug(bytes) + // todo("some bytes") + // } +} + +pub fn round_trip_test() -> Nil { + let tree = e.Let("xyz", e.Integer(5), e.Variable("xyz")) + let source = linear(tree) + decode(source) + |> should.equal(Ok(#(tree, <<>>))) + + // gather_hash(<<1, 1, "ab":utf8>>) + gather_hash(source) + todo +} From 464ed773b9d92938deb03a2ad341e570e0508f15 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 6 Apr 2023 20:01:23 +0200 Subject: [PATCH 02/62] ziping trees for incremental --- eyg/test/incremental_test.gleam | 320 +++++++++++++++++++++++--------- 1 file changed, 233 insertions(+), 87 deletions(-) diff --git a/eyg/test/incremental_test.gleam b/eyg/test/incremental_test.gleam index 20537a9a8..8794c838d 100644 --- a/eyg/test/incremental_test.gleam +++ b/eyg/test/incremental_test.gleam @@ -1,112 +1,258 @@ -import gleam/bit_string import gleam/io -import gleam/result +import gleam/list +import gleam/map.{Map} +import gleam/option +import gleam/set.{Set} +import gleam/setx import eygir/expression as e -import gleeunit/should -pub fn encode_string(label) { - let binary = bit_string.from_string(label) - <> +pub type Exp { + Var(String) + Fn(String, Int) + Let(String, Int, Int) + Call(Int, Int) + Integer(Int) + String(String) } -pub fn linear(source) { - case source { - e.Variable(label) -> <<1, encode_string(label):bit_string>> - e.Lambda(label, body) -> << - 2, - encode_string(label):bit_string, - linear(body):bit_string, - >> - e.Apply(func, arg) -> <<3, linear(func):bit_string, linear(arg):bit_string>> - e.Let(label, value, then) -> << - 4, - encode_string(label):bit_string, - linear(value):bit_string, - linear(then):bit_string, - >> - e.Integer(value) -> <<5, value:32>> - _ -> todo +type Source = + Map(Int, #(Exp, Set(String))) + +fn let_(label, value, then) { + fn(count) { + let #(count, v) = value(count) + let value_id = count - 1 + let assert Ok(#(_, free_v)) = map.get(v, value_id) + + let #(count, t) = then(count) + let then_id = count - 1 + let assert Ok(#(_, free_t)) = map.get(t, then_id) + let free = set.union(free_v, set.delete(free_t, label)) + + #( + count, + map.merge(v, t) + |> map.insert(count, #(Let(label, value_id, then_id), free)), + ) + } +} + +fn var(x) { + fn(count) { + #( + count + 1, + map.new() + |> map.insert( + count, + #( + Var(x), + set.new() + |> set.insert(x), + ), + ), + ) } } -fn decode_label(x, rest) { - use label <- result.then(bit_string.slice(rest, 0, x)) - use rest <- result.then(bit_string.slice( - rest, - x, - bit_string.byte_size(rest) - x, - )) - use label <- result.then(bit_string.to_string(label)) - Ok(#(label, rest)) +fn integer(i) { + fn(count) { + #( + count + 1, + map.new() + |> map.insert(count, #(Integer(i), set.new())), + ) + } +} + +// TODO ask +// type State { +// State(next: Int) +// } + +// fn fresh(then) { + +// } + +// pub fn function_name() -> Nil { +// use i <- fresh() +// } + +pub type T { + TInt } -pub fn decode(bytes) { - case bytes { - <<1, x, rest:binary>> -> { - use #(label, rest) <- result.then(decode_label(x, rest)) - Ok(#(e.Variable(label), rest)) +fn w(env, exp, source, fresh, cache) { + let assert Ok(#(node, free)) = map.get(source, exp) + io.debug(node) + let #(s, t, fresh, cache) = case node { + Let(label, v, t) -> { + let #(s1, t1, fresh, cache) = w(env, v, source, fresh, cache) + let env1 = map.insert(env, label, t1) + let #(s2, t2, fresh, cache) = w(env1, t, source, fresh, cache) + // TODO real s + #(s2, t2, fresh, cache) } - <<4, x, rest:binary>> -> { - io.debug("matched") - use #(label, rest) <- result.then(decode_label(x, rest)) - use #(value, rest) <- result.then(decode(rest)) - use #(then, rest) <- result.then(decode(rest)) - Ok(#(e.Let(label, value, then), rest)) + Var(x) -> { + let assert Ok(t) = map.get(env, x) + #(Nil, t, fresh, cache) } - <<5, value:32, rest:binary>> -> Ok(#(e.Integer(value), rest)) - _ -> { - io.debug(bytes) - todo("some bytes") + Integer(_) -> #(Nil, TInt, fresh, cache) + + _ -> todo("22w") + } + let cache = + map.update( + cache, + exp, + fn(previous) { + let by_env = option.unwrap(previous, map.new()) + map.insert(by_env, map.take(env, set.to_list(free)), t) + }, + ) + #(s, t, fresh, cache) +} + +fn unzip(cursor, exp, source) { + let id = map.size(source) + let source = map.insert(source, id, exp) + let #(rev, _initial) = cursor + case rev { + [] -> #(id, source) + } + + // [key, parent, ..rest] | [key] parent + // [x, ..rest] -> { + // let assert Ok(#(node, free)) = map.get(source, x) + // } + todo("banana") +} + +// pub fn function_name_test() -> Nil { +// let #(size, source) = let_("x", integer(2), var("x"))(0) +// io.debug(size) +// source +// |> map.to_list +// |> io.debug + +// io.debug("---") +// let path = [0] +// let cursor = zip(source, path, 2) +// io.debug(cursor) + +// io.debug("---!!!!!") +// unzip(cursor, #(String("foo"), set.new()), source) + +// let #(s, t, fresh, cache) = w(map.new(), 2, source, 0, map.new()) +// map.get(cache, 0) +// |> io.debug + +// todo +// } + +fn do_tree_to_ref( + tree, + acc, +) -> #(Exp, set.Set(String), List(#(Exp, set.Set(String)))) { + case tree { + e.Variable(label) -> { + let free = setx.singleton(label) + #(Var(label), free, acc) + } + e.Lambda(label, body) -> { + let #(node, free, acc) = do_tree_to_ref(body, acc) + let index = list.length(acc) + let acc = [#(node, free), ..acc] + let free = set.delete(free, label) + #(Fn(label, index), free, acc) } + e.Let(label, value, then) -> { + let #(then, free_t, acc) = do_tree_to_ref(then, acc) + let then_index = list.length(acc) + let acc = [#(then, free_t), ..acc] + let #(value, free_v, acc) = do_tree_to_ref(value, acc) + let value_index = list.length(acc) + let acc = [#(value, free_v), ..acc] + + let free = set.union(free_v, set.delete(free_t, label)) + #(Let(label, value_index, then_index), free, acc) + } + e.Binary(value) -> { + #(String(value), set.new(), acc) + } + e.Integer(value) -> { + #(Integer(value), set.new(), acc) + } + _ -> todo("rest of ref") } } -external fn log(a) -> Nil = - "" "console.log" +fn tree_to_ref(tree) { + let #(exp, free, acc) = do_tree_to_ref(tree, []) + let index = list.length(acc) + let source = list.reverse([#(exp, free), ..acc]) + #(index, source) +} -// hash and digest -external fn hash(BitString) -> String = - "./node_ffi.js" "hash" +fn zip_match(node, path_element) { + case node, path_element { + Let(_, index, _), 0 -> index -fn gather_hash(source) { - case source { - <<1, x, rest:binary>> -> { - use part <- result.then(bit_string.slice(rest, 0, x)) - Ok(log(hash(<<1, x, part:bit_string>>))) + Let(_, _, index), 1 -> index + Fn(_, index), 0 -> index + } +} + +fn do_zip(path, refs, current, zoom, root) { + case path { + [] -> #([current, ..zoom], root) + [path_element, ..path] -> { + let assert Ok(#(node, _free)) = list.at(refs, current) + io.debug(node) + let zoom = [current, ..zoom] + let current = zip_match(node, path_element) + do_zip(path, refs, current, zoom, root) } - // TODO need a pop function that doesn't turn to string, i.e.utf16 on JS - - <<4, x, rest:binary>> -> { - io.debug("matched") - use #(label, rest) <- result.then(decode_label(x, rest)) - use #(value, rest) <- result.then(decode(rest)) - use #(then, rest) <- result.then(decode(rest)) - Ok(#(e.Let(label, value, then), rest)) + } +} + +// root and refs together from tree +fn zip(path, root, refs) { + case path { + [] -> #([], root) + [path_element, ..path] -> { + let assert Ok(#(node, _free)) = list.at(refs, root) + io.debug(node) + let current = zip_match(node, path_element) + do_zip(path, refs, current, [], root) } } - // Ok(#(e.Variable(label), rest)) - - // <<4, x, rest:binary>> -> { - // io.debug("matched") - // use #(label, rest) <- result.then(decode_label(x, rest)) - // use #(value, rest) <- result.then(decode(rest)) - // use #(then, rest) <- result.then(decode(rest)) - // Ok(#(e.Let(label, value, then), rest)) - // } - // <<5, value:32, rest:binary>> -> Ok(#(e.Integer(value), rest)) - // _ -> { - // io.debug(bytes) - // todo("some bytes") - // } } -pub fn round_trip_test() -> Nil { - let tree = e.Let("xyz", e.Integer(5), e.Variable("xyz")) - let source = linear(tree) - decode(source) - |> should.equal(Ok(#(tree, <<>>))) +pub fn two_test() { + let tree = + e.Let( + "x", + e.Integer(1), + e.Let("y", e.Binary("hey"), e.Lambda("p", e.Variable("y"))), + ) - // gather_hash(<<1, 1, "ab":utf8>>) - gather_hash(source) - todo + let #(root, refs) = tree_to_ref(tree) + io.debug(root) + io.debug(refs) + io.debug(list.at(refs, root)) + + // binary + let path = [1, 0] + let cursor = zip(path, root, refs) + io.debug(cursor) + let [point, ..] = cursor.0 + io.debug(list.at(refs, point)) + let path = [1, 1, 0] + let cursor = zip(path, root, refs) + io.debug(cursor) + let [point, ..] = cursor.0 + io.debug(list.at(refs, point)) } + +// TODO printing map in node +// TODO binary-size in JS match \ No newline at end of file From dd86f6cd5354eac198c6a8b92d3c0f2461e32f9c Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 6 Apr 2023 20:02:06 +0200 Subject: [PATCH 03/62] and the hash test --- eyg/test/hash_test.gleam | 113 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 eyg/test/hash_test.gleam diff --git a/eyg/test/hash_test.gleam b/eyg/test/hash_test.gleam new file mode 100644 index 000000000..18fbee041 --- /dev/null +++ b/eyg/test/hash_test.gleam @@ -0,0 +1,113 @@ +import gleam/bit_string +import gleam/io +import gleam/result +import eygir/expression as e +import gleeunit/should + +pub fn encode_string(label) { + let binary = bit_string.from_string(label) + <> +} + +pub fn linear(source) { + case source { + e.Variable(label) -> <<1, encode_string(label):bit_string>> + e.Lambda(label, body) -> << + 2, + encode_string(label):bit_string, + linear(body):bit_string, + >> + e.Apply(func, arg) -> <<3, linear(func):bit_string, linear(arg):bit_string>> + e.Let(label, value, then) -> << + 4, + encode_string(label):bit_string, + linear(value):bit_string, + linear(then):bit_string, + >> + e.Integer(value) -> <<5, value:32>> + _ -> todo + } +} + +fn decode_label(x, rest) { + use label <- result.then(bit_string.slice(rest, 0, x)) + use rest <- result.then(bit_string.slice( + rest, + x, + bit_string.byte_size(rest) - x, + )) + use label <- result.then(bit_string.to_string(label)) + Ok(#(label, rest)) +} + +pub fn decode(bytes) { + case bytes { + <<1, x, rest:binary>> -> { + use #(label, rest) <- result.then(decode_label(x, rest)) + Ok(#(e.Variable(label), rest)) + } + <<4, x, rest:binary>> -> { + io.debug("matched") + use #(label, rest) <- result.then(decode_label(x, rest)) + use #(value, rest) <- result.then(decode(rest)) + use #(then, rest) <- result.then(decode(rest)) + Ok(#(e.Let(label, value, then), rest)) + } + <<5, value:32, rest:binary>> -> Ok(#(e.Integer(value), rest)) + _ -> { + io.debug(bytes) + todo("some bytes") + } + } +} + +external fn log(a) -> Nil = + "" "console.log" + +// hash and digest +external fn hash(BitString) -> String = + "./node_ffi.js" "hash" + +fn gather_hash(source) { + case source { + <<1, x, rest:binary>> -> { + use part <- result.then(bit_string.slice(rest, 0, x)) + Ok(log(hash(<<1, x, part:bit_string>>))) + } + + // TODO need a pop function that doesn't turn to string, i.e.utf16 on JS + <<4, x, rest:binary>> -> { + io.debug("matched") + use #(label, rest) <- result.then(decode_label(x, rest)) + use #(value, rest) <- result.then(decode(rest)) + use #(then, rest) <- result.then(decode(rest)) + Ok(#(e.Let(label, value, then), rest)) + todo + } + } + // Ok(#(e.Variable(label), rest)) + + // <<4, x, rest:binary>> -> { + // io.debug("matched") + // use #(label, rest) <- result.then(decode_label(x, rest)) + // use #(value, rest) <- result.then(decode(rest)) + // use #(then, rest) <- result.then(decode(rest)) + // Ok(#(e.Let(label, value, then), rest)) + // } + // <<5, value:32, rest:binary>> -> Ok(#(e.Integer(value), rest)) + // _ -> { + // io.debug(bytes) + // todo("some bytes") + // } +} + +pub fn round_trip_test() -> Nil { + let tree = e.Let("xyz", e.Integer(5), e.Variable("xyz")) + let source = linear(tree) + decode(source) + |> should.equal(Ok(#(tree, <<>>))) + + // gather_hash(<<1, 1, "ab":utf8>>) + gather_hash(source) + todo +} From d0ba4b4c3c42b42533e1e54fe21e3dd6ff95a339 Mon Sep 17 00:00:00 2001 From: Peter Saxton Date: Thu, 6 Apr 2023 23:09:41 +0200 Subject: [PATCH 04/62] fix unzipping --- eyg/test/incremental_test.gleam | 94 +++++++++++++-------------------- 1 file changed, 38 insertions(+), 56 deletions(-) diff --git a/eyg/test/incremental_test.gleam b/eyg/test/incremental_test.gleam index 8794c838d..50cad2e37 100644 --- a/eyg/test/incremental_test.gleam +++ b/eyg/test/incremental_test.gleam @@ -64,19 +64,6 @@ fn integer(i) { } } -// TODO ask -// type State { -// State(next: Int) -// } - -// fn fresh(then) { - -// } - -// pub fn function_name() -> Nil { -// use i <- fresh() -// } - pub type T { TInt } @@ -112,43 +99,6 @@ fn w(env, exp, source, fresh, cache) { #(s, t, fresh, cache) } -fn unzip(cursor, exp, source) { - let id = map.size(source) - let source = map.insert(source, id, exp) - let #(rev, _initial) = cursor - case rev { - [] -> #(id, source) - } - - // [key, parent, ..rest] | [key] parent - // [x, ..rest] -> { - // let assert Ok(#(node, free)) = map.get(source, x) - // } - todo("banana") -} - -// pub fn function_name_test() -> Nil { -// let #(size, source) = let_("x", integer(2), var("x"))(0) -// io.debug(size) -// source -// |> map.to_list -// |> io.debug - -// io.debug("---") -// let path = [0] -// let cursor = zip(source, path, 2) -// io.debug(cursor) - -// io.debug("---!!!!!") -// unzip(cursor, #(String("foo"), set.new()), source) - -// let #(s, t, fresh, cache) = w(map.new(), 2, source, 0, map.new()) -// map.get(cache, 0) -// |> io.debug - -// todo -// } - fn do_tree_to_ref( tree, acc, @@ -196,7 +146,6 @@ fn tree_to_ref(tree) { fn zip_match(node, path_element) { case node, path_element { Let(_, index, _), 0 -> index - Let(_, _, index), 1 -> index Fn(_, index), 0 -> index } @@ -207,7 +156,6 @@ fn do_zip(path, refs, current, zoom, root) { [] -> #([current, ..zoom], root) [path_element, ..path] -> { let assert Ok(#(node, _free)) = list.at(refs, current) - io.debug(node) let zoom = [current, ..zoom] let current = zip_match(node, path_element) do_zip(path, refs, current, zoom, root) @@ -221,13 +169,43 @@ fn zip(path, root, refs) { [] -> #([], root) [path_element, ..path] -> { let assert Ok(#(node, _free)) = list.at(refs, root) - io.debug(node) let current = zip_match(node, path_element) do_zip(path, refs, current, [], root) } } } +pub fn do_unzip(old, new, zoom, rev) { + case zoom { + [] -> #(new, list.reverse(rev)) + [next, ..zoom] -> { + let assert Ok(#(node, free)) = list.at(list.reverse(rev), next) + // TODO free + io.debug(#(node, old)) + let exp = case node { + Let(label, value, then) if value == old -> Let(label, new, then) + Let(label, value, then) if then == old -> Let(label, value, new) + Fn(param, body) if body == old -> Fn(param, new) + _ -> todo("moo") + } + // TODO real free + let new = list.length(rev) + let rev = [#(exp, free), ..rev] + do_unzip(next, new, zoom, rev) + } + } +} + +pub fn unzip(tree, cursor, refs) { + let #(exp, free, acc) = do_tree_to_ref(tree, list.reverse(refs)) + let new = list.length(acc) + let rev = [#(exp, free), ..acc] + case cursor { + #([], old) -> do_unzip(old, new, [], rev) + #([old, ..zoom], root) -> do_unzip(old, new, list.append(zoom, [root]), rev) + } +} + pub fn two_test() { let tree = e.Let( @@ -241,18 +219,22 @@ pub fn two_test() { io.debug(refs) io.debug(list.at(refs, root)) - // binary + // binary let path = [1, 0] let cursor = zip(path, root, refs) io.debug(cursor) let [point, ..] = cursor.0 io.debug(list.at(refs, point)) + + unzip(e.Integer(10), cursor, refs) + |> io.debug + + todo("moo") let path = [1, 1, 0] let cursor = zip(path, root, refs) io.debug(cursor) let [point, ..] = cursor.0 io.debug(list.at(refs, point)) } - // TODO printing map in node -// TODO binary-size in JS match \ No newline at end of file +// TODO binary-size in JS match From 2fcb361d4d41bc109b59b64293c02645e7b128d5 Mon Sep 17 00:00:00 2001 From: Peter Saxton Date: Thu, 6 Apr 2023 23:49:32 +0200 Subject: [PATCH 05/62] incremental w --- eyg/test/incremental_test.gleam | 145 +++++++++++++------------------- 1 file changed, 59 insertions(+), 86 deletions(-) diff --git a/eyg/test/incremental_test.gleam b/eyg/test/incremental_test.gleam index 50cad2e37..ec27a1413 100644 --- a/eyg/test/incremental_test.gleam +++ b/eyg/test/incremental_test.gleam @@ -5,6 +5,11 @@ import gleam/option import gleam/set.{Set} import gleam/setx import eygir/expression as e +import eyg/analysis/typ as t +import eyg/analysis/substitutions as sub +import eyg/analysis/scheme.{Scheme} +import eyg/analysis/env +import eyg/analysis/unification pub type Exp { Var(String) @@ -15,90 +20,6 @@ pub type Exp { String(String) } -type Source = - Map(Int, #(Exp, Set(String))) - -fn let_(label, value, then) { - fn(count) { - let #(count, v) = value(count) - let value_id = count - 1 - let assert Ok(#(_, free_v)) = map.get(v, value_id) - - let #(count, t) = then(count) - let then_id = count - 1 - let assert Ok(#(_, free_t)) = map.get(t, then_id) - let free = set.union(free_v, set.delete(free_t, label)) - - #( - count, - map.merge(v, t) - |> map.insert(count, #(Let(label, value_id, then_id), free)), - ) - } -} - -fn var(x) { - fn(count) { - #( - count + 1, - map.new() - |> map.insert( - count, - #( - Var(x), - set.new() - |> set.insert(x), - ), - ), - ) - } -} - -fn integer(i) { - fn(count) { - #( - count + 1, - map.new() - |> map.insert(count, #(Integer(i), set.new())), - ) - } -} - -pub type T { - TInt -} - -fn w(env, exp, source, fresh, cache) { - let assert Ok(#(node, free)) = map.get(source, exp) - io.debug(node) - let #(s, t, fresh, cache) = case node { - Let(label, v, t) -> { - let #(s1, t1, fresh, cache) = w(env, v, source, fresh, cache) - let env1 = map.insert(env, label, t1) - let #(s2, t2, fresh, cache) = w(env1, t, source, fresh, cache) - // TODO real s - #(s2, t2, fresh, cache) - } - Var(x) -> { - let assert Ok(t) = map.get(env, x) - #(Nil, t, fresh, cache) - } - Integer(_) -> #(Nil, TInt, fresh, cache) - - _ -> todo("22w") - } - let cache = - map.update( - cache, - exp, - fn(previous) { - let by_env = option.unwrap(previous, map.new()) - map.insert(by_env, map.take(env, set.to_list(free)), t) - }, - ) - #(s, t, fresh, cache) -} - fn do_tree_to_ref( tree, acc, @@ -180,13 +101,15 @@ pub fn do_unzip(old, new, zoom, rev) { [] -> #(new, list.reverse(rev)) [next, ..zoom] -> { let assert Ok(#(node, free)) = list.at(list.reverse(rev), next) - // TODO free + // TODO free, maybe free should be a separate step io.debug(#(node, old)) let exp = case node { Let(label, value, then) if value == old -> Let(label, new, then) Let(label, value, then) if then == old -> Let(label, value, new) Fn(param, body) if body == old -> Fn(param, new) - _ -> todo("moo") + Call(func, arg) if func == old -> Call(new, arg) + Call(func, arg) if arg == old -> Call(func, new) + _ -> todo("Can't have a path into literal") } // TODO real free let new = list.length(rev) @@ -206,6 +129,55 @@ pub fn unzip(tree, cursor, refs) { } } +fn do_w(env, exp, refs, cache) { + let t = todo + let #(s, t, cache) = case node { + Let(label, v, t) -> { + let #(s1, t1, cache) = w(env, v, refs, cache) + let env1 = map.insert(env, label, t1) + let #(s2, t2, cache) = w(env1, t, refs, cache) + // TODO real s + #(s2, t2, cache) + } + Var(x) -> { + let assert Ok(t) = map.get(env, x) + #(sub.none(), t, cache) + } + Integer(_) -> #(sub.none(), t.Integer, cache) + + _ -> todo("22w") + } +} + +// Need single map of substitutions, is this the efficient J algo? +// Free should be easy in bottom up order assume need value is already present +// probably not fast in edits to std lib. maybe with only part of record field it would be faster. +// but if async and cooperative then we can just manage without as needed. +// TODO have building type stuff happen at startup. try it out in browser +fn w(env, exp, refs, cache) { + let assert Ok(#(node, free)) = list.at(refs, exp) + // can always use small env + let env = map.take(env, set.to_list(free)) + case map.get(cache, exp) { + Ok(envs) -> + case map.get(envs, env) { + Ok(r) -> r + _ -> do_w(env, exp, refs, cache) + } + _ -> do_w(env, exp, refs, cache) + } + let cache = + map.update( + cache, + exp, + fn(previous) { + let by_env = option.unwrap(previous, map.new()) + map.insert(by_env, map.take(env, set.to_list(free)), t) + }, + ) + #(s, t, cache) +} + pub fn two_test() { let tree = e.Let( @@ -226,6 +198,7 @@ pub fn two_test() { let [point, ..] = cursor.0 io.debug(list.at(refs, point)) + w(map.new(), root, refs, map.new()) unzip(e.Integer(10), cursor, refs) |> io.debug From a8282d0222a945e34d454806a99bd18bb7b1426f Mon Sep 17 00:00:00 2001 From: Peter Saxton Date: Fri, 7 Apr 2023 07:08:56 +0200 Subject: [PATCH 06/62] extract free calc --- eyg/test/incremental_and_zip_test.gleam | 218 ++++++++++++++++++++++++ eyg/test/incremental_test.gleam | 179 +++++++++++-------- 2 files changed, 326 insertions(+), 71 deletions(-) create mode 100644 eyg/test/incremental_and_zip_test.gleam diff --git a/eyg/test/incremental_and_zip_test.gleam b/eyg/test/incremental_and_zip_test.gleam new file mode 100644 index 000000000..b268a07e2 --- /dev/null +++ b/eyg/test/incremental_and_zip_test.gleam @@ -0,0 +1,218 @@ +import gleam/io +import gleam/list +import gleam/map.{Map} +import gleam/option +import gleam/set.{Set} +import gleam/setx +import eygir/expression as e +import eyg/analysis/typ as t +import eyg/analysis/substitutions as sub +import eyg/analysis/scheme.{Scheme} +import eyg/analysis/env +import eyg/analysis/unification + +pub type Exp { + Var(String) + Fn(String, Int) + Let(String, Int, Int) + Call(Int, Int) + Integer(Int) + String(String) +} + +fn do_tree_to_ref( + tree, + acc, +) -> #(Exp, set.Set(String), List(#(Exp, set.Set(String)))) { + case tree { + e.Variable(label) -> { + let free = setx.singleton(label) + #(Var(label), free, acc) + } + e.Lambda(label, body) -> { + let #(node, free, acc) = do_tree_to_ref(body, acc) + let index = list.length(acc) + let acc = [#(node, free), ..acc] + let free = set.delete(free, label) + #(Fn(label, index), free, acc) + } + e.Let(label, value, then) -> { + let #(then, free_t, acc) = do_tree_to_ref(then, acc) + let then_index = list.length(acc) + let acc = [#(then, free_t), ..acc] + let #(value, free_v, acc) = do_tree_to_ref(value, acc) + let value_index = list.length(acc) + let acc = [#(value, free_v), ..acc] + + let free = set.union(free_v, set.delete(free_t, label)) + #(Let(label, value_index, then_index), free, acc) + } + e.Binary(value) -> { + #(String(value), set.new(), acc) + } + e.Integer(value) -> { + #(Integer(value), set.new(), acc) + } + _ -> todo("rest of ref") + } +} + +fn tree_to_ref(tree) { + let #(exp, free, acc) = do_tree_to_ref(tree, []) + let index = list.length(acc) + let source = list.reverse([#(exp, free), ..acc]) + #(index, source) +} + +fn zip_match(node, path_element) { + case node, path_element { + Let(_, index, _), 0 -> index + Let(_, _, index), 1 -> index + Fn(_, index), 0 -> index + } +} + +fn do_zip(path, refs, current, zoom, root) { + case path { + [] -> #([current, ..zoom], root) + [path_element, ..path] -> { + let assert Ok(#(node, _free)) = list.at(refs, current) + let zoom = [current, ..zoom] + let current = zip_match(node, path_element) + do_zip(path, refs, current, zoom, root) + } + } +} + +// root and refs together from tree +fn zip(path, root, refs) { + case path { + [] -> #([], root) + [path_element, ..path] -> { + let assert Ok(#(node, _free)) = list.at(refs, root) + let current = zip_match(node, path_element) + do_zip(path, refs, current, [], root) + } + } +} + +pub fn do_unzip(old, new, zoom, rev) { + case zoom { + [] -> #(new, list.reverse(rev)) + [next, ..zoom] -> { + let assert Ok(#(node, free)) = list.at(list.reverse(rev), next) + // TODO free, maybe free should be a separate step + io.debug(#(node, old)) + let exp = case node { + Let(label, value, then) if value == old -> Let(label, new, then) + Let(label, value, then) if then == old -> Let(label, value, new) + Fn(param, body) if body == old -> Fn(param, new) + Call(func, arg) if func == old -> Call(new, arg) + Call(func, arg) if arg == old -> Call(func, new) + _ -> todo("Can't have a path into literal") + } + // TODO real free + let new = list.length(rev) + let rev = [#(exp, free), ..rev] + do_unzip(next, new, zoom, rev) + } + } +} + +pub fn unzip(tree, cursor, refs) { + let #(exp, free, acc) = do_tree_to_ref(tree, list.reverse(refs)) + let new = list.length(acc) + let rev = [#(exp, free), ..acc] + case cursor { + #([], old) -> do_unzip(old, new, [], rev) + #([old, ..zoom], root) -> do_unzip(old, new, list.append(zoom, [root]), rev) + } +} + +// fn do_w(env, exp, refs, cache) { +// let t = todo +// let #(s, t, cache) = case node { +// Let(label, v, t) -> { +// let #(s1, t1, cache) = w(env, v, refs, cache) +// let env1 = map.insert(env, label, t1) +// let #(s2, t2, cache) = w(env1, t, refs, cache) +// // TODO real s +// #(s2, t2, cache) +// } +// Var(x) -> { +// let assert Ok(t) = map.get(env, x) +// #(sub.none(), t, cache) +// } +// Integer(_) -> #(sub.none(), t.Integer, cache) + +// _ -> todo("22w") +// } +// } + +// // Need single map of substitutions, is this the efficient J algo? +// // Free should be easy in bottom up order assume need value is already present +// // probably not fast in edits to std lib. maybe with only part of record field it would be faster. +// // but if async and cooperative then we can just manage without as needed. +// // TODO have building type stuff happen at startup. try it out in browser +// fn w(env, exp, refs, cache) { +// let assert Ok(#(node, free)) = list.at(refs, exp) +// // can always use small env +// let env = map.take(env, set.to_list(free)) +// case map.get(cache, exp) { +// Ok(envs) -> +// case map.get(envs, env) { +// Ok(r) -> r +// _ -> do_w(env, exp, refs, cache) +// } +// _ -> do_w(env, exp, refs, cache) +// } +// let t = todo +// let cache = +// map.update( +// cache, +// exp, +// fn(previous) { +// let by_env = option.unwrap(previous, map.new()) +// map.insert(by_env, map.take(env, set.to_list(free)), t) +// }, +// ) +// #(s, t, cache) +// } + +pub fn w(env, exp, refs, cache) -> Nil { + todo +} + +pub fn two_test() { + let tree = + e.Let( + "x", + e.Integer(1), + e.Let("y", e.Binary("hey"), e.Lambda("p", e.Variable("y"))), + ) + + let #(root, refs) = tree_to_ref(tree) + io.debug(root) + io.debug(refs) + io.debug(list.at(refs, root)) + + // binary + let path = [1, 0] + let cursor = zip(path, root, refs) + io.debug(cursor) + let [point, ..] = cursor.0 + io.debug(list.at(refs, point)) + + w(map.new(), root, refs, map.new()) + unzip(e.Integer(10), cursor, refs) + |> io.debug + + todo("moo") + let path = [1, 1, 0] + let cursor = zip(path, root, refs) + io.debug(cursor) + let [point, ..] = cursor.0 + io.debug(list.at(refs, point)) +} +// TODO printing map in node +// TODO binary-size in JS match diff --git a/eyg/test/incremental_test.gleam b/eyg/test/incremental_test.gleam index ec27a1413..1b23730cc 100644 --- a/eyg/test/incremental_test.gleam +++ b/eyg/test/incremental_test.gleam @@ -20,47 +20,41 @@ pub type Exp { String(String) } -fn do_tree_to_ref( - tree, - acc, -) -> #(Exp, set.Set(String), List(#(Exp, set.Set(String)))) { +fn do_tree_to_ref(tree, acc) -> #(Exp, List(Exp)) { case tree { e.Variable(label) -> { - let free = setx.singleton(label) - #(Var(label), free, acc) + #(Var(label), acc) } e.Lambda(label, body) -> { - let #(node, free, acc) = do_tree_to_ref(body, acc) + let #(node, acc) = do_tree_to_ref(body, acc) let index = list.length(acc) - let acc = [#(node, free), ..acc] - let free = set.delete(free, label) - #(Fn(label, index), free, acc) + let acc = [node, ..acc] + #(Fn(label, index), acc) } e.Let(label, value, then) -> { - let #(then, free_t, acc) = do_tree_to_ref(then, acc) + let #(then, acc) = do_tree_to_ref(then, acc) let then_index = list.length(acc) - let acc = [#(then, free_t), ..acc] - let #(value, free_v, acc) = do_tree_to_ref(value, acc) + let acc = [then, ..acc] + let #(value, acc) = do_tree_to_ref(value, acc) let value_index = list.length(acc) - let acc = [#(value, free_v), ..acc] + let acc = [value, ..acc] - let free = set.union(free_v, set.delete(free_t, label)) - #(Let(label, value_index, then_index), free, acc) + #(Let(label, value_index, then_index), acc) } e.Binary(value) -> { - #(String(value), set.new(), acc) + #(String(value), acc) } e.Integer(value) -> { - #(Integer(value), set.new(), acc) + #(Integer(value), acc) } _ -> todo("rest of ref") } } fn tree_to_ref(tree) { - let #(exp, free, acc) = do_tree_to_ref(tree, []) + let #(exp, acc) = do_tree_to_ref(tree, []) let index = list.length(acc) - let source = list.reverse([#(exp, free), ..acc]) + let source = list.reverse([exp, ..acc]) #(index, source) } @@ -76,7 +70,7 @@ fn do_zip(path, refs, current, zoom, root) { case path { [] -> #([current, ..zoom], root) [path_element, ..path] -> { - let assert Ok(#(node, _free)) = list.at(refs, current) + let assert Ok(node) = list.at(refs, current) let zoom = [current, ..zoom] let current = zip_match(node, path_element) do_zip(path, refs, current, zoom, root) @@ -89,7 +83,7 @@ fn zip(path, root, refs) { case path { [] -> #([], root) [path_element, ..path] -> { - let assert Ok(#(node, _free)) = list.at(refs, root) + let assert Ok(node) = list.at(refs, root) let current = zip_match(node, path_element) do_zip(path, refs, current, [], root) } @@ -100,9 +94,7 @@ pub fn do_unzip(old, new, zoom, rev) { case zoom { [] -> #(new, list.reverse(rev)) [next, ..zoom] -> { - let assert Ok(#(node, free)) = list.at(list.reverse(rev), next) - // TODO free, maybe free should be a separate step - io.debug(#(node, old)) + let assert Ok(node) = list.at(list.reverse(rev), next) let exp = case node { Let(label, value, then) if value == old -> Let(label, new, then) Let(label, value, then) if then == old -> Let(label, value, new) @@ -111,71 +103,112 @@ pub fn do_unzip(old, new, zoom, rev) { Call(func, arg) if arg == old -> Call(func, new) _ -> todo("Can't have a path into literal") } - // TODO real free let new = list.length(rev) - let rev = [#(exp, free), ..rev] + let rev = [exp, ..rev] do_unzip(next, new, zoom, rev) } } } pub fn unzip(tree, cursor, refs) { - let #(exp, free, acc) = do_tree_to_ref(tree, list.reverse(refs)) + let #(exp, acc) = do_tree_to_ref(tree, list.reverse(refs)) let new = list.length(acc) - let rev = [#(exp, free), ..acc] + let rev = [exp, ..acc] case cursor { #([], old) -> do_unzip(old, new, [], rev) #([old, ..zoom], root) -> do_unzip(old, new, list.append(zoom, [root]), rev) } } -fn do_w(env, exp, refs, cache) { - let t = todo - let #(s, t, cache) = case node { - Let(label, v, t) -> { - let #(s1, t1, cache) = w(env, v, refs, cache) - let env1 = map.insert(env, label, t1) - let #(s2, t2, cache) = w(env1, t, refs, cache) - // TODO real s - #(s2, t2, cache) - } - Var(x) -> { - let assert Ok(t) = map.get(env, x) - #(sub.none(), t, cache) - } - Integer(_) -> #(sub.none(), t.Integer, cache) +// fn do_w(env, exp, refs, cache) { +// let t = todo +// let #(s, t, cache) = case node { +// Let(label, v, t) -> { +// let #(s1, t1, cache) = w(env, v, refs, cache) +// let env1 = map.insert(env, label, t1) +// let #(s2, t2, cache) = w(env1, t, refs, cache) +// // TODO real s +// #(s2, t2, cache) +// } +// Var(x) -> { +// let assert Ok(t) = map.get(env, x) +// #(sub.none(), t, cache) +// } +// Integer(_) -> #(sub.none(), t.Integer, cache) + +// _ -> todo("22w") +// } +// } + +// // Need single map of substitutions, is this the efficient J algo? +// // Free should be easy in bottom up order assume need value is already present +// // probably not fast in edits to std lib. maybe with only part of record field it would be faster. +// // but if async and cooperative then we can just manage without as needed. +// // TODO have building type stuff happen at startup. try it out in browser +// fn w(env, exp, refs, cache) { +// let assert Ok(#(node, free)) = list.at(refs, exp) +// // can always use small env +// let env = map.take(env, set.to_list(free)) +// case map.get(cache, exp) { +// Ok(envs) -> +// case map.get(envs, env) { +// Ok(r) -> r +// _ -> do_w(env, exp, refs, cache) +// } +// _ -> do_w(env, exp, refs, cache) +// } +// let t = todo +// let cache = +// map.update( +// cache, +// exp, +// fn(previous) { +// let by_env = option.unwrap(previous, map.new()) +// map.insert(by_env, map.take(env, set.to_list(free)), t) +// }, +// ) +// #(s, t, cache) +// } + +pub fn w(env, exp, refs, cache) -> Nil { + todo +} - _ -> todo("22w") - } +fn from_end(items, i) { + list.at(items, list.length(items) - 1 - i) } -// Need single map of substitutions, is this the efficient J algo? -// Free should be easy in bottom up order assume need value is already present -// probably not fast in edits to std lib. maybe with only part of record field it would be faster. -// but if async and cooperative then we can just manage without as needed. -// TODO have building type stuff happen at startup. try it out in browser -fn w(env, exp, refs, cache) { - let assert Ok(#(node, free)) = list.at(refs, exp) - // can always use small env - let env = map.take(env, set.to_list(free)) - case map.get(cache, exp) { - Ok(envs) -> - case map.get(envs, env) { - Ok(r) -> r - _ -> do_w(env, exp, refs, cache) +pub fn do_free(rest, acc) { + case rest { + [] -> list.reverse(acc) + [node, ..rest] -> { + let free = case node { + Var(x) -> setx.singleton(x) + Fn(x, ref) -> { + let assert Ok(body) = from_end(acc, ref) + set.delete(body, x) + } + Let(x, ref_v, ref_t) -> { + let assert Ok(value) = from_end(acc, ref_v) + let assert Ok(then) = from_end(acc, ref_t) + set.union(value, set.delete(then, x)) + } + Call(ref_func, ref_arg) -> { + let assert Ok(func) = from_end(acc, ref_func) + let assert Ok(arg) = from_end(acc, ref_arg) + set.union(func, arg) + } + + Integer(_) -> set.new() + String(_) -> set.new() } - _ -> do_w(env, exp, refs, cache) + do_free(rest, [free, ..acc]) + } } - let cache = - map.update( - cache, - exp, - fn(previous) { - let by_env = option.unwrap(previous, map.new()) - map.insert(by_env, map.take(env, set.to_list(free)), t) - }, - ) - #(s, t, cache) +} + +pub fn free(refs) { + do_free(refs, []) } pub fn two_test() { @@ -189,6 +222,10 @@ pub fn two_test() { let #(root, refs) = tree_to_ref(tree) io.debug(root) io.debug(refs) + io.debug( + free(refs) + |> list.map(set.to_list), + ) io.debug(list.at(refs, root)) // binary From 8d1811f18961a15e1447bf49dca522af6bfbb183 Mon Sep 17 00:00:00 2001 From: Peter Saxton Date: Fri, 7 Apr 2023 07:22:08 +0200 Subject: [PATCH 07/62] free with previous --- eyg/test/incremental_test.gleam | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/eyg/test/incremental_test.gleam b/eyg/test/incremental_test.gleam index 1b23730cc..2f2f47aaa 100644 --- a/eyg/test/incremental_test.gleam +++ b/eyg/test/incremental_test.gleam @@ -207,8 +207,8 @@ pub fn do_free(rest, acc) { } } -pub fn free(refs) { - do_free(refs, []) +pub fn free(refs, previous) { + do_free(list.drop(refs, list.length(previous)), list.reverse(previous)) } pub fn two_test() { @@ -222,10 +222,8 @@ pub fn two_test() { let #(root, refs) = tree_to_ref(tree) io.debug(root) io.debug(refs) - io.debug( - free(refs) - |> list.map(set.to_list), - ) + let f = free(refs, []) + io.debug(list.map(f, set.to_list)) io.debug(list.at(refs, root)) // binary @@ -235,9 +233,12 @@ pub fn two_test() { let [point, ..] = cursor.0 io.debug(list.at(refs, point)) - w(map.new(), root, refs, map.new()) - unzip(e.Integer(10), cursor, refs) - |> io.debug + // w(map.new(), root, refs, map.new()) + let #(root, refs) = unzip(e.Variable("x"), cursor, refs) + + io.debug(refs) + let f2 = free(refs, f) + io.debug(list.map(f2, set.to_list)) todo("moo") let path = [1, 1, 0] From e687b5e0313809607d89c11d980a724f073f510d Mon Sep 17 00:00:00 2001 From: Peter Saxton Date: Fri, 7 Apr 2023 10:43:40 +0200 Subject: [PATCH 08/62] cached --- eyg/test/incremental_test.gleam | 139 +++++++++++++++++++------------- 1 file changed, 84 insertions(+), 55 deletions(-) diff --git a/eyg/test/incremental_test.gleam b/eyg/test/incremental_test.gleam index 2f2f47aaa..35e3823a8 100644 --- a/eyg/test/incremental_test.gleam +++ b/eyg/test/incremental_test.gleam @@ -2,8 +2,10 @@ import gleam/io import gleam/list import gleam/map.{Map} import gleam/option +import gleam/result import gleam/set.{Set} import gleam/setx +import gleam/javascript import eygir/expression as e import eyg/analysis/typ as t import eyg/analysis/substitutions as sub @@ -120,60 +122,6 @@ pub fn unzip(tree, cursor, refs) { } } -// fn do_w(env, exp, refs, cache) { -// let t = todo -// let #(s, t, cache) = case node { -// Let(label, v, t) -> { -// let #(s1, t1, cache) = w(env, v, refs, cache) -// let env1 = map.insert(env, label, t1) -// let #(s2, t2, cache) = w(env1, t, refs, cache) -// // TODO real s -// #(s2, t2, cache) -// } -// Var(x) -> { -// let assert Ok(t) = map.get(env, x) -// #(sub.none(), t, cache) -// } -// Integer(_) -> #(sub.none(), t.Integer, cache) - -// _ -> todo("22w") -// } -// } - -// // Need single map of substitutions, is this the efficient J algo? -// // Free should be easy in bottom up order assume need value is already present -// // probably not fast in edits to std lib. maybe with only part of record field it would be faster. -// // but if async and cooperative then we can just manage without as needed. -// // TODO have building type stuff happen at startup. try it out in browser -// fn w(env, exp, refs, cache) { -// let assert Ok(#(node, free)) = list.at(refs, exp) -// // can always use small env -// let env = map.take(env, set.to_list(free)) -// case map.get(cache, exp) { -// Ok(envs) -> -// case map.get(envs, env) { -// Ok(r) -> r -// _ -> do_w(env, exp, refs, cache) -// } -// _ -> do_w(env, exp, refs, cache) -// } -// let t = todo -// let cache = -// map.update( -// cache, -// exp, -// fn(previous) { -// let by_env = option.unwrap(previous, map.new()) -// map.insert(by_env, map.take(env, set.to_list(free)), t) -// }, -// ) -// #(s, t, cache) -// } - -pub fn w(env, exp, refs, cache) -> Nil { - todo -} - fn from_end(items, i) { list.at(items, list.length(items) - 1 - i) } @@ -211,6 +159,79 @@ pub fn free(refs, previous) { do_free(list.drop(refs, list.length(previous)), list.reverse(previous)) } +// TODO incremental/source +// TODO incremental/free +// TODO incremental/cursor.{from_path, replace} + +// fn do_w(env, exp, refs, cache) { +// let t = todo +// let #(s, t, cache) = case node { +// Let(label, v, t) -> { +// let #(s1, t1, cache) = w(env, v, refs, cache) +// let env1 = map.insert(env, label, t1) +// let #(s2, t2, cache) = w(env1, t, refs, cache) +// // TODO real s +// #(s2, t2, cache) +// } +// Var(x) -> { +// let assert Ok(t) = map.get(env, x) +// #(sub.none(), t, cache) +// } +// Integer(_) -> #(sub.none(), t.Integer, cache) + +// _ -> todo("22w") +// } +// } + +// // Need single map of substitutions, is this the efficient J algo? +// // Free should be easy in bottom up order assume need value is already present +// // probably not fast in edits to std lib. maybe with only part of record field it would be faster. +// // but if async and cooperative then we can just manage without as needed. +// // TODO have building type stuff happen at startup. try it out in browser + +// TODO test calling the same node twice hits the cach + +fn cache_lookup(cache, ref, env) { + use envs <- result.then(map.get(cache, ref)) + map.get(envs, env) +} + +// frees can be built lazily as a map +// hash cache can exist for saving to file +pub fn cached(ref: Int, source, frees, types, env, subs, count) { + let assert Ok(free) = list.at(frees, ref) + let required = map.take(env, set.to_list(free)) + case cache_lookup(types, ref, required) { + Ok(t) -> #(t, subs, types) + Error(Nil) -> { + let assert Ok(node) = list.at(source, ref) + case node { + Let(x, value, then) -> { + let #(t1, subs, types) = + cached(value, source, frees, types, env, subs, count) + let scheme = unification.generalise(env, t1) + let env = map.insert(env, x, scheme) + cached(then, source, frees, types, env, subs, count) + } + Fn(x, body) -> { + let param = unification.fresh(count) + let env = map.insert(env, x, Scheme([], t.Unbound(param))) + let #(body, subs, types) = + cached(body, source, frees, types, env, subs, count) + let t = t.Fun(t.Unbound(param), t.Closed, body) + #(t, subs, types) + } + Integer(_) -> #(t.Integer, subs, types) + String(_) -> #(t.Binary, subs, types) + _ -> { + io.debug(node) + todo("other nodes") + } + } + } + } +} + pub fn two_test() { let tree = e.Let( @@ -233,7 +254,15 @@ pub fn two_test() { let [point, ..] = cursor.0 io.debug(list.at(refs, point)) - // w(map.new(), root, refs, map.new()) + cached( + root, + refs, + f, + map.new(), + env.empty(), + sub.none(), + javascript.make_reference(0), + ) let #(root, refs) = unzip(e.Variable("x"), cursor, refs) io.debug(refs) From df12d1df82096b5fd83c2d636e13480b95311006 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 7 Apr 2023 11:09:30 +0200 Subject: [PATCH 09/62] rest of type checking --- eyg/test/incremental_test.gleam | 59 +++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/eyg/test/incremental_test.gleam b/eyg/test/incremental_test.gleam index 35e3823a8..faae0857e 100644 --- a/eyg/test/incremental_test.gleam +++ b/eyg/test/incremental_test.gleam @@ -192,8 +192,22 @@ pub fn free(refs, previous) { // TODO test calling the same node twice hits the cach fn cache_lookup(cache, ref, env) { - use envs <- result.then(map.get(cache, ref)) + io.debug(#("-----------", ref, env)) + use envs <- result.then(io.debug(map.get(cache, ref))) + map.get(envs, env) + |> io.debug +} + +fn cache_update(cache, ref, env, t) { + map.update( + cache, + ref, + fn(cached) { + option.unwrap(cached, map.new()) + |> map.insert(env, t) + }, + ) } // frees can be built lazily as a map @@ -205,7 +219,16 @@ pub fn cached(ref: Int, source, frees, types, env, subs, count) { Ok(t) -> #(t, subs, types) Error(Nil) -> { let assert Ok(node) = list.at(source, ref) - case node { + let #(t, subs, cache) = case node { + Var(x) -> { + case map.get(env, x) { + Ok(scheme) -> { + let t = unification.instantiate(scheme, count) + #(t, subs, types) + } + Error(Nil) -> todo("no var") + } + } Let(x, value, then) -> { let #(t1, subs, types) = cached(value, source, frees, types, env, subs, count) @@ -228,11 +251,15 @@ pub fn cached(ref: Int, source, frees, types, env, subs, count) { todo("other nodes") } } + let cache = cache_update(cache, ref, required, t) + #(t, subs, cache) } } } pub fn two_test() { + todo("moo") + let tree = e.Let( "x", @@ -254,27 +281,33 @@ pub fn two_test() { let [point, ..] = cursor.0 io.debug(list.at(refs, point)) - cached( - root, - refs, - f, - map.new(), - env.empty(), - sub.none(), - javascript.make_reference(0), - ) - let #(root, refs) = unzip(e.Variable("x"), cursor, refs) + let count = javascript.make_reference(0) + let #(t, subs, cache) = + cached(root, refs, f, map.new(), env.empty(), sub.none(), count) + io.debug(t) + let #(root, refs) = unzip(e.Integer(3), cursor, refs) io.debug(refs) let f2 = free(refs, f) io.debug(list.map(f2, set.to_list)) - todo("moo") let path = [1, 1, 0] let cursor = zip(path, root, refs) io.debug(cursor) let [point, ..] = cursor.0 io.debug(list.at(refs, point)) + + io.debug("====") + io.debug(cache) + io.debug("====") + + let #(t2, subs, cache) = + cached(root, refs, f2, cache, env.empty(), subs, count) + io.debug(t2) } // TODO printing map in node // TODO binary-size in JS match + +pub fn all_test() { + +} From 4265552b10c313d9c6882b637f478e0151330287 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 7 Apr 2023 11:26:13 +0200 Subject: [PATCH 10/62] extract incremental files --- eyg/src/eyg/incremental/cursor.gleam | 66 ++++++ eyg/src/eyg/incremental/inference.gleam | 128 +++++++++++ eyg/src/eyg/incremental/source.gleam | 62 ++++++ eyg/test/incremental_test.gleam | 268 ++---------------------- 4 files changed, 270 insertions(+), 254 deletions(-) create mode 100644 eyg/src/eyg/incremental/cursor.gleam create mode 100644 eyg/src/eyg/incremental/inference.gleam create mode 100644 eyg/src/eyg/incremental/source.gleam diff --git a/eyg/src/eyg/incremental/cursor.gleam b/eyg/src/eyg/incremental/cursor.gleam new file mode 100644 index 000000000..dfa283b04 --- /dev/null +++ b/eyg/src/eyg/incremental/cursor.gleam @@ -0,0 +1,66 @@ +import gleam/list +import eygir/expression as e +import eyg/incremental/source.{Call, Fn, Let} + +fn zip_match(node, path_element) { + case node, path_element { + Let(_, index, _), 0 -> index + Let(_, _, index), 1 -> index + Fn(_, index), 0 -> index + } +} + +fn do_at(path, refs, current, zoom, root) { + case path { + [] -> #([current, ..zoom], root) + [path_element, ..path] -> { + let assert Ok(node) = list.at(refs, current) + let zoom = [current, ..zoom] + let current = zip_match(node, path_element) + do_at(path, refs, current, zoom, root) + } + } +} + +// root and refs together from tree +pub fn at(path, root, refs) { + case path { + [] -> #([], root) + [path_element, ..path] -> { + let assert Ok(node) = list.at(refs, root) + let current = zip_match(node, path_element) + do_at(path, refs, current, [], root) + } + } +} + +fn do_replace(old, new, zoom, rev) { + case zoom { + [] -> #(new, list.reverse(rev)) + [next, ..zoom] -> { + let assert Ok(node) = list.at(list.reverse(rev), next) + let exp = case node { + Let(label, value, then) if value == old -> Let(label, new, then) + Let(label, value, then) if then == old -> Let(label, value, new) + Fn(param, body) if body == old -> Fn(param, new) + Call(func, arg) if func == old -> Call(new, arg) + Call(func, arg) if arg == old -> Call(func, new) + _ -> todo("Can't have a path into literal") + } + let new = list.length(rev) + let rev = [exp, ..rev] + do_replace(next, new, zoom, rev) + } + } +} + +pub fn replace(tree, cursor, refs) { + let #(exp, acc) = source.do_from_tree(tree, list.reverse(refs)) + let new = list.length(acc) + let rev = [exp, ..acc] + case cursor { + #([], old) -> do_replace(old, new, [], rev) + #([old, ..zoom], root) -> + do_replace(old, new, list.append(zoom, [root]), rev) + } +} diff --git a/eyg/src/eyg/incremental/inference.gleam b/eyg/src/eyg/incremental/inference.gleam new file mode 100644 index 000000000..ad92cfee0 --- /dev/null +++ b/eyg/src/eyg/incremental/inference.gleam @@ -0,0 +1,128 @@ +import gleam/io +import gleam/list +import gleam/map.{Map} +import gleam/option +import gleam/result +import gleam/set.{Set} +import gleam/setx +import gleam/javascript +import eygir/expression as e +import eyg/analysis/typ as t +import eyg/analysis/substitutions as sub +import eyg/analysis/scheme.{Scheme} +import eyg/analysis/env +import eyg/analysis/unification +import eyg/incremental/source +import eyg/incremental/cursor + +fn from_end(items, i) { + list.at(items, list.length(items) - 1 - i) +} + +fn do_free(rest, acc) { + case rest { + [] -> list.reverse(acc) + [node, ..rest] -> { + let free = case node { + source.Var(x) -> setx.singleton(x) + source.Fn(x, ref) -> { + let assert Ok(body) = from_end(acc, ref) + set.delete(body, x) + } + source.Let(x, ref_v, ref_t) -> { + let assert Ok(value) = from_end(acc, ref_v) + let assert Ok(then) = from_end(acc, ref_t) + set.union(value, set.delete(then, x)) + } + source.Call(ref_func, ref_arg) -> { + let assert Ok(func) = from_end(acc, ref_func) + let assert Ok(arg) = from_end(acc, ref_arg) + set.union(func, arg) + } + _ -> set.new() + } + do_free(rest, [free, ..acc]) + } + } +} + +pub fn free(refs, previous) { + do_free(list.drop(refs, list.length(previous)), list.reverse(previous)) +} + +// TODO incremental/free +// TODO incremental/cursor.{from_path, replace} + +// // Need single map of substitutions, is this the efficient J algo? +// // Free should be easy in bottom up order assume need value is already present +// // probably not fast in edits to std lib. maybe with only part of record field it would be faster. +// // but if async and cooperative then we can just manage without as needed. +// // TODO have building type stuff happen at startup. try it out in browser + +// TODO test calling the same node twice hits the cach + +fn cache_lookup(cache, ref, env) { + io.debug(#("-----------", ref, env)) + use envs <- result.then(io.debug(map.get(cache, ref))) + + map.get(envs, env) + |> io.debug +} + +fn cache_update(cache, ref, env, t) { + map.update( + cache, + ref, + fn(cached) { + option.unwrap(cached, map.new()) + |> map.insert(env, t) + }, + ) +} + +// frees can be built lazily as a map +// hash cache can exist for saving to file +pub fn cached(ref: Int, source, frees, types, env, subs, count) { + let assert Ok(free) = list.at(frees, ref) + let required = map.take(env, set.to_list(free)) + case cache_lookup(types, ref, required) { + Ok(t) -> #(t, subs, types) + Error(Nil) -> { + let assert Ok(node) = list.at(source, ref) + let #(t, subs, cache) = case node { + source.Var(x) -> { + case map.get(env, x) { + Ok(scheme) -> { + let t = unification.instantiate(scheme, count) + #(t, subs, types) + } + Error(Nil) -> todo("no var") + } + } + source.Let(x, value, then) -> { + let #(t1, subs, types) = + cached(value, source, frees, types, env, subs, count) + let scheme = unification.generalise(env, t1) + let env = map.insert(env, x, scheme) + cached(then, source, frees, types, env, subs, count) + } + source.Fn(x, body) -> { + let param = unification.fresh(count) + let env = map.insert(env, x, Scheme([], t.Unbound(param))) + let #(body, subs, types) = + cached(body, source, frees, types, env, subs, count) + let t = t.Fun(t.Unbound(param), t.Closed, body) + #(t, subs, types) + } + source.Integer(_) -> #(t.Integer, subs, types) + source.String(_) -> #(t.Binary, subs, types) + _ -> { + io.debug(node) + todo("other nodes") + } + } + let cache = cache_update(cache, ref, required, t) + #(t, subs, cache) + } + } +} diff --git a/eyg/src/eyg/incremental/source.gleam b/eyg/src/eyg/incremental/source.gleam new file mode 100644 index 000000000..b5d70e8ab --- /dev/null +++ b/eyg/src/eyg/incremental/source.gleam @@ -0,0 +1,62 @@ +import gleam/list +import eygir/expression as e + +pub type Expression { + Var(String) + Fn(String, Int) + Let(String, Int, Int) + Call(Int, Int) + Integer(Int) + String(String) + Tail + Cons + Vacant(comment: String) + Empty + Extend(label: String) + Select(label: String) + Overwrite(label: String) + Tag(label: String) + Case(label: String) + NoCases + Perform(label: String) + Handle(label: String) + Builtin(identifier: String) +} + +pub fn do_from_tree(tree, acc) { + case tree { + e.Variable(label) -> { + #(Var(label), acc) + } + e.Lambda(label, body) -> { + let #(node, acc) = do_from_tree(body, acc) + let index = list.length(acc) + let acc = [node, ..acc] + #(Fn(label, index), acc) + } + e.Let(label, value, then) -> { + let #(then, acc) = do_from_tree(then, acc) + let then_index = list.length(acc) + let acc = [then, ..acc] + let #(value, acc) = do_from_tree(value, acc) + let value_index = list.length(acc) + let acc = [value, ..acc] + + #(Let(label, value_index, then_index), acc) + } + e.Binary(value) -> { + #(String(value), acc) + } + e.Integer(value) -> { + #(Integer(value), acc) + } + _ -> todo("rest of ref") + } +} + +pub fn from_tree(tree) { + let #(exp, acc) = do_from_tree(tree, []) + let index = list.length(acc) + let source = list.reverse([exp, ..acc]) + #(index, source) +} diff --git a/eyg/test/incremental_test.gleam b/eyg/test/incremental_test.gleam index faae0857e..3dafab26e 100644 --- a/eyg/test/incremental_test.gleam +++ b/eyg/test/incremental_test.gleam @@ -12,253 +12,12 @@ import eyg/analysis/substitutions as sub import eyg/analysis/scheme.{Scheme} import eyg/analysis/env import eyg/analysis/unification - -pub type Exp { - Var(String) - Fn(String, Int) - Let(String, Int, Int) - Call(Int, Int) - Integer(Int) - String(String) -} - -fn do_tree_to_ref(tree, acc) -> #(Exp, List(Exp)) { - case tree { - e.Variable(label) -> { - #(Var(label), acc) - } - e.Lambda(label, body) -> { - let #(node, acc) = do_tree_to_ref(body, acc) - let index = list.length(acc) - let acc = [node, ..acc] - #(Fn(label, index), acc) - } - e.Let(label, value, then) -> { - let #(then, acc) = do_tree_to_ref(then, acc) - let then_index = list.length(acc) - let acc = [then, ..acc] - let #(value, acc) = do_tree_to_ref(value, acc) - let value_index = list.length(acc) - let acc = [value, ..acc] - - #(Let(label, value_index, then_index), acc) - } - e.Binary(value) -> { - #(String(value), acc) - } - e.Integer(value) -> { - #(Integer(value), acc) - } - _ -> todo("rest of ref") - } -} - -fn tree_to_ref(tree) { - let #(exp, acc) = do_tree_to_ref(tree, []) - let index = list.length(acc) - let source = list.reverse([exp, ..acc]) - #(index, source) -} - -fn zip_match(node, path_element) { - case node, path_element { - Let(_, index, _), 0 -> index - Let(_, _, index), 1 -> index - Fn(_, index), 0 -> index - } -} - -fn do_zip(path, refs, current, zoom, root) { - case path { - [] -> #([current, ..zoom], root) - [path_element, ..path] -> { - let assert Ok(node) = list.at(refs, current) - let zoom = [current, ..zoom] - let current = zip_match(node, path_element) - do_zip(path, refs, current, zoom, root) - } - } -} - -// root and refs together from tree -fn zip(path, root, refs) { - case path { - [] -> #([], root) - [path_element, ..path] -> { - let assert Ok(node) = list.at(refs, root) - let current = zip_match(node, path_element) - do_zip(path, refs, current, [], root) - } - } -} - -pub fn do_unzip(old, new, zoom, rev) { - case zoom { - [] -> #(new, list.reverse(rev)) - [next, ..zoom] -> { - let assert Ok(node) = list.at(list.reverse(rev), next) - let exp = case node { - Let(label, value, then) if value == old -> Let(label, new, then) - Let(label, value, then) if then == old -> Let(label, value, new) - Fn(param, body) if body == old -> Fn(param, new) - Call(func, arg) if func == old -> Call(new, arg) - Call(func, arg) if arg == old -> Call(func, new) - _ -> todo("Can't have a path into literal") - } - let new = list.length(rev) - let rev = [exp, ..rev] - do_unzip(next, new, zoom, rev) - } - } -} - -pub fn unzip(tree, cursor, refs) { - let #(exp, acc) = do_tree_to_ref(tree, list.reverse(refs)) - let new = list.length(acc) - let rev = [exp, ..acc] - case cursor { - #([], old) -> do_unzip(old, new, [], rev) - #([old, ..zoom], root) -> do_unzip(old, new, list.append(zoom, [root]), rev) - } -} - -fn from_end(items, i) { - list.at(items, list.length(items) - 1 - i) -} - -pub fn do_free(rest, acc) { - case rest { - [] -> list.reverse(acc) - [node, ..rest] -> { - let free = case node { - Var(x) -> setx.singleton(x) - Fn(x, ref) -> { - let assert Ok(body) = from_end(acc, ref) - set.delete(body, x) - } - Let(x, ref_v, ref_t) -> { - let assert Ok(value) = from_end(acc, ref_v) - let assert Ok(then) = from_end(acc, ref_t) - set.union(value, set.delete(then, x)) - } - Call(ref_func, ref_arg) -> { - let assert Ok(func) = from_end(acc, ref_func) - let assert Ok(arg) = from_end(acc, ref_arg) - set.union(func, arg) - } - - Integer(_) -> set.new() - String(_) -> set.new() - } - do_free(rest, [free, ..acc]) - } - } -} - -pub fn free(refs, previous) { - do_free(list.drop(refs, list.length(previous)), list.reverse(previous)) -} - -// TODO incremental/source -// TODO incremental/free -// TODO incremental/cursor.{from_path, replace} - -// fn do_w(env, exp, refs, cache) { -// let t = todo -// let #(s, t, cache) = case node { -// Let(label, v, t) -> { -// let #(s1, t1, cache) = w(env, v, refs, cache) -// let env1 = map.insert(env, label, t1) -// let #(s2, t2, cache) = w(env1, t, refs, cache) -// // TODO real s -// #(s2, t2, cache) -// } -// Var(x) -> { -// let assert Ok(t) = map.get(env, x) -// #(sub.none(), t, cache) -// } -// Integer(_) -> #(sub.none(), t.Integer, cache) - -// _ -> todo("22w") -// } -// } - -// // Need single map of substitutions, is this the efficient J algo? -// // Free should be easy in bottom up order assume need value is already present -// // probably not fast in edits to std lib. maybe with only part of record field it would be faster. -// // but if async and cooperative then we can just manage without as needed. -// // TODO have building type stuff happen at startup. try it out in browser - -// TODO test calling the same node twice hits the cach - -fn cache_lookup(cache, ref, env) { - io.debug(#("-----------", ref, env)) - use envs <- result.then(io.debug(map.get(cache, ref))) - - map.get(envs, env) - |> io.debug -} - -fn cache_update(cache, ref, env, t) { - map.update( - cache, - ref, - fn(cached) { - option.unwrap(cached, map.new()) - |> map.insert(env, t) - }, - ) -} - -// frees can be built lazily as a map -// hash cache can exist for saving to file -pub fn cached(ref: Int, source, frees, types, env, subs, count) { - let assert Ok(free) = list.at(frees, ref) - let required = map.take(env, set.to_list(free)) - case cache_lookup(types, ref, required) { - Ok(t) -> #(t, subs, types) - Error(Nil) -> { - let assert Ok(node) = list.at(source, ref) - let #(t, subs, cache) = case node { - Var(x) -> { - case map.get(env, x) { - Ok(scheme) -> { - let t = unification.instantiate(scheme, count) - #(t, subs, types) - } - Error(Nil) -> todo("no var") - } - } - Let(x, value, then) -> { - let #(t1, subs, types) = - cached(value, source, frees, types, env, subs, count) - let scheme = unification.generalise(env, t1) - let env = map.insert(env, x, scheme) - cached(then, source, frees, types, env, subs, count) - } - Fn(x, body) -> { - let param = unification.fresh(count) - let env = map.insert(env, x, Scheme([], t.Unbound(param))) - let #(body, subs, types) = - cached(body, source, frees, types, env, subs, count) - let t = t.Fun(t.Unbound(param), t.Closed, body) - #(t, subs, types) - } - Integer(_) -> #(t.Integer, subs, types) - String(_) -> #(t.Binary, subs, types) - _ -> { - io.debug(node) - todo("other nodes") - } - } - let cache = cache_update(cache, ref, required, t) - #(t, subs, cache) - } - } -} +import eyg/incremental/source +import eyg/incremental/cursor +import eyg/incremental/inference pub fn two_test() { - todo("moo") + // todo("moo") let tree = e.Let( @@ -267,32 +26,32 @@ pub fn two_test() { e.Let("y", e.Binary("hey"), e.Lambda("p", e.Variable("y"))), ) - let #(root, refs) = tree_to_ref(tree) + let #(root, refs) = source.from_tree(tree) io.debug(root) io.debug(refs) - let f = free(refs, []) + let f = inference.free(refs, []) io.debug(list.map(f, set.to_list)) io.debug(list.at(refs, root)) // binary let path = [1, 0] - let cursor = zip(path, root, refs) + let cursor = cursor.at(path, root, refs) io.debug(cursor) let [point, ..] = cursor.0 io.debug(list.at(refs, point)) let count = javascript.make_reference(0) let #(t, subs, cache) = - cached(root, refs, f, map.new(), env.empty(), sub.none(), count) + inference.cached(root, refs, f, map.new(), env.empty(), sub.none(), count) io.debug(t) - let #(root, refs) = unzip(e.Integer(3), cursor, refs) + let #(root, refs) = cursor.replace(e.Integer(3), cursor, refs) io.debug(refs) - let f2 = free(refs, f) + let f2 = inference.free(refs, f) io.debug(list.map(f2, set.to_list)) let path = [1, 1, 0] - let cursor = zip(path, root, refs) + let cursor = cursor.at(path, root, refs) io.debug(cursor) let [point, ..] = cursor.0 io.debug(list.at(refs, point)) @@ -302,12 +61,13 @@ pub fn two_test() { io.debug("====") let #(t2, subs, cache) = - cached(root, refs, f2, cache, env.empty(), subs, count) + inference.cached(root, refs, f2, cache, env.empty(), subs, count) io.debug(t2) } + // TODO printing map in node // TODO binary-size in JS match pub fn all_test() { - + todo } From ac12fcb29899bf210b6bce54cd6d49fd1c64521d Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 7 Apr 2023 12:08:11 +0200 Subject: [PATCH 11/62] update app --- eyg/src/atelier/app.gleam | 41 +++++++++++++++++++------ eyg/src/eyg/incremental/inference.gleam | 32 ++++++++++++++----- eyg/src/eyg/incremental/source.gleam | 30 +++++++++++++----- eyg/src/platforms/cli.gleam | 14 +++------ eyg/src/plinth/nodejs.gleam | 8 +++++ 5 files changed, 90 insertions(+), 35 deletions(-) diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index 848471b7b..7e862e929 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -3,17 +3,23 @@ import gleam/result import gleam/io import gleam/int import gleam/list +import gleam/map import gleam/option.{None, Option, Some} import gleam/string import gleam/fetch import gleam/http import gleam/http/request +import gleam/javascript import lustre/cmd import atelier/transform.{Act} import eygir/expression as e import eygir/encode import eyg/analysis/inference import eyg/runtime/standard +import eyg/incremental/source as incremental +import eyg/incremental/inference as new_i +import eyg/analysis/substitutions as sub +import eyg/analysis/env pub type WorkSpace { WorkSpace( @@ -27,6 +33,7 @@ pub type WorkSpace { List(#(e.Expression, List(Int))), List(#(e.Expression, List(Int))), ), + incremental: new_i.Cache, ) } @@ -46,19 +53,29 @@ pub type Action { ClickOption(chosen: e.Expression) } +external fn pnow() -> Int = + "" "performance.now" + pub fn init(source) { let assert Ok(act) = transform.prepare(source, []) let mode = Navigate(act) + let start = pnow() + let inferred = Some(standard.infer(source)) + io.debug(#("standard infer took ms:", pnow() - start)) + let start = pnow() + let #(root, refs) = incremental.from_tree(source) + io.debug(#("building incremental took ms:", pnow() - start, list.length(refs))) + + let start = pnow() + let f = new_i.free(refs, []) + io.debug(#("finding free took ms:", pnow() - start)) + let count = javascript.make_reference(0) + let start = pnow() + let #(t, s, cache) = + new_i.cached(root, refs, f, map.new(), env.empty(), sub.none(), count) + io.debug(#("finding free took ms:", pnow() - start)) // Have inference work once for showing elements but need to also background this - WorkSpace( - [], - source, - Some(standard.infer(source)), - mode, - None, - None, - #([], []), - ) + WorkSpace([], source, inferred, mode, None, None, #([], []), #(s, cache)) } pub fn update(state: WorkSpace, action) { @@ -335,11 +352,15 @@ fn delete(act: Act, state) { // an assignment vacant or not is always deleted. // when deleting with a vacant as a target there is no change // we can instead bump up the path + let start = pnow() let source = case act.target { e.Let(_label, _, then) -> act.update(then) _ -> act.update(e.Vacant("")) } - update_source(state, source) + let ret = update_source(state, source) + io.debug(#("normal update took ms:", pnow() - start)) + + ret } fn abstract(act: Act, state) { diff --git a/eyg/src/eyg/incremental/inference.gleam b/eyg/src/eyg/incremental/inference.gleam index ad92cfee0..d47a33680 100644 --- a/eyg/src/eyg/incremental/inference.gleam +++ b/eyg/src/eyg/incremental/inference.gleam @@ -15,6 +15,9 @@ import eyg/analysis/unification import eyg/incremental/source import eyg/incremental/cursor +pub type Cache = + #(sub.Substitutions, Map(Int, Map(Map(String, Scheme), t.Term))) + fn from_end(items, i) { list.at(items, list.length(items) - 1 - i) } @@ -62,11 +65,9 @@ pub fn free(refs, previous) { // TODO test calling the same node twice hits the cach fn cache_lookup(cache, ref, env) { - io.debug(#("-----------", ref, env)) - use envs <- result.then(io.debug(map.get(cache, ref))) + use envs <- result.then(map.get(cache, ref)) map.get(envs, env) - |> io.debug } fn cache_update(cache, ref, env, t) { @@ -82,7 +83,15 @@ fn cache_update(cache, ref, env, t) { // frees can be built lazily as a map // hash cache can exist for saving to file -pub fn cached(ref: Int, source, frees, types, env, subs, count) { +pub fn cached( + ref: Int, + source, + frees, + types, + env, + subs: sub.Substitutions, + count, +) { let assert Ok(free) = list.at(frees, ref) let required = map.take(env, set.to_list(free)) case cache_lookup(types, ref, required) { @@ -114,12 +123,19 @@ pub fn cached(ref: Int, source, frees, types, env, subs, count) { let t = t.Fun(t.Unbound(param), t.Closed, body) #(t, subs, types) } + source.Call(func, arg) -> { + let ret = unification.fresh(count) + let #(t1, s1, types) = + cached(func, source, frees, types, env, subs, count) + let #(t2, s2, types) = + cached(arg, source, frees, types, env, subs, count) + let s0 = + unification.unify(t.Fun(t2, t.Closed, t.Unbound(ret)), t1, count) + #(t.Unbound(ret), s1, types) + } source.Integer(_) -> #(t.Integer, subs, types) source.String(_) -> #(t.Binary, subs, types) - _ -> { - io.debug(node) - todo("other nodes") - } + _ -> #(t.Unbound(unification.fresh(count)), subs, types) } let cache = cache_update(cache, ref, required, t) #(t, subs, cache) diff --git a/eyg/src/eyg/incremental/source.gleam b/eyg/src/eyg/incremental/source.gleam index b5d70e8ab..1223cba29 100644 --- a/eyg/src/eyg/incremental/source.gleam +++ b/eyg/src/eyg/incremental/source.gleam @@ -41,16 +41,32 @@ pub fn do_from_tree(tree, acc) { let #(value, acc) = do_from_tree(value, acc) let value_index = list.length(acc) let acc = [value, ..acc] - #(Let(label, value_index, then_index), acc) } - e.Binary(value) -> { - #(String(value), acc) - } - e.Integer(value) -> { - #(Integer(value), acc) + e.Apply(func, arg) -> { + let #(arg, acc) = do_from_tree(arg, acc) + let arg_index = list.length(acc) + let acc = [arg, ..acc] + let #(func, acc) = do_from_tree(func, acc) + let func_index = list.length(acc) + let acc = [func, ..acc] + #(Call(func_index, arg_index), acc) } - _ -> todo("rest of ref") + e.Binary(value) -> #(String(value), acc) + e.Integer(value) -> #(Integer(value), acc) + e.Tail -> #(Tail, acc) + e.Cons -> #(Cons, acc) + e.Vacant(comment) -> #(Vacant(comment), acc) + e.Empty -> #(Empty, acc) + e.Extend(label) -> #(Extend(label), acc) + e.Select(label) -> #(Select(label), acc) + e.Overwrite(label) -> #(Overwrite(label), acc) + e.Tag(label) -> #(Tag(label), acc) + e.Case(label) -> #(Case(label), acc) + e.NoCases -> #(NoCases, acc) + e.Perform(label) -> #(Perform(label), acc) + e.Handle(label) -> #(Handle(label), acc) + e.Builtin(identifier) -> #(Builtin(identifier), acc) } } diff --git a/eyg/src/platforms/cli.gleam b/eyg/src/platforms/cli.gleam index 479a29316..30c3b3204 100644 --- a/eyg/src/platforms/cli.gleam +++ b/eyg/src/platforms/cli.gleam @@ -21,24 +21,18 @@ pub fn typ() { t.Fun(t.LinkedList(t.Binary), handlers().0, t.Integer) } -external fn start() -> #(Int, Int) = - "process" "hrtime" - -external fn duration(#(Int, Int)) -> #(Int, Int) = - "process" "hrtime" - pub fn run(source, args) { let #(types, _values) = stdlib.lib() let prog = e.Apply(e.Select("cli"), source) - let hrstart = start() + let hrstart = nodejs.start() use code <- // let inferred = inference.infer(types, prog, typ(), t.Closed) - // let hrend = duration(hrstart) + // let hrend = nodejs.duration(hrstart) // io.debug(#("inference", hrend)) // console.info("Inference time (hr): %ds %dms", hrend) promise.await(case Ok(Nil) { Ok(Nil) -> { - let hrstart = start() + let hrstart = nodejs.start() use ret <- promise.map(r.run_async( prog, stdlib.env(), @@ -48,7 +42,7 @@ pub fn run(source, args) { io.debug(ret) let assert Ok(r.Integer(return)) = ret - let hrend = duration(hrstart) + let hrend = nodejs.duration(hrstart) io.debug(#("run", hrend)) return } diff --git a/eyg/src/plinth/nodejs.gleam b/eyg/src/plinth/nodejs.gleam index 8fbf30439..a30b7f842 100644 --- a/eyg/src/plinth/nodejs.gleam +++ b/eyg/src/plinth/nodejs.gleam @@ -19,3 +19,11 @@ pub external fn cwd() -> String = /// Node.js will not terminate until all the `exit` event listeners are called. pub external fn exit(code: Int) -> Nil = "" "process.exit" + +pub external type HRTime + +pub external fn start() -> HRTime = + "process" "hrtime" + +pub external fn duration(HRTime) -> #(Int, Int) = + "process" "hrtime" From b05cb0cd342571c3d61e220ce86fe5bcd0ac920e Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 7 Apr 2023 13:28:19 +0200 Subject: [PATCH 12/62] more timing for improvements --- eyg/manifest.toml | 2 +- eyg/src/atelier/app.gleam | 27 +++++++++++++++++++++---- eyg/src/atelier/main.gleam | 2 ++ eyg/src/atelier/view/projection.gleam | 8 +++++++- eyg/src/eyg/incremental/cursor.gleam | 7 +++++++ eyg/src/eyg/incremental/inference.gleam | 3 +-- eyg/src/eyg/incremental/source.gleam | 4 +--- eyg/test/incremental_and_zip_test.gleam | 8 ++------ 8 files changed, 44 insertions(+), 17 deletions(-) diff --git a/eyg/manifest.toml b/eyg/manifest.toml index 4a9ee291e..2f3fe0112 100644 --- a/eyg/manifest.toml +++ b/eyg/manifest.toml @@ -6,7 +6,7 @@ packages = [ { name = "gleam_fetch", version = "0.1.0", build_tools = ["gleam"], requirements = ["gleam_javascript", "gleam_http"], otp_app = "gleam_fetch", source = "hex", outer_checksum = "C66E68D8AE5D1D8C4120C4F8EF8133E680B7EF20A7DBF5BFAABD9390FF8E9B90" }, { name = "gleam_http", version = "3.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "7BE7A80B5AC8357827169107FAE15AD8423629E6BBBD39A8B4217AFF879B4520" }, { name = "gleam_javascript", version = "0.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_javascript", source = "hex", outer_checksum = "E0E8D33461776BFCC124838183F85E430D3A71D7318F210C9DE0CFB52E5AC8DE" }, - { name = "gleam_json", version = "0.5.1", build_tools = ["gleam"], requirements = ["thoas", "gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "9A805C1E60FB9CD73AF3034EB464268A6B522D937FCD2DF92BD246F2F4B37930" }, + { name = "gleam_json", version = "0.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "9A805C1E60FB9CD73AF3034EB464268A6B522D937FCD2DF92BD246F2F4B37930" }, { name = "gleam_stdlib", version = "0.28.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "1BB6A3E53F7576B9F5C4E5D4AE16487E526BE383B03CBF4068C7DFC77CF38A1C" }, { name = "gleeunit", version = "0.10.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "ECEA2DE4BE6528D36AFE74F42A21CDF99966EC36D7F25DEB34D47DD0F7977BAF" }, { name = "lustre", version = "2.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "EFF2C221C364BDE621E01F2917B620E3B2B181C5FBAF5EB9FA0B1488ADF7327E" }, diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index 7e862e929..7ebc7f28d 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -18,6 +18,7 @@ import eyg/analysis/inference import eyg/runtime/standard import eyg/incremental/source as incremental import eyg/incremental/inference as new_i +import eyg/incremental/cursor import eyg/analysis/substitutions as sub import eyg/analysis/env @@ -60,9 +61,6 @@ pub fn init(source) { let assert Ok(act) = transform.prepare(source, []) let mode = Navigate(act) let start = pnow() - let inferred = Some(standard.infer(source)) - io.debug(#("standard infer took ms:", pnow() - start)) - let start = pnow() let #(root, refs) = incremental.from_tree(source) io.debug(#("building incremental took ms:", pnow() - start, list.length(refs))) @@ -73,7 +71,28 @@ pub fn init(source) { let start = pnow() let #(t, s, cache) = new_i.cached(root, refs, f, map.new(), env.empty(), sub.none(), count) - io.debug(#("finding free took ms:", pnow() - start)) + io.debug(#("initial type check took ms:", pnow() - start)) + let path = [1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0] + let start = pnow() + let c = cursor.at(path, root, refs) + io.debug(#("building cursor took ms:", pnow() - start)) + io.debug(c) + + let start = pnow() + let #(x, refs) = cursor.replace(e.Binary("hello"), c, refs) + io.debug(#("replacing at cursor took ms:", pnow() - start)) + io.debug(x) + + let start = pnow() + let f2 = new_i.free(refs, f) + io.debug(#("f2 took ms:", pnow() - start)) + let #(t, s, cache) = new_i.cached(root, refs, f, cache, env.empty(), s, count) + io.debug(#("partial type check took ms:", pnow() - start)) + + let start = pnow() + let inferred = Some(standard.infer(source)) + io.debug(#("standard infer took ms:", pnow() - start)) + // Have inference work once for showing elements but need to also background this WorkSpace([], source, inferred, mode, None, None, #([], []), #(s, cache)) } diff --git a/eyg/src/atelier/main.gleam b/eyg/src/atelier/main.gleam index fca42bd1b..7f29fe5fd 100644 --- a/eyg/src/atelier/main.gleam +++ b/eyg/src/atelier/main.gleam @@ -1,3 +1,4 @@ +import gleam/io import lustre import lustre/cmd import atelier/app @@ -15,6 +16,7 @@ pub fn main(source) { lustre.application(#(app.init(source), cmd.none()), app.update, root.render) |> lustre.start("#app") + io.debug(dispatch) listen_keypress(fn(key) { dispatch(app.Keypress(key)) }) } diff --git a/eyg/src/atelier/view/projection.gleam b/eyg/src/atelier/view/projection.gleam index 064618a4e..49f4684f7 100644 --- a/eyg/src/atelier/view/projection.gleam +++ b/eyg/src/atelier/view/projection.gleam @@ -15,7 +15,13 @@ pub fn render(source, selection, inferred: Option(inference.Infered)) { let loc = Location([], Some(selection)) pre( [style([#("cursor", "pointer")]), class("w-full max-w-6xl")], - do_render(source, "\n", loc, inferred), + [ + text( + list.map(selection, int.to_string) + |> string.join(","), + ), + ..do_render(source, "\n", loc, inferred) + ], ) } diff --git a/eyg/src/eyg/incremental/cursor.gleam b/eyg/src/eyg/incremental/cursor.gleam index dfa283b04..c25d9622b 100644 --- a/eyg/src/eyg/incremental/cursor.gleam +++ b/eyg/src/eyg/incremental/cursor.gleam @@ -1,3 +1,4 @@ +import gleam/io import gleam/list import eygir/expression as e import eyg/incremental/source.{Call, Fn, Let} @@ -7,6 +8,12 @@ fn zip_match(node, path_element) { Let(_, index, _), 0 -> index Let(_, _, index), 1 -> index Fn(_, index), 0 -> index + Call(index, _), 0 -> index + Call(_, index), 1 -> index + _, _ -> { + io.debug(#(node, path_element)) + todo("no_zip_match") + } } } diff --git a/eyg/src/eyg/incremental/inference.gleam b/eyg/src/eyg/incremental/inference.gleam index d47a33680..0392ab32d 100644 --- a/eyg/src/eyg/incremental/inference.gleam +++ b/eyg/src/eyg/incremental/inference.gleam @@ -99,7 +99,7 @@ pub fn cached( Error(Nil) -> { let assert Ok(node) = list.at(source, ref) let #(t, subs, cache) = case node { - source.Var(x) -> { + source.Var(x) -> case map.get(env, x) { Ok(scheme) -> { let t = unification.instantiate(scheme, count) @@ -107,7 +107,6 @@ pub fn cached( } Error(Nil) -> todo("no var") } - } source.Let(x, value, then) -> { let #(t1, subs, types) = cached(value, source, frees, types, env, subs, count) diff --git a/eyg/src/eyg/incremental/source.gleam b/eyg/src/eyg/incremental/source.gleam index 1223cba29..b75eea9b7 100644 --- a/eyg/src/eyg/incremental/source.gleam +++ b/eyg/src/eyg/incremental/source.gleam @@ -25,9 +25,7 @@ pub type Expression { pub fn do_from_tree(tree, acc) { case tree { - e.Variable(label) -> { - #(Var(label), acc) - } + e.Variable(label) -> #(Var(label), acc) e.Lambda(label, body) -> { let #(node, acc) = do_from_tree(body, acc) let index = list.length(acc) diff --git a/eyg/test/incremental_and_zip_test.gleam b/eyg/test/incremental_and_zip_test.gleam index b268a07e2..35d784068 100644 --- a/eyg/test/incremental_and_zip_test.gleam +++ b/eyg/test/incremental_and_zip_test.gleam @@ -47,12 +47,8 @@ fn do_tree_to_ref( let free = set.union(free_v, set.delete(free_t, label)) #(Let(label, value_index, then_index), free, acc) } - e.Binary(value) -> { - #(String(value), set.new(), acc) - } - e.Integer(value) -> { - #(Integer(value), set.new(), acc) - } + e.Binary(value) -> #(String(value), set.new(), acc) + e.Integer(value) -> #(Integer(value), set.new(), acc) _ -> todo("rest of ref") } } From 2d0d9d07f1eaece3922638199a6302aa377218db Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 7 Apr 2023 13:48:10 +0200 Subject: [PATCH 13/62] more timing --- eyg/src/atelier/app.gleam | 6 +++++ eyg/src/eyg/incremental/inference.gleam | 33 +++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index 7ebc7f28d..c8d1e1ea0 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -69,6 +69,9 @@ pub fn init(source) { io.debug(#("finding free took ms:", pnow() - start)) let count = javascript.make_reference(0) let start = pnow() + let fm = new_i.free_map(refs, map.new()) + io.debug(#("finding free took ms:", pnow() - start)) + let start = pnow() let #(t, s, cache) = new_i.cached(root, refs, f, map.new(), env.empty(), sub.none(), count) io.debug(#("initial type check took ms:", pnow() - start)) @@ -88,6 +91,9 @@ pub fn init(source) { io.debug(#("f2 took ms:", pnow() - start)) let #(t, s, cache) = new_i.cached(root, refs, f, cache, env.empty(), s, count) io.debug(#("partial type check took ms:", pnow() - start)) + let start = pnow() + let fm2 = new_i.free_map(refs, fm) + io.debug(#("finding fm2 took ms:", pnow() - start)) let start = pnow() let inferred = Some(standard.infer(source)) diff --git a/eyg/src/eyg/incremental/inference.gleam b/eyg/src/eyg/incremental/inference.gleam index 0392ab32d..9ad068489 100644 --- a/eyg/src/eyg/incremental/inference.gleam +++ b/eyg/src/eyg/incremental/inference.gleam @@ -53,8 +53,37 @@ pub fn free(refs, previous) { do_free(list.drop(refs, list.length(previous)), list.reverse(previous)) } -// TODO incremental/free -// TODO incremental/cursor.{from_path, replace} +fn do_free_map(rest, acc) { + case rest { + [] -> acc + [node, ..rest] -> { + let free = case node { + source.Var(x) -> setx.singleton(x) + source.Fn(x, ref) -> { + let assert Ok(body) = map.get(acc, ref) + set.delete(body, x) + } + source.Let(x, ref_v, ref_t) -> { + let assert Ok(value) = map.get(acc, ref_v) + let assert Ok(then) = map.get(acc, ref_t) + set.union(value, set.delete(then, x)) + } + source.Call(ref_func, ref_arg) -> { + let assert Ok(func) = map.get(acc, ref_func) + let assert Ok(arg) = map.get(acc, ref_arg) + set.union(func, arg) + } + _ -> set.new() + } + do_free_map(rest, map.insert(acc, map.size(acc), free)) + } + } +} + +pub fn free_map(refs, previous) { + // TODO need to be careful on taking new only + do_free_map(list.drop(refs, map.size(previous)), previous) +} // // Need single map of substitutions, is this the efficient J algo? // // Free should be easy in bottom up order assume need value is already present From 94381e0a2efa5b8d1bde44794e19abf7680725ed Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 7 Apr 2023 16:44:43 +0200 Subject: [PATCH 14/62] start incremental store --- eyg/src/atelier/app.gleam | 46 ++++++++- eyg/src/eyg/incremental/cursor.gleam | 30 ++++++ eyg/src/eyg/incremental/inference.gleam | 4 +- eyg/src/eyg/incremental/source.gleam | 53 +++++++++++ eyg/src/eyg/incremental/store.gleam | 109 ++++++++++++++++++++++ eyg/test/eyg/incremental/store_test.gleam | 24 +++++ 6 files changed, 263 insertions(+), 3 deletions(-) create mode 100644 eyg/src/eyg/incremental/store.gleam create mode 100644 eyg/test/eyg/incremental/store_test.gleam diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index c8d1e1ea0..2c0edd7fd 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -19,6 +19,7 @@ import eyg/runtime/standard import eyg/incremental/source as incremental import eyg/incremental/inference as new_i import eyg/incremental/cursor +import eyg/incremental/store import eyg/analysis/substitutions as sub import eyg/analysis/env @@ -60,32 +61,75 @@ external fn pnow() -> Int = pub fn init(source) { let assert Ok(act) = transform.prepare(source, []) let mode = Navigate(act) + + let start = pnow() + let #(root, s) = store.load(store.empty(), source) + io.debug(#( + "loading store took ms:", + pnow() - start, + map.size(s.source), + map.size(s.free), + )) + + let start = pnow() + let assert Ok(#(vars, s)) = store.free(s, root) + // TODO i think should be same size + io.debug(#( + "memoizing free took ms:", + pnow() - start, + map.size(s.source), + map.size(s.free), + vars, + )) + + io.debug("------------------------") + let start = pnow() let #(root, refs) = incremental.from_tree(source) io.debug(#("building incremental took ms:", pnow() - start, list.length(refs))) + let start = pnow() + let #(root, refs_map) = incremental.from_tree_map(source) + io.debug(#( + "building incremental map took ms:", + pnow() - start, + map.size(refs_map), + )) let start = pnow() let f = new_i.free(refs, []) io.debug(#("finding free took ms:", pnow() - start)) - let count = javascript.make_reference(0) let start = pnow() let fm = new_i.free_map(refs, map.new()) io.debug(#("finding free took ms:", pnow() - start)) + + let count = javascript.make_reference(0) let start = pnow() let #(t, s, cache) = new_i.cached(root, refs, f, map.new(), env.empty(), sub.none(), count) io.debug(#("initial type check took ms:", pnow() - start)) + let path = [1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0] let start = pnow() let c = cursor.at(path, root, refs) io.debug(#("building cursor took ms:", pnow() - start)) io.debug(c) + let start = pnow() + let refs_map = + list.index_map(refs, fn(i, r) { #(i, r) }) + |> map.from_list() + io.debug(#("list to map took ms:", pnow() - start)) + let start = pnow() let #(x, refs) = cursor.replace(e.Binary("hello"), c, refs) io.debug(#("replacing at cursor took ms:", pnow() - start)) io.debug(x) + // let start = pnow() + // let #(x, refs) = cursor.replace_map(e.Binary("hello"), c, refs_map) + // io.debug(#("replacing at cursor took ms:", pnow() - start)) + // io.debug(x) + let start = pnow() let f2 = new_i.free(refs, f) io.debug(#("f2 took ms:", pnow() - start)) diff --git a/eyg/src/eyg/incremental/cursor.gleam b/eyg/src/eyg/incremental/cursor.gleam index c25d9622b..b6d79b1c9 100644 --- a/eyg/src/eyg/incremental/cursor.gleam +++ b/eyg/src/eyg/incremental/cursor.gleam @@ -71,3 +71,33 @@ pub fn replace(tree, cursor, refs) { do_replace(old, new, list.append(zoom, [root]), rev) } } +// fn do_replace_map(old, new, zoom, rev) { +// case zoom { +// [] -> #(new, list.reverse(rev)) +// [next, ..zoom] -> { +// let assert Ok(node) = list.at(list.reverse(rev), next) +// let exp = case node { +// Let(label, value, then) if value == old -> Let(label, new, then) +// Let(label, value, then) if then == old -> Let(label, value, new) +// Fn(param, body) if body == old -> Fn(param, new) +// Call(func, arg) if func == old -> Call(new, arg) +// Call(func, arg) if arg == old -> Call(func, new) +// _ -> todo("Can't have a path into literal") +// } +// let new = list.length(rev) +// let rev = [exp, ..rev] +// do_replace_map(next, new, zoom, rev) +// } +// } +// } + +// pub fn replace_map(tree, cursor, refs) { +// let #(exp, acc) = source.do_from_tree(tree, list.reverse(refs)) +// let new = list.length(acc) +// let rev = [exp, ..acc] +// case cursor { +// #([], old) -> do_replace_map(old, new, [], rev) +// #([old, ..zoom], root) -> +// do_replace_map(old, new, list.append(zoom, [root]), rev) +// } +// } diff --git a/eyg/src/eyg/incremental/inference.gleam b/eyg/src/eyg/incremental/inference.gleam index 9ad068489..6f866ee12 100644 --- a/eyg/src/eyg/incremental/inference.gleam +++ b/eyg/src/eyg/incremental/inference.gleam @@ -93,13 +93,13 @@ pub fn free_map(refs, previous) { // TODO test calling the same node twice hits the cach -fn cache_lookup(cache, ref, env) { +pub fn cache_lookup(cache, ref, env) { use envs <- result.then(map.get(cache, ref)) map.get(envs, env) } -fn cache_update(cache, ref, env, t) { +pub fn cache_update(cache, ref, env, t) { map.update( cache, ref, diff --git a/eyg/src/eyg/incremental/source.gleam b/eyg/src/eyg/incremental/source.gleam index b75eea9b7..65e8ae635 100644 --- a/eyg/src/eyg/incremental/source.gleam +++ b/eyg/src/eyg/incremental/source.gleam @@ -1,4 +1,5 @@ import gleam/list +import gleam/map import eygir/expression as e pub type Expression { @@ -74,3 +75,55 @@ pub fn from_tree(tree) { let source = list.reverse([exp, ..acc]) #(index, source) } + +pub fn do_from_tree_map(tree, acc) { + case tree { + e.Variable(label) -> #(Var(label), acc) + e.Lambda(label, body) -> { + let #(node, acc) = do_from_tree_map(body, acc) + let index = map.size(acc) + let acc = map.insert(acc, index, node) + #(Fn(label, index), acc) + } + e.Let(label, value, then) -> { + let #(then, acc) = do_from_tree_map(then, acc) + let then_index = map.size(acc) + let acc = map.insert(acc, then_index, then) + let #(value, acc) = do_from_tree_map(value, acc) + let value_index = map.size(acc) + let acc = map.insert(acc, value_index, value) + #(Let(label, value_index, then_index), acc) + } + e.Apply(func, arg) -> { + let #(arg, acc) = do_from_tree_map(arg, acc) + let arg_index = map.size(acc) + let acc = map.insert(acc, arg_index, arg) + let #(func, acc) = do_from_tree_map(func, acc) + let func_index = map.size(acc) + let acc = map.insert(acc, func_index, func) + #(Call(func_index, arg_index), acc) + } + e.Binary(value) -> #(String(value), acc) + e.Integer(value) -> #(Integer(value), acc) + e.Tail -> #(Tail, acc) + e.Cons -> #(Cons, acc) + e.Vacant(comment) -> #(Vacant(comment), acc) + e.Empty -> #(Empty, acc) + e.Extend(label) -> #(Extend(label), acc) + e.Select(label) -> #(Select(label), acc) + e.Overwrite(label) -> #(Overwrite(label), acc) + e.Tag(label) -> #(Tag(label), acc) + e.Case(label) -> #(Case(label), acc) + e.NoCases -> #(NoCases, acc) + e.Perform(label) -> #(Perform(label), acc) + e.Handle(label) -> #(Handle(label), acc) + e.Builtin(identifier) -> #(Builtin(identifier), acc) + } +} + +pub fn from_tree_map(tree) { + let #(exp, acc) = do_from_tree_map(tree, map.new()) + let index = map.size(acc) + let source = map.insert(acc, index, exp) + #(index, source) +} diff --git a/eyg/src/eyg/incremental/store.gleam b/eyg/src/eyg/incremental/store.gleam new file mode 100644 index 000000000..1151f8e09 --- /dev/null +++ b/eyg/src/eyg/incremental/store.gleam @@ -0,0 +1,109 @@ +import gleam/map.{Map} +import gleam/result +import gleam/set.{Set} +import gleam/setx +// TODO source -> ref +import eyg/incremental/source +import eyg/incremental/inference + +pub type Store { + Store(source: Map(Int, source.Expression), free: Map(Int, Set(String))) +} + +pub fn empty() { + Store(source: map.new(), free: map.new()) +} + +pub fn load(store: Store, tree) { + let #(exp, acc) = source.do_from_tree_map(tree, store.source) + let index = map.size(acc) + let source = map.insert(acc, index, exp) + #(index, Store(..store, source: source)) +} + +pub fn free(store: Store, root) { + case map.get(store.free, root) { + Ok(vars) -> Ok(#(vars, store)) + Error(Nil) -> { + use node <- result.then(map.get(store.source, root)) + use #(vars, store) <- result.then(case node { + source.Var(x) -> Ok(#(setx.singleton(x), store)) + source.Fn(x, ref) -> { + use #(vars, store) <- result.then(free(store, ref)) + Ok(#(set.delete(vars, x), store)) + } + source.Let(x, ref_v, ref_t) -> { + use #(value, store) <- result.then(free(store, ref_v)) + use #(then, store) <- result.then(free(store, ref_t)) + let vars = set.union(value, set.delete(then, x)) + Ok(#(vars, store)) + } + source.Call(ref_func, ref_arg) -> { + use #(func, store) <- result.then(free(store, ref_func)) + use #(arg, store) <- result.then(free(store, ref_arg)) + let vars = set.union(func, arg) + Ok(#(vars, store)) + } + _ -> Ok(#(set.new(), store)) + }) + let free = map.insert(store.free, root, vars) + let store = Store(..store, free: free) + Ok(#(vars, store)) + } + } +} + +pub fn type_(store: Store, root) { + // inference.cached(root, store.source, f, cache, env.empty(), s, count) + todo("do type") +} +// pub fn do_type(store: Store, ref) { +// let assert Ok(free) = list.at(frees, ref) +// let required = map.take(env, set.to_list(free)) +// case cache_lookup(types, ref, required) { +// Ok(t) -> #(t, subs, types) +// Error(Nil) -> { +// let assert Ok(node) = list.at(source, ref) +// let #(t, subs, cache) = case node { +// source.Var(x) -> +// case map.get(env, x) { +// Ok(scheme) -> { +// let t = unification.instantiate(scheme, count) +// #(t, subs, types) +// } +// Error(Nil) -> todo("no var") +// } +// source.Let(x, value, then) -> { +// let #(t1, subs, types) = +// cached(value, source, frees, types, env, subs, count) +// let scheme = unification.generalise(env, t1) +// let env = map.insert(env, x, scheme) +// cached(then, source, frees, types, env, subs, count) +// } +// source.Fn(x, body) -> { +// let param = unification.fresh(count) +// let env = map.insert(env, x, Scheme([], t.Unbound(param))) +// let #(body, subs, types) = +// cached(body, source, frees, types, env, subs, count) +// let t = t.Fun(t.Unbound(param), t.Closed, body) +// #(t, subs, types) +// } +// source.Call(func, arg) -> { +// let ret = unification.fresh(count) +// let #(t1, s1, types) = +// cached(func, source, frees, types, env, subs, count) +// let #(t2, s2, types) = +// cached(arg, source, frees, types, env, subs, count) +// let s0 = +// unification.unify(t.Fun(t2, t.Closed, t.Unbound(ret)), t1, count) +// #(t.Unbound(ret), s1, types) +// } +// source.Integer(_) -> #(t.Integer, subs, types) +// source.String(_) -> #(t.Binary, subs, types) +// _ -> #(t.Unbound(unification.fresh(count)), subs, types) +// } +// let cache = cache_update(cache, ref, required, t) +// #(t, subs, cache) +// } +// } +// } diff --git a/eyg/test/eyg/incremental/store_test.gleam b/eyg/test/eyg/incremental/store_test.gleam new file mode 100644 index 000000000..4fd880eae --- /dev/null +++ b/eyg/test/eyg/incremental/store_test.gleam @@ -0,0 +1,24 @@ +import gleam/io +import gleam/map +import gleam/set +import eygir/expression as e +import eyg/incremental/store +import gleeunit/should + +pub fn literal_test() { + let s = store.empty() + + let tree = e.Binary("hello") + let #(ref_binary, s) = store.load(s, tree) + should.equal(ref_binary, 0) + // should.equal(store.tree(s, ref_binary), Ok(tree)) + let assert Ok(#(free, s)) = store.free(s, ref_binary) + should.equal(map.size(s.free), 1) + should.equal(free, set.new()) + + let #(ref_integer, s) = store.load(s, e.Integer(5)) + should.equal(ref_integer, 1) + let assert Ok(#(free, s)) = store.free(s, ref_integer) + should.equal(map.size(s.free), 2) + should.equal(free, set.new()) +} From beb9ba82852cba00eae7ad91db1d590f397f63f2 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 7 Apr 2023 17:04:22 +0200 Subject: [PATCH 15/62] typecheck in store --- eyg/src/atelier/app.gleam | 12 +++ eyg/src/eyg/incremental/store.gleam | 125 ++++++++++++---------- eyg/test/eyg/incremental/store_test.gleam | 7 ++ 3 files changed, 90 insertions(+), 54 deletions(-) diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index 2c0edd7fd..63672aad3 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -82,6 +82,18 @@ pub fn init(source) { vars, )) + let start = pnow() + let assert Ok(#(t, s)) = store.type_(s, root) + // TODO i think should be same size + io.debug(#( + "typing took ms:", + pnow() - start, + map.size(s.source), + map.size(s.free), + map.size(s.types), + t, + )) + io.debug("------------------------") let start = pnow() diff --git a/eyg/src/eyg/incremental/store.gleam b/eyg/src/eyg/incremental/store.gleam index 1151f8e09..004df492e 100644 --- a/eyg/src/eyg/incremental/store.gleam +++ b/eyg/src/eyg/incremental/store.gleam @@ -2,16 +2,31 @@ import gleam/map.{Map} import gleam/result import gleam/set.{Set} import gleam/setx +import gleam/javascript // TODO source -> ref +import eyg/analysis/typ as t +import eyg/analysis/substitutions as sub +import eyg/analysis/scheme.{Scheme} +import eyg/analysis/unification import eyg/incremental/source import eyg/incremental/inference pub type Store { - Store(source: Map(Int, source.Expression), free: Map(Int, Set(String))) + Store( + source: Map(Int, source.Expression), + free: Map(Int, Set(String)), + types: Map(Int, Map(Map(String, Scheme), t.Term)), + counter: javascript.Reference(Int), + ) } pub fn empty() { - Store(source: map.new(), free: map.new()) + Store( + source: map.new(), + free: map.new(), + types: map.new(), + counter: javascript.make_reference(0), + ) } pub fn load(store: Store, tree) { @@ -54,56 +69,58 @@ pub fn free(store: Store, root) { } pub fn type_(store: Store, root) { - // inference.cached(root, store.source, f, cache, env.empty(), s, count) - todo("do type") + do_type(map.new(), root, store) +} + +// Error only for invalid ref +pub fn do_type(env, ref, store: Store) -> Result(_, _) { + use #(vars, store) <- result.then(free(store, ref)) + let required = map.take(env, set.to_list(vars)) + case inference.cache_lookup(store.types, ref, required) { + Ok(t) -> Ok(#(t, store)) + Error(Nil) -> { + use node <- result.then(map.get(store.source, ref)) + use #(t, store) <- result.then(case node { + source.Var(x) -> + case map.get(env, x) { + Ok(scheme) -> { + let t = unification.instantiate(scheme, store.counter) + Ok(#(t, store)) + } + Error(Nil) -> todo("no var") + } + source.Let(x, value, then) -> { + use #(t1, store) <- result.then(do_type(env, value, store)) + let scheme = unification.generalise(env, t1) + let env = map.insert(env, x, scheme) + do_type(env, then, store) + } + source.Fn(x, body) -> { + let param = unification.fresh(store.counter) + let env = map.insert(env, x, Scheme([], t.Unbound(param))) + use #(body, store) <- result.then(do_type(env, body, store)) + let t = t.Fun(t.Unbound(param), t.Closed, body) + Ok(#(t, store)) + } + source.Call(func, arg) -> { + let ret = unification.fresh(store.counter) + use #(t1, store) <- result.then(do_type(env, func, store)) + use #(t2, store) <- result.then(do_type(env, arg, store)) + let s0 = + unification.unify( + t.Fun(t2, t.Closed, t.Unbound(ret)), + t1, + store.counter, + ) + Ok(#(t.Unbound(ret), store)) + } + source.Integer(_) -> Ok(#(t.Integer, store)) + source.String(_) -> Ok(#(t.Binary, store)) + _ -> Ok(#(t.Unbound(unification.fresh(store.counter)), store)) + }) + let types = inference.cache_update(store.types, ref, required, t) + let store = Store(..store, types: types) + Ok(#(t, store)) + } + } } -// pub fn do_type(store: Store, ref) { -// let assert Ok(free) = list.at(frees, ref) -// let required = map.take(env, set.to_list(free)) -// case cache_lookup(types, ref, required) { -// Ok(t) -> #(t, subs, types) -// Error(Nil) -> { -// let assert Ok(node) = list.at(source, ref) -// let #(t, subs, cache) = case node { -// source.Var(x) -> -// case map.get(env, x) { -// Ok(scheme) -> { -// let t = unification.instantiate(scheme, count) -// #(t, subs, types) -// } -// Error(Nil) -> todo("no var") -// } -// source.Let(x, value, then) -> { -// let #(t1, subs, types) = -// cached(value, source, frees, types, env, subs, count) -// let scheme = unification.generalise(env, t1) -// let env = map.insert(env, x, scheme) -// cached(then, source, frees, types, env, subs, count) -// } -// source.Fn(x, body) -> { -// let param = unification.fresh(count) -// let env = map.insert(env, x, Scheme([], t.Unbound(param))) -// let #(body, subs, types) = -// cached(body, source, frees, types, env, subs, count) -// let t = t.Fun(t.Unbound(param), t.Closed, body) -// #(t, subs, types) -// } -// source.Call(func, arg) -> { -// let ret = unification.fresh(count) -// let #(t1, s1, types) = -// cached(func, source, frees, types, env, subs, count) -// let #(t2, s2, types) = -// cached(arg, source, frees, types, env, subs, count) -// let s0 = -// unification.unify(t.Fun(t2, t.Closed, t.Unbound(ret)), t1, count) -// #(t.Unbound(ret), s1, types) -// } -// source.Integer(_) -> #(t.Integer, subs, types) -// source.String(_) -> #(t.Binary, subs, types) -// _ -> #(t.Unbound(unification.fresh(count)), subs, types) -// } -// let cache = cache_update(cache, ref, required, t) -// #(t, subs, cache) -// } -// } -// } diff --git a/eyg/test/eyg/incremental/store_test.gleam b/eyg/test/eyg/incremental/store_test.gleam index 4fd880eae..aae97eee2 100644 --- a/eyg/test/eyg/incremental/store_test.gleam +++ b/eyg/test/eyg/incremental/store_test.gleam @@ -2,6 +2,7 @@ import gleam/io import gleam/map import gleam/set import eygir/expression as e +import eyg/analysis/typ as t import eyg/incremental/store import gleeunit/should @@ -15,10 +16,16 @@ pub fn literal_test() { let assert Ok(#(free, s)) = store.free(s, ref_binary) should.equal(map.size(s.free), 1) should.equal(free, set.new()) + let assert Ok(#(t, s)) = store.type_(s, ref_binary) + should.equal(map.size(s.types), 1) + should.equal(t, t.Binary) let #(ref_integer, s) = store.load(s, e.Integer(5)) should.equal(ref_integer, 1) let assert Ok(#(free, s)) = store.free(s, ref_integer) should.equal(map.size(s.free), 2) should.equal(free, set.new()) + let assert Ok(#(t, s)) = store.type_(s, ref_integer) + should.equal(map.size(s.types), 2) + should.equal(t, t.Integer) } From f381fee78d7b512a8fb4a808002b1761b75a88d7 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 7 Apr 2023 17:13:52 +0200 Subject: [PATCH 16/62] dont know why partial types --- eyg/src/atelier/app.gleam | 2 ++ 1 file changed, 2 insertions(+) diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index 63672aad3..41053647c 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -94,6 +94,8 @@ pub fn init(source) { t, )) +// not helpful + // list.map(map.to_list(s.types), io.debug) io.debug("------------------------") let start = pnow() From f9da53b45108baec902f03ab59bb0e79fc3b3265 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 7 Apr 2023 19:45:09 +0200 Subject: [PATCH 17/62] test application --- eyg/src/atelier/app.gleam | 2 +- eyg/src/eyg/analysis/inference.gleam | 11 +--- eyg/src/eyg/analysis/typ.gleam | 17 +++++++ eyg/src/eyg/incremental/cursor.gleam | 36 ++++++++++++- eyg/src/eyg/incremental/store.gleam | 32 ++++++++++-- eyg/test/eyg/incremental/store_test.gleam | 62 +++++++++++++++++++++++ 6 files changed, 146 insertions(+), 14 deletions(-) diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index 41053647c..f22ee2d25 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -94,7 +94,7 @@ pub fn init(source) { t, )) -// not helpful + // not helpful // list.map(map.to_list(s.types), io.debug) io.debug("------------------------") diff --git a/eyg/src/eyg/analysis/inference.gleam b/eyg/src/eyg/analysis/inference.gleam index 39782d890..ab304acbf 100644 --- a/eyg/src/eyg/analysis/inference.gleam +++ b/eyg/src/eyg/analysis/inference.gleam @@ -188,15 +188,8 @@ fn do_infer(env, exp, typ, eff, ref, path) { // Primitive e.Binary(_) -> unify(typ, t.Binary, ref, path) e.Integer(_) -> unify(typ, t.Integer, ref, path) - e.Tail -> unify(typ, t.LinkedList(t.Unbound(fresh(ref))), ref, path) - e.Cons -> { - let t = t.Unbound(fresh(ref)) - let e1 = t.Open(fresh(ref)) - let e2 = t.Open(fresh(ref)) - t.Fun(t, e1, t.Fun(t.LinkedList(t), e2, t.LinkedList(t))) - |> unify(typ, _, ref, path) - } - + e.Tail -> unify(typ, t.tail(ref), ref, path) + e.Cons -> unify(typ, t.cons(ref), ref, path) e.Vacant(_comment) -> Infered( sub.none(), diff --git a/eyg/src/eyg/analysis/typ.gleam b/eyg/src/eyg/analysis/typ.gleam index 251e894a9..43aff50c3 100644 --- a/eyg/src/eyg/analysis/typ.gleam +++ b/eyg/src/eyg/analysis/typ.gleam @@ -1,5 +1,6 @@ import gleam/set import gleam/setx +import gleam/javascript // This separation of kinds could be opened as a PR to the F-sharp project @@ -66,3 +67,19 @@ pub fn result(value, reason) { pub fn option(value) { Union(Extend("Some", value, Extend("None", unit, Closed))) } + +pub fn tail(ref) { + LinkedList(Unbound(fresh(ref))) +} + +pub fn cons(ref) { + let t = Unbound(fresh(ref)) + let e1 = Open(fresh(ref)) + let e2 = Open(fresh(ref)) + Fun(t, e1, Fun(LinkedList(t), e2, LinkedList(t))) +} + +// copied from unification to not get circular ref +pub fn fresh(ref) { + javascript.update_reference(ref, fn(x) { x + 1 }) +} diff --git a/eyg/src/eyg/incremental/cursor.gleam b/eyg/src/eyg/incremental/cursor.gleam index b6d79b1c9..12d26a61d 100644 --- a/eyg/src/eyg/incremental/cursor.gleam +++ b/eyg/src/eyg/incremental/cursor.gleam @@ -1,9 +1,11 @@ import gleam/io import gleam/list +import gleam/map +import gleam/result import eygir/expression as e import eyg/incremental/source.{Call, Fn, Let} -fn zip_match(node, path_element) { +pub fn zip_match(node, path_element) { case node, path_element { Let(_, index, _), 0 -> index Let(_, _, index), 1 -> index @@ -41,6 +43,30 @@ pub fn at(path, root, refs) { } } +fn do_at_map(path, refs, current, zoom, root) { + case path { + [] -> Ok(#([current, ..zoom], root)) + [path_element, ..path] -> { + use node <- result.then(map.get(refs, root)) + let zoom = [current, ..zoom] + let current = zip_match(node, path_element) + do_at_map(path, refs, current, zoom, root) + } + } +} + +// root and refs together from tree +pub fn at_map(path, root, refs) { + case path { + [] -> Ok(#([], root)) + [path_element, ..path] -> { + use node <- result.then(map.get(refs, root)) + let current = zip_match(node, path_element) + do_at_map(path, refs, current, [], root) + } + } +} + fn do_replace(old, new, zoom, rev) { case zoom { [] -> #(new, list.reverse(rev)) @@ -71,6 +97,7 @@ pub fn replace(tree, cursor, refs) { do_replace(old, new, list.append(zoom, [root]), rev) } } + // fn do_replace_map(old, new, zoom, rev) { // case zoom { // [] -> #(new, list.reverse(rev)) @@ -101,3 +128,10 @@ pub fn replace(tree, cursor, refs) { // do_replace_map(old, new, list.append(zoom, [root]), rev) // } // } + +pub fn inner(c) { + case c { + #([], root) -> root + #([ref, ..], _) -> ref + } +} diff --git a/eyg/src/eyg/incremental/store.gleam b/eyg/src/eyg/incremental/store.gleam index 004df492e..8808ea4dc 100644 --- a/eyg/src/eyg/incremental/store.gleam +++ b/eyg/src/eyg/incremental/store.gleam @@ -1,3 +1,4 @@ +import gleam/io import gleam/map.{Map} import gleam/result import gleam/set.{Set} @@ -10,12 +11,14 @@ import eyg/analysis/scheme.{Scheme} import eyg/analysis/unification import eyg/incremental/source import eyg/incremental/inference +import eyg/incremental/cursor pub type Store { Store( source: Map(Int, source.Expression), free: Map(Int, Set(String)), types: Map(Int, Map(Map(String, Scheme), t.Term)), + substitutions: sub.Substitutions, counter: javascript.Reference(Int), ) } @@ -25,6 +28,7 @@ pub fn empty() { source: map.new(), free: map.new(), types: map.new(), + substitutions: sub.none(), counter: javascript.make_reference(0), ) } @@ -69,7 +73,9 @@ pub fn free(store: Store, root) { } pub fn type_(store: Store, root) { - do_type(map.new(), root, store) + use #(unresolved, store) <- result.then(do_type(map.new(), root, store)) + let t = unification.resolve(store.substitutions, unresolved) + Ok(#(t, store)) } // Error only for invalid ref @@ -106,17 +112,29 @@ pub fn do_type(env, ref, store: Store) -> Result(_, _) { let ret = unification.fresh(store.counter) use #(t1, store) <- result.then(do_type(env, func, store)) use #(t2, store) <- result.then(do_type(env, arg, store)) - let s0 = + let unified = unification.unify( t.Fun(t2, t.Closed, t.Unbound(ret)), t1, store.counter, ) + io.debug(unified) + let store = case unified { + Ok(s) -> + Store(..store, substitutions: sub.compose(store.substitutions, s)) + Error(_reason) -> todo("unifiy failed") + } + Ok(#(t.Unbound(ret), store)) } source.Integer(_) -> Ok(#(t.Integer, store)) source.String(_) -> Ok(#(t.Binary, store)) - _ -> Ok(#(t.Unbound(unification.fresh(store.counter)), store)) + source.Tail -> Ok(#(t.tail(store.counter), store)) + source.Cons -> Ok(#(t.cons(store.counter), store)) + other -> { + io.debug(other) + todo("type needed") + } }) let types = inference.cache_update(store.types, ref, required, t) let store = Store(..store, types: types) @@ -124,3 +142,11 @@ pub fn do_type(env, ref, store: Store) -> Result(_, _) { } } } + +pub fn cursor(store: Store, root, path) { + cursor.at_map(path, root, store.source) +} + +pub fn focus(store: Store, c) { + map.get(store.source, cursor.inner(c)) +} diff --git a/eyg/test/eyg/incremental/store_test.gleam b/eyg/test/eyg/incremental/store_test.gleam index aae97eee2..8a4ab5037 100644 --- a/eyg/test/eyg/incremental/store_test.gleam +++ b/eyg/test/eyg/incremental/store_test.gleam @@ -1,9 +1,11 @@ import gleam/io +import gleam/list import gleam/map import gleam/set import eygir/expression as e import eyg/analysis/typ as t import eyg/incremental/store +import eyg/incremental/cursor import gleeunit/should pub fn literal_test() { @@ -29,3 +31,63 @@ pub fn literal_test() { should.equal(map.size(s.types), 2) should.equal(t, t.Integer) } + +pub fn function_unification_test() { + let s = store.empty() + + let tree = e.Apply(e.Lambda("x", e.Variable("x")), e.Binary("hey")) + let #(root, s) = store.load(s, tree) + should.equal(root, 3) + should.equal(map.size(s.source), 4) + + let assert Ok(#(t, s)) = store.type_(s, root) + should.equal(map.size(s.free), 4) + should.equal(map.size(s.types), 4) + + let assert Ok(c) = store.cursor(s, root, [1]) + let assert Ok(node) = store.focus(s, c) + // io.debug(node) test node + + // s should not change + let assert Ok(#(type_, _)) = store.type_(s, cursor.inner(c)) + should.equal(type_, t.Binary) + + let assert Ok(c) = store.cursor(s, root, [0]) + let assert Ok(node) = store.focus(s, c) + // io.debug(node) test node + + // s should not change + let assert Ok(#(type_, _)) = store.type_(s, cursor.inner(c)) + // binary -> binary because not generalised in let statement + should.equal(type_, t.Fun(t.Binary, t.Closed, t.Binary)) + + // should.equal(n, ) + should.equal(t, t.Binary) +} +// pub fn let_scope_test() { +// let s = store.empty() + +// let tree = +// e.Let( +// "x", +// e.Integer(10), +// e.Let( +// "y", +// e.Integer(20), +// e.Apply( +// e.Apply(e.Cons, e.Variable("y")), +// e.Apply(e.Apply(e.Cons, e.Variable("x")), e.Tail), +// ), +// ), +// ) +// let #(ref_binary, s) = store.load(s, tree) +// should.equal(ref_binary, 12) +// should.equal(map.size(s.source), 13) + +// let assert Ok(#(free, s)) = store.free(s, ref_binary) +// should.equal(map.size(s.free), 13) +// should.equal(free, set.new()) +// let assert Ok(#(t, s)) = store.type_(s, ref_binary) +// should.equal(map.size(s.types), 13) +// should.equal(t, t.LinkedList(t.Integer)) +// } From 4eef9fc26ac98a281401d80a8d4a901b28225dc0 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 7 Apr 2023 19:59:39 +0200 Subject: [PATCH 18/62] reuse language type def --- eyg/src/eyg/analysis/inference.gleam | 98 ++++------------------------ eyg/src/eyg/analysis/typ.gleam | 76 +++++++++++++++++++++ eyg/src/eyg/incremental/store.gleam | 20 ++++-- 3 files changed, 106 insertions(+), 88 deletions(-) diff --git a/eyg/src/eyg/analysis/inference.gleam b/eyg/src/eyg/analysis/inference.gleam index ab304acbf..f3873f6f8 100644 --- a/eyg/src/eyg/analysis/inference.gleam +++ b/eyg/src/eyg/analysis/inference.gleam @@ -197,92 +197,22 @@ fn do_infer(env, exp, typ, eff, ref, path) { map.new(), ) - e.Empty -> { - let t = t.Record(t.Closed) - unify(typ, t, ref, path) - } - e.Extend(label) -> { - let t = t.Unbound(fresh(ref)) - let r = t.Open(fresh(ref)) - let e1 = t.Open(fresh(ref)) - let e2 = t.Open(fresh(ref)) - t.Fun(t, e1, t.Fun(t.Record(r), e2, t.Record(t.Extend(label, t, r)))) - |> unify(typ, _, ref, path) - } - e.Overwrite(label) -> { - let t = t.Unbound(fresh(ref)) - let u = t.Unbound(fresh(ref)) - let r = t.Open(fresh(ref)) - let e1 = t.Open(fresh(ref)) - let e2 = t.Open(fresh(ref)) - t.Fun( - t, - e1, - t.Fun( - t.Record(t.Extend(label, u, r)), - e2, - t.Record(t.Extend(label, t, r)), - ), - ) - |> unify(typ, _, ref, path) - } - e.Select(label) -> { - let t = t.Unbound(fresh(ref)) - let r = t.Open(fresh(ref)) - let e = t.Open(fresh(ref)) - unify(typ, t.Fun(t.Record(t.Extend(label, t, r)), e, t), ref, path) - } + // Record + e.Empty -> unify(typ, t.empty(), ref, path) + e.Extend(label) -> unify(typ, t.extend(label, ref), ref, path) + e.Overwrite(label) -> unify(typ, t.overwrite(label, ref), ref, path) + e.Select(label) -> unify(typ, t.select(label, ref), ref, path) + // Union - e.Tag(label) -> { - let t = t.Unbound(fresh(ref)) - let r = t.Open(fresh(ref)) - let e = t.Open(fresh(ref)) - unify(typ, t.Fun(t, e, t.Union(t.Extend(label, t, r))), ref, path) - } - e.Case(label) -> { - let t = t.Unbound(fresh(ref)) - let ret = t.Unbound(fresh(ref)) - let r = t.Open(fresh(ref)) - let e1 = t.Open(fresh(ref)) - let e2 = t.Open(fresh(ref)) - let e3 = t.Open(fresh(ref)) - let e4 = t.Open(fresh(ref)) - let e5 = t.Open(fresh(ref)) - let branch = t.Fun(t, e1, ret) - let else = t.Fun(t.Union(r), e2, ret) - let exec = t.Fun(t.Union(t.Extend(label, t, r)), e3, ret) - t.Fun(branch, e4, t.Fun(else, e5, exec)) - |> unify(typ, _, ref, path) - } - e.NoCases -> { - // unbound return to match cases - let t = t.Unbound(fresh(ref)) - let e = t.Open(fresh(ref)) - t.Fun(t.Union(t.Closed), e, t) - |> unify(typ, _, ref, path) - } - e.Perform(label) -> { - let arg = t.Unbound(fresh(ref)) - let ret = t.Unbound(fresh(ref)) - let tail = t.Open(fresh(ref)) - unify(typ, t.Fun(arg, t.Extend(label, #(arg, ret), tail), ret), ref, path) - } - e.Handle(label) -> { - let ret = t.Unbound(fresh(ref)) - let lift = t.Unbound(fresh(ref)) - let reply = t.Unbound(fresh(ref)) - let tail = t.Open(fresh(ref)) + e.Tag(label) -> unify(typ, t.tag(label, ref), ref, path) + e.Case(label) -> unify(typ, t.case_(label, ref), ref, path) + e.NoCases -> unify(typ, t.nocases(ref), ref, path) + + // Effect + e.Perform(label) -> unify(typ, t.perform(label, ref), ref, path) + + e.Handle(label) -> unify(typ, t.handle(label, ref), ref, path) - let kont = t.Fun(reply, tail, ret) - let handler = t.Fun(lift, tail, t.Fun(kont, tail, ret)) - let exec = t.Fun(t.unit, t.Extend(label, #(lift, reply), tail), ret) - unify( - typ, - t.Fun(handler, t.Open(fresh(ref)), t.Fun(exec, tail, ret)), - ref, - path, - ) - } e.Builtin(identifier) -> case map.get(stdlib.lib().0, identifier) { Ok(scheme) -> unify(typ, instantiate(scheme, ref), ref, path) diff --git a/eyg/src/eyg/analysis/typ.gleam b/eyg/src/eyg/analysis/typ.gleam index 43aff50c3..b0e61e202 100644 --- a/eyg/src/eyg/analysis/typ.gleam +++ b/eyg/src/eyg/analysis/typ.gleam @@ -79,6 +79,82 @@ pub fn cons(ref) { Fun(t, e1, Fun(LinkedList(t), e2, LinkedList(t))) } +pub fn empty() { + Record(Closed) +} + +pub fn extend(label, ref) { + let t = Unbound(fresh(ref)) + let r = Open(fresh(ref)) + let e1 = Open(fresh(ref)) + let e2 = Open(fresh(ref)) + Fun(t, e1, Fun(Record(r), e2, Record(Extend(label, t, r)))) +} + +pub fn select(label, ref) { + let t = Unbound(fresh(ref)) + let r = Open(fresh(ref)) + let e = Open(fresh(ref)) + Fun(Record(Extend(label, t, r)), e, t) +} + +pub fn overwrite(label, ref) { + let t = Unbound(fresh(ref)) + let u = Unbound(fresh(ref)) + let r = Open(fresh(ref)) + let e1 = Open(fresh(ref)) + let e2 = Open(fresh(ref)) + Fun(t, e1, Fun(Record(Extend(label, u, r)), e2, Record(Extend(label, t, r)))) +} + +pub fn tag(label, ref) { + let t = Unbound(fresh(ref)) + let r = Open(fresh(ref)) + let e = Open(fresh(ref)) + Fun(t, e, Union(Extend(label, t, r))) +} + +pub fn case_(label, ref) { + let t = Unbound(fresh(ref)) + let ret = Unbound(fresh(ref)) + let r = Open(fresh(ref)) + let e1 = Open(fresh(ref)) + let e2 = Open(fresh(ref)) + let e3 = Open(fresh(ref)) + let e4 = Open(fresh(ref)) + let e5 = Open(fresh(ref)) + let branch = Fun(t, e1, ret) + let else = Fun(Union(r), e2, ret) + let exec = Fun(Union(Extend(label, t, r)), e3, ret) + Fun(branch, e4, Fun(else, e5, exec)) +} + +pub fn nocases(ref) { + // unbound return to match cases + let t = Unbound(fresh(ref)) + let e = Open(fresh(ref)) + Fun(Union(Closed), e, t) +} + +pub fn perform(label, ref) { + let arg = Unbound(fresh(ref)) + let ret = Unbound(fresh(ref)) + let tail = Open(fresh(ref)) + Fun(arg, Extend(label, #(arg, ret), tail), ret) +} + +pub fn handle(label, ref) { + let ret = Unbound(fresh(ref)) + let lift = Unbound(fresh(ref)) + let reply = Unbound(fresh(ref)) + let tail = Open(fresh(ref)) + + let kont = Fun(reply, tail, ret) + let handler = Fun(lift, tail, Fun(kont, tail, ret)) + let exec = Fun(unit, Extend(label, #(lift, reply), tail), ret) + Fun(handler, Open(fresh(ref)), Fun(exec, tail, ret)) +} + // copied from unification to not get circular ref pub fn fresh(ref) { javascript.update_reference(ref, fn(x) { x + 1 }) diff --git a/eyg/src/eyg/incremental/store.gleam b/eyg/src/eyg/incremental/store.gleam index 8808ea4dc..ce4cabbdc 100644 --- a/eyg/src/eyg/incremental/store.gleam +++ b/eyg/src/eyg/incremental/store.gleam @@ -131,11 +131,23 @@ pub fn do_type(env, ref, store: Store) -> Result(_, _) { source.String(_) -> Ok(#(t.Binary, store)) source.Tail -> Ok(#(t.tail(store.counter), store)) source.Cons -> Ok(#(t.cons(store.counter), store)) - other -> { - io.debug(other) - todo("type needed") - } + source.Vacant(_) -> + Ok(#(t.Unbound(unification.fresh(store.counter)), store)) + source.Empty -> Ok(#(t.empty(), store)) + source.Extend(label) -> Ok(#(t.extend(label, store.counter), store)) + source.Select(label) -> Ok(#(t.select(label, store.counter), store)) + source.Overwrite(label) -> + Ok(#(t.overwrite(label, store.counter), store)) + source.Tag(label) -> Ok(#(t.tag(label, store.counter), store)) + source.Case(label) -> Ok(#(t.case_(label, store.counter), store)) + source.NoCases -> Ok(#(t.nocases(store.counter), store)) + source.Perform(label) -> Ok(#(t.perform(label, store.counter), store)) + source.Handle(label) -> Ok(#(t.handle(label, store.counter), store)) + source.Builtin(_) -> + Ok(#(t.Unbound(unification.fresh(store.counter)), store)) }) + // TODO lookup builtins + // Ok(#(t.builtin(store.counter), store)) let types = inference.cache_update(store.types, ref, required, t) let store = Store(..store, types: types) Ok(#(t, store)) From 55c6632b9adf3a1cc07b6bc84c7e69fb096d5208 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 7 Apr 2023 20:02:05 +0200 Subject: [PATCH 19/62] just log failure --- eyg/src/eyg/incremental/store.gleam | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/eyg/src/eyg/incremental/store.gleam b/eyg/src/eyg/incremental/store.gleam index ce4cabbdc..256d5692f 100644 --- a/eyg/src/eyg/incremental/store.gleam +++ b/eyg/src/eyg/incremental/store.gleam @@ -122,7 +122,11 @@ pub fn do_type(env, ref, store: Store) -> Result(_, _) { let store = case unified { Ok(s) -> Store(..store, substitutions: sub.compose(store.substitutions, s)) - Error(_reason) -> todo("unifiy failed") + Error(_reason) -> { + io.debug("unifiy failed") + // TODO handle failure + store + } } Ok(#(t.Unbound(ret), store)) From 8aa27dd3b08963717671cdbdaf1664f9c8eba3c3 Mon Sep 17 00:00:00 2001 From: Peter Saxton Date: Fri, 7 Apr 2023 22:21:46 +0200 Subject: [PATCH 20/62] fix map cursor build --- eyg/src/eyg/incremental/cursor.gleam | 3 +-- eyg/test/eyg/incremental/store_test.gleam | 10 ++++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/eyg/src/eyg/incremental/cursor.gleam b/eyg/src/eyg/incremental/cursor.gleam index 12d26a61d..c78ef5943 100644 --- a/eyg/src/eyg/incremental/cursor.gleam +++ b/eyg/src/eyg/incremental/cursor.gleam @@ -2,7 +2,6 @@ import gleam/io import gleam/list import gleam/map import gleam/result -import eygir/expression as e import eyg/incremental/source.{Call, Fn, Let} pub fn zip_match(node, path_element) { @@ -47,7 +46,7 @@ fn do_at_map(path, refs, current, zoom, root) { case path { [] -> Ok(#([current, ..zoom], root)) [path_element, ..path] -> { - use node <- result.then(map.get(refs, root)) + use node <- result.then(map.get(refs, current)) let zoom = [current, ..zoom] let current = zip_match(node, path_element) do_at_map(path, refs, current, zoom, root) diff --git a/eyg/test/eyg/incremental/store_test.gleam b/eyg/test/eyg/incremental/store_test.gleam index 8a4ab5037..cb431abca 100644 --- a/eyg/test/eyg/incremental/store_test.gleam +++ b/eyg/test/eyg/incremental/store_test.gleam @@ -1,9 +1,9 @@ import gleam/io -import gleam/list import gleam/map import gleam/set import eygir/expression as e import eyg/analysis/typ as t +import eyg/incremental/source import eyg/incremental/store import eyg/incremental/cursor import gleeunit/should @@ -46,14 +46,16 @@ pub fn function_unification_test() { let assert Ok(c) = store.cursor(s, root, [1]) let assert Ok(node) = store.focus(s, c) - // io.debug(node) test node + should.equal(node, source.String("hey")) - // s should not change + // s does not change on fetching inner type let assert Ok(#(type_, _)) = store.type_(s, cursor.inner(c)) should.equal(type_, t.Binary) - let assert Ok(c) = store.cursor(s, root, [0]) + let assert Ok(c) = store.cursor(s, root, [0, 0]) let assert Ok(node) = store.focus(s, c) + should.equal(node, source.Var("x")) + // io.debug(node) test node // s should not change From 081556f56941d3d8257dda6d87ed23882af8cdd2 Mon Sep 17 00:00:00 2001 From: Peter Saxton Date: Fri, 7 Apr 2023 23:04:19 +0200 Subject: [PATCH 21/62] store replace --- eyg/src/eyg/incremental/store.gleam | 51 +++++++++++++++++++++-- eyg/test/eyg/incremental/store_test.gleam | 42 ++++++++++++++++--- 2 files changed, 85 insertions(+), 8 deletions(-) diff --git a/eyg/src/eyg/incremental/store.gleam b/eyg/src/eyg/incremental/store.gleam index 256d5692f..11fa8b7d0 100644 --- a/eyg/src/eyg/incremental/store.gleam +++ b/eyg/src/eyg/incremental/store.gleam @@ -1,4 +1,5 @@ import gleam/io +import gleam/list import gleam/map.{Map} import gleam/result import gleam/set.{Set} @@ -87,14 +88,23 @@ pub fn do_type(env, ref, store: Store) -> Result(_, _) { Error(Nil) -> { use node <- result.then(map.get(store.source, ref)) use #(t, store) <- result.then(case node { - source.Var(x) -> - case map.get(env, x) { + source.Var(x) -> { + io.debug(#( + env + |> map.to_list, + x, + )) + case + map.get(env, x) + |> io.debug + { Ok(scheme) -> { let t = unification.instantiate(scheme, store.counter) Ok(#(t, store)) } - Error(Nil) -> todo("no var") + Error(Nil) -> todo("no var in env") } + } source.Let(x, value, then) -> { use #(t1, store) <- result.then(do_type(env, value, store)) let scheme = unification.generalise(env, t1) @@ -163,6 +173,41 @@ pub fn cursor(store: Store, root, path) { cursor.at_map(path, root, store.source) } +fn do_replace(old_id, new_id, zoom, store: Store) { + case zoom { + [] -> Ok(#(new_id, store)) + [next, ..zoom] -> { + use node <- result.then(map.get(store.source, next)) + let exp = case node { + source.Let(label, value, then) if value == old_id -> + source.Let(label, new_id, then) + source.Let(label, value, then) if then == old_id -> + source.Let(label, value, new_id) + source.Fn(param, body) if body == old_id -> source.Fn(param, new_id) + source.Call(func, arg) if func == old_id -> source.Call(new_id, arg) + source.Call(func, arg) if arg == old_id -> source.Call(func, new_id) + _ -> todo("Can't have a path into literal") + } + let new_id = map.size(store.source) + let source = map.insert(store.source, new_id, exp) + let store = Store(..store, source: source) + do_replace(next, new_id, zoom, store) + } + } +} + +// could separate pushing one item from fn and pass in new index here +pub fn replace(store: Store, cursor, exp) { + let new_id = map.size(store.source) + let source = map.insert(store.source, new_id, exp) + let store = Store(..store, source: source) + case cursor { + #([], old) -> do_replace(old, new_id, [], store) + #([old, ..zoom], root) -> + do_replace(old, new_id, list.append(zoom, [root]), store) + } +} + pub fn focus(store: Store, c) { map.get(store.source, cursor.inner(c)) } diff --git a/eyg/test/eyg/incremental/store_test.gleam b/eyg/test/eyg/incremental/store_test.gleam index cb431abca..97e4e42b7 100644 --- a/eyg/test/eyg/incremental/store_test.gleam +++ b/eyg/test/eyg/incremental/store_test.gleam @@ -41,12 +41,37 @@ pub fn function_unification_test() { should.equal(map.size(s.source), 4) let assert Ok(#(t, s)) = store.type_(s, root) + should.equal(t, t.Binary) should.equal(map.size(s.free), 4) should.equal(map.size(s.types), 4) let assert Ok(c) = store.cursor(s, root, [1]) let assert Ok(node) = store.focus(s, c) should.equal(node, source.String("hey")) + let assert Ok(#(root1, s)) = store.replace(s, c, source.Integer(10)) + should.equal(map.size(s.source), 6) + + let assert Ok(c) = store.cursor(s, root, [0, 0]) + let assert Ok(node) = store.focus(s, c) + should.equal(node, source.Var("x")) + let assert Ok(#(root2, s)) = store.replace(s, c, source.Empty) + should.equal(map.size(s.source), 9) + // source increase by path length + 1 + // free and types are lazy so stay at 4 + should.equal(map.size(s.free), 4) + should.equal(map.size(s.types), 4) + + let assert Ok(#(t, s)) = store.type_(s, root1) + should.equal(t, t.Integer) + let assert Ok(#(t, s)) = store.type_(s, root2) + should.equal(t, t.unit) + + should.equal(map.size(s.free), 9) + should.equal(map.size(s.types), 9) + + todo("not here because type_ doesn't work to just reach in") + // hash of type or id includes free + // TODO need type in tree, and errors // s does not change on fetching inner type let assert Ok(#(type_, _)) = store.type_(s, cursor.inner(c)) @@ -56,16 +81,23 @@ pub fn function_unification_test() { let assert Ok(node) = store.focus(s, c) should.equal(node, source.Var("x")) - // io.debug(node) test node - - // s should not change + // s does not change on fetching inner type + io.debug("------------") + io.debug(#( + cursor.inner(c), + map.keys(s.types), + s.types + |> map.get(cursor.inner(c)), + )) + // How do I get the actual type value. only root works + // |> map.to_list, let assert Ok(#(type_, _)) = store.type_(s, cursor.inner(c)) // binary -> binary because not generalised in let statement should.equal(type_, t.Fun(t.Binary, t.Closed, t.Binary)) - + io.debug("------------") // should.equal(n, ) - should.equal(t, t.Binary) } +// TODO generalization test // pub fn let_scope_test() { // let s = store.empty() From ca19adc0b56eef61ec2aecb2e1118bdd759ed57e Mon Sep 17 00:00:00 2001 From: Peter Saxton Date: Fri, 7 Apr 2023 23:19:37 +0200 Subject: [PATCH 22/62] time store in browser --- eyg/src/atelier/app.gleam | 31 +++++++++++++++++++++++++++-- eyg/src/eyg/incremental/store.gleam | 11 +--------- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index f22ee2d25..c84b980f3 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -5,6 +5,7 @@ import gleam/int import gleam/list import gleam/map import gleam/option.{None, Option, Some} +import gleam/set import gleam/string import gleam/fetch import gleam/http @@ -62,6 +63,7 @@ pub fn init(source) { let assert Ok(act) = transform.prepare(source, []) let mode = Navigate(act) + let path = [1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0] let start = pnow() let #(root, s) = store.load(store.empty(), source) io.debug(#( @@ -79,7 +81,8 @@ pub fn init(source) { pnow() - start, map.size(s.source), map.size(s.free), - vars, + vars + |> set.to_list, )) let start = pnow() @@ -94,6 +97,31 @@ pub fn init(source) { t, )) + let start = pnow() + let assert Ok(c) = store.cursor(s, root, path) + io.debug(#("building store.cursor took ms:", pnow() - start)) + // io.debug(c) + let start = pnow() + let assert Ok(#(root_, s)) = store.replace(s, c, incremental.String("hello")) + io.debug(#( + "updating store.replace took ms:", + pnow() - start, + map.size(s.source), + map.size(s.free), + map.size(s.types), + )) + let start = pnow() + let assert Ok(#(t, s)) = store.type_(s, root_) + // TODO i think should be same size + io.debug(#( + "typing took ms:", + pnow() - start, + map.size(s.source), + map.size(s.free), + map.size(s.types), + t, + )) + // not helpful // list.map(map.to_list(s.types), io.debug) io.debug("------------------------") @@ -122,7 +150,6 @@ pub fn init(source) { new_i.cached(root, refs, f, map.new(), env.empty(), sub.none(), count) io.debug(#("initial type check took ms:", pnow() - start)) - let path = [1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0] let start = pnow() let c = cursor.at(path, root, refs) io.debug(#("building cursor took ms:", pnow() - start)) diff --git a/eyg/src/eyg/incremental/store.gleam b/eyg/src/eyg/incremental/store.gleam index 11fa8b7d0..f39319181 100644 --- a/eyg/src/eyg/incremental/store.gleam +++ b/eyg/src/eyg/incremental/store.gleam @@ -89,15 +89,7 @@ pub fn do_type(env, ref, store: Store) -> Result(_, _) { use node <- result.then(map.get(store.source, ref)) use #(t, store) <- result.then(case node { source.Var(x) -> { - io.debug(#( - env - |> map.to_list, - x, - )) - case - map.get(env, x) - |> io.debug - { + case map.get(env, x) { Ok(scheme) -> { let t = unification.instantiate(scheme, store.counter) Ok(#(t, store)) @@ -128,7 +120,6 @@ pub fn do_type(env, ref, store: Store) -> Result(_, _) { t1, store.counter, ) - io.debug(unified) let store = case unified { Ok(s) -> Store(..store, substitutions: sub.compose(store.substitutions, s)) From ccbb1bb6b56e87b8f2290fc0fa09a9861a03a2d9 Mon Sep 17 00:00:00 2001 From: Peter Saxton Date: Sat, 8 Apr 2023 00:18:58 +0200 Subject: [PATCH 23/62] show that free mem is empty sometimes --- eyg/src/atelier/app.gleam | 26 ++++++++++- eyg/src/eyg/incremental/store.gleam | 56 +++++++++++++++++------ eyg/test/eyg/incremental/store_test.gleam | 32 +++++++++++-- 3 files changed, 95 insertions(+), 19 deletions(-) diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index c84b980f3..d99af1b92 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -69,12 +69,15 @@ pub fn init(source) { io.debug(#( "loading store took ms:", pnow() - start, + root, map.size(s.source), map.size(s.free), )) let start = pnow() - let assert Ok(#(vars, s)) = store.free(s, root) + let assert Ok(#(vars, s, x)) = store.free(s, root, []) + // OK map works + io.debug(#("othr", list.length(x))) // TODO i think should be same size io.debug(#( "memoizing free took ms:", @@ -84,6 +87,27 @@ pub fn init(source) { vars |> set.to_list, )) + io.debug(map.get(s.source, root)) + io.debug(map.get(s.source, root - 1)) + io.debug(map.get(s.source, root - 2)) + io.debug(map.get(s.source, root - 3)) + io.debug(map.get(s.source, root - 4)) + io.debug(map.get(s.source, 0)) + io.debug(map.get(s.source, 1)) + + io.debug(map.get(s.free, root)) + io.debug(map.get(s.free, root - 1)) + io.debug(map.get(s.free, root - 2)) + io.debug(map.get(s.free, root - 3)) + io.debug(map.get(s.free, root - 4)) + io.debug(map.get(s.free, 0)) + io.debug(map.get(s.free, 1)) + + // io.debug(#("free--", map.get(s.free, 5757))) + io.debug(list.length(map.to_list(s.source))) + + io.debug(list.length(map.to_list(s.free))) + // todo("wat") let start = pnow() let assert Ok(#(t, s)) = store.type_(s, root) diff --git a/eyg/src/eyg/incremental/store.gleam b/eyg/src/eyg/incremental/store.gleam index f39319181..7f08aaf65 100644 --- a/eyg/src/eyg/incremental/store.gleam +++ b/eyg/src/eyg/incremental/store.gleam @@ -35,40 +35,66 @@ pub fn empty() { } pub fn load(store: Store, tree) { + // maybe just include the exp let #(exp, acc) = source.do_from_tree_map(tree, store.source) let index = map.size(acc) let source = map.insert(acc, index, exp) #(index, Store(..store, source: source)) } -pub fn free(store: Store, root) { +pub fn free( + store: Store, + root, + acc, +) -> Result(#(Set(String), Store, List(#(Int, Set(String)))), Nil) { case map.get(store.free, root) { - Ok(vars) -> Ok(#(vars, store)) + Ok(vars) -> { + io.debug(#( + "found----", + root, + map.get(store.source, root), + map.size(store.free), + list.length(acc), + )) + Ok(#(vars, store, acc)) + } Error(Nil) -> { use node <- result.then(map.get(store.source, root)) - use #(vars, store) <- result.then(case node { - source.Var(x) -> Ok(#(setx.singleton(x), store)) + use #(vars, store, acc) <- result.then(case node { + source.Var(x) -> Ok(#(setx.singleton(x), store, acc)) source.Fn(x, ref) -> { - use #(vars, store) <- result.then(free(store, ref)) - Ok(#(set.delete(vars, x), store)) + use #(vars, store, acc) <- result.then(free(store, ref, acc)) + Ok(#(set.delete(vars, x), store, acc)) } source.Let(x, ref_v, ref_t) -> { - use #(value, store) <- result.then(free(store, ref_v)) - use #(then, store) <- result.then(free(store, ref_t)) + use #(value, store, acc) <- result.then(free(store, ref_v, acc)) + use #(then, store, acc) <- result.then(free(store, ref_t, acc)) let vars = set.union(value, set.delete(then, x)) - Ok(#(vars, store)) + Ok(#(vars, store, acc)) } source.Call(ref_func, ref_arg) -> { - use #(func, store) <- result.then(free(store, ref_func)) - use #(arg, store) <- result.then(free(store, ref_arg)) + use #(func, store, acc) <- result.then(free(store, ref_func, acc)) + use #(arg, store, acc) <- result.then(free(store, ref_arg, acc)) let vars = set.union(func, arg) - Ok(#(vars, store)) + Ok(#(vars, store, acc)) } - _ -> Ok(#(set.new(), store)) + _ -> Ok(#(set.new(), store, acc)) }) + let before = map.size(store.free) let free = map.insert(store.free, root, vars) + let acc = [#(root, vars), ..acc] let store = Store(..store, free: free) - Ok(#(vars, store)) + let after = map.size(store.free) + case after - before { + 0 -> { + io.debug(#(node, before, root)) + todo("this shouldn't happen") + // and it doesn't + Nil + } + 1 -> Nil + } + Ok(#(vars, store, acc)) } } } @@ -81,7 +107,7 @@ pub fn type_(store: Store, root) { // Error only for invalid ref pub fn do_type(env, ref, store: Store) -> Result(_, _) { - use #(vars, store) <- result.then(free(store, ref)) + use #(vars, store, _) <- result.then(free(store, ref, [])) let required = map.take(env, set.to_list(vars)) case inference.cache_lookup(store.types, ref, required) { Ok(t) -> Ok(#(t, store)) diff --git a/eyg/test/eyg/incremental/store_test.gleam b/eyg/test/eyg/incremental/store_test.gleam index 97e4e42b7..110c435dc 100644 --- a/eyg/test/eyg/incremental/store_test.gleam +++ b/eyg/test/eyg/incremental/store_test.gleam @@ -15,7 +15,7 @@ pub fn literal_test() { let #(ref_binary, s) = store.load(s, tree) should.equal(ref_binary, 0) // should.equal(store.tree(s, ref_binary), Ok(tree)) - let assert Ok(#(free, s)) = store.free(s, ref_binary) + let assert Ok(#(free, s, _)) = store.free(s, ref_binary, []) should.equal(map.size(s.free), 1) should.equal(free, set.new()) let assert Ok(#(t, s)) = store.type_(s, ref_binary) @@ -24,7 +24,7 @@ pub fn literal_test() { let #(ref_integer, s) = store.load(s, e.Integer(5)) should.equal(ref_integer, 1) - let assert Ok(#(free, s)) = store.free(s, ref_integer) + let assert Ok(#(free, s, _)) = store.free(s, ref_integer, []) should.equal(map.size(s.free), 2) should.equal(free, set.new()) let assert Ok(#(t, s)) = store.type_(s, ref_integer) @@ -97,6 +97,32 @@ pub fn function_unification_test() { io.debug("------------") // should.equal(n, ) } + +pub fn let_test() { + let s = store.empty() + + let tree = + e.Let( + "x", + e.Let("tmp", e.Binary("i"), e.Binary("o")), + e.Let( + "y", + e.Integer(1), + e.Apply(e.Apply(e.Extend("a"), e.Variable("x")), e.Empty), + ), + ) + let #(root, s) = store.load(s, tree) + should.equal(root, 10) + should.equal(map.size(s.source), 11) + + let assert Ok(#(t, s, _)) = store.free(s, root, []) + // should.equal(t, t.Integer) + should.equal(map.size(s.free), 11) + // Where is it going wrong + should.equal(map.size(s.types), 0) + // all seems to work. + // TODO where am I loosing elements +} // TODO generalization test // pub fn let_scope_test() { // let s = store.empty() @@ -118,7 +144,7 @@ pub fn function_unification_test() { // should.equal(ref_binary, 12) // should.equal(map.size(s.source), 13) -// let assert Ok(#(free, s)) = store.free(s, ref_binary) +// let assert Ok(#(free, s,_)) = store.free(s, ref_binary, []) // should.equal(map.size(s.free), 13) // should.equal(free, set.new()) // let assert Ok(#(t, s)) = store.type_(s, ref_binary) From 572138e67f615d67723eefe0b60cede8703bf4cf Mon Sep 17 00:00:00 2001 From: Peter Saxton Date: Sat, 8 Apr 2023 00:25:41 +0200 Subject: [PATCH 24/62] give up --- eyg/src/atelier/app.gleam | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index d99af1b92..7c84f474f 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -103,11 +103,20 @@ pub fn init(source) { io.debug(map.get(s.free, 0)) io.debug(map.get(s.free, 1)) + io.debug("====================") + // Not all in a line + + let at = map.size(s.source) - map.size(s.free) + io.debug(#(map.get(s.free, at - 100), at - 100)) + io.debug(#(map.get(s.free, at), at)) + io.debug(#(map.get(s.free, at + 1), at + 1)) + io.debug("====================") + // io.debug(#("free--", map.get(s.free, 5757))) io.debug(list.length(map.to_list(s.source))) io.debug(list.length(map.to_list(s.free))) - // todo("wat") + todo("wat") let start = pnow() let assert Ok(#(t, s)) = store.type_(s, root) From 6e05067d66f8b0c0f28d90099460e5d2b0ad63dc Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 8 Apr 2023 11:03:25 +0200 Subject: [PATCH 25/62] fix subs --- eyg/src/eyg/incremental/inference.gleam | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/eyg/src/eyg/incremental/inference.gleam b/eyg/src/eyg/incremental/inference.gleam index 6f866ee12..32351e53d 100644 --- a/eyg/src/eyg/incremental/inference.gleam +++ b/eyg/src/eyg/incremental/inference.gleam @@ -153,13 +153,20 @@ pub fn cached( } source.Call(func, arg) -> { let ret = unification.fresh(count) - let #(t1, s1, types) = + let #(t1, subs, types) = cached(func, source, frees, types, env, subs, count) - let #(t2, s2, types) = + let #(t2, subs, types) = cached(arg, source, frees, types, env, subs, count) - let s0 = + let subs = case unification.unify(t.Fun(t2, t.Closed, t.Unbound(ret)), t1, count) - #(t.Unbound(ret), s1, types) + { + Ok(su) -> sub.compose(subs, su) + Error(reason) -> { + io.debug(reason) + subs + } + } + #(t.Unbound(ret), subs, types) } source.Integer(_) -> #(t.Integer, subs, types) source.String(_) -> #(t.Binary, subs, types) From 7916808adc767c82ee1917d1c3eea8b785ff4c51 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 8 Apr 2023 11:44:18 +0200 Subject: [PATCH 26/62] fix all warnings --- eyg/src/atelier/app.gleam | 264 +++++++++++----------- eyg/src/eyg/incremental/cursor.gleam | 4 +- eyg/src/eyg/incremental/inference.gleam | 12 +- eyg/src/eyg/incremental/store.gleam | 6 +- eyg/src/eyg/runtime/capture.gleam | 4 +- eyg/src/eyg/runtime/interpreter.gleam | 8 +- eyg/src/harness/effect.gleam | 9 +- eyg/src/harness/ffi/core.gleam | 3 - eyg/src/platforms/browser.gleam | 4 +- eyg/src/platforms/cli.gleam | 7 +- eyg/src/platforms/serverless.gleam | 7 +- eyg/src/plinth/browser/document.gleam | 1 - eyg/test/eyg/incremental/store_test.gleam | 6 +- eyg/test/hash_test.gleam | 17 +- eyg/test/incremental_and_zip_test.gleam | 214 ------------------ eyg/test/incremental_test.gleam | 16 +- 16 files changed, 174 insertions(+), 408 deletions(-) delete mode 100644 eyg/test/incremental_and_zip_test.gleam diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index 7c84f474f..989aae50c 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -5,24 +5,17 @@ import gleam/int import gleam/list import gleam/map import gleam/option.{None, Option, Some} -import gleam/set import gleam/string import gleam/fetch import gleam/http import gleam/http/request -import gleam/javascript import lustre/cmd import atelier/transform.{Act} import eygir/expression as e import eygir/encode import eyg/analysis/inference import eyg/runtime/standard -import eyg/incremental/source as incremental -import eyg/incremental/inference as new_i -import eyg/incremental/cursor import eyg/incremental/store -import eyg/analysis/substitutions as sub -import eyg/analysis/env pub type WorkSpace { WorkSpace( @@ -36,7 +29,6 @@ pub type WorkSpace { List(#(e.Expression, List(Int))), List(#(e.Expression, List(Int))), ), - incremental: new_i.Cache, ) } @@ -63,7 +55,7 @@ pub fn init(source) { let assert Ok(act) = transform.prepare(source, []) let mode = Navigate(act) - let path = [1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0] + // let path = [1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0] let start = pnow() let #(root, s) = store.load(store.empty(), source) io.debug(#( @@ -74,151 +66,153 @@ pub fn init(source) { map.size(s.free), )) - let start = pnow() - let assert Ok(#(vars, s, x)) = store.free(s, root, []) - // OK map works - io.debug(#("othr", list.length(x))) - // TODO i think should be same size - io.debug(#( - "memoizing free took ms:", - pnow() - start, - map.size(s.source), - map.size(s.free), - vars - |> set.to_list, - )) - io.debug(map.get(s.source, root)) - io.debug(map.get(s.source, root - 1)) - io.debug(map.get(s.source, root - 2)) - io.debug(map.get(s.source, root - 3)) - io.debug(map.get(s.source, root - 4)) - io.debug(map.get(s.source, 0)) - io.debug(map.get(s.source, 1)) - - io.debug(map.get(s.free, root)) - io.debug(map.get(s.free, root - 1)) - io.debug(map.get(s.free, root - 2)) - io.debug(map.get(s.free, root - 3)) - io.debug(map.get(s.free, root - 4)) - io.debug(map.get(s.free, 0)) - io.debug(map.get(s.free, 1)) - - io.debug("====================") - // Not all in a line - - let at = map.size(s.source) - map.size(s.free) - io.debug(#(map.get(s.free, at - 100), at - 100)) - io.debug(#(map.get(s.free, at), at)) - io.debug(#(map.get(s.free, at + 1), at + 1)) - io.debug("====================") - - // io.debug(#("free--", map.get(s.free, 5757))) - io.debug(list.length(map.to_list(s.source))) - - io.debug(list.length(map.to_list(s.free))) - todo("wat") - - let start = pnow() - let assert Ok(#(t, s)) = store.type_(s, root) - // TODO i think should be same size - io.debug(#( - "typing took ms:", - pnow() - start, - map.size(s.source), - map.size(s.free), - map.size(s.types), - t, - )) - - let start = pnow() - let assert Ok(c) = store.cursor(s, root, path) - io.debug(#("building store.cursor took ms:", pnow() - start)) - // io.debug(c) - let start = pnow() - let assert Ok(#(root_, s)) = store.replace(s, c, incremental.String("hello")) - io.debug(#( - "updating store.replace took ms:", - pnow() - start, - map.size(s.source), - map.size(s.free), - map.size(s.types), - )) - let start = pnow() - let assert Ok(#(t, s)) = store.type_(s, root_) - // TODO i think should be same size - io.debug(#( - "typing took ms:", - pnow() - start, - map.size(s.source), - map.size(s.free), - map.size(s.types), - t, - )) + // let start = pnow() + // let assert Ok(#(vars, s, x)) = store.free(s, root, []) + // // OK map works + // io.debug(#("othr", list.length(x))) + // // TODO i think should be same size + // io.debug(#( + // "memoizing free took ms:", + // pnow() - start, + // map.size(s.source), + // map.size(s.free), + // vars + // |> set.to_list, + // )) + // io.debug(map.get(s.source, root)) + // io.debug(map.get(s.source, root - 1)) + // io.debug(map.get(s.source, root - 2)) + // io.debug(map.get(s.source, root - 3)) + // io.debug(map.get(s.source, root - 4)) + // io.debug(map.get(s.source, 0)) + // io.debug(map.get(s.source, 1)) + + // io.debug(map.get(s.free, root)) + // io.debug(map.get(s.free, root - 1)) + // io.debug(map.get(s.free, root - 2)) + // io.debug(map.get(s.free, root - 3)) + // io.debug(map.get(s.free, root - 4)) + // io.debug(map.get(s.free, 0)) + // io.debug(map.get(s.free, 1)) + + // io.debug("====================") + // // Not all in a line + + // let at = map.size(s.source) - map.size(s.free) + // io.debug(#(map.get(s.free, at - 100), at - 100)) + // io.debug(#(map.get(s.free, at), at)) + // io.debug(#(map.get(s.free, at + 1), at + 1)) + // io.debug("====================") + + // // io.debug(#("free--", map.get(s.free, 5757))) + // io.debug(list.length(map.to_list(s.source))) + + // io.debug(list.length(map.to_list(s.free))) + // todo("wat") + + // let start = pnow() + // let assert Ok(#(t, s)) = store.type_(s, root) + // // TODO i think should be same size + // io.debug(#( + // "typing took ms:", + // pnow() - start, + // map.size(s.source), + // map.size(s.free), + // map.size(s.types), + // t, + // )) + + // let start = pnow() + // let assert Ok(c) = store.cursor(s, root, path) + // io.debug(#("building store.cursor took ms:", pnow() - start)) + // // io.debug(c) + // let start = pnow() + // let assert Ok(#(root_, s)) = store.replace(s, c, incremental.String("hello")) + // io.debug(#( + // "updating store.replace took ms:", + // pnow() - start, + // map.size(s.source), + // map.size(s.free), + // map.size(s.types), + // )) + // let start = pnow() + // let assert Ok(#(t, s)) = store.type_(s, root_) + // // TODO i think should be same size + // io.debug(#( + // "typing took ms:", + // pnow() - start, + // map.size(s.source), + // map.size(s.free), + // map.size(s.types), + // t, + // )) // not helpful // list.map(map.to_list(s.types), io.debug) io.debug("------------------------") - let start = pnow() - let #(root, refs) = incremental.from_tree(source) - io.debug(#("building incremental took ms:", pnow() - start, list.length(refs))) - let start = pnow() - let #(root, refs_map) = incremental.from_tree_map(source) - io.debug(#( - "building incremental map took ms:", - pnow() - start, - map.size(refs_map), - )) - - let start = pnow() - let f = new_i.free(refs, []) - io.debug(#("finding free took ms:", pnow() - start)) - let start = pnow() - let fm = new_i.free_map(refs, map.new()) - io.debug(#("finding free took ms:", pnow() - start)) - - let count = javascript.make_reference(0) - let start = pnow() - let #(t, s, cache) = - new_i.cached(root, refs, f, map.new(), env.empty(), sub.none(), count) - io.debug(#("initial type check took ms:", pnow() - start)) - - let start = pnow() - let c = cursor.at(path, root, refs) - io.debug(#("building cursor took ms:", pnow() - start)) - io.debug(c) + // let start = pnow() + // let #(root, refs) = incremental.from_tree(source) + // io.debug(#("building incremental took ms:", pnow() - start, list.length(refs))) + // let start = pnow() + // let #(root, refs_map) = incremental.from_tree_map(source) + // io.debug(#( + // "building incremental map took ms:", + // pnow() - start, + // map.size(refs_map), + // )) + + // let start = pnow() + // let f = new_i.free(refs, []) + // io.debug(#("finding free took ms:", pnow() - start)) + // let start = pnow() + // let fm = new_i.free_map(refs, map.new()) + // io.debug(#("finding free took ms:", pnow() - start)) + + // let count = javascript.make_reference(0) + // let start = pnow() + // let #(t, s, cache) = + // new_i.cached(root, refs, f, map.new(), env.empty(), sub.none(), count) + // io.debug(#("initial type check took ms:", pnow() - start)) + + // let start = pnow() + // let c = cursor.at(path, root, refs) + // io.debug(#("building cursor took ms:", pnow() - start)) + // io.debug(c) - let start = pnow() - let refs_map = - list.index_map(refs, fn(i, r) { #(i, r) }) - |> map.from_list() - io.debug(#("list to map took ms:", pnow() - start)) + // let start = pnow() + // let refs_map = + // list.index_map(refs, fn(i, r) { #(i, r) }) + // |> map.from_list() + // io.debug(#("list to map took ms:", pnow() - start)) - let start = pnow() - let #(x, refs) = cursor.replace(e.Binary("hello"), c, refs) - io.debug(#("replacing at cursor took ms:", pnow() - start)) - io.debug(x) + // let start = pnow() + // let #(x, refs) = cursor.replace(e.Binary("hello"), c, refs) + // io.debug(#("replacing at cursor took ms:", pnow() - start)) + // io.debug(x) // let start = pnow() // let #(x, refs) = cursor.replace_map(e.Binary("hello"), c, refs_map) // io.debug(#("replacing at cursor took ms:", pnow() - start)) // io.debug(x) - let start = pnow() - let f2 = new_i.free(refs, f) - io.debug(#("f2 took ms:", pnow() - start)) - let #(t, s, cache) = new_i.cached(root, refs, f, cache, env.empty(), s, count) - io.debug(#("partial type check took ms:", pnow() - start)) - let start = pnow() - let fm2 = new_i.free_map(refs, fm) - io.debug(#("finding fm2 took ms:", pnow() - start)) + // let start = pnow() + // let f2 = new_i.free(refs, f) + // io.debug(#("f2 took ms:", pnow() - start)) + + + // let #(t, s, cache) = new_i.cached(root, refs, f, cache, env.empty(), s, count) + // io.debug(#("partial type check took ms:", pnow() - start)) + // let start = pnow() + // let fm2 = new_i.free_map(refs, fm) + // io.debug(#("finding fm2 took ms:", pnow() - start)) let start = pnow() let inferred = Some(standard.infer(source)) io.debug(#("standard infer took ms:", pnow() - start)) // Have inference work once for showing elements but need to also background this - WorkSpace([], source, inferred, mode, None, None, #([], []), #(s, cache)) + WorkSpace([], source, inferred, mode, None, None, #([], [])) } pub fn update(state: WorkSpace, action) { diff --git a/eyg/src/eyg/incremental/cursor.gleam b/eyg/src/eyg/incremental/cursor.gleam index c78ef5943..d9e8e837f 100644 --- a/eyg/src/eyg/incremental/cursor.gleam +++ b/eyg/src/eyg/incremental/cursor.gleam @@ -13,7 +13,7 @@ pub fn zip_match(node, path_element) { Call(_, index), 1 -> index _, _ -> { io.debug(#(node, path_element)) - todo("no_zip_match") + panic("no_zip_match") } } } @@ -77,7 +77,7 @@ fn do_replace(old, new, zoom, rev) { Fn(param, body) if body == old -> Fn(param, new) Call(func, arg) if func == old -> Call(new, arg) Call(func, arg) if arg == old -> Call(func, new) - _ -> todo("Can't have a path into literal") + _ -> panic("Can't have a path into literal so invalid path, TODO make return error, cursor is invalid") } let new = list.length(rev) let rev = [exp, ..rev] diff --git a/eyg/src/eyg/incremental/inference.gleam b/eyg/src/eyg/incremental/inference.gleam index 32351e53d..f45fbe1c6 100644 --- a/eyg/src/eyg/incremental/inference.gleam +++ b/eyg/src/eyg/incremental/inference.gleam @@ -1,22 +1,16 @@ import gleam/io import gleam/list -import gleam/map.{Map} +import gleam/map import gleam/option import gleam/result -import gleam/set.{Set} +import gleam/set import gleam/setx -import gleam/javascript -import eygir/expression as e import eyg/analysis/typ as t import eyg/analysis/substitutions as sub import eyg/analysis/scheme.{Scheme} -import eyg/analysis/env import eyg/analysis/unification import eyg/incremental/source -import eyg/incremental/cursor -pub type Cache = - #(sub.Substitutions, Map(Int, Map(Map(String, Scheme), t.Term))) fn from_end(items, i) { list.at(items, list.length(items) - 1 - i) @@ -134,7 +128,7 @@ pub fn cached( let t = unification.instantiate(scheme, count) #(t, subs, types) } - Error(Nil) -> todo("no var") + Error(Nil) -> panic("no var in env need to add errors but return normal type") } source.Let(x, value, then) -> { let #(t1, subs, types) = diff --git a/eyg/src/eyg/incremental/store.gleam b/eyg/src/eyg/incremental/store.gleam index 7f08aaf65..6af5a39e3 100644 --- a/eyg/src/eyg/incremental/store.gleam +++ b/eyg/src/eyg/incremental/store.gleam @@ -88,7 +88,7 @@ pub fn free( case after - before { 0 -> { io.debug(#(node, before, root)) - todo("this shouldn't happen") + panic("this shouldn't happen as adding a new item should always make the map bigger") // and it doesn't Nil } @@ -120,7 +120,7 @@ pub fn do_type(env, ref, store: Store) -> Result(_, _) { let t = unification.instantiate(scheme, store.counter) Ok(#(t, store)) } - Error(Nil) -> todo("no var in env") + Error(Nil) -> panic("no var in env, this should return an ok value from do_type function but needs to add an error to the list type info") } } source.Let(x, value, then) -> { @@ -203,7 +203,7 @@ fn do_replace(old_id, new_id, zoom, store: Store) { source.Fn(param, body) if body == old_id -> source.Fn(param, new_id) source.Call(func, arg) if func == old_id -> source.Call(new_id, arg) source.Call(func, arg) if arg == old_id -> source.Call(func, new_id) - _ -> todo("Can't have a path into literal") + _ -> panic("Can't have a path into literal") } let new_id = map.size(store.source) let source = map.insert(store.source, new_id, exp) diff --git a/eyg/src/eyg/runtime/capture.gleam b/eyg/src/eyg/runtime/capture.gleam index d0e3fbb3e..ad9be4778 100644 --- a/eyg/src/eyg/runtime/capture.gleam +++ b/eyg/src/eyg/runtime/capture.gleam @@ -48,7 +48,7 @@ pub fn capture(term) { } r.Defunc(switch) -> capture_defunc(switch) r.Promise(_) -> - todo("not capturing promise, yet. Can be done making serialize async") + panic("not capturing promise, yet. Can be done making serialize async") } } @@ -74,7 +74,7 @@ fn capture_defunc(switch) { // possibly we do nothing as the context of the handler has been lost // Resume needs to be an expression I think e.Apply(e.Handle(label), capture(handler)) - todo("not idea how to capture the func here") + panic("not idea how to capture the func here, is it even possible") } r.Builtin(identifier, args) -> list.fold( diff --git a/eyg/src/eyg/runtime/interpreter.gleam b/eyg/src/eyg/runtime/interpreter.gleam index e40d45445..cdbeb0b10 100644 --- a/eyg/src/eyg/runtime/interpreter.gleam +++ b/eyg/src/eyg/runtime/interpreter.gleam @@ -1,4 +1,3 @@ -import gleam/io import gleam/int import gleam/list import gleam/map @@ -36,9 +35,10 @@ pub fn run(source, env, term, extrinsic) { Value(term) -> Ok(term) Abort(failure) -> Error(failure) Effect(label, lifted, _) -> Error(UnhandledEffect(label, lifted)) - Cont(_, _) -> todo("should have evaluated and not be a Cont at all") + Cont(_, _) -> panic("should have evaluated and not be a Cont at all") + // other runtime errors return error, maybe this should be the same Async(_, _) -> - todo("cannot return async value some sync run. This effect would not be allowed by type system") + panic("cannot return async value some sync run. This effect would not be allowed by type system") } } @@ -67,7 +67,7 @@ pub fn flatten_promise(ret, env: Env, extrinsic) { Abort(failure) -> promise.resolve(Error(failure)) Effect(label, lifted, _) -> promise.resolve(Error(UnhandledEffect(label, lifted))) - Cont(_, _) -> todo("should have evaluated and not be a Cont at all") + Cont(_, _) -> panic("should have evaluated and not be a Cont at all") Async(p, k) -> promise.await( p, diff --git a/eyg/src/harness/effect.gleam b/eyg/src/harness/effect.gleam index 84e1c1747..bfe103314 100644 --- a/eyg/src/harness/effect.gleam +++ b/eyg/src/harness/effect.gleam @@ -3,7 +3,6 @@ import gleam/map import gleam/fetch import gleam/http.{Get} import gleam/http/request -import gleam/http/response import gleam/javascript/promise.{try_await} import eyg/analysis/typ as t import plinth/browser/window @@ -52,13 +51,21 @@ pub fn http() { t.unit, fn(request, k) { use method <- cast.field("method", cast.any, request) + io.debug(method) use scheme <- cast.field("scheme", cast.any, request) + io.debug(scheme) use host <- cast.field("host", cast.string, request) + io.debug(host) use port <- cast.field("port", cast.any, request) + io.debug(port) use path <- cast.field("path", cast.string, request) + io.debug(path) use query <- cast.field("query", cast.any, request) + io.debug(query) use headers <- cast.field("headers", cast.any, request) + io.debug(headers) use body <- cast.field("body", cast.any, request) + io.debug(body) let request = request.new() diff --git a/eyg/src/harness/ffi/core.gleam b/eyg/src/harness/ffi/core.gleam index 2de1cbfe7..0233a8024 100644 --- a/eyg/src/harness/ffi/core.gleam +++ b/eyg/src/harness/ffi/core.gleam @@ -1,12 +1,9 @@ -import gleam/io import gleam/list -import gleam/map import eygir/expression as e import eyg/analysis/typ as t import eygir/encode import eyg/runtime/interpreter as r import eyg/runtime/capture -import gleam/javascript/promise import harness/ffi/cast import plinth/browser/window diff --git a/eyg/src/platforms/browser.gleam b/eyg/src/platforms/browser.gleam index a38b86912..5772d1bbd 100644 --- a/eyg/src/platforms/browser.gleam +++ b/eyg/src/platforms/browser.gleam @@ -78,7 +78,7 @@ fn render() { let assert r.Binary(page) = page case document.query_selector("#app") { Ok(Some(element)) -> document.set_html(element, page) - _ -> todo("error from render") + _ -> panic("could not render as no app element found, the reference to the app element should exist from start time and not be checked on every render") } r.continue(k, r.unit) }, @@ -111,7 +111,7 @@ pub fn async() { Ok(term) -> term Error(reason) -> { io.debug(reason) - todo("this shouldn't fail") + panic("this shouldn't fail") } } }) diff --git a/eyg/src/platforms/cli.gleam b/eyg/src/platforms/cli.gleam index 30c3b3204..352431df8 100644 --- a/eyg/src/platforms/cli.gleam +++ b/eyg/src/platforms/cli.gleam @@ -4,10 +4,9 @@ import plinth/nodejs import eygir/expression as e import eyg/analysis/typ as t import eyg/runtime/interpreter as r -import eyg/analysis/inference import harness/stdlib import harness/effect -import gleam/javascript/promise.{Promise} +import gleam/javascript/promise fn handlers() { effect.init() @@ -22,9 +21,9 @@ pub fn typ() { } pub fn run(source, args) { - let #(types, _values) = stdlib.lib() + // let #(types, _values) = stdlib.lib() let prog = e.Apply(e.Select("cli"), source) - let hrstart = nodejs.start() + // let hrstart = nodejs.start() use code <- // let inferred = inference.infer(types, prog, typ(), t.Closed) // let hrend = nodejs.duration(hrstart) diff --git a/eyg/src/platforms/serverless.gleam b/eyg/src/platforms/serverless.gleam index 3ea1c776a..e93b52482 100644 --- a/eyg/src/platforms/serverless.gleam +++ b/eyg/src/platforms/serverless.gleam @@ -2,21 +2,18 @@ import gleam/io import plinth/nodejs/fs import gleam/javascript/promise.{Promise} import eygir/expression as e -import eyg/analysis/typ as t import eyg/runtime/interpreter as r -import eyg/analysis/inference import harness/stdlib import harness/effect import gleam/javascript import eygir/decode -import eyg/runtime/standard pub fn run(source, _) { let store = javascript.make_reference(source) - let #(types, _values) = stdlib.lib() + // let #(types, _values) = stdlib.lib() // prog is new on every request could store eval'd in store - let prog = e.Apply(e.Select("web"), javascript.dereference(store)) + // let prog = e.Apply(e.Select("web"), javascript.dereference(store)) // let inferred = inference.infer(types, prog, standard.web(), t.Closed) // Inference is just handled on page load diff --git a/eyg/src/plinth/browser/document.gleam b/eyg/src/plinth/browser/document.gleam index 138f3d44b..aab61841a 100644 --- a/eyg/src/plinth/browser/document.gleam +++ b/eyg/src/plinth/browser/document.gleam @@ -1,4 +1,3 @@ -import gleam/io import gleam/dynamic.{Dynamic} import gleam/option.{Option} diff --git a/eyg/test/eyg/incremental/store_test.gleam b/eyg/test/eyg/incremental/store_test.gleam index 110c435dc..e643dd306 100644 --- a/eyg/test/eyg/incremental/store_test.gleam +++ b/eyg/test/eyg/incremental/store_test.gleam @@ -69,7 +69,7 @@ pub fn function_unification_test() { should.equal(map.size(s.free), 9) should.equal(map.size(s.types), 9) - todo("not here because type_ doesn't work to just reach in") + panic("not here because type_ doesn't work to just reach in") // hash of type or id includes free // TODO need type in tree, and errors @@ -115,8 +115,8 @@ pub fn let_test() { should.equal(root, 10) should.equal(map.size(s.source), 11) - let assert Ok(#(t, s, _)) = store.free(s, root, []) - // should.equal(t, t.Integer) + let assert Ok(#(f, s, _)) = store.free(s, root, []) + should.equal(f, set.new()) should.equal(map.size(s.free), 11) // Where is it going wrong should.equal(map.size(s.types), 0) diff --git a/eyg/test/hash_test.gleam b/eyg/test/hash_test.gleam index 18fbee041..50296f612 100644 --- a/eyg/test/hash_test.gleam +++ b/eyg/test/hash_test.gleam @@ -25,7 +25,7 @@ pub fn linear(source) { linear(then):bit_string, >> e.Integer(value) -> <<5, value:32>> - _ -> todo + _ -> panic } } @@ -56,23 +56,23 @@ pub fn decode(bytes) { <<5, value:32, rest:binary>> -> Ok(#(e.Integer(value), rest)) _ -> { io.debug(bytes) - todo("some bytes") + panic("some bytes") } } } -external fn log(a) -> Nil = +pub external fn log(a) -> Nil = "" "console.log" // hash and digest external fn hash(BitString) -> String = "./node_ffi.js" "hash" -fn gather_hash(source) { +pub fn gather_hash(source) { case source { <<1, x, rest:binary>> -> { use part <- result.then(bit_string.slice(rest, 0, x)) - Ok(log(hash(<<1, x, part:bit_string>>))) + Ok(hash(<<1, x, part:bit_string>>)) } // TODO need a pop function that doesn't turn to string, i.e.utf16 on JS @@ -82,7 +82,8 @@ fn gather_hash(source) { use #(value, rest) <- result.then(decode(rest)) use #(then, rest) <- result.then(decode(rest)) Ok(#(e.Let(label, value, then), rest)) - todo + |> io.debug + panic("not done") } } // Ok(#(e.Variable(label), rest)) @@ -108,6 +109,6 @@ pub fn round_trip_test() -> Nil { |> should.equal(Ok(#(tree, <<>>))) // gather_hash(<<1, 1, "ab":utf8>>) - gather_hash(source) - todo + // gather_hash(source) + // TODO not really useful } diff --git a/eyg/test/incremental_and_zip_test.gleam b/eyg/test/incremental_and_zip_test.gleam deleted file mode 100644 index 35d784068..000000000 --- a/eyg/test/incremental_and_zip_test.gleam +++ /dev/null @@ -1,214 +0,0 @@ -import gleam/io -import gleam/list -import gleam/map.{Map} -import gleam/option -import gleam/set.{Set} -import gleam/setx -import eygir/expression as e -import eyg/analysis/typ as t -import eyg/analysis/substitutions as sub -import eyg/analysis/scheme.{Scheme} -import eyg/analysis/env -import eyg/analysis/unification - -pub type Exp { - Var(String) - Fn(String, Int) - Let(String, Int, Int) - Call(Int, Int) - Integer(Int) - String(String) -} - -fn do_tree_to_ref( - tree, - acc, -) -> #(Exp, set.Set(String), List(#(Exp, set.Set(String)))) { - case tree { - e.Variable(label) -> { - let free = setx.singleton(label) - #(Var(label), free, acc) - } - e.Lambda(label, body) -> { - let #(node, free, acc) = do_tree_to_ref(body, acc) - let index = list.length(acc) - let acc = [#(node, free), ..acc] - let free = set.delete(free, label) - #(Fn(label, index), free, acc) - } - e.Let(label, value, then) -> { - let #(then, free_t, acc) = do_tree_to_ref(then, acc) - let then_index = list.length(acc) - let acc = [#(then, free_t), ..acc] - let #(value, free_v, acc) = do_tree_to_ref(value, acc) - let value_index = list.length(acc) - let acc = [#(value, free_v), ..acc] - - let free = set.union(free_v, set.delete(free_t, label)) - #(Let(label, value_index, then_index), free, acc) - } - e.Binary(value) -> #(String(value), set.new(), acc) - e.Integer(value) -> #(Integer(value), set.new(), acc) - _ -> todo("rest of ref") - } -} - -fn tree_to_ref(tree) { - let #(exp, free, acc) = do_tree_to_ref(tree, []) - let index = list.length(acc) - let source = list.reverse([#(exp, free), ..acc]) - #(index, source) -} - -fn zip_match(node, path_element) { - case node, path_element { - Let(_, index, _), 0 -> index - Let(_, _, index), 1 -> index - Fn(_, index), 0 -> index - } -} - -fn do_zip(path, refs, current, zoom, root) { - case path { - [] -> #([current, ..zoom], root) - [path_element, ..path] -> { - let assert Ok(#(node, _free)) = list.at(refs, current) - let zoom = [current, ..zoom] - let current = zip_match(node, path_element) - do_zip(path, refs, current, zoom, root) - } - } -} - -// root and refs together from tree -fn zip(path, root, refs) { - case path { - [] -> #([], root) - [path_element, ..path] -> { - let assert Ok(#(node, _free)) = list.at(refs, root) - let current = zip_match(node, path_element) - do_zip(path, refs, current, [], root) - } - } -} - -pub fn do_unzip(old, new, zoom, rev) { - case zoom { - [] -> #(new, list.reverse(rev)) - [next, ..zoom] -> { - let assert Ok(#(node, free)) = list.at(list.reverse(rev), next) - // TODO free, maybe free should be a separate step - io.debug(#(node, old)) - let exp = case node { - Let(label, value, then) if value == old -> Let(label, new, then) - Let(label, value, then) if then == old -> Let(label, value, new) - Fn(param, body) if body == old -> Fn(param, new) - Call(func, arg) if func == old -> Call(new, arg) - Call(func, arg) if arg == old -> Call(func, new) - _ -> todo("Can't have a path into literal") - } - // TODO real free - let new = list.length(rev) - let rev = [#(exp, free), ..rev] - do_unzip(next, new, zoom, rev) - } - } -} - -pub fn unzip(tree, cursor, refs) { - let #(exp, free, acc) = do_tree_to_ref(tree, list.reverse(refs)) - let new = list.length(acc) - let rev = [#(exp, free), ..acc] - case cursor { - #([], old) -> do_unzip(old, new, [], rev) - #([old, ..zoom], root) -> do_unzip(old, new, list.append(zoom, [root]), rev) - } -} - -// fn do_w(env, exp, refs, cache) { -// let t = todo -// let #(s, t, cache) = case node { -// Let(label, v, t) -> { -// let #(s1, t1, cache) = w(env, v, refs, cache) -// let env1 = map.insert(env, label, t1) -// let #(s2, t2, cache) = w(env1, t, refs, cache) -// // TODO real s -// #(s2, t2, cache) -// } -// Var(x) -> { -// let assert Ok(t) = map.get(env, x) -// #(sub.none(), t, cache) -// } -// Integer(_) -> #(sub.none(), t.Integer, cache) - -// _ -> todo("22w") -// } -// } - -// // Need single map of substitutions, is this the efficient J algo? -// // Free should be easy in bottom up order assume need value is already present -// // probably not fast in edits to std lib. maybe with only part of record field it would be faster. -// // but if async and cooperative then we can just manage without as needed. -// // TODO have building type stuff happen at startup. try it out in browser -// fn w(env, exp, refs, cache) { -// let assert Ok(#(node, free)) = list.at(refs, exp) -// // can always use small env -// let env = map.take(env, set.to_list(free)) -// case map.get(cache, exp) { -// Ok(envs) -> -// case map.get(envs, env) { -// Ok(r) -> r -// _ -> do_w(env, exp, refs, cache) -// } -// _ -> do_w(env, exp, refs, cache) -// } -// let t = todo -// let cache = -// map.update( -// cache, -// exp, -// fn(previous) { -// let by_env = option.unwrap(previous, map.new()) -// map.insert(by_env, map.take(env, set.to_list(free)), t) -// }, -// ) -// #(s, t, cache) -// } - -pub fn w(env, exp, refs, cache) -> Nil { - todo -} - -pub fn two_test() { - let tree = - e.Let( - "x", - e.Integer(1), - e.Let("y", e.Binary("hey"), e.Lambda("p", e.Variable("y"))), - ) - - let #(root, refs) = tree_to_ref(tree) - io.debug(root) - io.debug(refs) - io.debug(list.at(refs, root)) - - // binary - let path = [1, 0] - let cursor = zip(path, root, refs) - io.debug(cursor) - let [point, ..] = cursor.0 - io.debug(list.at(refs, point)) - - w(map.new(), root, refs, map.new()) - unzip(e.Integer(10), cursor, refs) - |> io.debug - - todo("moo") - let path = [1, 1, 0] - let cursor = zip(path, root, refs) - io.debug(cursor) - let [point, ..] = cursor.0 - io.debug(list.at(refs, point)) -} -// TODO printing map in node -// TODO binary-size in JS match diff --git a/eyg/test/incremental_test.gleam b/eyg/test/incremental_test.gleam index 3dafab26e..350068d50 100644 --- a/eyg/test/incremental_test.gleam +++ b/eyg/test/incremental_test.gleam @@ -1,17 +1,11 @@ import gleam/io import gleam/list -import gleam/map.{Map} -import gleam/option -import gleam/result -import gleam/set.{Set} -import gleam/setx +import gleam/map +import gleam/set import gleam/javascript import eygir/expression as e -import eyg/analysis/typ as t import eyg/analysis/substitutions as sub -import eyg/analysis/scheme.{Scheme} import eyg/analysis/env -import eyg/analysis/unification import eyg/incremental/source import eyg/incremental/cursor import eyg/incremental/inference @@ -62,12 +56,10 @@ pub fn two_test() { let #(t2, subs, cache) = inference.cached(root, refs, f2, cache, env.empty(), subs, count) - io.debug(t2) + io.debug(#(t2, subs, cache)) } // TODO printing map in node // TODO binary-size in JS match -pub fn all_test() { - todo -} + From 9b62399a11c59d8317ef20cf840f6d5a583c5e66 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 8 Apr 2023 15:25:49 +0200 Subject: [PATCH 27/62] remove spike of test --- eyg/test/eyg/incremental/store_test.gleam | 3 ++ eyg/test/incremental_test.gleam | 65 ----------------------- 2 files changed, 3 insertions(+), 65 deletions(-) delete mode 100644 eyg/test/incremental_test.gleam diff --git a/eyg/test/eyg/incremental/store_test.gleam b/eyg/test/eyg/incremental/store_test.gleam index e643dd306..7c2401413 100644 --- a/eyg/test/eyg/incremental/store_test.gleam +++ b/eyg/test/eyg/incremental/store_test.gleam @@ -8,6 +8,9 @@ import eyg/incremental/store import eyg/incremental/cursor import gleeunit/should +// TODO printing map in node +// TODO binary-size in JS match + pub fn literal_test() { let s = store.empty() diff --git a/eyg/test/incremental_test.gleam b/eyg/test/incremental_test.gleam deleted file mode 100644 index 350068d50..000000000 --- a/eyg/test/incremental_test.gleam +++ /dev/null @@ -1,65 +0,0 @@ -import gleam/io -import gleam/list -import gleam/map -import gleam/set -import gleam/javascript -import eygir/expression as e -import eyg/analysis/substitutions as sub -import eyg/analysis/env -import eyg/incremental/source -import eyg/incremental/cursor -import eyg/incremental/inference - -pub fn two_test() { - // todo("moo") - - let tree = - e.Let( - "x", - e.Integer(1), - e.Let("y", e.Binary("hey"), e.Lambda("p", e.Variable("y"))), - ) - - let #(root, refs) = source.from_tree(tree) - io.debug(root) - io.debug(refs) - let f = inference.free(refs, []) - io.debug(list.map(f, set.to_list)) - io.debug(list.at(refs, root)) - - // binary - let path = [1, 0] - let cursor = cursor.at(path, root, refs) - io.debug(cursor) - let [point, ..] = cursor.0 - io.debug(list.at(refs, point)) - - let count = javascript.make_reference(0) - let #(t, subs, cache) = - inference.cached(root, refs, f, map.new(), env.empty(), sub.none(), count) - io.debug(t) - let #(root, refs) = cursor.replace(e.Integer(3), cursor, refs) - - io.debug(refs) - let f2 = inference.free(refs, f) - io.debug(list.map(f2, set.to_list)) - - let path = [1, 1, 0] - let cursor = cursor.at(path, root, refs) - io.debug(cursor) - let [point, ..] = cursor.0 - io.debug(list.at(refs, point)) - - io.debug("====") - io.debug(cache) - io.debug("====") - - let #(t2, subs, cache) = - inference.cached(root, refs, f2, cache, env.empty(), subs, count) - io.debug(#(t2, subs, cache)) -} - -// TODO printing map in node -// TODO binary-size in JS match - - From 9eccb98c04ec9d2b1a46a9a02e34fa3bd8626dda Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 8 Apr 2023 17:21:02 +0200 Subject: [PATCH 28/62] better tests --- eyg/test/eyg/incremental/store_test.gleam | 173 +++++++++++++--------- 1 file changed, 102 insertions(+), 71 deletions(-) diff --git a/eyg/test/eyg/incremental/store_test.gleam b/eyg/test/eyg/incremental/store_test.gleam index 7c2401413..cc62c1d46 100644 --- a/eyg/test/eyg/incremental/store_test.gleam +++ b/eyg/test/eyg/incremental/store_test.gleam @@ -5,7 +5,6 @@ import eygir/expression as e import eyg/analysis/typ as t import eyg/incremental/source import eyg/incremental/store -import eyg/incremental/cursor import gleeunit/should // TODO printing map in node @@ -71,86 +70,118 @@ pub fn function_unification_test() { should.equal(map.size(s.free), 9) should.equal(map.size(s.types), 9) +} - panic("not here because type_ doesn't work to just reach in") - // hash of type or id includes free - // TODO need type in tree, and errors +pub fn let_literal_test() { + let s = store.empty() - // s does not change on fetching inner type - let assert Ok(#(type_, _)) = store.type_(s, cursor.inner(c)) - should.equal(type_, t.Binary) + let tree = e.Let("x", e.Binary("hey"), e.Variable("x")) + let #(root, s) = store.load(s, tree) + should.equal(root, 2) + should.equal(map.size(s.source), 3) - let assert Ok(c) = store.cursor(s, root, [0, 0]) + let assert Ok(#(t, s)) = store.type_(s, root) + should.equal(t, t.Binary) + should.equal(map.size(s.free), 3) + should.equal(map.size(s.types), 3) + + let assert Ok(c) = store.cursor(s, root, [0]) + let assert Ok(node) = store.focus(s, c) + should.equal(node, source.String("hey")) + let assert Ok(#(root1, s)) = store.replace(s, c, source.Integer(10)) + should.equal(map.size(s.source), 5) + + let assert Ok(c) = store.cursor(s, root, [1]) let assert Ok(node) = store.focus(s, c) should.equal(node, source.Var("x")) + let assert Ok(#(root2, s)) = store.replace(s, c, source.Empty) + should.equal(map.size(s.source), 7) + // source increase by path length + 1 + // free and types are lazy so stay at 4 + should.equal(map.size(s.free), 3) + should.equal(map.size(s.types), 3) - // s does not change on fetching inner type - io.debug("------------") - io.debug(#( - cursor.inner(c), - map.keys(s.types), - s.types - |> map.get(cursor.inner(c)), - )) - // How do I get the actual type value. only root works - // |> map.to_list, - let assert Ok(#(type_, _)) = store.type_(s, cursor.inner(c)) - // binary -> binary because not generalised in let statement - should.equal(type_, t.Fun(t.Binary, t.Closed, t.Binary)) - io.debug("------------") - // should.equal(n, ) + let assert Ok(#(t, s)) = store.type_(s, root1) + should.equal(t, t.Integer) + let assert Ok(#(t, s)) = store.type_(s, root2) + should.equal(t, t.unit) + + should.equal(map.size(s.free), 7) + should.equal(map.size(s.types), 7) } -pub fn let_test() { +pub fn fn_poly_test() { let s = store.empty() - let tree = - e.Let( - "x", - e.Let("tmp", e.Binary("i"), e.Binary("o")), - e.Let( - "y", - e.Integer(1), - e.Apply(e.Apply(e.Extend("a"), e.Variable("x")), e.Empty), - ), - ) + let tree = e.Let("id", e.Lambda("x", e.Variable("x")), e.Apply(e.Variable("id"), e.Integer(10))) let #(root, s) = store.load(s, tree) - should.equal(root, 10) - should.equal(map.size(s.source), 11) + should.equal(root, 5) + should.equal(map.size(s.source), 6) - let assert Ok(#(f, s, _)) = store.free(s, root, []) - should.equal(f, set.new()) - should.equal(map.size(s.free), 11) - // Where is it going wrong - should.equal(map.size(s.types), 0) - // all seems to work. - // TODO where am I loosing elements + let assert Ok(#(t, s)) = store.type_(s, root) + should.equal(t, t.Integer) + should.equal(map.size(s.free), 6) + should.equal(map.size(s.types), 6) +} + +pub fn nested_fn_test() { + let s = store.empty() + + let tree = e.Lambda("x", e.Lambda("y", e.Empty)) + let #(root, s) = store.load(s, tree) + should.equal(root, 2) + should.equal(map.size(s.source), 3) + + let assert Ok(#(t, s)) = store.type_(s, root) + should.equal(t, t.Fun(t.Unbound(0), t.Closed, t.Fun(t.Unbound(1), t.Closed, t.Record(t.Closed)))) + should.equal(map.size(s.free), 3) + should.equal(map.size(s.types), 3) + + let assert Ok(c) = store.cursor(s, root, [0, 0]) + let assert Ok(node) = store.focus(s, c) + should.equal(node, source.Empty) + let assert Ok(#(root1, s)) = store.replace(s, c, source.Integer(10)) + should.equal(map.size(s.source), 6) + + let assert Ok(node) = store.focus(s, c) + // same cursor points to same item, store replace gives new root + should.equal(node, source.Empty) + let assert Ok(#(root2, s)) = store.replace(s, c, source.Var("y")) + should.equal(map.size(s.source), 9) + // source increase by path length + 1 + // free and types are lazy so stay at 4 + should.equal(map.size(s.free), 3) + should.equal(map.size(s.types), 3) + + let assert Ok(#(t, s)) = store.type_(s, root1) + should.equal(t, t.Fun(t.Unbound(2), t.Closed, t.Fun(t.Unbound(3), t.Closed, t.Integer))) + let assert Ok(#(t, s)) = store.type_(s, root2) + should.equal(t, t.Fun(t.Unbound(4), t.Closed, t.Fun(t.Unbound(5), t.Closed, t.Unbound(5)))) + + should.equal(map.size(s.free), 9) + should.equal(map.size(s.types), 9) } -// TODO generalization test -// pub fn let_scope_test() { -// let s = store.empty() - -// let tree = -// e.Let( -// "x", -// e.Integer(10), -// e.Let( -// "y", -// e.Integer(20), -// e.Apply( -// e.Apply(e.Cons, e.Variable("y")), -// e.Apply(e.Apply(e.Cons, e.Variable("x")), e.Tail), -// ), -// ), -// ) -// let #(ref_binary, s) = store.load(s, tree) -// should.equal(ref_binary, 12) -// should.equal(map.size(s.source), 13) - -// let assert Ok(#(free, s,_)) = store.free(s, ref_binary, []) -// should.equal(map.size(s.free), 13) -// should.equal(free, set.new()) -// let assert Ok(#(t, s)) = store.type_(s, ref_binary) -// should.equal(map.size(s.types), 13) -// should.equal(t, t.LinkedList(t.Integer)) -// } + +pub fn branched_apply_test() { + let s = store.empty() + + let tree = e.Let("id", e.Lambda("x", e.Variable("x")), + e.Apply(e.Apply(e.Variable("id"), e.Variable("id")), e.Apply(e.Variable("id"), e.Integer(1)))) + + let #(root, s) = store.load(s, tree) + should.equal(root, 9) + should.equal(map.size(s.source), 10) + + let assert Ok(c) = store.cursor(s, root, []) + let assert Ok(node) = store.focus(s, c) + should.equal(node, source.Let("id", 8, 6)) + let assert Ok(#(vars, s, _acc)) = store.free(s, root, []) + should.equal(vars, set.new()) + should.equal(map.size(s.free), 10) + should.equal(map.size(s.types), 0) + + let assert Ok(#(t, s)) = store.type_(s, root) + should.equal(map.size(s.types), 10) + io.debug(s.substitutions.terms |> map.to_list) + should.equal(t, t.Integer) +} \ No newline at end of file From 5659fd1f35280d239b52d13794af7ab522815668 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 8 Apr 2023 18:20:08 +0200 Subject: [PATCH 29/62] try looking up the double ref --- eyg/src/atelier/app.gleam | 30 ++++++++++------ eyg/src/eyg/incremental/source.gleam | 42 +++++++++++------------ eyg/src/eyg/incremental/store.gleam | 40 +++++++++++++++++++-- eyg/test/eyg/incremental/store_test.gleam | 4 +++ 4 files changed, 82 insertions(+), 34 deletions(-) diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index 989aae50c..a18dd6eb6 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -66,19 +66,29 @@ pub fn init(source) { map.size(s.free), )) - // let start = pnow() - // let assert Ok(#(vars, s, x)) = store.free(s, root, []) + let start = pnow() + let doubled = store.ref_group(s) + io.debug(#( + "doubled took ms:", + pnow() - start, + map.size(doubled), + map.to_list(doubled) + )) + + + let start = pnow() + let assert Ok(#(vars, s, x)) = store.free(s, root, []) // // OK map works // io.debug(#("othr", list.length(x))) // // TODO i think should be same size - // io.debug(#( - // "memoizing free took ms:", - // pnow() - start, - // map.size(s.source), - // map.size(s.free), - // vars - // |> set.to_list, - // )) + io.debug(#( + "memoizing free took ms:", + pnow() - start, + map.size(s.source), + map.size(s.free), + // vars + // |> set.to_list, + )) // io.debug(map.get(s.source, root)) // io.debug(map.get(s.source, root - 1)) // io.debug(map.get(s.source, root - 2)) diff --git a/eyg/src/eyg/incremental/source.gleam b/eyg/src/eyg/incremental/source.gleam index 65e8ae635..e1bd12e2a 100644 --- a/eyg/src/eyg/incremental/source.gleam +++ b/eyg/src/eyg/incremental/source.gleam @@ -1,5 +1,6 @@ import gleam/list import gleam/map +import gleam/javascript import eygir/expression as e pub type Expression { @@ -75,33 +76,33 @@ pub fn from_tree(tree) { let source = list.reverse([exp, ..acc]) #(index, source) } +fn next(ref) { + javascript.update_reference(ref, fn(x) { x + 1 }) +} + +fn push(x, ref) { + let #(node, source) = x + let index = next(ref) + let source = map.insert(source, index, node) + #(index, source) + } -pub fn do_from_tree_map(tree, acc) { +pub fn do_from_tree_map(tree, acc, ref) -> #(Int, map.Map(Int, Expression)) { case tree { e.Variable(label) -> #(Var(label), acc) e.Lambda(label, body) -> { - let #(node, acc) = do_from_tree_map(body, acc) - let index = map.size(acc) - let acc = map.insert(acc, index, node) + let #(index, acc) = do_from_tree_map(body, acc, ref) #(Fn(label, index), acc) } e.Let(label, value, then) -> { - let #(then, acc) = do_from_tree_map(then, acc) - let then_index = map.size(acc) - let acc = map.insert(acc, then_index, then) - let #(value, acc) = do_from_tree_map(value, acc) - let value_index = map.size(acc) - let acc = map.insert(acc, value_index, value) - #(Let(label, value_index, then_index), acc) + let #(then, acc) = do_from_tree_map(then, acc, ref) + let #(value, acc) = do_from_tree_map(value, acc, ref) + #(Let(label, value, then), acc) } e.Apply(func, arg) -> { - let #(arg, acc) = do_from_tree_map(arg, acc) - let arg_index = map.size(acc) - let acc = map.insert(acc, arg_index, arg) - let #(func, acc) = do_from_tree_map(func, acc) - let func_index = map.size(acc) - let acc = map.insert(acc, func_index, func) - #(Call(func_index, arg_index), acc) + let #(arg, acc) = do_from_tree_map(arg, acc, ref) + let #(func, acc) = do_from_tree_map(func, acc, ref) + #(Call(func, arg), acc) } e.Binary(value) -> #(String(value), acc) e.Integer(value) -> #(Integer(value), acc) @@ -119,11 +120,10 @@ pub fn do_from_tree_map(tree, acc) { e.Handle(label) -> #(Handle(label), acc) e.Builtin(identifier) -> #(Builtin(identifier), acc) } + |> push(ref) } pub fn from_tree_map(tree) { - let #(exp, acc) = do_from_tree_map(tree, map.new()) - let index = map.size(acc) - let source = map.insert(acc, index, exp) + let #(index, source) = do_from_tree_map(tree, map.new(), javascript.make_reference(0)) #(index, source) } diff --git a/eyg/src/eyg/incremental/store.gleam b/eyg/src/eyg/incremental/store.gleam index 6af5a39e3..741eaf254 100644 --- a/eyg/src/eyg/incremental/store.gleam +++ b/eyg/src/eyg/incremental/store.gleam @@ -34,11 +34,12 @@ pub fn empty() { ) } + + pub fn load(store: Store, tree) { + let ref = javascript.make_reference(0) // maybe just include the exp - let #(exp, acc) = source.do_from_tree_map(tree, store.source) - let index = map.size(acc) - let source = map.insert(acc, index, exp) + let #(index, source) = source.do_from_tree_map(tree, store.source, ref) #(index, Store(..store, source: source)) } @@ -228,3 +229,36 @@ pub fn replace(store: Store, cursor, exp) { pub fn focus(store: Store, c) { map.get(store.source, cursor.inner(c)) } + +pub fn ref_group(store: Store) { + let child_refs = list.flat_map(map.to_list(store.source),fn(entry) { + let #(_ref, node) = entry + case node { + // source.Var(String) + source.Fn(_, child) -> [#(child, entry)] + source.Let(_, c1, c2)-> [#(c1, entry), #(c2, entry)] + source.Call(c1, c2)-> [#(c1, entry), #(c2, entry)] + _ -> [] + // source.Integer(Int) + // source.String(String) + // source.Tail + // source.Cons + // source.Vacant(comment: String) + // source.Empty + // source.Extend(label: String) + // source.Select(label: String) + // source.Overwrite(label: String) + // source.Tag(label: String) + // source.Case(label: String) + // source.NoCases + // source.Perform(label: String) + // source.Handle(label: String) + // source.Builtin(identifier: String) + } + }) + // Makes sense there should be one thing, the root that is not referenced, one more for each cursor update + io.debug(#("child refs", list.length(child_refs), map.size(store.source))) + child_refs + |> list.group(fn(x) {x.0}) + |> map.filter(fn(_, v) {list.length(v) < 1}) +} \ No newline at end of file diff --git a/eyg/test/eyg/incremental/store_test.gleam b/eyg/test/eyg/incremental/store_test.gleam index cc62c1d46..e8ec4217c 100644 --- a/eyg/test/eyg/incremental/store_test.gleam +++ b/eyg/test/eyg/incremental/store_test.gleam @@ -84,6 +84,7 @@ pub fn let_literal_test() { should.equal(t, t.Binary) should.equal(map.size(s.free), 3) should.equal(map.size(s.types), 3) + io.debug(#("============",store.ref_group(s) |> map.to_list)) let assert Ok(c) = store.cursor(s, root, [0]) let assert Ok(node) = store.focus(s, c) @@ -108,6 +109,7 @@ pub fn let_literal_test() { should.equal(map.size(s.free), 7) should.equal(map.size(s.types), 7) + io.debug(#("============",store.ref_group(s) |> map.to_list)) } pub fn fn_poly_test() { @@ -183,5 +185,7 @@ pub fn branched_apply_test() { let assert Ok(#(t, s)) = store.type_(s, root) should.equal(map.size(s.types), 10) io.debug(s.substitutions.terms |> map.to_list) + io.debug(#("============",store.ref_group(s) |> map.to_list)) should.equal(t, t.Integer) + panic } \ No newline at end of file From fa193d3e6c149944f2e41203a8cf1f0de00307c7 Mon Sep 17 00:00:00 2001 From: Peter Saxton Date: Mon, 10 Apr 2023 15:56:42 +0200 Subject: [PATCH 30/62] 0.28.1 map version --- eyg/manifest.toml | 4 +- eyg/src/eyg/incremental/store.gleam | 105 ++++++++++++++--- eyg/src/plinth/javascript/map.gleam | 13 +++ eyg/src/plinth_ffi.js | 20 ++++ eyg/test/eyg/incremental/store_test.gleam | 131 ++++++++++++++++++++-- 5 files changed, 241 insertions(+), 32 deletions(-) create mode 100644 eyg/src/plinth/javascript/map.gleam diff --git a/eyg/manifest.toml b/eyg/manifest.toml index 2f3fe0112..a178ee675 100644 --- a/eyg/manifest.toml +++ b/eyg/manifest.toml @@ -3,11 +3,11 @@ packages = [ { name = "gleam_bitwise", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_bitwise", source = "hex", outer_checksum = "6064699EFBABB1CA392DCB193D0E8B402FB042B4B46857B01E6875E643B57F54" }, - { name = "gleam_fetch", version = "0.1.0", build_tools = ["gleam"], requirements = ["gleam_javascript", "gleam_http"], otp_app = "gleam_fetch", source = "hex", outer_checksum = "C66E68D8AE5D1D8C4120C4F8EF8133E680B7EF20A7DBF5BFAABD9390FF8E9B90" }, + { name = "gleam_fetch", version = "0.1.0", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_javascript"], otp_app = "gleam_fetch", source = "hex", outer_checksum = "C66E68D8AE5D1D8C4120C4F8EF8133E680B7EF20A7DBF5BFAABD9390FF8E9B90" }, { name = "gleam_http", version = "3.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "7BE7A80B5AC8357827169107FAE15AD8423629E6BBBD39A8B4217AFF879B4520" }, { name = "gleam_javascript", version = "0.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_javascript", source = "hex", outer_checksum = "E0E8D33461776BFCC124838183F85E430D3A71D7318F210C9DE0CFB52E5AC8DE" }, { name = "gleam_json", version = "0.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "9A805C1E60FB9CD73AF3034EB464268A6B522D937FCD2DF92BD246F2F4B37930" }, - { name = "gleam_stdlib", version = "0.28.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "1BB6A3E53F7576B9F5C4E5D4AE16487E526BE383B03CBF4068C7DFC77CF38A1C" }, + { name = "gleam_stdlib", version = "0.28.1", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "73F0A89FADE5022CBEF6D6C3551F9ADCE7054AFCE0CB1DC4C6D5AB4CA62D0111" }, { name = "gleeunit", version = "0.10.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "ECEA2DE4BE6528D36AFE74F42A21CDF99966EC36D7F25DEB34D47DD0F7977BAF" }, { name = "lustre", version = "2.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "EFF2C221C364BDE621E01F2917B620E3B2B181C5FBAF5EB9FA0B1488ADF7327E" }, { name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" }, diff --git a/eyg/src/eyg/incremental/store.gleam b/eyg/src/eyg/incremental/store.gleam index 741eaf254..233932a29 100644 --- a/eyg/src/eyg/incremental/store.gleam +++ b/eyg/src/eyg/incremental/store.gleam @@ -34,8 +34,6 @@ pub fn empty() { ) } - - pub fn load(store: Store, tree) { let ref = javascript.make_reference(0) // maybe just include the exp @@ -89,7 +87,9 @@ pub fn free( case after - before { 0 -> { io.debug(#(node, before, root)) - panic("this shouldn't happen as adding a new item should always make the map bigger") + panic( + "this shouldn't happen as adding a new item should always make the map bigger", + ) // and it doesn't Nil } @@ -100,6 +100,68 @@ pub fn free( } } +pub fn free_m(store: Store, root) -> Result(#(Set(String), Store), Nil) { + io.debug(root) + case map.get(store.free, 0) { + Ok(_) -> { + io.debug("found") + Nil + } + Error(_) -> Nil + } + case map.get(store.free, root) { + Ok(vars) -> { + io.debug(#( + "found----", + root, + map.get(store.source, root), + map.size(store.free), + )) + Ok(#(vars, store)) + } + Error(Nil) -> { + use node <- result.then(map.get(store.source, root)) + use #(vars, store) <- result.then(case node { + source.Var(x) -> Ok(#(setx.singleton(x), store)) + source.Fn(x, ref) -> { + use #(vars, store) <- result.then(free_m(store, ref)) + Ok(#(set.delete(vars, x), store)) + } + source.Let(x, ref_v, ref_t) -> { + use #(value, store) <- result.then(free_m(store, ref_v)) + use #(then, store) <- result.then(free_m(store, ref_t)) + let vars = set.union(value, set.delete(then, x)) + Ok(#(vars, store)) + } + source.Call(ref_func, ref_arg) -> { + use #(func, store) <- result.then(free_m(store, ref_func)) + use #(arg, store) <- result.then(free_m(store, ref_arg)) + let vars = set.union(func, arg) + Ok(#(vars, store)) + } + _ -> Ok(#(set.new(), store)) + }) + let before = map.size(store.free) + io.debug(#("insert", root)) + let free = map.insert(store.free, root, vars) + let store = Store(..store, free: free) + let after = map.size(store.free) + case after - before { + 0 -> { + io.debug(#(node, before, root)) + panic( + "this shouldn't happen as adding a new item should always make the map bigger", + ) + // and it doesn't + Nil + } + 1 -> Nil + } + Ok(#(vars, store)) + } + } +} + pub fn type_(store: Store, root) { use #(unresolved, store) <- result.then(do_type(map.new(), root, store)) let t = unification.resolve(store.substitutions, unresolved) @@ -121,7 +183,10 @@ pub fn do_type(env, ref, store: Store) -> Result(_, _) { let t = unification.instantiate(scheme, store.counter) Ok(#(t, store)) } - Error(Nil) -> panic("no var in env, this should return an ok value from do_type function but needs to add an error to the list type info") + Error(Nil) -> + panic( + "no var in env, this should return an ok value from do_type function but needs to add an error to the list type info", + ) } } source.Let(x, value, then) -> { @@ -230,15 +295,21 @@ pub fn focus(store: Store, c) { map.get(store.source, cursor.inner(c)) } -pub fn ref_group(store: Store) { - let child_refs = list.flat_map(map.to_list(store.source),fn(entry) { - let #(_ref, node) = entry - case node { - // source.Var(String) - source.Fn(_, child) -> [#(child, entry)] - source.Let(_, c1, c2)-> [#(c1, entry), #(c2, entry)] - source.Call(c1, c2)-> [#(c1, entry), #(c2, entry)] - _ -> [] +pub fn ref_group(store: Store) { + let child_refs = + list.flat_map( + map.to_list(store.source), + fn(entry) { + let #(_ref, node) = entry + case node { + // source.Var(String) + source.Fn(_, child) -> [#(child, entry)] + source.Let(_, c1, c2) -> [#(c1, entry), #(c2, entry)] + source.Call(c1, c2) -> [#(c1, entry), #(c2, entry)] + _ -> [] + } + }, + ) // source.Integer(Int) // source.String(String) // source.Tail @@ -254,11 +325,9 @@ pub fn ref_group(store: Store) { // source.Perform(label: String) // source.Handle(label: String) // source.Builtin(identifier: String) - } - }) // Makes sense there should be one thing, the root that is not referenced, one more for each cursor update io.debug(#("child refs", list.length(child_refs), map.size(store.source))) child_refs - |> list.group(fn(x) {x.0}) - |> map.filter(fn(_, v) {list.length(v) < 1}) -} \ No newline at end of file + |> list.group(fn(x) { x.0 }) + |> map.filter(fn(_, v) { list.length(v) < 1 }) +} diff --git a/eyg/src/plinth/javascript/map.gleam b/eyg/src/plinth/javascript/map.gleam new file mode 100644 index 000000000..0c90a5ccb --- /dev/null +++ b/eyg/src/plinth/javascript/map.gleam @@ -0,0 +1,13 @@ +pub external type MutableMap(k, v) + +pub external fn new() -> MutableMap(k, v) = + "../../plinth_ffi.js" "map_new" + +pub external fn set(MutableMap(k, v), k, v) -> MutableMap(k, v) = + "../../plinth_ffi.js" "map_set" + +pub external fn get(MutableMap(k, v), k) -> Result(v, Nil) = + "../../plinth_ffi.js" "map_get" + +pub external fn size(MutableMap(k, v)) -> Int = + "../../plinth_ffi.js" "map_size" diff --git a/eyg/src/plinth_ffi.js b/eyg/src/plinth_ffi.js index beceb4f7e..8b8795023 100644 --- a/eyg/src/plinth_ffi.js +++ b/eyg/src/plinth_ffi.js @@ -1,3 +1,5 @@ +import { Ok, Error } from "./gleam.mjs"; + export function wait(milliseconds) { return new Promise((resolve) => setTimeout(resolve, milliseconds)); } @@ -26,3 +28,21 @@ export function onKeyDown(f) { export function insertAfter(e, text) { e.insertAdjacentHTML("afterend", text); } + +export function map_new() { + return new Map() +} + +export function map_set(map, key, value) { + return map.set(key, value) +} + +export function map_get(map, key) { + if (map.has(key)) { + return new Ok(map.get(key)) + } + return new Error(undefined) +} +export function map_size(map) { + return map.size +} diff --git a/eyg/test/eyg/incremental/store_test.gleam b/eyg/test/eyg/incremental/store_test.gleam index e8ec4217c..dfea438e9 100644 --- a/eyg/test/eyg/incremental/store_test.gleam +++ b/eyg/test/eyg/incremental/store_test.gleam @@ -1,7 +1,10 @@ import gleam/io +import gleam/int +import gleam/list import gleam/map import gleam/set import eygir/expression as e +import eygir/decode import eyg/analysis/typ as t import eyg/incremental/source import eyg/incremental/store @@ -84,7 +87,11 @@ pub fn let_literal_test() { should.equal(t, t.Binary) should.equal(map.size(s.free), 3) should.equal(map.size(s.types), 3) - io.debug(#("============",store.ref_group(s) |> map.to_list)) + io.debug(#( + "============", + store.ref_group(s) + |> map.to_list, + )) let assert Ok(c) = store.cursor(s, root, [0]) let assert Ok(node) = store.focus(s, c) @@ -109,13 +116,22 @@ pub fn let_literal_test() { should.equal(map.size(s.free), 7) should.equal(map.size(s.types), 7) - io.debug(#("============",store.ref_group(s) |> map.to_list)) + io.debug(#( + "============", + store.ref_group(s) + |> map.to_list, + )) } pub fn fn_poly_test() { let s = store.empty() - let tree = e.Let("id", e.Lambda("x", e.Variable("x")), e.Apply(e.Variable("id"), e.Integer(10))) + let tree = + e.Let( + "id", + e.Lambda("x", e.Variable("x")), + e.Apply(e.Variable("id"), e.Integer(10)), + ) let #(root, s) = store.load(s, tree) should.equal(root, 5) should.equal(map.size(s.source), 6) @@ -126,7 +142,7 @@ pub fn fn_poly_test() { should.equal(map.size(s.types), 6) } -pub fn nested_fn_test() { +pub fn nested_fn_test() { let s = store.empty() let tree = e.Lambda("x", e.Lambda("y", e.Empty)) @@ -135,7 +151,14 @@ pub fn nested_fn_test() { should.equal(map.size(s.source), 3) let assert Ok(#(t, s)) = store.type_(s, root) - should.equal(t, t.Fun(t.Unbound(0), t.Closed, t.Fun(t.Unbound(1), t.Closed, t.Record(t.Closed)))) + should.equal( + t, + t.Fun( + t.Unbound(0), + t.Closed, + t.Fun(t.Unbound(1), t.Closed, t.Record(t.Closed)), + ), + ) should.equal(map.size(s.free), 3) should.equal(map.size(s.types), 3) @@ -156,9 +179,15 @@ pub fn nested_fn_test() { should.equal(map.size(s.types), 3) let assert Ok(#(t, s)) = store.type_(s, root1) - should.equal(t, t.Fun(t.Unbound(2), t.Closed, t.Fun(t.Unbound(3), t.Closed, t.Integer))) + should.equal( + t, + t.Fun(t.Unbound(2), t.Closed, t.Fun(t.Unbound(3), t.Closed, t.Integer)), + ) let assert Ok(#(t, s)) = store.type_(s, root2) - should.equal(t, t.Fun(t.Unbound(4), t.Closed, t.Fun(t.Unbound(5), t.Closed, t.Unbound(5)))) + should.equal( + t, + t.Fun(t.Unbound(4), t.Closed, t.Fun(t.Unbound(5), t.Closed, t.Unbound(5))), + ) should.equal(map.size(s.free), 9) should.equal(map.size(s.types), 9) @@ -167,8 +196,15 @@ pub fn nested_fn_test() { pub fn branched_apply_test() { let s = store.empty() - let tree = e.Let("id", e.Lambda("x", e.Variable("x")), - e.Apply(e.Apply(e.Variable("id"), e.Variable("id")), e.Apply(e.Variable("id"), e.Integer(1)))) + let tree = + e.Let( + "id", + e.Lambda("x", e.Variable("x")), + e.Apply( + e.Apply(e.Variable("id"), e.Variable("id")), + e.Apply(e.Variable("id"), e.Integer(1)), + ), + ) let #(root, s) = store.load(s, tree) should.equal(root, 9) @@ -184,8 +220,79 @@ pub fn branched_apply_test() { let assert Ok(#(t, s)) = store.type_(s, root) should.equal(map.size(s.types), 10) - io.debug(s.substitutions.terms |> map.to_list) - io.debug(#("============",store.ref_group(s) |> map.to_list)) + io.debug( + s.substitutions.terms + |> map.to_list, + ) + io.debug(#( + "============", + store.ref_group(s) + |> map.to_list, + )) should.equal(t, t.Integer) panic -} \ No newline at end of file +} + +pub fn debug_test() { + map.new() + |> map.insert(22, Nil) + |> map.insert(21, Nil) + |> map.insert(23, Nil) + |> map.insert(18, Nil) + |> map.insert(17, Nil) + |> map.insert(19, Nil) + |> map.insert(14, Nil) + |> map.insert(13, Nil) + |> map.insert(15, Nil) + |> map.insert(10, Nil) + |> map.insert(9, Nil) + |> map.insert(11, Nil) + |> map.insert(6, Nil) + |> map.insert(5, Nil) + |> map.insert(7, Nil) + |> map.insert(2, Nil) + |> map.insert(1, Nil) + |> map.insert(3, Nil) + |> map.get(0) + |> io.debug + todo +} + +pub fn debug_test_o() { + let s = store.empty() + + // ok + // {foo: "foo", {bar: "bar", {}}} + // let assert Ok(tree) = + // "{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"equal\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"debug\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"fix\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"capture\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"serialize\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"u\"}}}}}}" + // not ok + // {foo: "foo", {bar: "bar", {bar: "bar", {}}}} + let assert Ok(tree) = + "{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"equal\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"debug\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"fix\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"capture\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"serialize\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"foo\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"u\"}}}}}}}" + |> decode.from_json + // |> io.debug + + let #(root, s) = store.load(s, tree) + // should.equal(root, 24) + should.equal(map.size(s.source), 25) + // let assert Ok(#(free, s, _)) = store.free(s, root, []) + should.equal(map.size(s.free), 0) + let assert Ok(#(free, s)) = store.free_m(s, root) + + map.size(s.free) + |> io.debug + map.to_list(s.source) + |> list.sort(by_first) + |> list.map(io.debug) + map.to_list(s.free) + |> list.sort(by_first) + |> list.map(io.debug) + // should.equal(, 25) + store.ref_group(s) + |> io.debug + // todo +} + +pub fn by_first(x: #(Int, _), y: #(Int, _)) { + int.compare(x.0, y.0) +} From c42a5335df12176ecb5fa740b5a60337c7d6876c Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 10 Apr 2023 16:33:53 +0200 Subject: [PATCH 31/62] clean up store map type --- eyg/src/atelier/app.gleam | 63 +++---------- eyg/src/eyg/incremental/store.gleam | 105 ++-------------------- eyg/test/eyg/incremental/store_test.gleam | 68 +------------- 3 files changed, 25 insertions(+), 211 deletions(-) diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index a18dd6eb6..c89cb2776 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -55,7 +55,7 @@ pub fn init(source) { let assert Ok(act) = transform.prepare(source, []) let mode = Navigate(act) - // let path = [1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0] + let path = [1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0] let start = pnow() let #(root, s) = store.load(store.empty(), source) io.debug(#( @@ -77,66 +77,32 @@ pub fn init(source) { let start = pnow() - let assert Ok(#(vars, s, x)) = store.free(s, root, []) - // // OK map works - // io.debug(#("othr", list.length(x))) - // // TODO i think should be same size + let assert Ok(#(vars, s)) = store.free(s, root) io.debug(#( "memoizing free took ms:", pnow() - start, map.size(s.source), map.size(s.free), - // vars - // |> set.to_list, )) - // io.debug(map.get(s.source, root)) - // io.debug(map.get(s.source, root - 1)) - // io.debug(map.get(s.source, root - 2)) - // io.debug(map.get(s.source, root - 3)) - // io.debug(map.get(s.source, root - 4)) - // io.debug(map.get(s.source, 0)) - // io.debug(map.get(s.source, 1)) - - // io.debug(map.get(s.free, root)) - // io.debug(map.get(s.free, root - 1)) - // io.debug(map.get(s.free, root - 2)) - // io.debug(map.get(s.free, root - 3)) - // io.debug(map.get(s.free, root - 4)) - // io.debug(map.get(s.free, 0)) - // io.debug(map.get(s.free, 1)) - - // io.debug("====================") - // // Not all in a line - - // let at = map.size(s.source) - map.size(s.free) - // io.debug(#(map.get(s.free, at - 100), at - 100)) - // io.debug(#(map.get(s.free, at), at)) - // io.debug(#(map.get(s.free, at + 1), at + 1)) - // io.debug("====================") - - // // io.debug(#("free--", map.get(s.free, 5757))) - // io.debug(list.length(map.to_list(s.source))) - - // io.debug(list.length(map.to_list(s.free))) - // todo("wat") - // let start = pnow() - // let assert Ok(#(t, s)) = store.type_(s, root) - // // TODO i think should be same size - // io.debug(#( - // "typing took ms:", - // pnow() - start, - // map.size(s.source), - // map.size(s.free), - // map.size(s.types), - // t, - // )) + let start = pnow() + let assert Ok(#(t, s)) = store.type_(s, root) + // TODO i think should be same size + io.debug(#( + "typing took ms:", + pnow() - start, + map.size(s.source), + map.size(s.free), + map.size(s.types), + t, + )) // let start = pnow() // let assert Ok(c) = store.cursor(s, root, path) // io.debug(#("building store.cursor took ms:", pnow() - start)) // // io.debug(c) // let start = pnow() + // TODO need to time new typing // let assert Ok(#(root_, s)) = store.replace(s, c, incremental.String("hello")) // io.debug(#( // "updating store.replace took ms:", @@ -147,7 +113,6 @@ pub fn init(source) { // )) // let start = pnow() // let assert Ok(#(t, s)) = store.type_(s, root_) - // // TODO i think should be same size // io.debug(#( // "typing took ms:", // pnow() - start, diff --git a/eyg/src/eyg/incremental/store.gleam b/eyg/src/eyg/incremental/store.gleam index 233932a29..cda04e130 100644 --- a/eyg/src/eyg/incremental/store.gleam +++ b/eyg/src/eyg/incremental/store.gleam @@ -41,122 +41,33 @@ pub fn load(store: Store, tree) { #(index, Store(..store, source: source)) } -pub fn free( - store: Store, - root, - acc, -) -> Result(#(Set(String), Store, List(#(Int, Set(String)))), Nil) { +pub fn free(store: Store, root) -> Result(#(Set(String), Store), Nil) { case map.get(store.free, root) { - Ok(vars) -> { - io.debug(#( - "found----", - root, - map.get(store.source, root), - map.size(store.free), - list.length(acc), - )) - Ok(#(vars, store, acc)) - } - Error(Nil) -> { - use node <- result.then(map.get(store.source, root)) - use #(vars, store, acc) <- result.then(case node { - source.Var(x) -> Ok(#(setx.singleton(x), store, acc)) - source.Fn(x, ref) -> { - use #(vars, store, acc) <- result.then(free(store, ref, acc)) - Ok(#(set.delete(vars, x), store, acc)) - } - source.Let(x, ref_v, ref_t) -> { - use #(value, store, acc) <- result.then(free(store, ref_v, acc)) - use #(then, store, acc) <- result.then(free(store, ref_t, acc)) - let vars = set.union(value, set.delete(then, x)) - Ok(#(vars, store, acc)) - } - source.Call(ref_func, ref_arg) -> { - use #(func, store, acc) <- result.then(free(store, ref_func, acc)) - use #(arg, store, acc) <- result.then(free(store, ref_arg, acc)) - let vars = set.union(func, arg) - Ok(#(vars, store, acc)) - } - _ -> Ok(#(set.new(), store, acc)) - }) - let before = map.size(store.free) - let free = map.insert(store.free, root, vars) - let acc = [#(root, vars), ..acc] - let store = Store(..store, free: free) - let after = map.size(store.free) - case after - before { - 0 -> { - io.debug(#(node, before, root)) - panic( - "this shouldn't happen as adding a new item should always make the map bigger", - ) - // and it doesn't - Nil - } - 1 -> Nil - } - Ok(#(vars, store, acc)) - } - } -} - -pub fn free_m(store: Store, root) -> Result(#(Set(String), Store), Nil) { - io.debug(root) - case map.get(store.free, 0) { - Ok(_) -> { - io.debug("found") - Nil - } - Error(_) -> Nil - } - case map.get(store.free, root) { - Ok(vars) -> { - io.debug(#( - "found----", - root, - map.get(store.source, root), - map.size(store.free), - )) - Ok(#(vars, store)) - } + Ok(vars) -> Ok(#(vars, store)) Error(Nil) -> { use node <- result.then(map.get(store.source, root)) use #(vars, store) <- result.then(case node { source.Var(x) -> Ok(#(setx.singleton(x), store)) source.Fn(x, ref) -> { - use #(vars, store) <- result.then(free_m(store, ref)) + use #(vars, store) <- result.then(free(store, ref)) Ok(#(set.delete(vars, x), store)) } source.Let(x, ref_v, ref_t) -> { - use #(value, store) <- result.then(free_m(store, ref_v)) - use #(then, store) <- result.then(free_m(store, ref_t)) + use #(value, store) <- result.then(free(store, ref_v)) + use #(then, store) <- result.then(free(store, ref_t)) let vars = set.union(value, set.delete(then, x)) Ok(#(vars, store)) } source.Call(ref_func, ref_arg) -> { - use #(func, store) <- result.then(free_m(store, ref_func)) - use #(arg, store) <- result.then(free_m(store, ref_arg)) + use #(func, store) <- result.then(free(store, ref_func)) + use #(arg, store) <- result.then(free(store, ref_arg)) let vars = set.union(func, arg) Ok(#(vars, store)) } _ -> Ok(#(set.new(), store)) }) - let before = map.size(store.free) - io.debug(#("insert", root)) let free = map.insert(store.free, root, vars) let store = Store(..store, free: free) - let after = map.size(store.free) - case after - before { - 0 -> { - io.debug(#(node, before, root)) - panic( - "this shouldn't happen as adding a new item should always make the map bigger", - ) - // and it doesn't - Nil - } - 1 -> Nil - } Ok(#(vars, store)) } } @@ -170,7 +81,7 @@ pub fn type_(store: Store, root) { // Error only for invalid ref pub fn do_type(env, ref, store: Store) -> Result(_, _) { - use #(vars, store, _) <- result.then(free(store, ref, [])) + use #(vars, store) <- result.then(free(store, ref)) let required = map.take(env, set.to_list(vars)) case inference.cache_lookup(store.types, ref, required) { Ok(t) -> Ok(#(t, store)) diff --git a/eyg/test/eyg/incremental/store_test.gleam b/eyg/test/eyg/incremental/store_test.gleam index dfea438e9..7567ce183 100644 --- a/eyg/test/eyg/incremental/store_test.gleam +++ b/eyg/test/eyg/incremental/store_test.gleam @@ -1,10 +1,7 @@ import gleam/io -import gleam/int -import gleam/list import gleam/map import gleam/set import eygir/expression as e -import eygir/decode import eyg/analysis/typ as t import eyg/incremental/source import eyg/incremental/store @@ -20,7 +17,7 @@ pub fn literal_test() { let #(ref_binary, s) = store.load(s, tree) should.equal(ref_binary, 0) // should.equal(store.tree(s, ref_binary), Ok(tree)) - let assert Ok(#(free, s, _)) = store.free(s, ref_binary, []) + let assert Ok(#(free, s)) = store.free(s, ref_binary) should.equal(map.size(s.free), 1) should.equal(free, set.new()) let assert Ok(#(t, s)) = store.type_(s, ref_binary) @@ -29,7 +26,7 @@ pub fn literal_test() { let #(ref_integer, s) = store.load(s, e.Integer(5)) should.equal(ref_integer, 1) - let assert Ok(#(free, s, _)) = store.free(s, ref_integer, []) + let assert Ok(#(free, s)) = store.free(s, ref_integer) should.equal(map.size(s.free), 2) should.equal(free, set.new()) let assert Ok(#(t, s)) = store.type_(s, ref_integer) @@ -213,7 +210,7 @@ pub fn branched_apply_test() { let assert Ok(c) = store.cursor(s, root, []) let assert Ok(node) = store.focus(s, c) should.equal(node, source.Let("id", 8, 6)) - let assert Ok(#(vars, s, _acc)) = store.free(s, root, []) + let assert Ok(#(vars, s)) = store.free(s, root) should.equal(vars, set.new()) should.equal(map.size(s.free), 10) should.equal(map.size(s.types), 0) @@ -233,66 +230,7 @@ pub fn branched_apply_test() { panic } -pub fn debug_test() { - map.new() - |> map.insert(22, Nil) - |> map.insert(21, Nil) - |> map.insert(23, Nil) - |> map.insert(18, Nil) - |> map.insert(17, Nil) - |> map.insert(19, Nil) - |> map.insert(14, Nil) - |> map.insert(13, Nil) - |> map.insert(15, Nil) - |> map.insert(10, Nil) - |> map.insert(9, Nil) - |> map.insert(11, Nil) - |> map.insert(6, Nil) - |> map.insert(5, Nil) - |> map.insert(7, Nil) - |> map.insert(2, Nil) - |> map.insert(1, Nil) - |> map.insert(3, Nil) - |> map.get(0) - |> io.debug - todo -} -pub fn debug_test_o() { - let s = store.empty() - // ok - // {foo: "foo", {bar: "bar", {}}} - // let assert Ok(tree) = - // "{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"equal\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"debug\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"fix\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"capture\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"serialize\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"u\"}}}}}}" - // not ok - // {foo: "foo", {bar: "bar", {bar: "bar", {}}}} - let assert Ok(tree) = - "{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"equal\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"debug\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"fix\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"capture\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"serialize\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"a\",\"f\":{\"0\":\"a\",\"f\":{\"0\":\"e\",\"l\":\"foo\"},\"a\":{\"0\":\"s\",\"v\":\"b\"}},\"a\":{\"0\":\"u\"}}}}}}}" - |> decode.from_json - // |> io.debug - let #(root, s) = store.load(s, tree) - // should.equal(root, 24) - should.equal(map.size(s.source), 25) - // let assert Ok(#(free, s, _)) = store.free(s, root, []) - should.equal(map.size(s.free), 0) - let assert Ok(#(free, s)) = store.free_m(s, root) - - map.size(s.free) - |> io.debug - map.to_list(s.source) - |> list.sort(by_first) - |> list.map(io.debug) - map.to_list(s.free) - |> list.sort(by_first) - |> list.map(io.debug) - // should.equal(, 25) - store.ref_group(s) - |> io.debug - // todo -} -pub fn by_first(x: #(Int, _), y: #(Int, _)) { - int.compare(x.0, y.0) -} From 2b9a569e676acca6553aaf2c16c01e292c28a72c Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 10 Apr 2023 16:38:40 +0200 Subject: [PATCH 32/62] undo debug info --- eyg/src/atelier/view/projection.gleam | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/eyg/src/atelier/view/projection.gleam b/eyg/src/atelier/view/projection.gleam index 49f4684f7..064618a4e 100644 --- a/eyg/src/atelier/view/projection.gleam +++ b/eyg/src/atelier/view/projection.gleam @@ -15,13 +15,7 @@ pub fn render(source, selection, inferred: Option(inference.Infered)) { let loc = Location([], Some(selection)) pre( [style([#("cursor", "pointer")]), class("w-full max-w-6xl")], - [ - text( - list.map(selection, int.to_string) - |> string.join(","), - ), - ..do_render(source, "\n", loc, inferred) - ], + do_render(source, "\n", loc, inferred), ) } From 5b25232746183776467f5880c26fcd90b2a4515f Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 10 Apr 2023 16:54:31 +0200 Subject: [PATCH 33/62] mutable store --- eyg/src/atelier/app.gleam | 11 +++++++++ eyg/src/eyg/incremental/store.gleam | 36 +++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index c89cb2776..95ed5f59f 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -16,6 +16,8 @@ import eygir/encode import eyg/analysis/inference import eyg/runtime/standard import eyg/incremental/store +import plinth/javascript/map as mutable_map + pub type WorkSpace { WorkSpace( @@ -85,6 +87,15 @@ pub fn init(source) { map.size(s.free), )) + let start = pnow() + let assert Ok(#(vars, s)) = store.free_mut(s, root) + io.debug(#( + "memoizing free mut took ms:", + pnow() - start, + map.size(s.source), + mutable_map.size(s.free_mut), + )) + let start = pnow() let assert Ok(#(t, s)) = store.type_(s, root) // TODO i think should be same size diff --git a/eyg/src/eyg/incremental/store.gleam b/eyg/src/eyg/incremental/store.gleam index cda04e130..32b476930 100644 --- a/eyg/src/eyg/incremental/store.gleam +++ b/eyg/src/eyg/incremental/store.gleam @@ -13,11 +13,13 @@ import eyg/analysis/unification import eyg/incremental/source import eyg/incremental/inference import eyg/incremental/cursor +import plinth/javascript/map as mutable_map pub type Store { Store( source: Map(Int, source.Expression), free: Map(Int, Set(String)), + free_mut: mutable_map.MutableMap(Int, Set(String)), types: Map(Int, Map(Map(String, Scheme), t.Term)), substitutions: sub.Substitutions, counter: javascript.Reference(Int), @@ -28,6 +30,7 @@ pub fn empty() { Store( source: map.new(), free: map.new(), + free_mut: mutable_map.new(), types: map.new(), substitutions: sub.none(), counter: javascript.make_reference(0), @@ -73,6 +76,39 @@ pub fn free(store: Store, root) -> Result(#(Set(String), Store), Nil) { } } +pub fn free_mut(store: Store, root) -> Result(#(Set(String), Store), Nil) { + case mutable_map.get(store.free_mut, root) { + Ok(vars) -> Ok(#(vars, store)) + Error(Nil) -> { + use node <- result.then(map.get(store.source, root)) + use #(vars, store) <- result.then(case node { + source.Var(x) -> Ok(#(setx.singleton(x), store)) + source.Fn(x, ref) -> { + use #(vars, store) <- result.then(free_mut(store, ref)) + Ok(#(set.delete(vars, x), store)) + } + source.Let(x, ref_v, ref_t) -> { + use #(value, store) <- result.then(free_mut(store, ref_v)) + use #(then, store) <- result.then(free_mut(store, ref_t)) + let vars = set.union(value, set.delete(then, x)) + Ok(#(vars, store)) + } + source.Call(ref_func, ref_arg) -> { + use #(func, store) <- result.then(free_mut(store, ref_func)) + use #(arg, store) <- result.then(free_mut(store, ref_arg)) + let vars = set.union(func, arg) + Ok(#(vars, store)) + } + _ -> Ok(#(set.new(), store)) + }) + let free = mutable_map.set(store.free_mut, root, vars) + // let store = Store(..store, free: free) + Ok(#(vars, store)) + } + } +} + + pub fn type_(store: Store, root) { use #(unresolved, store) <- result.then(do_type(map.new(), root, store)) let t = unification.resolve(store.substitutions, unresolved) From fdde1491a9d015a74bbd4c52c81052c2fc154da9 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 18 Apr 2023 08:04:40 +0200 Subject: [PATCH 34/62] clean up cursor --- eyg/src/eyg/incremental/cursor.gleam | 99 ++-------------------------- 1 file changed, 6 insertions(+), 93 deletions(-) diff --git a/eyg/src/eyg/incremental/cursor.gleam b/eyg/src/eyg/incremental/cursor.gleam index d9e8e837f..b7d07763c 100644 --- a/eyg/src/eyg/incremental/cursor.gleam +++ b/eyg/src/eyg/incremental/cursor.gleam @@ -1,16 +1,15 @@ import gleam/io -import gleam/list import gleam/map import gleam/result -import eyg/incremental/source.{Call, Fn, Let} +import eyg/incremental/source pub fn zip_match(node, path_element) { case node, path_element { - Let(_, index, _), 0 -> index - Let(_, _, index), 1 -> index - Fn(_, index), 0 -> index - Call(index, _), 0 -> index - Call(_, index), 1 -> index + source.Let(_, index, _), 0 -> index + source.Let(_, _, index), 1 -> index + source.Fn(_, index), 0 -> index + source.Call(index, _), 0 -> index + source.Call(_, index), 1 -> index _, _ -> { io.debug(#(node, path_element)) panic("no_zip_match") @@ -18,30 +17,6 @@ pub fn zip_match(node, path_element) { } } -fn do_at(path, refs, current, zoom, root) { - case path { - [] -> #([current, ..zoom], root) - [path_element, ..path] -> { - let assert Ok(node) = list.at(refs, current) - let zoom = [current, ..zoom] - let current = zip_match(node, path_element) - do_at(path, refs, current, zoom, root) - } - } -} - -// root and refs together from tree -pub fn at(path, root, refs) { - case path { - [] -> #([], root) - [path_element, ..path] -> { - let assert Ok(node) = list.at(refs, root) - let current = zip_match(node, path_element) - do_at(path, refs, current, [], root) - } - } -} - fn do_at_map(path, refs, current, zoom, root) { case path { [] -> Ok(#([current, ..zoom], root)) @@ -66,68 +41,6 @@ pub fn at_map(path, root, refs) { } } -fn do_replace(old, new, zoom, rev) { - case zoom { - [] -> #(new, list.reverse(rev)) - [next, ..zoom] -> { - let assert Ok(node) = list.at(list.reverse(rev), next) - let exp = case node { - Let(label, value, then) if value == old -> Let(label, new, then) - Let(label, value, then) if then == old -> Let(label, value, new) - Fn(param, body) if body == old -> Fn(param, new) - Call(func, arg) if func == old -> Call(new, arg) - Call(func, arg) if arg == old -> Call(func, new) - _ -> panic("Can't have a path into literal so invalid path, TODO make return error, cursor is invalid") - } - let new = list.length(rev) - let rev = [exp, ..rev] - do_replace(next, new, zoom, rev) - } - } -} - -pub fn replace(tree, cursor, refs) { - let #(exp, acc) = source.do_from_tree(tree, list.reverse(refs)) - let new = list.length(acc) - let rev = [exp, ..acc] - case cursor { - #([], old) -> do_replace(old, new, [], rev) - #([old, ..zoom], root) -> - do_replace(old, new, list.append(zoom, [root]), rev) - } -} - -// fn do_replace_map(old, new, zoom, rev) { -// case zoom { -// [] -> #(new, list.reverse(rev)) -// [next, ..zoom] -> { -// let assert Ok(node) = list.at(list.reverse(rev), next) -// let exp = case node { -// Let(label, value, then) if value == old -> Let(label, new, then) -// Let(label, value, then) if then == old -> Let(label, value, new) -// Fn(param, body) if body == old -> Fn(param, new) -// Call(func, arg) if func == old -> Call(new, arg) -// Call(func, arg) if arg == old -> Call(func, new) -// _ -> todo("Can't have a path into literal") -// } -// let new = list.length(rev) -// let rev = [exp, ..rev] -// do_replace_map(next, new, zoom, rev) -// } -// } -// } - -// pub fn replace_map(tree, cursor, refs) { -// let #(exp, acc) = source.do_from_tree(tree, list.reverse(refs)) -// let new = list.length(acc) -// let rev = [exp, ..acc] -// case cursor { -// #([], old) -> do_replace_map(old, new, [], rev) -// #([old, ..zoom], root) -> -// do_replace_map(old, new, list.append(zoom, [root]), rev) -// } -// } - pub fn inner(c) { case c { #([], root) -> root From e23fc0847d47e99c9b4ac04262226fe5d2949f2f Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 18 Apr 2023 08:13:02 +0200 Subject: [PATCH 35/62] update docker --- fly.Dockerfile | 2 +- language.Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fly.Dockerfile b/fly.Dockerfile index 4057244a6..2f5f7928d 100644 --- a/fly.Dockerfile +++ b/fly.Dockerfile @@ -1,4 +1,4 @@ -FROM ghcr.io/gleam-lang/gleam:v0.27.0-node +FROM ghcr.io/gleam-lang/gleam:v0.28.3-node COPY . /opt/app WORKDIR /opt/app/eyg diff --git a/language.Dockerfile b/language.Dockerfile index 8cb682030..9b740ec74 100644 --- a/language.Dockerfile +++ b/language.Dockerfile @@ -1,6 +1,6 @@ FROM rust:1.67.1 AS build -ENV SHA="v0.28.1" +ENV SHA="v0.28.3" RUN set -xe \ && curl -fSL -o gleam-src.tar.gz "https://github.com/gleam-lang/gleam/archive/${SHA}.tar.gz" \ && mkdir -p /usr/src/gleam-src \ From 876860ffa54089175723353469edc7d2d82b9a20 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 18 Apr 2023 08:34:37 +0200 Subject: [PATCH 36/62] fix store load --- eyg/src/eyg/incremental/store.gleam | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eyg/src/eyg/incremental/store.gleam b/eyg/src/eyg/incremental/store.gleam index 32b476930..edc2ff01a 100644 --- a/eyg/src/eyg/incremental/store.gleam +++ b/eyg/src/eyg/incremental/store.gleam @@ -18,6 +18,7 @@ import plinth/javascript/map as mutable_map pub type Store { Store( source: Map(Int, source.Expression), + source_id_tracker: javascript.Reference(Int), free: Map(Int, Set(String)), free_mut: mutable_map.MutableMap(Int, Set(String)), types: Map(Int, Map(Map(String, Scheme), t.Term)), @@ -29,6 +30,7 @@ pub type Store { pub fn empty() { Store( source: map.new(), + source_id_tracker: javascript.make_reference(0), free: map.new(), free_mut: mutable_map.new(), types: map.new(), @@ -38,9 +40,7 @@ pub fn empty() { } pub fn load(store: Store, tree) { - let ref = javascript.make_reference(0) - // maybe just include the exp - let #(index, source) = source.do_from_tree_map(tree, store.source, ref) + let #(index, source) = source.do_from_tree_map(tree, store.source, store.source_id_tracker) #(index, Store(..store, source: source)) } From afeccc845f5b741e621fd645822519cf2a93a8de Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 18 Apr 2023 08:40:10 +0200 Subject: [PATCH 37/62] clean up tests --- eyg/src/eyg/incremental/store.gleam | 18 +----------------- eyg/test/eyg/incremental/store_test.gleam | 12 +----------- 2 files changed, 2 insertions(+), 28 deletions(-) diff --git a/eyg/src/eyg/incremental/store.gleam b/eyg/src/eyg/incremental/store.gleam index edc2ff01a..769e483bb 100644 --- a/eyg/src/eyg/incremental/store.gleam +++ b/eyg/src/eyg/incremental/store.gleam @@ -242,6 +242,7 @@ pub fn focus(store: Store, c) { map.get(store.source, cursor.inner(c)) } +// used for debugging maps. there should be only one reference to a node in a store with a single root. pub fn ref_group(store: Store) { let child_refs = list.flat_map( @@ -257,23 +258,6 @@ pub fn ref_group(store: Store) { } }, ) - // source.Integer(Int) - // source.String(String) - // source.Tail - // source.Cons - // source.Vacant(comment: String) - // source.Empty - // source.Extend(label: String) - // source.Select(label: String) - // source.Overwrite(label: String) - // source.Tag(label: String) - // source.Case(label: String) - // source.NoCases - // source.Perform(label: String) - // source.Handle(label: String) - // source.Builtin(identifier: String) - // Makes sense there should be one thing, the root that is not referenced, one more for each cursor update - io.debug(#("child refs", list.length(child_refs), map.size(store.source))) child_refs |> list.group(fn(x) { x.0 }) |> map.filter(fn(_, v) { list.length(v) < 1 }) diff --git a/eyg/test/eyg/incremental/store_test.gleam b/eyg/test/eyg/incremental/store_test.gleam index 7567ce183..aca18eb02 100644 --- a/eyg/test/eyg/incremental/store_test.gleam +++ b/eyg/test/eyg/incremental/store_test.gleam @@ -84,11 +84,6 @@ pub fn let_literal_test() { should.equal(t, t.Binary) should.equal(map.size(s.free), 3) should.equal(map.size(s.types), 3) - io.debug(#( - "============", - store.ref_group(s) - |> map.to_list, - )) let assert Ok(c) = store.cursor(s, root, [0]) let assert Ok(node) = store.focus(s, c) @@ -102,7 +97,7 @@ pub fn let_literal_test() { let assert Ok(#(root2, s)) = store.replace(s, c, source.Empty) should.equal(map.size(s.source), 7) // source increase by path length + 1 - // free and types are lazy so stay at 4 + // free and types are lazy so stay at previous value should.equal(map.size(s.free), 3) should.equal(map.size(s.types), 3) @@ -113,11 +108,6 @@ pub fn let_literal_test() { should.equal(map.size(s.free), 7) should.equal(map.size(s.types), 7) - io.debug(#( - "============", - store.ref_group(s) - |> map.to_list, - )) } pub fn fn_poly_test() { From dee513296f262f5931d1b6805e339adfc6f11500 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 18 Apr 2023 21:11:38 +0200 Subject: [PATCH 38/62] messing with monads --- eyg/src/eyg/incremental/continuation.gleam | 62 ++++++++++ eyg/src/eyg/incremental/state_monad.gleam | 129 +++++++++++++++++++++ eyg/src/eyg/incremental/store.gleam | 13 ++- eyg/test/eyg/incremental/store_test.gleam | 16 ++- 4 files changed, 212 insertions(+), 8 deletions(-) create mode 100644 eyg/src/eyg/incremental/continuation.gleam create mode 100644 eyg/src/eyg/incremental/state_monad.gleam diff --git a/eyg/src/eyg/incremental/continuation.gleam b/eyg/src/eyg/incremental/continuation.gleam new file mode 100644 index 000000000..e729a2bce --- /dev/null +++ b/eyg/src/eyg/incremental/continuation.gleam @@ -0,0 +1,62 @@ +import gleam/io +import gleam/list +import gleam/map.{Map} +import gleam/result +import gleam/set.{Set} +import gleam/setx +import gleam/javascript +import eygir/expression as e + +// TODO source -> ref +import eyg/analysis/typ as t +import eyg/analysis/substitutions as sub +import eyg/analysis/scheme.{Scheme} +import eyg/analysis/unification +import eyg/incremental/source +import eyg/analysis/env +import eyg/incremental/inference +import eyg/incremental/cursor +import plinth/javascript/map as mutable_map + +// type Continuation(arg, ret) = +// fn(fn(arg) -> ret) -> ret + +// fn do(st: Continuation(a, r), f: fn(r) -> Continuation(a1, r2)) -> Continuation(a1, r2) { +// fn(env) { +// let #(env, a) = st(env) +// let next = f(a) +// next(env) +// } +// } +// TODO continuation monad + +pub fn do(arg, k) { + // separate Cont from all other effects + case arg { + Push(env, exp) -> { + cache_lookup + // call do(push()) = > infer + } + } +} + +pub fn run() { + todo +} + + + +pub fn step(env, exp) { + case exp { + e.Apply(e1, e2) -> { + use #(s1, t1) <- do(push(env, e1)) + use #(s2, t2) <- do(push(env.apply(s1, env), e2)) + let tv = t.Unbound(0) + let ref = todo + use s3 <- result.then(unification.unify(sub.apply(s2, t1), t.Fun(t2, t.Closed, tv), ref)) + Ok(#(sub.compose(sub.compose(s3, s2), s2), sub.apply(s3, tv))) + } + e.Integer(_) -> Ok(#(sub.none(), t.Integer)) + _ -> todo + } +} \ No newline at end of file diff --git a/eyg/src/eyg/incremental/state_monad.gleam b/eyg/src/eyg/incremental/state_monad.gleam new file mode 100644 index 000000000..8d2c93ab3 --- /dev/null +++ b/eyg/src/eyg/incremental/state_monad.gleam @@ -0,0 +1,129 @@ +import gleam/io +import gleam/list +import gleam/map.{Map} +import gleam/result +import gleam/set.{Set} +import gleam/setx +import gleam/javascript +// TODO source -> ref +import eyg/analysis/typ as t +import eyg/analysis/substitutions as sub +import eyg/analysis/scheme.{Scheme} +import eyg/analysis/unification +import eyg/incremental/source +import eyg/analysis/env +import eyg/incremental/inference +import eyg/incremental/cursor +import plinth/javascript/map as mutable_map + + +type State(a, env) = + fn(env) -> #(env, a) + +fn do(st: State(a, env), f: fn(a) -> State(b, env)) -> State(b, env) { + fn(env) { + let #(env, a) = st(env) + let next = f(a) + next(env) + } +} + +fn return(a: a) -> State(a, env) { + fn(env) { + #(env, a) + } +} + +fn run(st: State(a, env), env: env) -> a { + st(env).1 +} + + +// you can write: + + + + +// fn lookup(pointer) { +// fn(infer: Infer) { +// #(infer, source.String("temp")) +// } +// } + + +// fn w_(env, pointer) { +// // do_w(env, do()) +// // run the internal one +// // fn(infer) {#(infer,run(do_w(env, todo), todo))} +// fn(infer) { +// do_w(env, todo)(infer) +// } +// } + +// fn unbound(k) { +// do(fn(infer) { +// use var <- do(fresh()) +// return(t.Unbound(var)) +// }, k) +// } + +pub type Infer { + Infer(counter: Int, source: Map(Int, source.Expression)) +} + +fn fresh() -> State(Int, Infer) { + fn(infer: Infer) { + let count = infer.counter + #(Infer(..infer, counter: count + 1), count) + } +} + +fn w(env, pointer, k) { + do(fn(infer: Infer) { + let assert Ok(exp) = map.get(infer.source, pointer) + do_w(env, exp)(infer) + }, k) +} + + +fn do_w(env, exp) { + case exp { + source.Fn(x, exp1) -> { + use tv <- do(fresh()) + use #(s1, t1) <- w(env, exp1) + return(#(s1, t.Fun(sub.apply(s1, t.Unbound(tv)), t.Closed, t1))) + } + source.String(_) -> return(#(sub.none(), t.Binary)) + _ -> todo + } +} + + +// pub fn run(step, k) { +// case step { +// Return(s, t) -> k(s,t) +// Continue(p,f)-> todo +// } +// } + +// pub fn w(env, pointer, k) { +// Continue(pointer, fn(exp) { +// // TODO need k +// run(do_w(env, exp), k) +// }) +// } + +// pub type Effect { +// Continue(Int, fn(source.Expression) -> Effect) +// Return(sub.Substitutions, t.Term) +// } + +// fn do_w(env, exp) { +// case exp { +// source.Fn(x, exp1) -> { +// use #(s1, t1) <- w(env, exp1) +// } +// source.String(_) -> Return(sub.none(), t.Binary) +// _ -> todo +// } +// } \ No newline at end of file diff --git a/eyg/src/eyg/incremental/store.gleam b/eyg/src/eyg/incremental/store.gleam index 769e483bb..5dcdde4ec 100644 --- a/eyg/src/eyg/incremental/store.gleam +++ b/eyg/src/eyg/incremental/store.gleam @@ -11,6 +11,7 @@ import eyg/analysis/substitutions as sub import eyg/analysis/scheme.{Scheme} import eyg/analysis/unification import eyg/incremental/source +import eyg/analysis/env import eyg/incremental/inference import eyg/incremental/cursor import plinth/javascript/map as mutable_map @@ -137,9 +138,15 @@ pub fn do_type(env, ref, store: Store) -> Result(_, _) { } } source.Let(x, value, then) -> { - use #(t1, store) <- result.then(do_type(env, value, store)) - let scheme = unification.generalise(env, t1) - let env = map.insert(env, x, scheme) + // Alg J single substitutions no what we have + // Should I throw away caching when there are free type variables, because they wont be the same + // however std will always be free + // all of std and other projects should trivially remain. and without free variables + // changing std if only extending types should have no changes in project + use #(t1, store): #(_, Store) <- result.then(do_type(env, value, store)) + let scheme = unification.generalise(env.apply(store.substitutions, env), sub.apply(store.substitutions,t1)) + // is this env.apply twice necessary + let env = env.apply(store.substitutions, map.insert(env, x, scheme)) do_type(env, then, store) } source.Fn(x, body) -> { diff --git a/eyg/test/eyg/incremental/store_test.gleam b/eyg/test/eyg/incremental/store_test.gleam index aca18eb02..6d828fe80 100644 --- a/eyg/test/eyg/incremental/store_test.gleam +++ b/eyg/test/eyg/incremental/store_test.gleam @@ -3,6 +3,7 @@ import gleam/map import gleam/set import eygir/expression as e import eyg/analysis/typ as t +import eyg/analysis/inference import eyg/incremental/source import eyg/incremental/store import gleeunit/should @@ -211,11 +212,16 @@ pub fn branched_apply_test() { s.substitutions.terms |> map.to_list, ) - io.debug(#( - "============", - store.ref_group(s) - |> map.to_list, - )) + + let sub = inference.infer(map.new(), tree, t.Unbound(-1), t.Open(-2)) + io.debug(sub.substitutions.terms |> map.to_list) + + inference.sound(sub) + |> should.equal(Ok(Nil)) + + inference.type_of(sub, []) + |> io.debug + should.equal(t, t.Integer) panic } From 7dd9b24cef66d07714aed7853ec13586efdb08c5 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 20 Apr 2023 21:07:27 +0200 Subject: [PATCH 39/62] messing with algorithm j --- eyg/src/eyg/analysis/jm/infer.gleam | 164 ++++++++++++++++++ eyg/src/eyg/analysis/jm/type_.gleam | 173 +++++++++++++++++++ eyg/src/eyg/analysis/jm/unify.gleam | 28 ++++ eyg/src/eyg/incremental/continuation.gleam | 123 +++++++------- eyg/test/examples/algorithm_j_test.gleam | 90 ++++++++++ eyg/test/examples/algorithm_w.gleam | 3 + eyg/test/examples/algorithm_w_test.gleam | 5 + eyg/test/examples/j_cont_test.gleam | 184 +++++++++++++++++++++ eyg/test/eyg/analysis/typing_test.gleam | 39 +++++ 9 files changed, 748 insertions(+), 61 deletions(-) create mode 100644 eyg/src/eyg/analysis/jm/infer.gleam create mode 100644 eyg/src/eyg/analysis/jm/type_.gleam create mode 100644 eyg/src/eyg/analysis/jm/unify.gleam create mode 100644 eyg/test/examples/algorithm_j_test.gleam create mode 100644 eyg/test/examples/algorithm_w.gleam create mode 100644 eyg/test/examples/algorithm_w_test.gleam create mode 100644 eyg/test/examples/j_cont_test.gleam diff --git a/eyg/src/eyg/analysis/jm/infer.gleam b/eyg/src/eyg/analysis/jm/infer.gleam new file mode 100644 index 000000000..ed0e0b719 --- /dev/null +++ b/eyg/src/eyg/analysis/jm/infer.gleam @@ -0,0 +1,164 @@ +import gleam/io +import gleam/list +import gleam/map +import gleam/set +import eyg/incremental/source as e +import eyg/analysis/jm/type_ as t +import eyg/analysis/jm/unify + +fn mono(type_) { + #([], type_) +} + +pub fn scheme_ftv(scheme) { + let #(forall, typ) = scheme + set.drop(t.ftv(typ), forall) +} + +pub fn scheme_apply(sub, scheme) { + let #(forall, typ) = scheme + #(forall, t.apply(map.drop(sub, forall), typ)) +} + +type TypeEnv = + map.Map(String, #(List(Int), t.Type)) + + +// TypeEnv +pub fn env_ftv(env: TypeEnv) { + map.fold( + env, + set.new(), + fn(state, _k, scheme) { set.union(state, scheme_ftv(scheme)) }, + ) +} + +pub fn env_apply(sub, env) { + map.map_values(env, fn(_k, scheme) { scheme_apply(sub, scheme) }) +} + +fn generalise(sub, env, t) { + let env = env_apply(sub, env) + let t = t.apply(sub, t) + let forall = set.drop(t.ftv(t), set.to_list(env_ftv(env))) + #(set.to_list(forall), t) +} + +fn instantiate(scheme, next) { + let #(forall, type_) = scheme + let s = list.index_map(forall, fn(i, old) { #(old, t.Var(next + i))}) + |> map.from_list() + let next = next + list.length(forall) + let type_ = t.apply(s, type_) + #(type_, next) +} + + +fn extend(env, label, scheme) { + map.insert(env, label, scheme) + } + +pub fn unify_at(type_, found, sub, next, types, ref) { + io.debug(#(type_, found)) + case unify.unify(type_, found, sub) { + Ok(s) -> #(s, next, map.insert(types, ref, Ok(type_))) + Error(_) -> #(sub, next, map.insert(types, ref, Error(t.Missing))) + } +} + +pub fn infer(sub, next, env, source, ref, type_, eff, types, k) { + case map.get(source, ref) { + Error(Nil) -> k(#(sub, next, types)) + Ok(exp) -> case exp { + e.Var(x) -> { + case map.get(env, x) { + Ok(scheme) -> { + let #(found, next) = instantiate(scheme, next) + k(unify_at(type_, found, sub, next, types, ref)) + } + Error(Nil) -> { + let types = map.insert(types, ref, todo) + k(#(sub, next, types)) + } + } + } + e.Call(e1, e2) -> { + io.debug(#(type_, e1, e2)) + // can't error + let types = map.insert(types, ref, Ok(type_)) + let #(arg, next) = t.fresh(next) + io.debug(arg) + use #(sub, next, types) <- infer(sub, next, env, source, e1, t.Fun(arg, eff, type_), eff, types) + use #(sub, next, types) <- infer(sub, next, env, source, e2, arg, eff, types) + k(#(sub, next, types)) + } + e.Fn(x, e1) -> { + let #(arg, next) = t.fresh(next) + let #(eff, next) = t.fresh(next) + let #(ret, next) = t.fresh(next) + let #(sub, next, types) = unify_at(type_, t.Fun(arg, eff, ret), sub, next, types, ref) + let env = extend(env, x, mono(arg)) + use #(sub, next, types) <- infer(sub, next, env, source, e1, ret, eff, types) + k(#(sub, next, types)) + } + e.Let(x, e1, e2) -> { + // can't error + let types = map.insert(types, ref, Ok(type_)) + let #(inner, next) = t.fresh(next) + use #(sub, next, types) <- infer(sub, next, env, source, e1, inner, eff, types) + let env = extend(env, x, generalise(sub, env, inner)) + use #(sub, next, types) <- infer(sub, next, env, source, e2, type_, eff, types) + k(#(sub, next, types)) + } + literal -> { + let #(found, next) = primitive(literal, next) + k(unify_at(type_, found, sub, next, types, ref)) + } + } + } +} + +fn primitive(exp, next) { + case exp { + e.Var(_) | e.Call(_,_) | e.Fn(_,_) | e.Let(_,_,_) -> panic("not a literal") + e.String(_) -> #(t.String, next) + e.Integer(_) -> #(t.Integer, next) + + e.Tail -> t.tail(next) + e.Cons -> t.cons(next) + |> io.debug + e.Vacant(_comment) -> t.fresh(next) + + // Record + e.Empty -> t.empty(next) + e.Extend(label) -> t.extend(label, next) + e.Overwrite(label) -> t.overwrite(label, next) + e.Select(label) -> t.select(label, next) + + // Union + e.Tag(label) -> t.tag(label, next) + e.Case(label) -> t.case_(label, next) + e.NoCases -> t.nocases(next) + + // Effect + e.Perform(label) -> t.perform(label, next) + + e.Handle(label) -> t.handle(label, next) + + // e.Builtin(identifier) + _ -> todo("pull from old inference") + } +} +// errors should be both wrong f and wrong arg + + +// Can have fast inference if existing before +// reuse next and t maybe +// returning a type is good but I need to return a list of errors at least +// can't unify binary to an error + +// we've got J with early return as an option +// need a building state for speed. +// Test infer not this one +// Test jm +// Write up wand \ No newline at end of file diff --git a/eyg/src/eyg/analysis/jm/type_.gleam b/eyg/src/eyg/analysis/jm/type_.gleam new file mode 100644 index 000000000..3efd320d4 --- /dev/null +++ b/eyg/src/eyg/analysis/jm/type_.gleam @@ -0,0 +1,173 @@ +import gleam/map +import gleam/result +import gleam/set +import gleam/setx + +pub type Type { + Var(Int) + Fun(Type, Type, Type) + Integer + String + LinkedList(Type) + // Types Record/Union must be Empty/Extend/Var + Record(Type) + Union(Type) + Empty + RowExtend(String, Type, Type) + EffectExtend(String, #(Type, Type), Type) +} + +pub type Reason { + Missing +} + +pub fn ftv(type_) { + case type_ { + Var(a) -> setx.singleton(a) + Fun(from, effects, to) -> + set.union(set.union(ftv(from), ftv(effects)), ftv(to)) + Integer | String -> set.new() + LinkedList(element) -> ftv(element) + Record(row) -> ftv(row) + Union(row) -> ftv(row) + Empty -> set.new() + RowExtend(_label, value, rest) -> set.union(ftv(value), ftv(rest)) + EffectExtend(_label, #(lift, reply), rest) -> set.union(set.union(ftv(lift), ftv(reply)), ftv(rest)) + } +} + +pub fn apply(s, type_) { + case type_ { + Var(a) -> result.unwrap(map.get(s, a), type_) + Fun(from, effects, to) -> + Fun(apply(s, from), apply(s, effects), apply(s, to)) + Integer | String -> type_ + LinkedList(element) -> LinkedList(apply(s, element)) + Record(row) -> Record(apply(s, row)) + Union(row) -> Union(apply(s, row)) + Empty -> type_ + RowExtend(label, value, rest) -> RowExtend(label, apply(s, value), apply(s, rest)) + EffectExtend(label, #(lift, reply), rest) -> EffectExtend(label, #(apply(s, lift), apply(s, reply)), apply(s, rest)) + + } +} + +pub fn resolve(t, s) { + case t { + Var(a) -> + map.get(s, a) + |> result.unwrap(t) + Fun(u, v, w) -> Fun(resolve(u, s), resolve(v, s), resolve(w, s)) + String | Integer | Empty -> t + LinkedList(element) -> LinkedList(resolve(element, s)) + Record(u) -> Record(resolve(u, s)) + Union(u) -> Union(resolve(u, s)) + RowExtend(label, u, v) -> RowExtend(label, resolve(u, s), resolve(v, s)) + EffectExtend(label, #(u, v), w) -> EffectExtend(label, #(resolve(u, s), resolve(v, s)), resolve(w, s)) + } +} + +pub fn fresh(next) { + #(Var(next), next + 1) +} + +pub fn tail(next) { + let #(item, next) = fresh(next) + #(LinkedList(item), next) +} + +pub fn cons(next) { + let #(item, next) = fresh(next) + let #(e1, next) = fresh(next) + let #(e2, next) = fresh(next) + let t = Fun(item, e1, Fun(LinkedList(item), e2, LinkedList(item))) + #(t, next) +} + +pub fn empty(next) { + #(Record(Empty), next) +} + +pub fn extend(label, next) { + let #(value, next) = fresh(next) + let #(rest, next) = fresh(next) + let #(e1, next) = fresh(next) + let #(e2, next) = fresh(next) + let t = Fun(value, e1, Fun(Record(rest), e2, Record(RowExtend(label, value, rest)))) + #(t, next) +} + +pub fn select(label, next) { + let #(value, next) = fresh(next) + let #(rest, next) = fresh(next) + let #(e, next) = fresh(next) + let t = Fun(Record(RowExtend(label, value, rest)), e, value) + #(t, next) +} + +pub fn overwrite(label, next) { + let #(new, next) = fresh(next) + let #(old, next) = fresh(next) + let #(rest, next) = fresh(next) + let #(e1, next) = fresh(next) + let #(e2, next) = fresh(next) + let t = Fun(new, e1, Fun(Record(RowExtend(label, old, rest)), e2, Record(RowExtend(label, new, rest)))) + #(t, next) +} + +pub fn tag(label, next) { + let #(value, next) = fresh(next) + let #(rest, next) = fresh(next) + let #(e, next) = fresh(next) + let t = Fun(value, e, Union(RowExtend(label, value, rest))) + #(t, next) +} + +pub fn case_(label, next) { + let #(value, next) = fresh(next) + let #(ret, next) = fresh(next) + let #(rest, next) = fresh(next) + let #(e1, next) = fresh(next) + let #(e2, next) = fresh(next) + let #(e3, next) = fresh(next) + let #(e4, next) = fresh(next) + let #(e5, next) = fresh(next) + let branch = Fun(value, e1, ret) + let else = Fun(Union(rest), e2, ret) + let exec = Fun(Union(RowExtend(label, value, rest)), e3, ret) + let t = Fun(branch, e4, Fun(else, e5, exec)) + #(t, next) +} + +pub fn nocases(next) { + let #(ret, next) = fresh(next) + let #(e, next) = fresh(next) + let t = Fun(Union(Empty), e, ret) + #(t, next) +} + +pub fn perform(label, next) { + let #(arg, next) = fresh(next) + let #(ret, next) = fresh(next) + let #(tail, next) = fresh(next) + let t = Fun(arg, EffectExtend(label, #(arg, ret), tail), ret) + #(t, next) +} + +pub fn handle(label, next) { + let #(ret, next) = fresh(next) + let #(lift, next) = fresh(next) + let #(reply, next) = fresh(next) + let #(tail, next) = fresh(next) + let #(e, next) = fresh(next) + + let kont = Fun(reply, tail, ret) + let handler = Fun(lift, tail, Fun(kont, tail, ret)) + let exec = Fun(unit, EffectExtend(label, #(lift, reply), tail), ret) + let t = Fun(handler, e, Fun(exec, tail, ret)) + #(t, next) +} + +pub const unit = Record(Empty) + +pub const boolean = Union(RowExtend("True", unit, RowExtend("False", unit, Empty))) \ No newline at end of file diff --git a/eyg/src/eyg/analysis/jm/unify.gleam b/eyg/src/eyg/analysis/jm/unify.gleam new file mode 100644 index 000000000..7e540bc02 --- /dev/null +++ b/eyg/src/eyg/analysis/jm/unify.gleam @@ -0,0 +1,28 @@ +import gleam/io +import gleam/map +import eyg/analysis/jm/type_ as t + +pub fn unify(t1, t2, s) { + do_unify([#(t1, t2)], s) +} + +// s is a function from var -> t +fn do_unify(constraints, s) { + // Have to try and substitute at every point because new substitutions can come into existance + case constraints { + [] -> Ok(s) + [#(t.Var(i), t.Var(infer)), ..constraints] -> do_unify(constraints, s) + [#(t.Var(i), t1), ..constraints] | [#(t1, t.Var(i)), ..constraints] -> case map.get(s, i) { + Ok(t2) -> do_unify([#(t1, t2),..constraints], s) + Error(Nil) -> do_unify(constraints, map.insert(s, i, t1)) + } + [#(t.Fun(a1, e1, r1), t.Fun(a2, e2, r2)), ..cs] -> do_unify([#(a1, a2), #(e1, e2), #(r1, r2), ..cs], s) + [#(t.LinkedList(i1), t.LinkedList(i2)), ..cs] -> do_unify([#(i1, i2), ..cs], s) + _ -> { + io.debug("I think this ods it") + io.debug(constraints) + todo("I need to handle records") + Error(Nil) + } + } +} \ No newline at end of file diff --git a/eyg/src/eyg/incremental/continuation.gleam b/eyg/src/eyg/incremental/continuation.gleam index e729a2bce..9fecdcf06 100644 --- a/eyg/src/eyg/incremental/continuation.gleam +++ b/eyg/src/eyg/incremental/continuation.gleam @@ -1,62 +1,63 @@ -import gleam/io -import gleam/list -import gleam/map.{Map} -import gleam/result -import gleam/set.{Set} -import gleam/setx -import gleam/javascript -import eygir/expression as e - -// TODO source -> ref -import eyg/analysis/typ as t -import eyg/analysis/substitutions as sub -import eyg/analysis/scheme.{Scheme} -import eyg/analysis/unification -import eyg/incremental/source -import eyg/analysis/env -import eyg/incremental/inference -import eyg/incremental/cursor -import plinth/javascript/map as mutable_map - -// type Continuation(arg, ret) = -// fn(fn(arg) -> ret) -> ret - -// fn do(st: Continuation(a, r), f: fn(r) -> Continuation(a1, r2)) -> Continuation(a1, r2) { -// fn(env) { -// let #(env, a) = st(env) -// let next = f(a) -// next(env) -// } +// import gleam/io +// import gleam/list +// import gleam/map.{Map} +// import gleam/result +// import gleam/set.{Set} +// import gleam/setx +// import gleam/javascript +// import eygir/expression as e + +// // TODO source -> ref +// import eyg/analysis/typ as t +// import eyg/analysis/substitutions as sub +// import eyg/analysis/scheme.{Scheme} +// import eyg/analysis/unification +// import eyg/incremental/source +// import eyg/analysis/env +// import eyg/incremental/inference +// import eyg/incremental/cursor +// import plinth/javascript/map as mutable_map + +// // type Continuation(arg, ret) = +// // fn(fn(arg) -> ret) -> ret + +// // fn do(st: Continuation(a, r), f: fn(r) -> Continuation(a1, r2)) -> Continuation(a1, r2) { +// // fn(env) { +// // let #(env, a) = st(env) +// // let next = f(a) +// // next(env) +// // } +// // } +// // TODO continuation monad + +// pub fn do(arg, k) { +// // separate Cont from all other effects +// case arg { +// // Push(env, exp) -> { +// // cache_lookup +// // // call do(push()) = > infer +// // } +// _ -> todo +// } // } -// TODO continuation monad - -pub fn do(arg, k) { - // separate Cont from all other effects - case arg { - Push(env, exp) -> { - cache_lookup - // call do(push()) = > infer - } - } -} - -pub fn run() { - todo -} - - - -pub fn step(env, exp) { - case exp { - e.Apply(e1, e2) -> { - use #(s1, t1) <- do(push(env, e1)) - use #(s2, t2) <- do(push(env.apply(s1, env), e2)) - let tv = t.Unbound(0) - let ref = todo - use s3 <- result.then(unification.unify(sub.apply(s2, t1), t.Fun(t2, t.Closed, tv), ref)) - Ok(#(sub.compose(sub.compose(s3, s2), s2), sub.apply(s3, tv))) - } - e.Integer(_) -> Ok(#(sub.none(), t.Integer)) - _ -> todo - } -} \ No newline at end of file + +// pub fn run() { +// todo +// } + + + +// pub fn step(env, exp) { +// case exp { +// e.Apply(e1, e2) -> { +// use #(s1, t1) <- do(push(env, e1)) +// use #(s2, t2) <- do(push(env.apply(s1, env), e2)) +// let tv = t.Unbound(0) +// let ref = todo +// use s3 <- result.then(unification.unify(sub.apply(s2, t1), t.Fun(t2, t.Closed, tv), ref)) +// Ok(#(sub.compose(sub.compose(s3, s2), s2), sub.apply(s3, tv))) +// } +// e.Integer(_) -> Ok(#(sub.none(), t.Integer)) +// _ -> todo +// } +// } \ No newline at end of file diff --git a/eyg/test/examples/algorithm_j_test.gleam b/eyg/test/examples/algorithm_j_test.gleam new file mode 100644 index 000000000..eb3bee65c --- /dev/null +++ b/eyg/test/examples/algorithm_j_test.gleam @@ -0,0 +1,90 @@ +import gleam/map.{get, insert as extend} +import gleam/result.{then as try_} + +pub type Literal { + Integer + String +} + +pub type Exp { + Var(String) + App(Exp, Exp) + Abs(String, Exp) + Let(String, Exp, Exp) + Lit(Literal) +} + +pub type Type { + TInt + // TString + Unbound(Int) + Fn(Type,Type) +} + +pub type Scheme = #(List(Int), Type) + +pub fn fresh(next) { + #(Unbound(next), next + 1) +} + +pub fn instantiate(scheme, next) { + todo +} + +pub fn mono(t) { + #([], t) +} + +pub fn generalise(env, t) { + todo +} + +pub fn unify(t1, t2, s) { + do_unify([#(t1, t2)], s) +} + +// s is a function from var -> t +pub fn do_unify(constraints, s) { + // Have to try and substitute at every point because new substitutions can come into existance + case constraints { + [] -> Ok(s) + [#(Unbound(i), Unbound(j)), ..constraints] -> do_unify(constraints, s) + [#(Unbound(i), t1), ..constraints] | [#(t1, Unbound(i)), ..constraints] -> case map.get(s, i) { + Ok(t2) -> do_unify([#(t1, t2),..constraints], s) + Error(Nil) -> do_unify(constraints, map.insert(s, i, t1)) + } + [#(Fn(a1, r1), Fn(a2, r2)), ..cs] -> do_unify([#(a1, a2), #(r1, r2), ..cs], s) + _ -> Error(Nil) + } +} + +// In exercise a type can be type err +pub fn j(env, exp, sub, next) { + case exp { + Var(x) -> { + use scheme <- try_(get(env, x)) + let #(type_, next) = instantiate(scheme, next) + Ok(#(sub, next, type_)) + } + App(e1, e2) -> { + use #(sub1, next, t1) <- try_(j(env, e1, sub, next)) + use #(sub2, next, t2) <- try_(j(env, e2, sub1, next)) + let #(beta, next) = fresh(next) + use sub3 <- try_(unify(t1, Fn(t2, beta), sub2)) + Ok(#(sub, next, beta)) + } + Abs(x, e1) -> { + let #(beta, next) = fresh(next) + let env1 = extend(env, x, mono(beta)) + use #(sub1, next, t1) <- try_(j(env, e1, sub, next)) + Ok(#(sub1, next, Fn(beta, t1))) + } + Let(x, e1, e2) -> { + use #(sub1, next, t1) <- try_(j(env, e1, sub, next)) + // generalise needs sub applied tot1 + let env1 = extend(env, x, generalise(env, t1)) + use #(sub2, next, t2) <- try_(j(env, e2, sub1, next)) + } + Lit(l) -> todo + } +} \ No newline at end of file diff --git a/eyg/test/examples/algorithm_w.gleam b/eyg/test/examples/algorithm_w.gleam new file mode 100644 index 000000000..1070abc01 --- /dev/null +++ b/eyg/test/examples/algorithm_w.gleam @@ -0,0 +1,3 @@ +pub fn w() { + "" +} \ No newline at end of file diff --git a/eyg/test/examples/algorithm_w_test.gleam b/eyg/test/examples/algorithm_w_test.gleam new file mode 100644 index 000000000..948e7457a --- /dev/null +++ b/eyg/test/examples/algorithm_w_test.gleam @@ -0,0 +1,5 @@ +import examples/algorithm_w.{w} + +pub fn function_name_test() -> Nil { + todo +} \ No newline at end of file diff --git a/eyg/test/examples/j_cont_test.gleam b/eyg/test/examples/j_cont_test.gleam new file mode 100644 index 000000000..4388a762f --- /dev/null +++ b/eyg/test/examples/j_cont_test.gleam @@ -0,0 +1,184 @@ +import gleam/io +import gleam/map.{get, insert as extend} +import gleam/result.{then as try_} + +pub type Literal { + Integer + String +} + +pub type Exp { + Var(String) + App(Exp, Exp) + Abs(String, Exp) + Let(String, Exp, Exp) + Lit(Literal) +} + +pub type Type { + TInt + TString + Unbound(Int) + Fn(Type,Type) + TErr(String) +} + +pub type Scheme = #(List(Int), Type) + +pub fn fresh(next) { + #(Unbound(next), next + 1) +} + +pub fn instantiate(scheme, next) { + todo +} + +pub fn mono(t) { + #([], t) +} + +pub fn generalise(env, t) { + todo +} + +pub fn unify(t1, t2, s) { + do_unify([#(t1, t2)], s) +} + +// s is a function from var -> t +pub fn do_unify(constraints, s) { + // Have to try and substitute at every point because new substitutions can come into existance + case constraints { + [] -> Ok(s) + [#(Unbound(i), Unbound(j)), ..constraints] -> do_unify(constraints, s) + [#(Unbound(i), t1), ..constraints] | [#(t1, Unbound(i)), ..constraints] -> case map.get(s, i) { + Ok(t2) -> do_unify([#(t1, t2),..constraints], s) + Error(Nil) -> do_unify(constraints, map.insert(s, i, t1)) + } + [#(Fn(a1, r1), Fn(a2, r2)), ..cs] -> do_unify([#(a1, a2), #(r1, r2), ..cs], s) + _ -> Error(Nil) + } +} + + + +pub type Run { + Done(#(map.Map(Int, Type), Int, #(List(Int), Type))) + Continue(#(map.Map(Int, Type), Int, #(List(Int), Type)), fn(#(map.Map(Int, Type), Int, #(List(Int), Type))) -> Run) +} + +// J gi +// In exercise a type can be type err +// If we ignore unification with error +// let a = 1(2) +// let b = a +// let c = a +// +// f(x) +// f String -> Int +// x Error +// Int +// unify(string -> int, fn(err -> beta)) +// int +// I think there is a version of next where we track id -> it replaces path +// incremental id and offset id are not the same thing at all. + +// Follow id of node -> need free and and types in scope + +// let's do j with effects and follow BUT the id's are NOT unique i.e. the types depend on the environment. +// let's try global inference and see if it's faster +pub fn step(env, exp, sub, next, path, k) { + case exp { + Var(x) -> { + let scheme = result.unwrap(get(env, x), #([], TErr("missing var"))) + let #(type_, next) = instantiate(scheme, next) + Continue(#(sub, next, #(path,type_)), k) + } + App(e1, e2) -> { + use #(sub1, next, #(_, t1)) <- step(env, e1, sub, next, [0,..path]) + use #(sub2, next, #(_, t2)) <- step(env, e2, sub1, next, [1,..path]) + let #(beta, next) = fresh(next) + // returns t error + let sub3 = case unify(t1, Fn(t2, beta), sub2) { + Ok(sub3) -> sub3 + // TODO record error + Error(_) -> sub + } + // let assert Ok(sub3) = + Continue(#(sub3, next, #(path,beta)), k) + } + Abs(x, e1) -> { + let #(beta, next) = fresh(next) + let env1 = extend(env, x, mono(beta)) + use #(sub1, next, #(_, t1)) <- step(env1, e1, sub, next, [0,..path]) + Continue(#(sub1, next, #(path,Fn(beta, t1))), k) + } + Let(x, e1, e2) -> { + use #(sub1, next, #(_, t1)) <- step(env, e1, sub, next, [0,..path]) + // generalise needs sub applied tot1 + let env1 = extend(env, x, generalise(env, t1)) + use #(sub2, next, #(_, t2)) <- step(env, e2, sub1, next, [1,..path]) + Continue(#(sub2, next, #(path,t2)), k) + } + Lit(Integer) -> Continue(#(sub, next, #(path,TInt)), k) + Lit(String) -> Continue(#(sub, next, #(path,TString)), k) + } + +} +pub fn loop(run) { + case run { + Done(r) -> r + Continue(r, k) -> { + io.debug(r) + loop(k(r)) + } + } +} + +pub fn j(env, exp, sub, next) { + loop(step(env, exp, sub, next, [], Done)) +} + +pub fn demo(items, k) { + case items { + [] -> k("done") + [g, ..rest] -> demo(rest, fn(x) { + // io.debug(g) + g + 1 + k(x) + }) + } +} + +pub fn demo2(items, k) { + case items { + [] -> k("done") + [g, ..rest] -> { + use x <- demo2(rest) + // io.debug(g) + g + 1 + k(x) + } + } +} + +// use twice makes reference to demo3, that blows the stack. Document this +// TODO plinth library +pub fn demo3(items, k) { + case items { + [] -> k("done") + [g, ..rest] -> { + use x <- demo3(rest) + use y <- demo3(rest) + + // io.debug(g) + g + 1 + k(x) + } + } +} +pub fn order_test() { + j(map.new(), App(Lit(Integer),Lit(String)), map.new(), 0) + |> io.debug + todo +} \ No newline at end of file diff --git a/eyg/test/eyg/analysis/typing_test.gleam b/eyg/test/eyg/analysis/typing_test.gleam index 7e52f2012..eaf41ca8c 100644 --- a/eyg/test/eyg/analysis/typing_test.gleam +++ b/eyg/test/eyg/analysis/typing_test.gleam @@ -1,14 +1,19 @@ +import gleam/io import gleam/map import gleam/set import gleam/setx import eygir/expression as e import eyg/analysis/typ.{ftv} as t +import eyg/analysis/jm/type_ import eyg/analysis/env import eyg/analysis/inference.{infer, type_of} // top level analysis import eyg/analysis/scheme.{Scheme} import eyg/analysis/unification import gleeunit/should +import eyg/incremental/store +import eyg/analysis/jm/infer as jm +import eyg/analysis/jm/type_ as jmt pub fn resolve(inf: inference.Infered, typ) { unification.resolve(inf.substitutions, typ) @@ -55,6 +60,34 @@ pub fn free_type_variables_test() { |> should.equal(set.from_list([t.Term(1), t.Term(2), t.Effect(3)])) } +fn jm(exp, type_, eff) { + let #(root, store) = store.load(store.empty(), exp) + + let sub = map.new() + let next = 0 + let env = map.new() + let source = store.source + let ref = root + let types = map.new() + + let k = fn(x){x} + let #(sub, _next, types) = jm.infer(sub, next, env, source, ref, type_, eff, types, k) + io.debug(sub |> map.to_list) + io.debug(types |> map.to_list) + io.debug("=-----") + case map.get(types, root) { + Ok(Ok(t)) -> Ok(jmt.resolve(t, sub)) + Ok(Error(reason)) -> Error(reason) + // DOes panic expression print message + Error(_) -> { + io.debug(root) + io.debug(source |> map.to_list) + io.debug(types |> map.to_list) + todo("no typr") + } + } +} + // Primitive pub fn binary_test() { let exp = e.Binary("hi") @@ -71,11 +104,13 @@ pub fn binary_test() { let sub = infer(env, exp, typ, eff) let assert t.Binary = resolve(sub, typ) let assert Ok(t.Binary) = type_of(sub, []) + let assert Ok(type_.String) = jm(exp, type_.Var(-1), type_.Empty) // incorrect type let typ = t.Integer let sub = infer(env, exp, typ, eff) let assert Error(_) = type_of(sub, []) + let assert Error(type_.Missing) = jm(exp, type_.Integer, type_.Empty) } pub fn integer_test() { @@ -138,6 +173,10 @@ pub fn primitive_list_test() { let eff = t.Closed let sub = infer(env, exp, typ, eff) let assert Ok(t.LinkedList(t.Binary)) = type_of(sub, []) + let assert Ok(type_.LinkedList(type_.Integer)) = jm(exp, type_.Var(-1), type_.Empty) + |> io.debug + // THere is an error missing and the principle is wrong + let assert Ok(t.Fun(t.LinkedList(t.Binary), t.Closed, t.LinkedList(t.Binary))) = type_of(sub, [0]) let assert Ok(t.LinkedList(t.Binary)) = type_of(sub, [1]) From 138bfde278a99578d59c5f877198ea18e543bfaf Mon Sep 17 00:00:00 2001 From: Peter Saxton Date: Fri, 21 Apr 2023 07:51:38 +0200 Subject: [PATCH 40/62] unificationfix --- eyg/src/eyg/analysis/jm/type_.gleam | 11 ++++++++--- eyg/src/eyg/analysis/jm/unify.gleam | 8 +++++--- eyg/src/eyg/incremental/store.gleam | 3 ++- eyg/test/eyg/analysis/typing_test.gleam | 2 +- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/eyg/src/eyg/analysis/jm/type_.gleam b/eyg/src/eyg/analysis/jm/type_.gleam index 3efd320d4..f1e9a7234 100644 --- a/eyg/src/eyg/analysis/jm/type_.gleam +++ b/eyg/src/eyg/analysis/jm/type_.gleam @@ -54,9 +54,14 @@ pub fn apply(s, type_) { pub fn resolve(t, s) { case t { - Var(a) -> - map.get(s, a) - |> result.unwrap(t) + // Var(a) -> + // map.get(s, a) + // |> result.unwrap(t) + Var(a) -> case map.get(s, a) { + // recursive resolve needed for non direct unification + Ok(u) -> resolve(u, s) + Error(Nil) -> t + } Fun(u, v, w) -> Fun(resolve(u, s), resolve(v, s), resolve(w, s)) String | Integer | Empty -> t LinkedList(element) -> LinkedList(resolve(element, s)) diff --git a/eyg/src/eyg/analysis/jm/unify.gleam b/eyg/src/eyg/analysis/jm/unify.gleam index 7e540bc02..49f8626f6 100644 --- a/eyg/src/eyg/analysis/jm/unify.gleam +++ b/eyg/src/eyg/analysis/jm/unify.gleam @@ -3,16 +3,18 @@ import gleam/map import eyg/analysis/jm/type_ as t pub fn unify(t1, t2, s) { + io.debug("????????????????") do_unify([#(t1, t2)], s) } - +// I dont think this is the same as described because we don't keep lookup to original i. // s is a function from var -> t fn do_unify(constraints, s) { + io.debug(constraints) // Have to try and substitute at every point because new substitutions can come into existance case constraints { [] -> Ok(s) - [#(t.Var(i), t.Var(infer)), ..constraints] -> do_unify(constraints, s) - [#(t.Var(i), t1), ..constraints] | [#(t1, t.Var(i)), ..constraints] -> case map.get(s, i) { + [#(t.Var(i), t.Var(j)), ..constraints] if i == j -> do_unify(constraints, s) + [#(t.Var(i), t1), ..constraints] | [#(t1, t.Var(i)), ..constraints] -> case map.get(s, i) |> io.debug { Ok(t2) -> do_unify([#(t1, t2),..constraints], s) Error(Nil) -> do_unify(constraints, map.insert(s, i, t1)) } diff --git a/eyg/src/eyg/incremental/store.gleam b/eyg/src/eyg/incremental/store.gleam index 5dcdde4ec..63255bffa 100644 --- a/eyg/src/eyg/incremental/store.gleam +++ b/eyg/src/eyg/incremental/store.gleam @@ -143,7 +143,8 @@ pub fn do_type(env, ref, store: Store) -> Result(_, _) { // however std will always be free // all of std and other projects should trivially remain. and without free variables // changing std if only extending types should have no changes in project - use #(t1, store): #(_, Store) <- result.then(do_type(env, value, store)) + use #(t1, store) <- result.then(do_type(env, value, store)) + let store: Store = store let scheme = unification.generalise(env.apply(store.substitutions, env), sub.apply(store.substitutions,t1)) // is this env.apply twice necessary let env = env.apply(store.substitutions, map.insert(env, x, scheme)) diff --git a/eyg/test/eyg/analysis/typing_test.gleam b/eyg/test/eyg/analysis/typing_test.gleam index eaf41ca8c..d4b1089eb 100644 --- a/eyg/test/eyg/analysis/typing_test.gleam +++ b/eyg/test/eyg/analysis/typing_test.gleam @@ -72,7 +72,7 @@ fn jm(exp, type_, eff) { let k = fn(x){x} let #(sub, _next, types) = jm.infer(sub, next, env, source, ref, type_, eff, types, k) - io.debug(sub |> map.to_list) + io.debug(#("sub", sub |> map.to_list)) io.debug(types |> map.to_list) io.debug("=-----") case map.get(types, root) { From 6f569d96107c5fc1a71883a163d8c821e1c31f66 Mon Sep 17 00:00:00 2001 From: Peter Saxton Date: Sat, 22 Apr 2023 10:35:34 +0200 Subject: [PATCH 41/62] gleam notes --- gleam.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 gleam.md diff --git a/gleam.md b/gleam.md new file mode 100644 index 000000000..c2363eb1b --- /dev/null +++ b/gleam.md @@ -0,0 +1,12 @@ +## Adding binary-size(a) to js backend. +This would be a very sensible addition as it stays in whole byte size subsections. +However it requires rewriting of sizing part of the code. +Currently the total offset is calculated at compile time and this would need to be a runtime thing + +Files needed for updates +``` + compiler-core/src/javascript/pattern.rs | 38 +++++++++++++++++++++++-- + compiler-core/src/javascript/tests/bit_strings.rs | 11 +++++++ + compiler-core/templates/prelude.js | 4 +++ + test/language/test/language_test.gleam | 10 +++++++ + ``` From 21e625318fe6c0c0527f14fd881d79a4ad0e8534 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 22 Apr 2023 11:31:47 +0200 Subject: [PATCH 42/62] crash on recursion --- eyg/src/atelier/app.gleam | 21 +++++++ eyg/src/eyg/analysis/jm/infer.gleam | 14 ++--- eyg/src/eyg/analysis/jm/unify.gleam | 86 +++++++++++++++++++++++------ 3 files changed, 95 insertions(+), 26 deletions(-) diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index 95ed5f59f..17a269b7e 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -17,6 +17,8 @@ import eyg/analysis/inference import eyg/runtime/standard import eyg/incremental/store import plinth/javascript/map as mutable_map +import eyg/analysis/jm/infer as jm +import eyg/analysis/jm/type_ as jmt pub type WorkSpace { @@ -108,6 +110,25 @@ pub fn init(source) { t, )) + + let _ = { + let sub = map.new() + let next = 0 + let env = map.new() + let source = s.source + let ref = root + let type_ = jmt.Var(-1) + let eff = jmt.Empty + let types = map.new() + let k = fn(x){x} + let start = pnow() + let #(sub, _next, typesjm) = jm.infer(sub, next, env, source, ref, type_, eff, types, k) + io.debug(#( + "typing jm took ms:", + pnow() - start, + map.size(typesjm), + )) + } // let start = pnow() // let assert Ok(c) = store.cursor(s, root, path) // io.debug(#("building store.cursor took ms:", pnow() - start)) diff --git a/eyg/src/eyg/analysis/jm/infer.gleam b/eyg/src/eyg/analysis/jm/infer.gleam index ed0e0b719..32b81e474 100644 --- a/eyg/src/eyg/analysis/jm/infer.gleam +++ b/eyg/src/eyg/analysis/jm/infer.gleam @@ -59,9 +59,8 @@ fn extend(env, label, scheme) { } pub fn unify_at(type_, found, sub, next, types, ref) { - io.debug(#(type_, found)) - case unify.unify(type_, found, sub) { - Ok(s) -> #(s, next, map.insert(types, ref, Ok(type_))) + case unify.unify(type_, found, sub, next) { + Ok(#(s, next)) -> #(s, next, map.insert(types, ref, Ok(type_))) Error(_) -> #(sub, next, map.insert(types, ref, Error(t.Missing))) } } @@ -83,11 +82,9 @@ pub fn infer(sub, next, env, source, ref, type_, eff, types, k) { } } e.Call(e1, e2) -> { - io.debug(#(type_, e1, e2)) // can't error let types = map.insert(types, ref, Ok(type_)) let #(arg, next) = t.fresh(next) - io.debug(arg) use #(sub, next, types) <- infer(sub, next, env, source, e1, t.Fun(arg, eff, type_), eff, types) use #(sub, next, types) <- infer(sub, next, env, source, e2, arg, eff, types) k(#(sub, next, types)) @@ -126,7 +123,6 @@ fn primitive(exp, next) { e.Tail -> t.tail(next) e.Cons -> t.cons(next) - |> io.debug e.Vacant(_comment) -> t.fresh(next) // Record @@ -145,8 +141,10 @@ fn primitive(exp, next) { e.Handle(label) -> t.handle(label, next) - // e.Builtin(identifier) - _ -> todo("pull from old inference") + // TODO use real builtins + e.Builtin(identifier) -> t.fresh(next) + // _ -> todo("pull from old inference") + } } // errors should be both wrong f and wrong arg diff --git a/eyg/src/eyg/analysis/jm/unify.gleam b/eyg/src/eyg/analysis/jm/unify.gleam index 49f8626f6..2c1b08966 100644 --- a/eyg/src/eyg/analysis/jm/unify.gleam +++ b/eyg/src/eyg/analysis/jm/unify.gleam @@ -1,30 +1,80 @@ import gleam/io import gleam/map +import gleam/result import eyg/analysis/jm/type_ as t -pub fn unify(t1, t2, s) { - io.debug("????????????????") - do_unify([#(t1, t2)], s) +pub fn unify(t1, t2, s, next) { + do_unify([#(t1, t2)], s, next) } // I dont think this is the same as described because we don't keep lookup to original i. // s is a function from var -> t -fn do_unify(constraints, s) { - io.debug(constraints) +fn do_unify(constraints, s, next) { // Have to try and substitute at every point because new substitutions can come into existance case constraints { - [] -> Ok(s) - [#(t.Var(i), t.Var(j)), ..constraints] if i == j -> do_unify(constraints, s) - [#(t.Var(i), t1), ..constraints] | [#(t1, t.Var(i)), ..constraints] -> case map.get(s, i) |> io.debug { - Ok(t2) -> do_unify([#(t1, t2),..constraints], s) - Error(Nil) -> do_unify(constraints, map.insert(s, i, t1)) + [] -> Ok(#(s, next)) + [#(t.Var(i), t.Var(j)), ..constraints] if i == j -> do_unify(constraints, s, next) + // TODO varbind occurs in + [#(t.Var(i), t1), ..constraints] | [#(t1, t.Var(i)), ..constraints] -> case map.get(s, i) { + Ok(t2) -> do_unify([#(t1, t2),..constraints], s, next) + Error(Nil) -> do_unify(constraints, map.insert(s, i, t1), next) } - [#(t.Fun(a1, e1, r1), t.Fun(a2, e2, r2)), ..cs] -> do_unify([#(a1, a2), #(e1, e2), #(r1, r2), ..cs], s) - [#(t.LinkedList(i1), t.LinkedList(i2)), ..cs] -> do_unify([#(i1, i2), ..cs], s) - _ -> { - io.debug("I think this ods it") - io.debug(constraints) - todo("I need to handle records") - Error(Nil) - } + [#(t.Fun(a1, e1, r1), t.Fun(a2, e2, r2)), ..cs] -> do_unify([#(a1, a2), #(e1, e2), #(r1, r2), ..cs], s, next) + [#(t.Integer, t.Integer), ..cs] -> do_unify(cs, s, next) + [#(t.String, t.String), ..cs] -> do_unify(cs, s, next) + [#(t.LinkedList(i1), t.LinkedList(i2)), ..cs] -> do_unify([#(i1, i2), ..cs], s, next) + [#(t.Record(r1), t.Record(r2)), ..cs] -> do_unify([#(r1, r2), ..cs], s, next) + [#(t.Union(r1), t.Union(r2)), ..cs] -> do_unify([#(r1, r2), ..cs], s, next) + [#(t.Empty, t.Empty), ..cs] -> do_unify(cs, s, next) + [#(t.RowExtend(label1, value1, tail1), t.RowExtend(_,_,_) as row2), ..cs] -> { + use #(value2, tail2, s, next) <- result.then(rewrite_row(label1, row2, s, next)) + do_unify([#(value1, value2), #(tail1, tail2), ..cs], s, next) + } + [#(t.EffectExtend(label1, #(lift1, reply1), tail1), t.EffectExtend(_,_,_) as row2), ..cs] -> { + use #(lift2, reply2, tail2, s, next) <- result.then(rewrite_effect(label1, row2, s, next)) + do_unify([#(lift1, lift2), #(reply1, reply2), #(tail1, tail2), ..cs], s, next) + } + _ -> Error(Nil) + } +} + +// alg J with rows is interesting +// I think fsharp impl has bug of not accepting open rows at first pass + +fn rewrite_row(new_label, row, s, next) { + case row { + t.Empty -> Error(Nil) + t.RowExtend(label, value, tail) if label == new_label -> + Ok(#(value, tail, s, next)) + t.Var(a) -> { + let #(value, next) = t.fresh(next) + let #(tail, next) = t.fresh(next) + let s = map.insert(s, a, t.RowExtend(new_label, value, tail)) + Ok(#(value, tail, s, next)) + } + t.RowExtend(label, value, tail) -> { + use #(value_new, tail_new, s, next) <- result.then(rewrite_row(new_label, tail, s, next)) + Ok(#(value_new, t.RowExtend(label, value, tail_new), s, next)) + } + _ -> Error(Nil) + } +} + +fn rewrite_effect(new_label, effect, s, next) { + case effect { + t.Empty -> Error(Nil) + t.EffectExtend(label, #(lift, reply), tail) if label == new_label -> + Ok(#(lift, reply, tail, s, next)) + t.Var(a) -> { + let #(lift, next) = t.fresh(next) + let #(reply, next) = t.fresh(next) + let #(tail, next) = t.fresh(next) + let s = map.insert(s, a, t.EffectExtend(new_label, #(lift, reply), tail)) + Ok(#(lift, reply, tail, s, next)) + } + t.EffectExtend(label, field, tail) -> { + use #(lift_new, reply_new, tail_new, s, next) <- result.then(rewrite_effect(new_label, tail, s, next)) + Ok(#(lift_new, reply_new, t.EffectExtend(label, field, tail_new), s, next)) + } + _ -> Error(Nil) } } \ No newline at end of file From 82b9f5e30feaff462b8820140ce4d77f70a4b859 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 22 Apr 2023 12:00:39 +0200 Subject: [PATCH 43/62] fix recursion to be tail recursive --- eyg/src/atelier/app.gleam | 24 ++++++++++- eyg/src/eyg/analysis/jm/infer.gleam | 53 ++++++++++++++++--------- eyg/test/eyg/analysis/typing_test.gleam | 3 +- 3 files changed, 58 insertions(+), 22 deletions(-) diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index 17a269b7e..3960a3bd4 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -120,14 +120,34 @@ pub fn init(source) { let type_ = jmt.Var(-1) let eff = jmt.Empty let types = map.new() - let k = fn(x){x} let start = pnow() - let #(sub, _next, typesjm) = jm.infer(sub, next, env, source, ref, type_, eff, types, k) + let #(sub, _next, typesjm) = jm.infer(sub, next, env, source, ref, type_, eff, types) io.debug(#( "typing jm took ms:", pnow() - start, map.size(typesjm), )) + let assert Ok(Ok(t)) = map.get(typesjm, 100) + io.debug(jmt.resolve(t, sub)) + let assert Ok(Ok(t)) = map.get(typesjm, 0) + io.debug(jmt.resolve(t, sub)) + let assert Ok(Ok(t)) = map.get(typesjm, 1) + io.debug(jmt.resolve(t, sub)) + let assert Ok(Ok(t)) = map.get(typesjm, 2) + io.debug(jmt.resolve(t, sub)) + + + list.map(map.to_list(typesjm), fn(r) { + let #(id, r) = r + case r { + Ok(_) -> Nil + Error(reason) -> { + io.debug(reason) + Nil + } + + } + }) } // let start = pnow() // let assert Ok(c) = store.cursor(s, root, path) diff --git a/eyg/src/eyg/analysis/jm/infer.gleam b/eyg/src/eyg/analysis/jm/infer.gleam index 32b81e474..a0f94d853 100644 --- a/eyg/src/eyg/analysis/jm/infer.gleam +++ b/eyg/src/eyg/analysis/jm/infer.gleam @@ -10,12 +10,12 @@ fn mono(type_) { #([], type_) } -pub fn scheme_ftv(scheme) { +fn scheme_ftv(scheme) { let #(forall, typ) = scheme set.drop(t.ftv(typ), forall) } -pub fn scheme_apply(sub, scheme) { +fn scheme_apply(sub, scheme) { let #(forall, typ) = scheme #(forall, t.apply(map.drop(sub, forall), typ)) } @@ -25,7 +25,7 @@ type TypeEnv = // TypeEnv -pub fn env_ftv(env: TypeEnv) { +fn env_ftv(env: TypeEnv) { map.fold( env, set.new(), @@ -33,7 +33,7 @@ pub fn env_ftv(env: TypeEnv) { ) } -pub fn env_apply(sub, env) { +fn env_apply(sub, env) { map.map_values(env, fn(_k, scheme) { scheme_apply(sub, scheme) }) } @@ -58,26 +58,43 @@ fn extend(env, label, scheme) { map.insert(env, label, scheme) } -pub fn unify_at(type_, found, sub, next, types, ref) { +fn unify_at(type_, found, sub, next, types, ref) { case unify.unify(type_, found, sub, next) { Ok(#(s, next)) -> #(s, next, map.insert(types, ref, Ok(type_))) Error(_) -> #(sub, next, map.insert(types, ref, Error(t.Missing))) } } -pub fn infer(sub, next, env, source, ref, type_, eff, types, k) { +type State = #(map.Map(Int, t.Type), Int, map.Map(Int, Result(t.Type, t.Reason))) +type Run { + Cont(State, fn(State) -> Run) + Done(State) +} + +pub fn infer(sub, next, env, source, ref, type_, eff, types) { + loop(step(sub, next, env, source, ref, type_, eff, types, Done)) +} + +fn loop(run) { + case run { + Done(state) -> state + Cont(state, k) -> loop(k(state)) + } +} + +fn step(sub, next, env, source, ref, type_, eff, types, k) { case map.get(source, ref) { - Error(Nil) -> k(#(sub, next, types)) + Error(Nil) -> Cont(#(sub, next, types), k) Ok(exp) -> case exp { e.Var(x) -> { case map.get(env, x) { Ok(scheme) -> { let #(found, next) = instantiate(scheme, next) - k(unify_at(type_, found, sub, next, types, ref)) + Cont(unify_at(type_, found, sub, next, types, ref), k) } Error(Nil) -> { let types = map.insert(types, ref, todo) - k(#(sub, next, types)) + Cont(#(sub, next, types), k) } } } @@ -85,9 +102,9 @@ pub fn infer(sub, next, env, source, ref, type_, eff, types, k) { // can't error let types = map.insert(types, ref, Ok(type_)) let #(arg, next) = t.fresh(next) - use #(sub, next, types) <- infer(sub, next, env, source, e1, t.Fun(arg, eff, type_), eff, types) - use #(sub, next, types) <- infer(sub, next, env, source, e2, arg, eff, types) - k(#(sub, next, types)) + use #(sub, next, types) <- step(sub, next, env, source, e1, t.Fun(arg, eff, type_), eff, types) + use #(sub, next, types) <- step(sub, next, env, source, e2, arg, eff, types) + Cont(#(sub, next, types), k) } e.Fn(x, e1) -> { let #(arg, next) = t.fresh(next) @@ -95,21 +112,21 @@ pub fn infer(sub, next, env, source, ref, type_, eff, types, k) { let #(ret, next) = t.fresh(next) let #(sub, next, types) = unify_at(type_, t.Fun(arg, eff, ret), sub, next, types, ref) let env = extend(env, x, mono(arg)) - use #(sub, next, types) <- infer(sub, next, env, source, e1, ret, eff, types) - k(#(sub, next, types)) + use #(sub, next, types) <- step(sub, next, env, source, e1, ret, eff, types) + Cont(#(sub, next, types), k) } e.Let(x, e1, e2) -> { // can't error let types = map.insert(types, ref, Ok(type_)) let #(inner, next) = t.fresh(next) - use #(sub, next, types) <- infer(sub, next, env, source, e1, inner, eff, types) + use #(sub, next, types) <- step(sub, next, env, source, e1, inner, eff, types) let env = extend(env, x, generalise(sub, env, inner)) - use #(sub, next, types) <- infer(sub, next, env, source, e2, type_, eff, types) - k(#(sub, next, types)) + use #(sub, next, types) <- step(sub, next, env, source, e2, type_, eff, types) + Cont(#(sub, next, types), k) } literal -> { let #(found, next) = primitive(literal, next) - k(unify_at(type_, found, sub, next, types, ref)) + Cont(unify_at(type_, found, sub, next, types, ref), k) } } } diff --git a/eyg/test/eyg/analysis/typing_test.gleam b/eyg/test/eyg/analysis/typing_test.gleam index d4b1089eb..6ca8cd93b 100644 --- a/eyg/test/eyg/analysis/typing_test.gleam +++ b/eyg/test/eyg/analysis/typing_test.gleam @@ -70,8 +70,7 @@ fn jm(exp, type_, eff) { let ref = root let types = map.new() - let k = fn(x){x} - let #(sub, _next, types) = jm.infer(sub, next, env, source, ref, type_, eff, types, k) + let #(sub, _next, types) = jm.infer(sub, next, env, source, ref, type_, eff, types) io.debug(#("sub", sub |> map.to_list)) io.debug(types |> map.to_list) io.debug("=-----") From 35d93d1cb1f393cda746c0763b5eeb8d7a0701e2 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 22 Apr 2023 13:11:50 +0200 Subject: [PATCH 44/62] start notes --- eyg/test/eyg/analysis/typing_test.gleam | 3 -- notes/README.md | 41 +++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 notes/README.md diff --git a/eyg/test/eyg/analysis/typing_test.gleam b/eyg/test/eyg/analysis/typing_test.gleam index 6ca8cd93b..cb33b7458 100644 --- a/eyg/test/eyg/analysis/typing_test.gleam +++ b/eyg/test/eyg/analysis/typing_test.gleam @@ -71,9 +71,6 @@ fn jm(exp, type_, eff) { let types = map.new() let #(sub, _next, types) = jm.infer(sub, next, env, source, ref, type_, eff, types) - io.debug(#("sub", sub |> map.to_list)) - io.debug(types |> map.to_list) - io.debug("=-----") case map.get(types, root) { Ok(Ok(t)) -> Ok(jmt.resolve(t, sub)) Ok(Error(reason)) -> Error(reason) diff --git a/notes/README.md b/notes/README.md new file mode 100644 index 000000000..930ce664a --- /dev/null +++ b/notes/README.md @@ -0,0 +1,41 @@ +# Notes + +## Type Inference + + +### Judgements + +### Algorithms + +Simple Lambda calculus is easily type checked. +Most of the below algorithms handle extension of at least let polymorphism + + +#### Algorithm W +Explained in Hindley Milner Paper + +Uses composition of substitutions + +#### Algorithm J +Explained in Hindley Milner Paper + +Uses a single global substitution. The global substitution doesn't have to + +### Algorithm M +Adds expected type as argument to algorithm. +This get's results in different orders + +#### Separate constraint collection from solving + +Does Wand fit into this? + +## Language extensions + +### Recursive functions +#### Fix point +Easy to add is just a function with the required type. +This type is not constructable within the lambda calculus + +#### Let Rec + +Every Let could test to see if let rec is used. From 77bb52989b862c74155599e831677fefaa72ecab Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 22 Apr 2023 13:28:58 +0200 Subject: [PATCH 45/62] extract env and scheme --- eyg/src/eyg/analysis/jm/env.gleam | 17 ++++++++++ eyg/src/eyg/analysis/jm/infer.gleam | 49 +++++----------------------- eyg/src/eyg/analysis/jm/scheme.gleam | 15 +++++++++ eyg/src/eyg/analysis/jm/type_.gleam | 3 ++ notes/README.md | 10 ++++++ 5 files changed, 53 insertions(+), 41 deletions(-) create mode 100644 eyg/src/eyg/analysis/jm/env.gleam create mode 100644 eyg/src/eyg/analysis/jm/scheme.gleam diff --git a/eyg/src/eyg/analysis/jm/env.gleam b/eyg/src/eyg/analysis/jm/env.gleam new file mode 100644 index 000000000..321103836 --- /dev/null +++ b/eyg/src/eyg/analysis/jm/env.gleam @@ -0,0 +1,17 @@ + +import gleam/map +import gleam/set +import eyg/analysis/jm/type_ as t +import eyg/analysis/jm/scheme + +pub type Env = map.Map(String, scheme.Scheme) + +fn ftv_for_key(state, _k, scheme) { set.union(state, scheme.ftv(scheme)) } + +pub fn ftv(env: Env) { + map.fold(env, set.new(), ftv_for_key) +} + +pub fn apply(sub, env) { + map.map_values(env, fn(_k, scheme) { scheme.apply(sub, scheme) }) +} \ No newline at end of file diff --git a/eyg/src/eyg/analysis/jm/infer.gleam b/eyg/src/eyg/analysis/jm/infer.gleam index a0f94d853..b199547fb 100644 --- a/eyg/src/eyg/analysis/jm/infer.gleam +++ b/eyg/src/eyg/analysis/jm/infer.gleam @@ -4,43 +4,19 @@ import gleam/map import gleam/set import eyg/incremental/source as e import eyg/analysis/jm/type_ as t +import eyg/analysis/jm/env import eyg/analysis/jm/unify fn mono(type_) { #([], type_) } -fn scheme_ftv(scheme) { - let #(forall, typ) = scheme - set.drop(t.ftv(typ), forall) -} - -fn scheme_apply(sub, scheme) { - let #(forall, typ) = scheme - #(forall, t.apply(map.drop(sub, forall), typ)) -} - -type TypeEnv = - map.Map(String, #(List(Int), t.Type)) - - -// TypeEnv -fn env_ftv(env: TypeEnv) { - map.fold( - env, - set.new(), - fn(state, _k, scheme) { set.union(state, scheme_ftv(scheme)) }, - ) -} - -fn env_apply(sub, env) { - map.map_values(env, fn(_k, scheme) { scheme_apply(sub, scheme) }) -} - +// reference substitution env and type. +// causes circular dependencies to move to any other file fn generalise(sub, env, t) { - let env = env_apply(sub, env) + let env = env.apply(sub, env) let t = t.apply(sub, t) - let forall = set.drop(t.ftv(t), set.to_list(env_ftv(env))) + let forall = set.drop(t.ftv(t), set.to_list(env.ftv(env))) #(set.to_list(forall), t) } @@ -56,7 +32,7 @@ fn instantiate(scheme, next) { fn extend(env, label, scheme) { map.insert(env, label, scheme) - } +} fn unify_at(type_, found, sub, next, types, ref) { case unify.unify(type_, found, sub, next) { @@ -65,7 +41,8 @@ fn unify_at(type_, found, sub, next, types, ref) { } } -type State = #(map.Map(Int, t.Type), Int, map.Map(Int, Result(t.Type, t.Reason))) +type State = #(t.Substitutions, Int, map.Map(Int, Result(t.Type, t.Reason))) + type Run { Cont(State, fn(State) -> Run) Done(State) @@ -167,13 +144,3 @@ fn primitive(exp, next) { // errors should be both wrong f and wrong arg -// Can have fast inference if existing before -// reuse next and t maybe -// returning a type is good but I need to return a list of errors at least -// can't unify binary to an error - -// we've got J with early return as an option -// need a building state for speed. -// Test infer not this one -// Test jm -// Write up wand \ No newline at end of file diff --git a/eyg/src/eyg/analysis/jm/scheme.gleam b/eyg/src/eyg/analysis/jm/scheme.gleam new file mode 100644 index 000000000..6833c84e5 --- /dev/null +++ b/eyg/src/eyg/analysis/jm/scheme.gleam @@ -0,0 +1,15 @@ +import gleam/map +import gleam/set +import eyg/analysis/jm/type_ as t + +pub type Scheme = #(List(Int), t.Type) + +pub fn ftv(scheme) { + let #(forall, typ) = scheme + set.drop(t.ftv(typ), forall) +} + +pub fn apply(sub, scheme) { + let #(forall, typ) = scheme + #(forall, t.apply(map.drop(sub, forall), typ)) +} \ No newline at end of file diff --git a/eyg/src/eyg/analysis/jm/type_.gleam b/eyg/src/eyg/analysis/jm/type_.gleam index f1e9a7234..23d0fd85b 100644 --- a/eyg/src/eyg/analysis/jm/type_.gleam +++ b/eyg/src/eyg/analysis/jm/type_.gleam @@ -17,6 +17,9 @@ pub type Type { EffectExtend(String, #(Type, Type), Type) } + +pub type Substitutions = map.Map(Int, Type) + pub type Reason { Missing } diff --git a/notes/README.md b/notes/README.md index 930ce664a..3d5731075 100644 --- a/notes/README.md +++ b/notes/README.md @@ -39,3 +39,13 @@ This type is not constructable within the lambda calculus #### Let Rec Every Let could test to see if let rec is used. + +## Incremental type checking + +J with early return is an option + +Unison hashes only terms without Free variables +There is the other paper that does both but building up the whole tree is tricky because the env at any given point depends on the tree so can't be cached through modifications + +### Differential Datalog + From 4220b6483516a7efa7a3fd07cbb1806a0025e22a Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 22 Apr 2023 13:44:19 +0200 Subject: [PATCH 46/62] standard error --- eyg/src/eyg/analysis/jm/error.gleam | 9 +++++++++ eyg/src/eyg/analysis/jm/infer.gleam | 7 ++++--- eyg/src/eyg/analysis/jm/type_.gleam | 5 ----- eyg/src/eyg/analysis/jm/unify.gleam | 11 ++++++----- eyg/test/eyg/analysis/typing_test.gleam | 3 ++- 5 files changed, 21 insertions(+), 14 deletions(-) create mode 100644 eyg/src/eyg/analysis/jm/error.gleam diff --git a/eyg/src/eyg/analysis/jm/error.gleam b/eyg/src/eyg/analysis/jm/error.gleam new file mode 100644 index 000000000..a0d155146 --- /dev/null +++ b/eyg/src/eyg/analysis/jm/error.gleam @@ -0,0 +1,9 @@ +import eyg/analysis/jm/type_ as t + +pub type Reason { + MissingVariable(String) + // unification + TypeMismatch(t.Type, t.Type) + RowMismatch(String) + InvalidTail(t.Type) +} \ No newline at end of file diff --git a/eyg/src/eyg/analysis/jm/infer.gleam b/eyg/src/eyg/analysis/jm/infer.gleam index b199547fb..9b7e2969f 100644 --- a/eyg/src/eyg/analysis/jm/infer.gleam +++ b/eyg/src/eyg/analysis/jm/infer.gleam @@ -3,6 +3,7 @@ import gleam/list import gleam/map import gleam/set import eyg/incremental/source as e +import eyg/analysis/jm/error import eyg/analysis/jm/type_ as t import eyg/analysis/jm/env import eyg/analysis/jm/unify @@ -37,11 +38,11 @@ fn extend(env, label, scheme) { fn unify_at(type_, found, sub, next, types, ref) { case unify.unify(type_, found, sub, next) { Ok(#(s, next)) -> #(s, next, map.insert(types, ref, Ok(type_))) - Error(_) -> #(sub, next, map.insert(types, ref, Error(t.Missing))) + Error(reason) -> #(sub, next, map.insert(types, ref, Error(#(reason, type_, found)))) } } -type State = #(t.Substitutions, Int, map.Map(Int, Result(t.Type, t.Reason))) +type State = #(t.Substitutions, Int, map.Map(Int, Result(t.Type, #(error.Reason, t.Type, t.Type)))) type Run { Cont(State, fn(State) -> Run) @@ -70,7 +71,7 @@ fn step(sub, next, env, source, ref, type_, eff, types, k) { Cont(unify_at(type_, found, sub, next, types, ref), k) } Error(Nil) -> { - let types = map.insert(types, ref, todo) + let types = map.insert(types, ref, Error(#(error.MissingVariable(x), type_, t.Var(-100)))) Cont(#(sub, next, types), k) } } diff --git a/eyg/src/eyg/analysis/jm/type_.gleam b/eyg/src/eyg/analysis/jm/type_.gleam index 23d0fd85b..dc3140e8d 100644 --- a/eyg/src/eyg/analysis/jm/type_.gleam +++ b/eyg/src/eyg/analysis/jm/type_.gleam @@ -17,13 +17,8 @@ pub type Type { EffectExtend(String, #(Type, Type), Type) } - pub type Substitutions = map.Map(Int, Type) -pub type Reason { - Missing -} - pub fn ftv(type_) { case type_ { Var(a) -> setx.singleton(a) diff --git a/eyg/src/eyg/analysis/jm/unify.gleam b/eyg/src/eyg/analysis/jm/unify.gleam index 2c1b08966..4906a5971 100644 --- a/eyg/src/eyg/analysis/jm/unify.gleam +++ b/eyg/src/eyg/analysis/jm/unify.gleam @@ -2,6 +2,7 @@ import gleam/io import gleam/map import gleam/result import eyg/analysis/jm/type_ as t +import eyg/analysis/jm/error pub fn unify(t1, t2, s, next) { do_unify([#(t1, t2)], s, next) @@ -33,7 +34,7 @@ fn do_unify(constraints, s, next) { use #(lift2, reply2, tail2, s, next) <- result.then(rewrite_effect(label1, row2, s, next)) do_unify([#(lift1, lift2), #(reply1, reply2), #(tail1, tail2), ..cs], s, next) } - _ -> Error(Nil) + [#(t1, t2), ..] -> Error(error.TypeMismatch(t1, t2)) } } @@ -42,7 +43,7 @@ fn do_unify(constraints, s, next) { fn rewrite_row(new_label, row, s, next) { case row { - t.Empty -> Error(Nil) + t.Empty -> Error(error.RowMismatch(new_label)) t.RowExtend(label, value, tail) if label == new_label -> Ok(#(value, tail, s, next)) t.Var(a) -> { @@ -55,13 +56,13 @@ fn rewrite_row(new_label, row, s, next) { use #(value_new, tail_new, s, next) <- result.then(rewrite_row(new_label, tail, s, next)) Ok(#(value_new, t.RowExtend(label, value, tail_new), s, next)) } - _ -> Error(Nil) + _ -> Error(error.InvalidTail(row)) } } fn rewrite_effect(new_label, effect, s, next) { case effect { - t.Empty -> Error(Nil) + t.Empty -> Error(error.RowMismatch(new_label)) t.EffectExtend(label, #(lift, reply), tail) if label == new_label -> Ok(#(lift, reply, tail, s, next)) t.Var(a) -> { @@ -75,6 +76,6 @@ fn rewrite_effect(new_label, effect, s, next) { use #(lift_new, reply_new, tail_new, s, next) <- result.then(rewrite_effect(new_label, tail, s, next)) Ok(#(lift_new, reply_new, t.EffectExtend(label, field, tail_new), s, next)) } - _ -> Error(Nil) + _ -> Error(error.InvalidTail(effect)) } } \ No newline at end of file diff --git a/eyg/test/eyg/analysis/typing_test.gleam b/eyg/test/eyg/analysis/typing_test.gleam index cb33b7458..37c551553 100644 --- a/eyg/test/eyg/analysis/typing_test.gleam +++ b/eyg/test/eyg/analysis/typing_test.gleam @@ -14,6 +14,7 @@ import gleeunit/should import eyg/incremental/store import eyg/analysis/jm/infer as jm import eyg/analysis/jm/type_ as jmt +import eyg/analysis/jm/error as jm_error pub fn resolve(inf: inference.Infered, typ) { unification.resolve(inf.substitutions, typ) @@ -106,7 +107,7 @@ pub fn binary_test() { let typ = t.Integer let sub = infer(env, exp, typ, eff) let assert Error(_) = type_of(sub, []) - let assert Error(type_.Missing) = jm(exp, type_.Integer, type_.Empty) + let assert Error(#(jm_error.TypeMismatch(jmt.Integer, jmt.String), jmt.Integer, jmt.String)) = jm(exp, type_.Integer, type_.Empty) } pub fn integer_test() { From 577f0682f9303700ca84d30edbc7a92a1bd36cc7 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 22 Apr 2023 14:03:02 +0200 Subject: [PATCH 47/62] extract tree and incremental inference --- eyg/src/atelier/app.gleam | 18 +++- eyg/src/eyg/analysis/jm/incremental.gleam | 98 +++++++++++++++++++ eyg/src/eyg/analysis/jm/infer.gleam | 107 ++------------------- eyg/src/eyg/analysis/jm/tree.gleam | 112 ++++++++++++++++++++++ eyg/test/eyg/analysis/typing_test.gleam | 2 +- 5 files changed, 235 insertions(+), 102 deletions(-) create mode 100644 eyg/src/eyg/analysis/jm/incremental.gleam create mode 100644 eyg/src/eyg/analysis/jm/tree.gleam diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index 3960a3bd4..69bab02de 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -17,7 +17,8 @@ import eyg/analysis/inference import eyg/runtime/standard import eyg/incremental/store import plinth/javascript/map as mutable_map -import eyg/analysis/jm/infer as jm +import eyg/analysis/jm/incremental as jm +import eyg/analysis/jm/tree as jm_tree import eyg/analysis/jm/type_ as jmt @@ -115,13 +116,13 @@ pub fn init(source) { let sub = map.new() let next = 0 let env = map.new() - let source = s.source + let source_map = s.source let ref = root let type_ = jmt.Var(-1) let eff = jmt.Empty let types = map.new() let start = pnow() - let #(sub, _next, typesjm) = jm.infer(sub, next, env, source, ref, type_, eff, types) + let #(sub, _next, typesjm) = jm.infer(sub, next, env, source_map, ref, type_, eff, types) io.debug(#( "typing jm took ms:", pnow() - start, @@ -148,6 +149,17 @@ pub fn init(source) { } }) + + // new map of types because non function not generic. + // TODO should this be the case add to gleam explainers + let types = map.new() + let start = pnow() + let #(sub, _next, typesjm) = jm_tree.infer(sub, next, env, source, [], type_, eff, types) + io.debug(#( + "typing jm took ms:", + pnow() - start, + map.size(typesjm), + )) } // let start = pnow() // let assert Ok(c) = store.cursor(s, root, path) diff --git a/eyg/src/eyg/analysis/jm/incremental.gleam b/eyg/src/eyg/analysis/jm/incremental.gleam new file mode 100644 index 000000000..476bc7a66 --- /dev/null +++ b/eyg/src/eyg/analysis/jm/incremental.gleam @@ -0,0 +1,98 @@ +import gleam/io +import gleam/list +import gleam/map +import gleam/set +import eyg/incremental/source as e +import eyg/analysis/jm/error +import eyg/analysis/jm/type_ as t +import eyg/analysis/jm/env +import eyg/analysis/jm/unify +import eyg/analysis/jm/infer.{Cont, loop, instantiate, generalise, unify_at, extend, mono, Done} + +pub fn infer(sub, next, env, source, ref, type_, eff, types) { + loop(step(sub, next, env, source, ref, type_, eff, types, Done)) +} + +fn step(sub, next, env, source, ref, type_, eff, types, k) { + case map.get(source, ref) { + Error(Nil) -> Cont(#(sub, next, types), k) + Ok(exp) -> case exp { + e.Var(x) -> { + case map.get(env, x) { + Ok(scheme) -> { + let #(found, next) = instantiate(scheme, next) + Cont(unify_at(type_, found, sub, next, types, ref), k) + } + Error(Nil) -> { + let types = map.insert(types, ref, Error(#(error.MissingVariable(x), type_, t.Var(-100)))) + Cont(#(sub, next, types), k) + } + } + } + e.Call(e1, e2) -> { + // can't error + let types = map.insert(types, ref, Ok(type_)) + let #(arg, next) = t.fresh(next) + use #(sub, next, types) <- step(sub, next, env, source, e1, t.Fun(arg, eff, type_), eff, types) + use #(sub, next, types) <- step(sub, next, env, source, e2, arg, eff, types) + Cont(#(sub, next, types), k) + } + e.Fn(x, e1) -> { + let #(arg, next) = t.fresh(next) + let #(eff, next) = t.fresh(next) + let #(ret, next) = t.fresh(next) + let #(sub, next, types) = unify_at(type_, t.Fun(arg, eff, ret), sub, next, types, ref) + let env = extend(env, x, mono(arg)) + use #(sub, next, types) <- step(sub, next, env, source, e1, ret, eff, types) + Cont(#(sub, next, types), k) + } + e.Let(x, e1, e2) -> { + // can't error + let types = map.insert(types, ref, Ok(type_)) + let #(inner, next) = t.fresh(next) + use #(sub, next, types) <- step(sub, next, env, source, e1, inner, eff, types) + let env = extend(env, x, generalise(sub, env, inner)) + use #(sub, next, types) <- step(sub, next, env, source, e2, type_, eff, types) + Cont(#(sub, next, types), k) + } + literal -> { + let #(found, next) = primitive(literal, next) + Cont(unify_at(type_, found, sub, next, types, ref), k) + } + } + } +} + +fn primitive(exp, next) { + case exp { + e.Var(_) | e.Call(_,_) | e.Fn(_,_) | e.Let(_,_,_) -> panic("not a literal") + e.String(_) -> #(t.String, next) + e.Integer(_) -> #(t.Integer, next) + + e.Tail -> t.tail(next) + e.Cons -> t.cons(next) + e.Vacant(_comment) -> t.fresh(next) + + // Record + e.Empty -> t.empty(next) + e.Extend(label) -> t.extend(label, next) + e.Overwrite(label) -> t.overwrite(label, next) + e.Select(label) -> t.select(label, next) + + // Union + e.Tag(label) -> t.tag(label, next) + e.Case(label) -> t.case_(label, next) + e.NoCases -> t.nocases(next) + + // Effect + e.Perform(label) -> t.perform(label, next) + + e.Handle(label) -> t.handle(label, next) + + // TODO use real builtins + e.Builtin(identifier) -> t.fresh(next) + // _ -> todo("pull from old inference") + + } +} +// errors should be both wrong f and wrong arg diff --git a/eyg/src/eyg/analysis/jm/infer.gleam b/eyg/src/eyg/analysis/jm/infer.gleam index 9b7e2969f..6ea1fc0f1 100644 --- a/eyg/src/eyg/analysis/jm/infer.gleam +++ b/eyg/src/eyg/analysis/jm/infer.gleam @@ -8,20 +8,20 @@ import eyg/analysis/jm/type_ as t import eyg/analysis/jm/env import eyg/analysis/jm/unify -fn mono(type_) { +pub fn mono(type_) { #([], type_) } // reference substitution env and type. // causes circular dependencies to move to any other file -fn generalise(sub, env, t) { +pub fn generalise(sub, env, t) { let env = env.apply(sub, env) let t = t.apply(sub, t) let forall = set.drop(t.ftv(t), set.to_list(env.ftv(env))) #(set.to_list(forall), t) } -fn instantiate(scheme, next) { +pub fn instantiate(scheme, next) { let #(forall, type_) = scheme let s = list.index_map(forall, fn(i, old) { #(old, t.Var(next + i))}) |> map.from_list() @@ -31,117 +31,28 @@ fn instantiate(scheme, next) { } -fn extend(env, label, scheme) { +pub fn extend(env, label, scheme) { map.insert(env, label, scheme) } -fn unify_at(type_, found, sub, next, types, ref) { +pub fn unify_at(type_, found, sub, next, types, ref) { case unify.unify(type_, found, sub, next) { Ok(#(s, next)) -> #(s, next, map.insert(types, ref, Ok(type_))) Error(reason) -> #(sub, next, map.insert(types, ref, Error(#(reason, type_, found)))) } } -type State = #(t.Substitutions, Int, map.Map(Int, Result(t.Type, #(error.Reason, t.Type, t.Type)))) +pub type State = #(t.Substitutions, Int, map.Map(Int, Result(t.Type, #(error.Reason, t.Type, t.Type)))) -type Run { +pub type Run { Cont(State, fn(State) -> Run) Done(State) } -pub fn infer(sub, next, env, source, ref, type_, eff, types) { - loop(step(sub, next, env, source, ref, type_, eff, types, Done)) -} - -fn loop(run) { +// this is required to make the infer function tail recursive +pub fn loop(run) { case run { Done(state) -> state Cont(state, k) -> loop(k(state)) } } - -fn step(sub, next, env, source, ref, type_, eff, types, k) { - case map.get(source, ref) { - Error(Nil) -> Cont(#(sub, next, types), k) - Ok(exp) -> case exp { - e.Var(x) -> { - case map.get(env, x) { - Ok(scheme) -> { - let #(found, next) = instantiate(scheme, next) - Cont(unify_at(type_, found, sub, next, types, ref), k) - } - Error(Nil) -> { - let types = map.insert(types, ref, Error(#(error.MissingVariable(x), type_, t.Var(-100)))) - Cont(#(sub, next, types), k) - } - } - } - e.Call(e1, e2) -> { - // can't error - let types = map.insert(types, ref, Ok(type_)) - let #(arg, next) = t.fresh(next) - use #(sub, next, types) <- step(sub, next, env, source, e1, t.Fun(arg, eff, type_), eff, types) - use #(sub, next, types) <- step(sub, next, env, source, e2, arg, eff, types) - Cont(#(sub, next, types), k) - } - e.Fn(x, e1) -> { - let #(arg, next) = t.fresh(next) - let #(eff, next) = t.fresh(next) - let #(ret, next) = t.fresh(next) - let #(sub, next, types) = unify_at(type_, t.Fun(arg, eff, ret), sub, next, types, ref) - let env = extend(env, x, mono(arg)) - use #(sub, next, types) <- step(sub, next, env, source, e1, ret, eff, types) - Cont(#(sub, next, types), k) - } - e.Let(x, e1, e2) -> { - // can't error - let types = map.insert(types, ref, Ok(type_)) - let #(inner, next) = t.fresh(next) - use #(sub, next, types) <- step(sub, next, env, source, e1, inner, eff, types) - let env = extend(env, x, generalise(sub, env, inner)) - use #(sub, next, types) <- step(sub, next, env, source, e2, type_, eff, types) - Cont(#(sub, next, types), k) - } - literal -> { - let #(found, next) = primitive(literal, next) - Cont(unify_at(type_, found, sub, next, types, ref), k) - } - } - } -} - -fn primitive(exp, next) { - case exp { - e.Var(_) | e.Call(_,_) | e.Fn(_,_) | e.Let(_,_,_) -> panic("not a literal") - e.String(_) -> #(t.String, next) - e.Integer(_) -> #(t.Integer, next) - - e.Tail -> t.tail(next) - e.Cons -> t.cons(next) - e.Vacant(_comment) -> t.fresh(next) - - // Record - e.Empty -> t.empty(next) - e.Extend(label) -> t.extend(label, next) - e.Overwrite(label) -> t.overwrite(label, next) - e.Select(label) -> t.select(label, next) - - // Union - e.Tag(label) -> t.tag(label, next) - e.Case(label) -> t.case_(label, next) - e.NoCases -> t.nocases(next) - - // Effect - e.Perform(label) -> t.perform(label, next) - - e.Handle(label) -> t.handle(label, next) - - // TODO use real builtins - e.Builtin(identifier) -> t.fresh(next) - // _ -> todo("pull from old inference") - - } -} -// errors should be both wrong f and wrong arg - - diff --git a/eyg/src/eyg/analysis/jm/tree.gleam b/eyg/src/eyg/analysis/jm/tree.gleam new file mode 100644 index 000000000..70f106f2f --- /dev/null +++ b/eyg/src/eyg/analysis/jm/tree.gleam @@ -0,0 +1,112 @@ +import gleam/io +import gleam/list +import gleam/map +import gleam/set +import eygir/expression as e +import eyg/analysis/jm/error +import eyg/analysis/jm/type_ as t +import eyg/analysis/jm/env +import eyg/analysis/jm/unify +import eyg/analysis/jm/infer.{ instantiate, generalise, unify_at, extend, mono} + +pub type State = #(t.Substitutions, Int, map.Map(List(Int), Result(t.Type, #(error.Reason, t.Type, t.Type)))) + +pub type Run { + Cont(State, fn(State) -> Run) + Done(State) +} + +// this is required to make the infer function tail recursive +pub fn loop(run) { + case run { + Done(state) -> state + Cont(state, k) -> loop(k(state)) + } +} + +pub fn infer(sub, next, env, exp, path, type_, eff, types) { + loop(step(sub, next, env, exp, path, type_, eff, types, Done)) +} + +fn step(sub, next, env, exp, path, type_, eff, types, k) { + io.debug(exp) + case exp { + e.Variable(x) -> { + case map.get(env, x) { + Ok(scheme) -> { + let #(found, next) = instantiate(scheme, next) + Cont(unify_at(type_, found, sub, next, types, path), k) + } + Error(Nil) -> { + let types = map.insert(types, path, Error(#(error.MissingVariable(x), type_, t.Var(-100)))) + Cont(#(sub, next, types), k) + } + } + } + e.Apply(e1, e2) -> { + // can't error + let types = map.insert(types, path, Ok(type_)) + let #(arg, next) = t.fresh(next) + use #(sub, next, types) <- step(sub, next, env, e1, [0,..path], t.Fun(arg, eff, type_), eff, types) + use #(sub, next, types) <- step(sub, next, env, e2, [1,..path], arg, eff, types) + Cont(#(sub, next, types), k) + } + e.Lambda(x, e1) -> { + let #(arg, next) = t.fresh(next) + let #(eff, next) = t.fresh(next) + let #(ret, next) = t.fresh(next) + let #(sub, next, types) = unify_at(type_, t.Fun(arg, eff, ret), sub, next, types, path) + let env = extend(env, x, mono(arg)) + use #(sub, next, types) <- step(sub, next, env, e1, [0, ..path], ret, eff, types) + Cont(#(sub, next, types), k) + } + e.Let(x, e1, e2) -> { + // can't error + let types = map.insert(types, path, Ok(type_)) + let #(inner, next) = t.fresh(next) + use #(sub, next, types) <- step(sub, next, env, e1, [0,..path], inner, eff, types) + let env = extend(env, x, generalise(sub, env, inner)) + use #(sub, next, types) <- step(sub, next, env, e2, [1,..path], type_, eff, types) + Cont(#(sub, next, types), k) + } + literal -> { + let #(found, next) = primitive(literal, next) + Cont(unify_at(type_, found, sub, next, types, path), k) + } + } + +} + +fn primitive(exp, next) { + case exp { + e.Variable(_) | e.Apply(_,_) | e.Lambda(_,_) | e.Let(_,_,_) -> panic("not a literal") + e.Binary(_) -> #(t.String, next) + e.Integer(_) -> #(t.Integer, next) + + e.Tail -> t.tail(next) + e.Cons -> t.cons(next) + e.Vacant(_comment) -> t.fresh(next) + + // Record + e.Empty -> t.empty(next) + e.Extend(label) -> t.extend(label, next) + e.Overwrite(label) -> t.overwrite(label, next) + e.Select(label) -> t.select(label, next) + + // Union + e.Tag(label) -> t.tag(label, next) + e.Case(label) -> t.case_(label, next) + e.NoCases -> t.nocases(next) + + // Effect + e.Perform(label) -> t.perform(label, next) + + e.Handle(label) -> t.handle(label, next) + + // TODO use real builtins + e.Builtin(identifier) -> t.fresh(next) + // _ -> todo("pull from old inference") + + } +} +// errors should be both wrong f and wrong arg diff --git a/eyg/test/eyg/analysis/typing_test.gleam b/eyg/test/eyg/analysis/typing_test.gleam index 37c551553..8ec0441b0 100644 --- a/eyg/test/eyg/analysis/typing_test.gleam +++ b/eyg/test/eyg/analysis/typing_test.gleam @@ -12,7 +12,7 @@ import eyg/analysis/scheme.{Scheme} import eyg/analysis/unification import gleeunit/should import eyg/incremental/store -import eyg/analysis/jm/infer as jm +import eyg/analysis/jm/incremental as jm import eyg/analysis/jm/type_ as jmt import eyg/analysis/jm/error as jm_error From db75b4aaf72d2c3a40e0453db1f106521891cbf8 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 22 Apr 2023 16:04:26 +0200 Subject: [PATCH 48/62] add builtins --- eyg/src/atelier/app.gleam | 52 ++++---- eyg/src/eyg/analysis/jm/incremental.gleam | 39 +++--- eyg/src/eyg/analysis/jm/infer.gleam | 151 ++++++++++++++++++++++ eyg/src/eyg/analysis/jm/tree.gleam | 9 +- eyg/src/eyg/analysis/jm/type_.gleam | 15 ++- eyg/src/harness/ffi/integer.gleam | 1 + eyg/test/eyg/analysis/jm/unify_test.gleam | 14 ++ 7 files changed, 231 insertions(+), 50 deletions(-) create mode 100644 eyg/test/eyg/analysis/jm/unify_test.gleam diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index 69bab02de..455681899 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -99,17 +99,17 @@ pub fn init(source) { mutable_map.size(s.free_mut), )) - let start = pnow() - let assert Ok(#(t, s)) = store.type_(s, root) - // TODO i think should be same size - io.debug(#( - "typing took ms:", - pnow() - start, - map.size(s.source), - map.size(s.free), - map.size(s.types), - t, - )) + // let start = pnow() + // let assert Ok(#(t, s)) = store.type_(s, root) + // // TODO i think should be same size + // io.debug(#( + // "typing took ms:", + // pnow() - start, + // map.size(s.source), + // map.size(s.free), + // map.size(s.types), + // t, + // )) let _ = { @@ -128,7 +128,7 @@ pub fn init(source) { pnow() - start, map.size(typesjm), )) - let assert Ok(Ok(t)) = map.get(typesjm, 100) + let assert Ok(Ok(t)) = map.get(typesjm, 6010) io.debug(jmt.resolve(t, sub)) let assert Ok(Ok(t)) = map.get(typesjm, 0) io.debug(jmt.resolve(t, sub)) @@ -138,28 +138,32 @@ pub fn init(source) { io.debug(jmt.resolve(t, sub)) + io.debug("================") list.map(map.to_list(typesjm), fn(r) { let #(id, r) = r case r { Ok(_) -> Nil Error(reason) -> { - io.debug(reason) + io.debug(map.get(s.source, id)) + // io.debug(reason) + io.debug(jmt.resolve_error(reason, sub)) Nil } } }) - - // new map of types because non function not generic. - // TODO should this be the case add to gleam explainers - let types = map.new() - let start = pnow() - let #(sub, _next, typesjm) = jm_tree.infer(sub, next, env, source, [], type_, eff, types) - io.debug(#( - "typing jm took ms:", - pnow() - start, - map.size(typesjm), - )) + io.debug("================") + + // // new map of types because non function not generic. + // // TODO should this be the case add to gleam explainers + // let types = map.new() + // let start = pnow() + // let #(sub, _next, typesjm) = jm_tree.infer(sub, next, env, source, [], type_, eff, types) + // io.debug(#( + // "typing jm took ms:", + // pnow() - start, + // map.size(typesjm), + // )) } // let start = pnow() // let assert Ok(c) = store.cursor(s, root, path) diff --git a/eyg/src/eyg/analysis/jm/incremental.gleam b/eyg/src/eyg/analysis/jm/incremental.gleam index 476bc7a66..db6d10714 100644 --- a/eyg/src/eyg/analysis/jm/incremental.gleam +++ b/eyg/src/eyg/analysis/jm/incremental.gleam @@ -7,7 +7,7 @@ import eyg/analysis/jm/error import eyg/analysis/jm/type_ as t import eyg/analysis/jm/env import eyg/analysis/jm/unify -import eyg/analysis/jm/infer.{Cont, loop, instantiate, generalise, unify_at, extend, mono, Done} +import eyg/analysis/jm/infer.{Cont, loop, instantiate, generalise, unify_at, extend, mono, Done, builtins} pub fn infer(sub, next, env, source, ref, type_, eff, types) { loop(step(sub, next, env, source, ref, type_, eff, types, Done)) @@ -17,18 +17,7 @@ fn step(sub, next, env, source, ref, type_, eff, types, k) { case map.get(source, ref) { Error(Nil) -> Cont(#(sub, next, types), k) Ok(exp) -> case exp { - e.Var(x) -> { - case map.get(env, x) { - Ok(scheme) -> { - let #(found, next) = instantiate(scheme, next) - Cont(unify_at(type_, found, sub, next, types, ref), k) - } - Error(Nil) -> { - let types = map.insert(types, ref, Error(#(error.MissingVariable(x), type_, t.Var(-100)))) - Cont(#(sub, next, types), k) - } - } - } + e.Var(x) -> fetch(env, x, sub, next, types, ref, type_, k) e.Call(e1, e2) -> { // can't error let types = map.insert(types, ref, Ok(type_)) @@ -55,6 +44,7 @@ fn step(sub, next, env, source, ref, type_, eff, types, k) { use #(sub, next, types) <- step(sub, next, env, source, e2, type_, eff, types) Cont(#(sub, next, types), k) } + e.Builtin(identifier) -> fetch(builtins(), identifier, sub, next, types, ref, type_, k) literal -> { let #(found, next) = primitive(literal, next) Cont(unify_at(type_, found, sub, next, types, ref), k) @@ -65,7 +55,7 @@ fn step(sub, next, env, source, ref, type_, eff, types, k) { fn primitive(exp, next) { case exp { - e.Var(_) | e.Call(_,_) | e.Fn(_,_) | e.Let(_,_,_) -> panic("not a literal") + e.Var(_) | e.Call(_,_) | e.Fn(_,_) | e.Let(_,_,_) | e.Builtin(_) -> panic("not a literal") e.String(_) -> #(t.String, next) e.Integer(_) -> #(t.Integer, next) @@ -89,10 +79,19 @@ fn primitive(exp, next) { e.Handle(label) -> t.handle(label, next) - // TODO use real builtins - e.Builtin(identifier) -> t.fresh(next) - // _ -> todo("pull from old inference") - - } + } +} + +fn fetch(env, x, sub, next, types, ref, type_, k) { + case map.get(env, x) { + Ok(scheme) -> { + let #(found, next) = instantiate(scheme, next) + Cont(unify_at(type_, found, sub, next, types, ref), k) + } + Error(Nil) -> { + let types = map.insert(types, ref, Error(#(error.MissingVariable(x), type_, t.Var(-100)))) + Cont(#(sub, next, types), k) + } + } } -// errors should be both wrong f and wrong arg + diff --git a/eyg/src/eyg/analysis/jm/infer.gleam b/eyg/src/eyg/analysis/jm/infer.gleam index 6ea1fc0f1..5f180b761 100644 --- a/eyg/src/eyg/analysis/jm/infer.gleam +++ b/eyg/src/eyg/analysis/jm/infer.gleam @@ -7,6 +7,12 @@ import eyg/analysis/jm/error import eyg/analysis/jm/type_ as t import eyg/analysis/jm/env import eyg/analysis/jm/unify +// import harness/ffi/core +// import harness/ffi/integer +// import harness/ffi/linked_list +// import harness/ffi/string +// import eyg/analysis/typ as old_t + pub fn mono(type_) { #([], type_) @@ -56,3 +62,148 @@ pub fn loop(run) { Cont(state, k) -> loop(k(state)) } } + +pub fn builtins() { + map.new() + |> extend_b("equal", equal()) + |> extend_b("debug", debug()) + |> extend_b("fix", fix()) + // |> extend_b("fixed", fixed()) + |> extend_b("serialize", serialize()) + |> extend_b("capture", capture()) + |> extend_b("encode_uri", encode_uri()) + // integer + |> extend_b("int_add", add()) + |> extend_b("int_subtract", subtract()) + |> extend_b("int_multiply", multiply()) + |> extend_b("int_divide", divide()) + |> extend_b("int_absolute", absolute()) + // |> extend_b("int_parse", parse()) + |> extend_b("int_to_string", to_string()) + // string + |> extend_b("string_append", append()) + |> extend_b("string_uppercase", uppercase()) + |> extend_b("string_lowercase", lowercase()) + |> extend_b("string_length", length()) + // list + |> extend_b("list_pop", pop()) + |> extend_b("list_fold", fold()) +} + + + +fn extend_b(env, key, t) { + let scheme = generalise( map.new(), map.new(), t) + extend(env, key, scheme) +} + +// THere could be part of std +pub fn equal() { + t.Fun(t.Var(0), t.Var(1), t.Var(0)) +} + +pub fn debug() { + t.Fun(t.Var(0), t.Var(1), t.String) +} + +pub fn fix() { + t.Fun( + t.Fun(t.Var(0), t.Var(1), t.Var(0)), + t.Var(2), + t.Var(0), + ) +} + +pub fn serialize() { + t.Fun(t.Var(0), t.Var(1), t.String) +} + +pub fn capture() { + t.Fun(t.Var(0), t.Var(1), t.Var(2)) +} + +pub fn encode_uri() { + t.Fun(t.String, t.Var(1), t.String) +} + +// int +// TODO fn2 taking a next would make handling curried fns easier +pub fn add() { + t.Fun(t.Integer, t.Var(0), t.Fun(t.Integer, t.Var(1), t.Integer)) +} + +pub fn subtract() { + t.Fun(t.Integer, t.Var(0), t.Fun(t.Integer, t.Var(1), t.Integer)) +} + +pub fn multiply() { + t.Fun(t.Integer, t.Var(0), t.Fun(t.Integer, t.Var(1), t.Integer)) +} + +pub fn divide() { + t.Fun(t.Integer, t.Var(0), t.Fun(t.Integer, t.Var(1), t.Integer)) +} + +pub fn absolute() { + t.Fun(t.Integer, t.Var(0), t.Integer) +} + +// TODO parse + +pub fn to_string() { + t.Fun(t.Integer, t.Var(0), t.String) +} + +pub fn append() { + t.Fun(t.String, t.Var(0), t.Fun(t.String, t.Var(1), t.String)) +} + +pub fn uppercase() { + t.Fun(t.String, t.Var(0), t.String) +} + +pub fn lowercase() { + t.Fun(t.String, t.Var(0), t.String) +} + +pub fn length() { + t.Fun(t.String, t.Var(0), t.Integer) +} + +pub fn pop() { + let parts = + t.Record(t.RowExtend( + "head", + t.Var(0), + t.RowExtend("tail", t.LinkedList(t.Var(0)), t.Empty), + )) + t.Fun(t.LinkedList(t.Var(0)), t.Var(1), t.result(parts, t.unit)) +} + +pub fn fold() { + let item = t.Var(0) + let eff1 = t.Var(1) + let acc = t.Var(2) + let eff2 = t.Var(3) + let eff3 = t.Var(4) + let eff4 = t.Var(5) + let eff5 = t.Var(6) + + t.Fun( + t.LinkedList(item), + eff1, + t.Fun( + acc, + eff2, + t.Fun( + t.Fun( + item, + eff3, + t.Fun(acc, eff4, acc), + ), + eff5, + acc, + ), + ), + ) +} \ No newline at end of file diff --git a/eyg/src/eyg/analysis/jm/tree.gleam b/eyg/src/eyg/analysis/jm/tree.gleam index 70f106f2f..578ff1028 100644 --- a/eyg/src/eyg/analysis/jm/tree.gleam +++ b/eyg/src/eyg/analysis/jm/tree.gleam @@ -8,6 +8,8 @@ import eyg/analysis/jm/type_ as t import eyg/analysis/jm/env import eyg/analysis/jm/unify import eyg/analysis/jm/infer.{ instantiate, generalise, unify_at, extend, mono} +import eyg/analysis/typ as old_t + pub type State = #(t.Substitutions, Int, map.Map(List(Int), Result(t.Type, #(error.Reason, t.Type, t.Type)))) @@ -29,7 +31,7 @@ pub fn infer(sub, next, env, exp, path, type_, eff, types) { } fn step(sub, next, env, exp, path, type_, eff, types, k) { - io.debug(exp) + // io.debug(exp) case exp { e.Variable(x) -> { case map.get(env, x) { @@ -100,13 +102,10 @@ fn primitive(exp, next) { // Effect e.Perform(label) -> t.perform(label, next) - e.Handle(label) -> t.handle(label, next) // TODO use real builtins e.Builtin(identifier) -> t.fresh(next) - // _ -> todo("pull from old inference") - + // _ -> todo("pull from old inference") } } -// errors should be both wrong f and wrong arg diff --git a/eyg/src/eyg/analysis/jm/type_.gleam b/eyg/src/eyg/analysis/jm/type_.gleam index dc3140e8d..e07776ea4 100644 --- a/eyg/src/eyg/analysis/jm/type_.gleam +++ b/eyg/src/eyg/analysis/jm/type_.gleam @@ -70,6 +70,11 @@ pub fn resolve(t, s) { } } +pub fn resolve_error(reason, s) { + let #(x, t1, t2) = reason + #(resolve(t1, s), resolve(t2, s)) +} + pub fn fresh(next) { #(Var(next), next + 1) } @@ -173,4 +178,12 @@ pub fn handle(label, next) { pub const unit = Record(Empty) -pub const boolean = Union(RowExtend("True", unit, RowExtend("False", unit, Empty))) \ No newline at end of file +pub const boolean = Union(RowExtend("True", unit, RowExtend("False", unit, Empty))) + +pub fn result(value, reason) { + Union(RowExtend("Ok", value, RowExtend("Error", reason, Empty))) +} + +pub fn option(value) { + Union(RowExtend("Some", value, RowExtend("None", unit, Empty))) +} \ No newline at end of file diff --git a/eyg/src/harness/ffi/integer.gleam b/eyg/src/harness/ffi/integer.gleam index 475b21926..ad96570c9 100644 --- a/eyg/src/harness/ffi/integer.gleam +++ b/eyg/src/harness/ffi/integer.gleam @@ -5,6 +5,7 @@ import harness/ffi/cast pub fn add() { let type_ = + // TODO not same effect t.Fun(t.Integer, t.Open(0), t.Fun(t.Integer, t.Open(0), t.Integer)) #(type_, r.Arity2(do_add)) } diff --git a/eyg/test/eyg/analysis/jm/unify_test.gleam b/eyg/test/eyg/analysis/jm/unify_test.gleam new file mode 100644 index 000000000..d3c1e2354 --- /dev/null +++ b/eyg/test/eyg/analysis/jm/unify_test.gleam @@ -0,0 +1,14 @@ +import gleam/io +import gleam/map +import eyg/analysis/jm/type_ as t +import eyg/analysis/jm/unify + +pub fn example_test() { + unify.unify( + t.Fun(t.Var(578), t.Var(579), t.Fun(t.Var(575), t.Var(579), t.Var(580))), + t.Fun(t.Fun(t.String, t.Var(584), t.String), t.Var(583), t.String), + map.new(), + 600 + ) + |> io.debug +} \ No newline at end of file From 4b50bb54675ffd2143c9a5ff9c6bda0345dcd877 Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 22 Apr 2023 16:23:36 +0200 Subject: [PATCH 49/62] fix type application --- eyg/src/atelier/app.gleam | 2 +- eyg/src/eyg/analysis/jm/incremental.gleam | 7 +++++-- eyg/src/eyg/analysis/jm/infer.gleam | 4 ++++ eyg/src/eyg/analysis/jm/type_.gleam | 7 +++++-- eyg/src/eyg/analysis/jm/unify.gleam | 1 + eyg/test/eyg/analysis/jm/infer_test.gleam | 3 +++ 6 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 eyg/test/eyg/analysis/jm/infer_test.gleam diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index 455681899..e772a0e7f 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -128,7 +128,7 @@ pub fn init(source) { pnow() - start, map.size(typesjm), )) - let assert Ok(Ok(t)) = map.get(typesjm, 6010) + let assert Ok(Ok(t)) = map.get(typesjm, root) io.debug(jmt.resolve(t, sub)) let assert Ok(Ok(t)) = map.get(typesjm, 0) io.debug(jmt.resolve(t, sub)) diff --git a/eyg/src/eyg/analysis/jm/incremental.gleam b/eyg/src/eyg/analysis/jm/incremental.gleam index db6d10714..c9df92946 100644 --- a/eyg/src/eyg/analysis/jm/incremental.gleam +++ b/eyg/src/eyg/analysis/jm/incremental.gleam @@ -28,11 +28,11 @@ fn step(sub, next, env, source, ref, type_, eff, types, k) { } e.Fn(x, e1) -> { let #(arg, next) = t.fresh(next) - let #(eff, next) = t.fresh(next) + let #(new_eff, next) = t.fresh(next) let #(ret, next) = t.fresh(next) let #(sub, next, types) = unify_at(type_, t.Fun(arg, eff, ret), sub, next, types, ref) let env = extend(env, x, mono(arg)) - use #(sub, next, types) <- step(sub, next, env, source, e1, ret, eff, types) + use #(sub, next, types) <- step(sub, next, env, source, e1, ret, new_eff, types) Cont(#(sub, next, types), k) } e.Let(x, e1, e2) -> { @@ -85,7 +85,10 @@ fn primitive(exp, next) { fn fetch(env, x, sub, next, types, ref, type_, k) { case map.get(env, x) { Ok(scheme) -> { + io.debug(#(x, scheme)) let #(found, next) = instantiate(scheme, next) + io.debug(found) + io.debug(next) Cont(unify_at(type_, found, sub, next, types, ref), k) } Error(Nil) -> { diff --git a/eyg/src/eyg/analysis/jm/infer.gleam b/eyg/src/eyg/analysis/jm/infer.gleam index 5f180b761..06f03c984 100644 --- a/eyg/src/eyg/analysis/jm/infer.gleam +++ b/eyg/src/eyg/analysis/jm/infer.gleam @@ -21,9 +21,13 @@ pub fn mono(type_) { // reference substitution env and type. // causes circular dependencies to move to any other file pub fn generalise(sub, env, t) { + io.debug("gen") + io.debug(#(sub |> map.to_list, env |> map.to_list, t)) let env = env.apply(sub, env) let t = t.apply(sub, t) + io.debug(t) let forall = set.drop(t.ftv(t), set.to_list(env.ftv(env))) + io.debug(forall) #(set.to_list(forall), t) } diff --git a/eyg/src/eyg/analysis/jm/type_.gleam b/eyg/src/eyg/analysis/jm/type_.gleam index e07776ea4..b90c79a76 100644 --- a/eyg/src/eyg/analysis/jm/type_.gleam +++ b/eyg/src/eyg/analysis/jm/type_.gleam @@ -36,7 +36,11 @@ pub fn ftv(type_) { pub fn apply(s, type_) { case type_ { - Var(a) -> result.unwrap(map.get(s, a), type_) + // This is recursive, get to the bottom of this + Var(a) -> case map.get(s, a) { + Ok(new) -> apply(s, new) + Error(Nil) -> type_ + } Fun(from, effects, to) -> Fun(apply(s, from), apply(s, effects), apply(s, to)) Integer | String -> type_ @@ -46,7 +50,6 @@ pub fn apply(s, type_) { Empty -> type_ RowExtend(label, value, rest) -> RowExtend(label, apply(s, value), apply(s, rest)) EffectExtend(label, #(lift, reply), rest) -> EffectExtend(label, #(apply(s, lift), apply(s, reply)), apply(s, rest)) - } } diff --git a/eyg/src/eyg/analysis/jm/unify.gleam b/eyg/src/eyg/analysis/jm/unify.gleam index 4906a5971..8e90aab3b 100644 --- a/eyg/src/eyg/analysis/jm/unify.gleam +++ b/eyg/src/eyg/analysis/jm/unify.gleam @@ -5,6 +5,7 @@ import eyg/analysis/jm/type_ as t import eyg/analysis/jm/error pub fn unify(t1, t2, s, next) { + io.debug(#(t1,t2)) do_unify([#(t1, t2)], s, next) } // I dont think this is the same as described because we don't keep lookup to original i. diff --git a/eyg/test/eyg/analysis/jm/infer_test.gleam b/eyg/test/eyg/analysis/jm/infer_test.gleam new file mode 100644 index 000000000..4edf9516c --- /dev/null +++ b/eyg/test/eyg/analysis/jm/infer_test.gleam @@ -0,0 +1,3 @@ +pub fn example_test() { + todo +} \ No newline at end of file From b547269cc010201bc88cbecab6b2ea23db35164c Mon Sep 17 00:00:00 2001 From: Peter Date: Sat, 22 Apr 2023 16:29:03 +0200 Subject: [PATCH 50/62] some notes --- eyg/src/eyg/analysis/jm/incremental.gleam | 7 +++---- eyg/src/eyg/analysis/jm/infer.gleam | 4 ---- eyg/src/eyg/analysis/jm/unify.gleam | 1 - 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/eyg/src/eyg/analysis/jm/incremental.gleam b/eyg/src/eyg/analysis/jm/incremental.gleam index c9df92946..577ecfc1d 100644 --- a/eyg/src/eyg/analysis/jm/incremental.gleam +++ b/eyg/src/eyg/analysis/jm/incremental.gleam @@ -13,6 +13,8 @@ pub fn infer(sub, next, env, source, ref, type_, eff, types) { loop(step(sub, next, env, source, ref, type_, eff, types, Done)) } +// TODO occurs in and recursive row check + fn step(sub, next, env, source, ref, type_, eff, types, k) { case map.get(source, ref) { Error(Nil) -> Cont(#(sub, next, types), k) @@ -30,7 +32,7 @@ fn step(sub, next, env, source, ref, type_, eff, types, k) { let #(arg, next) = t.fresh(next) let #(new_eff, next) = t.fresh(next) let #(ret, next) = t.fresh(next) - let #(sub, next, types) = unify_at(type_, t.Fun(arg, eff, ret), sub, next, types, ref) + let #(sub, next, types) = unify_at(type_, t.Fun(arg, new_eff, ret), sub, next, types, ref) let env = extend(env, x, mono(arg)) use #(sub, next, types) <- step(sub, next, env, source, e1, ret, new_eff, types) Cont(#(sub, next, types), k) @@ -85,10 +87,7 @@ fn primitive(exp, next) { fn fetch(env, x, sub, next, types, ref, type_, k) { case map.get(env, x) { Ok(scheme) -> { - io.debug(#(x, scheme)) let #(found, next) = instantiate(scheme, next) - io.debug(found) - io.debug(next) Cont(unify_at(type_, found, sub, next, types, ref), k) } Error(Nil) -> { diff --git a/eyg/src/eyg/analysis/jm/infer.gleam b/eyg/src/eyg/analysis/jm/infer.gleam index 06f03c984..5f180b761 100644 --- a/eyg/src/eyg/analysis/jm/infer.gleam +++ b/eyg/src/eyg/analysis/jm/infer.gleam @@ -21,13 +21,9 @@ pub fn mono(type_) { // reference substitution env and type. // causes circular dependencies to move to any other file pub fn generalise(sub, env, t) { - io.debug("gen") - io.debug(#(sub |> map.to_list, env |> map.to_list, t)) let env = env.apply(sub, env) let t = t.apply(sub, t) - io.debug(t) let forall = set.drop(t.ftv(t), set.to_list(env.ftv(env))) - io.debug(forall) #(set.to_list(forall), t) } diff --git a/eyg/src/eyg/analysis/jm/unify.gleam b/eyg/src/eyg/analysis/jm/unify.gleam index 8e90aab3b..4906a5971 100644 --- a/eyg/src/eyg/analysis/jm/unify.gleam +++ b/eyg/src/eyg/analysis/jm/unify.gleam @@ -5,7 +5,6 @@ import eyg/analysis/jm/type_ as t import eyg/analysis/jm/error pub fn unify(t1, t2, s, next) { - io.debug(#(t1,t2)) do_unify([#(t1, t2)], s, next) } // I dont think this is the same as described because we don't keep lookup to original i. From 11bdbf6b6260f87bde2af34d4de61aab0b3b8154 Mon Sep 17 00:00:00 2001 From: Peter Saxton Date: Mon, 24 Apr 2023 18:49:45 +0200 Subject: [PATCH 51/62] tiny notes --- notes/README.md | 15 ++++++++++++--- notes/unison.md | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 notes/unison.md diff --git a/notes/README.md b/notes/README.md index 3d5731075..e5c2c9018 100644 --- a/notes/README.md +++ b/notes/README.md @@ -7,11 +7,11 @@ ### Algorithms -Simple Lambda calculus is easily type checked. +Simple Lambda calculus is easily type checked. Most of the below algorithms handle extension of at least let polymorphism -#### Algorithm W +#### Algorithm W Explained in Hindley Milner Paper Uses composition of substitutions @@ -19,7 +19,7 @@ Uses composition of substitutions #### Algorithm J Explained in Hindley Milner Paper -Uses a single global substitution. The global substitution doesn't have to +Uses a single global substitution. The global substitution doesn't have to ### Algorithm M Adds expected type as argument to algorithm. @@ -40,6 +40,15 @@ This type is not constructable within the lambda calculus Every Let could test to see if let rec is used. +#### Extensible Records and Unions + +using Row types + +#### Effect types + +- [ ] How do we get polymorphic functions in effect types. +Can we use these to compile builtins. + ## Incremental type checking J with early return is an option diff --git a/notes/unison.md b/notes/unison.md new file mode 100644 index 000000000..fa911b0cc --- /dev/null +++ b/notes/unison.md @@ -0,0 +1,18 @@ +# Unison + + +Makes use of Abstract Binding Trees. https://semantic-domain.blogspot.com/2015/03/abstract-binding-trees.html + + +unison-hashing-v2/src/Unison/Hashing/V2 +defines all the terms in the tree an uses reference utils to do hashing + +```haskell +hashed $ hash b == hashed (hash b) +``` + +Once in the hash' function. Var is De Brijun index so int64 + + +Steps the compiler goes through +https://github.com/unisonweb/unison/blob/477371ba97a019fe36294a76faed52190ef29d75/parser-typechecker/src/Unison/Runtime/docs.markdown From e5ac8e0b159f775932bb4cf61c12ab52d91e4c74 Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 24 Apr 2023 20:06:36 +0200 Subject: [PATCH 52/62] fix recursive check --- eyg/src/atelier/app.gleam | 1 + eyg/src/eyg/analysis/jm/error.gleam | 1 + eyg/src/eyg/analysis/jm/incremental.gleam | 2 - eyg/src/eyg/analysis/jm/type_.gleam | 2 +- eyg/src/eyg/analysis/jm/unify.gleam | 54 ++++++++++++++--------- eyg/test/eyg/analysis/jm/unify_test.gleam | 15 ++++--- 6 files changed, 45 insertions(+), 30 deletions(-) diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index e772a0e7f..3fb82230e 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -131,6 +131,7 @@ pub fn init(source) { let assert Ok(Ok(t)) = map.get(typesjm, root) io.debug(jmt.resolve(t, sub)) let assert Ok(Ok(t)) = map.get(typesjm, 0) + |> io.debug io.debug(jmt.resolve(t, sub)) let assert Ok(Ok(t)) = map.get(typesjm, 1) io.debug(jmt.resolve(t, sub)) diff --git a/eyg/src/eyg/analysis/jm/error.gleam b/eyg/src/eyg/analysis/jm/error.gleam index a0d155146..cb3a8e59b 100644 --- a/eyg/src/eyg/analysis/jm/error.gleam +++ b/eyg/src/eyg/analysis/jm/error.gleam @@ -6,4 +6,5 @@ pub type Reason { TypeMismatch(t.Type, t.Type) RowMismatch(String) InvalidTail(t.Type) + RecursiveType } \ No newline at end of file diff --git a/eyg/src/eyg/analysis/jm/incremental.gleam b/eyg/src/eyg/analysis/jm/incremental.gleam index 577ecfc1d..eeb780bec 100644 --- a/eyg/src/eyg/analysis/jm/incremental.gleam +++ b/eyg/src/eyg/analysis/jm/incremental.gleam @@ -78,9 +78,7 @@ fn primitive(exp, next) { // Effect e.Perform(label) -> t.perform(label, next) - e.Handle(label) -> t.handle(label, next) - } } diff --git a/eyg/src/eyg/analysis/jm/type_.gleam b/eyg/src/eyg/analysis/jm/type_.gleam index b90c79a76..5bfb5491a 100644 --- a/eyg/src/eyg/analysis/jm/type_.gleam +++ b/eyg/src/eyg/analysis/jm/type_.gleam @@ -75,7 +75,7 @@ pub fn resolve(t, s) { pub fn resolve_error(reason, s) { let #(x, t1, t2) = reason - #(resolve(t1, s), resolve(t2, s)) + #(x, resolve(t1, s), resolve(t2, s)) } pub fn fresh(next) { diff --git a/eyg/src/eyg/analysis/jm/unify.gleam b/eyg/src/eyg/analysis/jm/unify.gleam index 4906a5971..c9845f09b 100644 --- a/eyg/src/eyg/analysis/jm/unify.gleam +++ b/eyg/src/eyg/analysis/jm/unify.gleam @@ -1,6 +1,7 @@ import gleam/io import gleam/map import gleam/result +import gleam/set import eyg/analysis/jm/type_ as t import eyg/analysis/jm/error @@ -11,30 +12,41 @@ pub fn unify(t1, t2, s, next) { // s is a function from var -> t fn do_unify(constraints, s, next) { // Have to try and substitute at every point because new substitutions can come into existance + // Because we don't replace for each new sub we need to apply at match time. + // Do unify can introduce new subs and get called recursivly case constraints { [] -> Ok(#(s, next)) - [#(t.Var(i), t.Var(j)), ..constraints] if i == j -> do_unify(constraints, s, next) - // TODO varbind occurs in - [#(t.Var(i), t1), ..constraints] | [#(t1, t.Var(i)), ..constraints] -> case map.get(s, i) { - Ok(t2) -> do_unify([#(t1, t2),..constraints], s, next) - Error(Nil) -> do_unify(constraints, map.insert(s, i, t1), next) + [#(t1, t2), ..rest] -> case t.apply(s, t1), t.apply(s,t2) { + t.Var(i), t.Var(j) if i == j -> do_unify(rest, s, next) + t.Var(i), t1 | t1, t.Var(i) -> case set.contains(t.ftv(t1), i) { + True -> Error(error.RecursiveType) + False -> do_unify(rest, map.insert(s, i, t1), next) + } + t.Fun(a1, e1, r1), t.Fun(a2, e2, r2) -> do_unify([#(a1, a2), #(e1, e2), #(r1, r2), ..rest], s, next) + t.Integer, t.Integer -> do_unify(rest, s, next) + t.String, t.String -> do_unify(rest, s, next) + t.LinkedList(i1), t.LinkedList(i2) -> do_unify([#(i1, i2), ..rest], s, next) + t.Record(r1), t.Record(r2) -> do_unify([#(r1, r2), ..rest], s, next) + t.Union(r1), t.Union(r2) -> do_unify([#(r1, r2), ..rest], s, next) + t.Empty, t.Empty -> do_unify(rest, s, next) + t.RowExtend(label1, value1, tail1), t.RowExtend(_,_,_) as row2 -> { + use #(value2, tail2, s1, next) <- result.then(rewrite_row(label1, row2, s, next)) + // case tail1 { + // t.Var(x) -> { + // io.debug(#("---->", map.get(s, x))) + // Nil + // } + // _ -> Nil + // } + let s = s1 + do_unify([#(value1, value2), #(tail1, tail2), ..rest], s, next) + } + t.EffectExtend(label1, #(lift1, reply1), tail1), t.EffectExtend(_,_,_) as row2 -> { + use #(lift2, reply2, tail2, s, next) <- result.then(rewrite_effect(label1, row2, s, next)) + do_unify([#(lift1, lift2), #(reply1, reply2), #(tail1, tail2), ..rest], s, next) + } + t1, t2 -> Error(error.TypeMismatch(t1, t2)) } - [#(t.Fun(a1, e1, r1), t.Fun(a2, e2, r2)), ..cs] -> do_unify([#(a1, a2), #(e1, e2), #(r1, r2), ..cs], s, next) - [#(t.Integer, t.Integer), ..cs] -> do_unify(cs, s, next) - [#(t.String, t.String), ..cs] -> do_unify(cs, s, next) - [#(t.LinkedList(i1), t.LinkedList(i2)), ..cs] -> do_unify([#(i1, i2), ..cs], s, next) - [#(t.Record(r1), t.Record(r2)), ..cs] -> do_unify([#(r1, r2), ..cs], s, next) - [#(t.Union(r1), t.Union(r2)), ..cs] -> do_unify([#(r1, r2), ..cs], s, next) - [#(t.Empty, t.Empty), ..cs] -> do_unify(cs, s, next) - [#(t.RowExtend(label1, value1, tail1), t.RowExtend(_,_,_) as row2), ..cs] -> { - use #(value2, tail2, s, next) <- result.then(rewrite_row(label1, row2, s, next)) - do_unify([#(value1, value2), #(tail1, tail2), ..cs], s, next) - } - [#(t.EffectExtend(label1, #(lift1, reply1), tail1), t.EffectExtend(_,_,_) as row2), ..cs] -> { - use #(lift2, reply2, tail2, s, next) <- result.then(rewrite_effect(label1, row2, s, next)) - do_unify([#(lift1, lift2), #(reply1, reply2), #(tail1, tail2), ..cs], s, next) - } - [#(t1, t2), ..] -> Error(error.TypeMismatch(t1, t2)) } } diff --git a/eyg/test/eyg/analysis/jm/unify_test.gleam b/eyg/test/eyg/analysis/jm/unify_test.gleam index d3c1e2354..3ca8c3e2c 100644 --- a/eyg/test/eyg/analysis/jm/unify_test.gleam +++ b/eyg/test/eyg/analysis/jm/unify_test.gleam @@ -3,12 +3,15 @@ import gleam/map import eyg/analysis/jm/type_ as t import eyg/analysis/jm/unify -pub fn example_test() { - unify.unify( - t.Fun(t.Var(578), t.Var(579), t.Fun(t.Var(575), t.Var(579), t.Var(580))), - t.Fun(t.Fun(t.String, t.Var(584), t.String), t.Var(583), t.String), +pub fn other_test() { + let assert Ok(#(s, _next)) = unify.unify( + t.Fun(t.Var(1), t.Empty, t.Var(1)), + t.Fun(t.Var(2), t.Empty, t.String), map.new(), 600 ) - |> io.debug -} \ No newline at end of file + s + |> map.to_list + |> io.debug + todo +} From 2ad1c4ce1991c5d385e34b3ecfe37429c7eb99be Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 24 Apr 2023 20:35:09 +0200 Subject: [PATCH 53/62] more tests --- eyg/src/eyg/analysis/jm/infer.gleam | 1 - eyg/test/eyg/analysis/typing_test.gleam | 11 ++++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/eyg/src/eyg/analysis/jm/infer.gleam b/eyg/src/eyg/analysis/jm/infer.gleam index 5f180b761..79f7ba965 100644 --- a/eyg/src/eyg/analysis/jm/infer.gleam +++ b/eyg/src/eyg/analysis/jm/infer.gleam @@ -36,7 +36,6 @@ pub fn instantiate(scheme, next) { #(type_, next) } - pub fn extend(env, label, scheme) { map.insert(env, label, scheme) } diff --git a/eyg/test/eyg/analysis/typing_test.gleam b/eyg/test/eyg/analysis/typing_test.gleam index 8ec0441b0..a0fd665f8 100644 --- a/eyg/test/eyg/analysis/typing_test.gleam +++ b/eyg/test/eyg/analysis/typing_test.gleam @@ -171,7 +171,6 @@ pub fn primitive_list_test() { let sub = infer(env, exp, typ, eff) let assert Ok(t.LinkedList(t.Binary)) = type_of(sub, []) let assert Ok(type_.LinkedList(type_.Integer)) = jm(exp, type_.Var(-1), type_.Empty) - |> io.debug // THere is an error missing and the principle is wrong let assert Ok(t.Fun(t.LinkedList(t.Binary), t.Closed, t.LinkedList(t.Binary))) = @@ -197,6 +196,7 @@ pub fn variables_test() { let typ = t.Unbound(1) let sub = infer(env, exp, typ, eff) let assert t.Binary = resolve(sub, typ) + let assert Ok(type_.String) = jm(exp, type_.Var(-1), type_.Empty) let assert Ok(t.Binary) = type_of(sub, [0]) let assert Ok(t.Binary) = type_of(sub, [1]) } @@ -213,6 +213,7 @@ pub fn function_test() { let typ = t.Unbound(-1) let sub = infer(env, exp, typ, eff) let assert t.Fun(t.Unbound(_), t.Open(_), t.Binary) = resolve(sub, typ) + let assert Ok(type_.Fun(type_.Var(_), type_.Var(_), type_.String)) = jm(exp, type_.Var(-1), type_.Empty) } pub fn pure_function_test() { @@ -226,6 +227,8 @@ pub fn pure_function_test() { should.equal(x, y) let assert Ok(t.Unbound(z)) = type_of(sub, [0]) should.equal(x, z) + let assert Ok(type_.Fun(type_.Var(x), type_.Var(_), type_.Var(y))) = jm(exp, type_.Var(-1), type_.Empty) + should.equal(x, y) } pub fn pure_function_call_test() { @@ -240,6 +243,7 @@ pub fn pure_function_call_test() { let typ = t.Unbound(-1) let sub = infer(env, exp, typ, eff) let assert t.Binary = resolve(sub, typ) + let assert Ok(type_.String) = jm(exp, type_.Var(-1), type_.Empty) } // call generic could be a test row(a = id(Int) b = id(Int)) @@ -265,6 +269,7 @@ pub fn select_test() { resolve(sub, typ) should.equal(a, b) should.equal(l, "foo") + let assert Ok(type_.Fun(type_.Record(type_.RowExtend("foo", type_.Var(x), type_.Var(_y))), type_.Var(_z), type_.Var(a))) = jm(exp, type_.Var(-1), type_.Empty) let exp = e.Apply(exp, e.Variable("x")) let env = env.empty() @@ -358,6 +363,10 @@ pub fn collect_effects_test() { let assert Ok(#(t.Unbound(lift2), t.Unbound(ret2))) = field(raised, "Log") should.equal(ret1, lift2) should.equal(ret2, final) + + let exp = e.Lambda("_", exp) + let assert Ok(type_.String) = jm(exp, type_.Var(-1), type_.Empty) + |> io.debug } pub fn anony_test() { From d8743bc11057d62021d53f807d943bb42ef21f83 Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 24 Apr 2023 21:12:48 +0200 Subject: [PATCH 54/62] debug this equal --- eyg/saved/saved.json | 2 +- eyg/src/eyg/analysis/jm/incremental.gleam | 7 +++++++ eyg/src/eyg/analysis/jm/infer.gleam | 9 ++++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/eyg/saved/saved.json b/eyg/saved/saved.json index 0979c0a92..36631bcb8 100644 --- a/eyg/saved/saved.json +++ b/eyg/saved/saved.json @@ -1 +1 @@ -{"0":"l","l":"async","v":{"0":"f","l":"exec","b":{"0":"a","f":{"0":"p","l":"Async"},"a":{"0":"v","l":"exec"}}},"t":{"0":"l","l":"std","v":{"0":"l","l":"equal","v":{"0":"b","l":"equal"},"t":{"0":"l","l":"debug","v":{"0":"b","l":"debug"},"t":{"0":"l","l":"fix","v":{"0":"b","l":"fix"},"t":{"0":"l","l":"capture","v":{"0":"b","l":"capture"},"t":{"0":"l","l":"serialize","v":{"0":"b","l":"serialize"},"t":{"0":"l","l":"encode_uri","v":{"0":"b","l":"encode_uri"},"t":{"0":"l","l":"boolean","v":{"0":"l","l":"and","v":{"0":"f","l":"a","b":{"0":"f","l":"b","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"True"},"a":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"False"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"b"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"False"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"a"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"and"},"a":{"0":"v","l":"and"}},"a":{"0":"u"}}},"t":{"0":"l","l":"result","v":{"0":"l","l":"unwrap","v":{"0":"f","l":"default","b":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"x","b":{"0":"v","l":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"v","l":"default"}}},"a":{"0":"n"}}}},"t":{"0":"u"}},"t":{"0":"l","l":"list","v":{"0":"l","l":"pop","v":{"0":"b","l":"list_pop"},"t":{"0":"l","l":"fold","v":{"0":"b","l":"list_fold"},"t":{"0":"l","l":"head","v":{"0":"f","l":"l","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"pop"},"a":{"0":"v","l":"l"}}}},"t":{"0":"l","l":"find","v":{"0":"a","f":{"0":"v","l":"fix"},"a":{"0":"f","l":"self","b":{"0":"f","l":"predicate","b":{"0":"f","l":"list","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}},"t":{"0":"l","l":"matched","v":{"0":"a","f":{"0":"v","l":"predicate"},"a":{"0":"v","l":"item"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"v","l":"item"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"predicate"}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"matched"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"t","l":"Error"}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"pop"},"a":{"0":"v","l":"list"}}}}}}},"t":{"0":"l","l":"reverse","v":{"0":"f","l":"list","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"fold"},"a":{"0":"v","l":"list"}},"a":{"0":"ta"}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"el"}},"a":{"0":"v","l":"acc"}}}}}},"t":{"0":"l","l":"append","v":{"0":"f","l":"first","b":{"0":"f","l":"second","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"fold"},"a":{"0":"a","f":{"0":"v","l":"reverse"},"a":{"0":"v","l":"first"}}},"a":{"0":"v","l":"second"}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"el"}},"a":{"0":"v","l":"acc"}}}}}}},"t":{"0":"l","l":"intersperse","v":{"0":"f","l":"list","b":{"0":"f","l":"element","b":{"0":"l","l":"reversed","v":{"0":"a","f":{"0":"v","l":"reverse"},"a":{"0":"v","l":"list"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"fold"},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}},"a":{"0":"ta"}}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"el"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"element"}},"a":{"0":"v","l":"acc"}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"ta"}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"pop"},"a":{"0":"v","l":"reversed"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"pop"},"a":{"0":"v","l":"pop"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"fold"},"a":{"0":"v","l":"fold"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"head"},"a":{"0":"v","l":"head"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"find"},"a":{"0":"v","l":"find"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"reverse"},"a":{"0":"v","l":"reverse"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"append"},"a":{"0":"v","l":"append"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"intersperse"},"a":{"0":"v","l":"intersperse"}},"a":{"0":"u"}}}}}}}}}}}}}}},"t":{"0":"l","l":"integer","v":{"0":"l","l":"add","v":{"0":"b","l":"int_add"},"t":{"0":"l","l":"subtract","v":{"0":"b","l":"int_subtract"},"t":{"0":"l","l":"to_string","v":{"0":"b","l":"int_to_string"},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"add"},"a":{"0":"v","l":"add"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"subtract"},"a":{"0":"v","l":"subtract"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"to_string"},"a":{"0":"v","l":"to_string"}},"a":{"0":"u"}}}}}}},"t":{"0":"l","l":"string","v":{"0":"l","l":"append","v":{"0":"b","l":"string_append"},"t":{"0":"l","l":"concat","v":{"0":"f","l":"l","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fold"},"a":{"0":"v","l":"list"}},"a":{"0":"v","l":"l"}},"a":{"0":"s","v":""}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"append"},"a":{"0":"v","l":"acc"}},"a":{"0":"v","l":"el"}}}}}},"t":{"0":"l","l":"join","v":{"0":"f","l":"strings","b":{"0":"f","l":"separator","b":{"0":"a","f":{"0":"v","l":"concat"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"v","l":"list"}},"a":{"0":"v","l":"strings"}},"a":{"0":"v","l":"separator"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"append"},"a":{"0":"v","l":"append"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"concat"},"a":{"0":"v","l":"concat"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"join"},"a":{"0":"v","l":"join"}},"a":{"0":"u"}}}}}}},"t":{"0":"l","l":"logs","v":{"0":"l","l":"log","v":{"0":"f","l":"term","b":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"v","l":"term"}}},"t":{"0":"l","l":"capture","v":{"0":"l","l":"handler","v":{"0":"f","l":"message","b":{"0":"f","l":"k","b":{"0":"l","l":"inner","v":{"0":"a","f":{"0":"v","l":"k"},"a":{"0":"u"}},"t":{"0":"a","f":{"0":"a","f":{"0":"o","l":"logs"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"message"}},"a":{"0":"a","f":{"0":"g","l":"logs"},"a":{"0":"v","l":"inner"}}}},"a":{"0":"v","l":"inner"}}}}},"t":{"0":"f","l":"run","b":{"0":"a","f":{"0":"a","f":{"0":"h","l":"Log"},"a":{"0":"v","l":"handler"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"return","v":{"0":"a","f":{"0":"v","l":"run"},"a":{"0":"u"}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"return"},"a":{"0":"v","l":"return"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"logs"},"a":{"0":"ta"}},"a":{"0":"u"}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"log"},"a":{"0":"v","l":"log"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"capture"},"a":{"0":"v","l":"capture"}},"a":{"0":"u"}}}}},"t":{"0":"l","l":"modules","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"boolean"},"a":{"0":"v","l":"boolean"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"result"},"a":{"0":"v","l":"result"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"list"},"a":{"0":"v","l":"list"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"integer"},"a":{"0":"v","l":"integer"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"string"},"a":{"0":"v","l":"string"}},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"modules","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"logs"},"a":{"0":"v","l":"logs"}},"a":{"0":"v","l":"modules"}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"equal"},"a":{"0":"v","l":"equal"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"debug"},"a":{"0":"v","l":"debug"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"fix"},"a":{"0":"v","l":"fix"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"capture"},"a":{"0":"v","l":"capture"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"serialize"},"a":{"0":"v","l":"serialize"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"encode_uri"},"a":{"0":"v","l":"encode_uri"}},"a":{"0":"v","l":"modules"}}}}}}}}}}}}}}}}}}}}},"t":{"0":"l","l":"should","v":{"0":"l","l":"equal","v":{"0":"f","l":"expected","b":{"0":"f","l":"given","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"u"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"l","l":"failure","v":{"0":"a","f":{"0":"t","l":"NotEqual"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"given"},"a":{"0":"v","l":"given"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"expected"},"a":{"0":"v","l":"expected"}},"a":{"0":"u"}}}},"t":{"0":"a","f":{"0":"p","l":"Fail"},"a":{"0":"v","l":"failure"}}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"expected"}},"a":{"0":"v","l":"given"}}}}},"t":{"0":"l","l":"be","v":{"0":"f","l":"match","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"match"},"a":{"0":"f","l":"value","b":{"0":"v","l":"value"}}},"a":{"0":"f","l":"other","b":{"0":"a","f":{"0":"p","l":"Abort"},"a":{"0":"s","v":"some other value"}}}}},"t":{"0":"l","l":"to_string","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"NotEqual"},"a":{"0":"f","l":"fail","b":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"expected: "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"debug"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"expected"},"a":{"0":"v","l":"fail"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" given: "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"debug"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"given"},"a":{"0":"v","l":"fail"}}}},"a":{"0":"ta"}}}}}}}},"a":{"0":"n"}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"equal"},"a":{"0":"v","l":"equal"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"be"},"a":{"0":"v","l":"be"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"to_string"},"a":{"0":"v","l":"to_string"}},"a":{"0":"u"}}}}}}},"t":{"0":"l","l":"legit","v":{"0":"l","l":"test","v":{"0":"f","l":"name","b":{"0":"f","l":"exec","b":{"0":"a","f":{"0":"a","f":{"0":"e","l":"exec"},"a":{"0":"v","l":"exec"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"v","l":"name"}},"a":{"0":"u"}}}}},"t":{"0":"l","l":"run_test","v":{"0":"f","l":"f","b":{"0":"a","f":{"0":"a","f":{"0":"h","l":"Fail"},"a":{"0":"f","l":"failure","b":{"0":"f","l":"_kont","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"v","l":"failure"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"a","f":{"0":"v","l":"f"},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"run","v":{"0":"f","l":"tests","b":{"0":"l","l":"initial","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"fails"},"a":{"0":"i","v":0}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"passes"},"a":{"0":"i","v":0}},"a":{"0":"u"}}},"t":{"0":"l","l":"acc","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fold"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"tests"}},"a":{"0":"v","l":"initial"}},"a":{"0":"f","l":"t","b":{"0":"f","l":"acc","b":{"0":"l","l":"result","v":{"0":"a","f":{"0":"v","l":"run_test"},"a":{"0":"a","f":{"0":"g","l":"exec"},"a":{"0":"v","l":"t"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"failure","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"❌ "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"name"},"a":{"0":"v","l":"t"}}},"a":{"0":"ta"}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"v","l":"should"}},"a":{"0":"v","l":"failure"}}},"t":{"0":"l","l":"fails","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"i","v":1}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"o","l":"fails"},"a":{"0":"v","l":"fails"}},"a":{"0":"v","l":"acc"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"_","b":{"0":"l","l":"passes","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"i","v":1}},"a":{"0":"a","f":{"0":"g","l":"passes"},"a":{"0":"v","l":"acc"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"o","l":"passes"},"a":{"0":"v","l":"passes"}},"a":{"0":"v","l":"acc"}}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"result"}}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"passes"},"a":{"0":"v","l":"acc"}}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" tests, "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" failures."}},"a":{"0":"ta"}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"i","v":0}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"i","v":-1}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}},"a":{"0":"i","v":0}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"run"},"a":{"0":"v","l":"run"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"test"},"a":{"0":"v","l":"test"}},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"std_test","v":{"0":"l","l":"t","v":{"0":"a","f":{"0":"g","l":"test"},"a":{"0":"v","l":"legit"}},"t":{"0":"l","l":"async_log","v":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"async log"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"captured","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"capture"},"a":{"0":"a","f":{"0":"g","l":"logs"},"a":{"0":"v","l":"std"}}},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"abc"}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Await"},"a":{"0":"a","f":{"0":"p","l":"Wait"},"a":{"0":"i","v":100}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"xyz"}},"t":{"0":"i","v":10}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"abc"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"xyz"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"g","l":"logs"},"a":{"0":"v","l":"captured"}}}}}},"t":{"0":"l","l":"_","v":{"0":"s","v":"todo we should have the same magic checking for catching effects"},"t":{"0":"l","l":"match_variant","v":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"match variant"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"term","v":{"0":"a","f":{"0":"t","l":"Some"},"a":{"0":"i","v":5}},"t":{"0":"l","l":"value","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"be"},"a":{"0":"v","l":"should"}},"a":{"0":"m","l":"Some"}},"a":{"0":"v","l":"term"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"i","v":5}},"a":{"0":"v","l":"value"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"`and`"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"a","f":{"0":"t","l":"True"},"a":{"0":"u"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"and"},"a":{"0":"a","f":{"0":"g","l":"boolean"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"t","l":"True"},"a":{"0":"u"}}},"a":{"0":"a","f":{"0":"t","l":"True"},"a":{"0":"u"}}}},"t":{"0":"u"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"`reverse`"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"i","v":2}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"i","v":1}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"i","v":1}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"i","v":2}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"ta"}},"a":{"0":"ta"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"`logs.capture`"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"captured","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"capture"},"a":{"0":"a","f":{"0":"g","l":"logs"},"a":{"0":"v","l":"std"}}},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"log"},"a":{"0":"a","f":{"0":"g","l":"logs"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"abc"}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"xyz"}},"t":{"0":"i","v":10}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"abc"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"xyz"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"g","l":"logs"},"a":{"0":"v","l":"captured"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"async_log"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"match_variant"}},"a":{"0":"ta"}}}}}}}}}},"t":{"0":"l","l":"expect","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"value","b":{"0":"v","l":"value"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"reason","b":{"0":"a","f":{"0":"p","l":"Error"},"a":{"0":"v","l":"reason"}}}},"a":{"0":"n"}}},"t":{"0":"l","l":"eygir","v":{"0":"l","l":"exp","v":{"0":"l","l":"variable","v":{"0":"t","l":"Variable"},"t":{"0":"l","l":"lambda","v":{"0":"t","l":"Lambda"},"t":{"0":"l","l":"apply","v":{"0":"a","f":{"0":"t","l":"Apply"},"a":{"0":"u"}},"t":{"0":"l","l":"let","v":{"0":"t","l":"Let"},"t":{"0":"l","l":"integer","v":{"0":"t","l":"Integer"},"t":{"0":"l","l":"string","v":{"0":"t","l":"Binary"},"t":{"0":"l","l":"tail","v":{"0":"a","f":{"0":"t","l":"Tail"},"a":{"0":"u"}},"t":{"0":"l","l":"cons","v":{"0":"a","f":{"0":"t","l":"Cons"},"a":{"0":"u"}},"t":{"0":"l","l":"empty","v":{"0":"a","f":{"0":"t","l":"Empty"},"a":{"0":"u"}},"t":{"0":"l","l":"extend","v":{"0":"t","l":"Extend"},"t":{"0":"l","l":"select","v":{"0":"t","l":"Select"},"t":{"0":"l","l":"overwrite","v":{"0":"t","l":"Overwrite"},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"variable"},"a":{"0":"v","l":"variable"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"lambda"},"a":{"0":"v","l":"lambda"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"apply"},"a":{"0":"v","l":"apply"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"let"},"a":{"0":"v","l":"let"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"integer"},"a":{"0":"v","l":"integer"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"tail"},"a":{"0":"v","l":"tail"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"cons"},"a":{"0":"v","l":"cons"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"string"},"a":{"0":"v","l":"string"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"empty"},"a":{"0":"v","l":"empty"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"extend"},"a":{"0":"v","l":"extend"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"select"},"a":{"0":"v","l":"select"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"overwrite"},"a":{"0":"v","l":"overwrite"}},"a":{"0":"u"}}}}}}}}}}}}}}}}}}}}}}}}},"t":{"0":"l","l":"render","v":{"0":"l","l":"expression","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"self","b":{"0":"f","l":"br","b":{"0":"f","l":"source","b":{"0":"l","l":"done","v":{"0":"f","l":"text","b":{"0":"f","l":"rest","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"text"},"a":{"0":"v","l":"text"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"rest"},"a":{"0":"v","l":"rest"}},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"then","v":{"0":"f","l":"renderer","b":{"0":"f","l":"then","b":{"0":"f","l":"rest","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"rendered","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"g","l":"text"},"a":{"0":"v","l":"rendered"}}},"a":{"0":"a","f":{"0":"g","l":"rest"},"a":{"0":"v","l":"rendered"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"reason","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"v","l":"reason"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"renderer"},"a":{"0":"v","l":"rest"}}}}}},"t":{"0":"l","l":"block","v":{"0":"f","l":"br","b":{"0":"f","l":"source","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Let"},"a":{"0":"f","l":"_","b":{"0":"l","l":"br_inner","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"br"}},"a":{"0":"s","v":" "}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"br_inner"}}},"a":{"0":"f","l":"value","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"{"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"br_inner"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"value"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"br"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"}"}},"a":{"0":"ta"}}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"debug"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"parts"}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"br"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"reason","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"v","l":"reason"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}},"t":{"0":"l","l":"spread","v":{"0":"f","l":"reversed","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"l","l":"tail","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":".."}},"a":{"0":"v","l":"tail"}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}}}},"t":{"0":"l","l":"gather_elements","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Tail"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Cons"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}}}},"t":{"0":"l","l":"gather_extend","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Extend"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Empty"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}}}},"t":{"0":"l","l":"gather_overwrite","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Empty"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Overwrite"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}}}},"t":{"0":"l","l":"gather_branches","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"br","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"NoCases"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Case"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"v","l":"br"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}}}}},"t":{"0":"l","l":"exp","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Variable"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"label"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Lambda"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"body","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" -> "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"body"}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"f","l":"source","b":{"0":"l","l":"default","v":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"func","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"arg","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"func"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"("}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"arg"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":")"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Extend"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"s","v":"{"},"t":{"0":"l","l":"post","v":{"0":"s","v":"}"},"t":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"gather_extend"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"s","v":", "}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Overwrite"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"s","v":"{"},"t":{"0":"l","l":"post","v":{"0":"s","v":"}"},"t":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"gather_overwrite"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"s","v":", "}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Case"},"a":{"0":"f","l":"label","b":{"0":"l","l":"br_inner","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"br"}},"a":{"0":"s","v":" "}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br_inner"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"match {"}},"a":{"0":"v","l":"br_inner"}},"t":{"0":"l","l":"post","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"br"}},"a":{"0":"s","v":"}"}},"t":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"gather_branches"},"a":{"0":"v","l":"br_inner"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"v","l":"br_inner"}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Cons"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"s","v":"["},"t":{"0":"l","l":"post","v":{"0":"s","v":"]"},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"gather_elements"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"s","v":", "}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Select"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"arg","b":{"0":"l","l":"rendered","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"arg"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"."}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"rendered"}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Let"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"value","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"rest_or_then","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"let "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" = "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"value"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"br"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"rest_or_then"}},"a":{"0":"ta"}}}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Integer"},"a":{"0":"f","l":"value","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"value"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Binary"},"a":{"0":"f","l":"value","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"\""}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"value"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"\""}},"a":{"0":"ta"}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Tail"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"[]"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Cons"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"cons"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Vacant"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"vacant"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Empty"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"{}"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Extend"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"+"}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Select"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"."}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Overwrite"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":":="}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Tag"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"label"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Case"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"match "}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"NoCases"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"--- no cases ---"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Perform"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"perform "}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Handle"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"handle "}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Builtin"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"TODO this shouldn't really be here"}}}},"a":{"0":"n"}}}}}}}}}}}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"exp"},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}}}}}}}}}}}}},"t":{"0":"a","f":{"0":"v","l":"expression"},"a":{"0":"s","v":"\n"}}},"t":{"0":"l","l":"t","v":{"0":"a","f":{"0":"g","l":"test"},"a":{"0":"v","l":"legit"}},"t":{"0":"l","l":"should_render","v":{"0":"f","l":"output","b":{"0":"f","l":"source","b":{"0":"l","l":"rendered","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"be"},"a":{"0":"v","l":"should"}},"a":{"0":"m","l":"Ok"}},"a":{"0":"a","f":{"0":"v","l":"render"},"a":{"0":"v","l":"source"}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"ta"}},"a":{"0":"a","f":{"0":"g","l":"rest"},"a":{"0":"v","l":"rendered"}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"v","l":"output"}},"a":{"0":"a","f":{"0":"g","l":"text"},"a":{"0":"v","l":"rendered"}}},"t":{"0":"u"}}}}}},"t":{"0":"l","l":"tests","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"empty"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"be"},"a":{"0":"v","l":"should"}},"a":{"0":"m","l":"Error"}},"a":{"0":"a","f":{"0":"v","l":"render"},"a":{"0":"ta"}}},"t":{"0":"u"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"variable"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"lambda"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"lambda"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"ta"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x -> 2"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"apply"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x(2)"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"let"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"let x = 2\nx"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"integer"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":5}}},"a":{"0":"ta"}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"5"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"string"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"hello"}}},"a":{"0":"ta"}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"\"hello\""}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"multiline lambda"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"lambda"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x -> {\n let y = x\n y\n}"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"multiline let"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"let x = {\n let y = 1\n y\n}\nx"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"extend list"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"exp"}}},"a":{"0":"ta"}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"[1, 2]"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"open list"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"[1, ..x]"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"open list fn application"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"ta"}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"[1, ..x(y)]"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"extend record"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"extend"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"foo"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"extend"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"bar"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"empty"},"a":{"0":"v","l":"exp"}}},"a":{"0":"ta"}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"{foo: 1, bar: 2}"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"select field from record"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"select"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"bar"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"select"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"foo"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x.foo.bar"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"ta"}}}}}}}}}}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"render"},"a":{"0":"v","l":"render"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"tests"},"a":{"0":"v","l":"tests"}},"a":{"0":"u"}}}}}}}},"t":{"0":"l","l":"html","v":{"0":"l","l":"el","v":{"0":"f","l":"tag","b":{"0":"f","l":"attrib","b":{"0":"f","l":"children","b":{"0":"l","l":"close","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":""}},"a":{"0":"ta"}}}}},"t":{"0":"l","l":"attributes","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fold"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"attrib"}},"a":{"0":"s","v":""}},"a":{"0":"f","l":"attribute","b":{"0":"f","l":"buffer","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"name"},"a":{"0":"v","l":"attribute"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"=\""}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"value"},"a":{"0":"v","l":"attribute"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"\""}},"a":{"0":"ta"}}}}}},"t":{"0":"l","l":"str","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"buffer"}},"a":{"0":"v","l":"str"}}}}}}},"t":{"0":"l","l":"tag_attributes","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tag"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"attributes"}},"a":{"0":"ta"}}}}},"t":{"0":"l","l":"open","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"<"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tag_attributes"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":">"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"open"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"children"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"close"}},"a":{"0":"ta"}}}}}}}}}}}},"t":{"0":"l","l":"attribute","v":{"0":"f","l":"name","b":{"0":"f","l":"value","b":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"v","l":"name"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"value"},"a":{"0":"v","l":"value"}},"a":{"0":"u"}}}}},"t":{"0":"l","l":"classes","v":{"0":"f","l":"classes","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"attribute"},"a":{"0":"s","v":"class"}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"join"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"classes"}},"a":{"0":"s","v":" "}}}},"t":{"0":"l","l":"a","v":{"0":"f","l":"href","b":{"0":"f","l":"extra","b":{"0":"f","l":"children","b":{"0":"l","l":"attributes","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"attribute"},"a":{"0":"s","v":"href"}},"a":{"0":"v","l":"href"}}},"a":{"0":"v","l":"extra"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"el"},"a":{"0":"s","v":"a"}},"a":{"0":"v","l":"attributes"}},"a":{"0":"v","l":"children"}}}}}},"t":{"0":"l","l":"basic","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"el"},"a":{"0":"v","l":"el"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"attribute"},"a":{"0":"v","l":"attribute"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"classes"},"a":{"0":"v","l":"classes"}},"a":{"0":"u"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"div"},"a":{"0":"a","f":{"0":"v","l":"el"},"a":{"0":"s","v":"div"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"h1"},"a":{"0":"a","f":{"0":"v","l":"el"},"a":{"0":"s","v":"h1"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"p"},"a":{"0":"a","f":{"0":"v","l":"el"},"a":{"0":"s","v":"p"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"span"},"a":{"0":"a","f":{"0":"v","l":"el"},"a":{"0":"s","v":"span"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"a"},"a":{"0":"v","l":"a"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"script"},"a":{"0":"a","f":{"0":"v","l":"el"},"a":{"0":"s","v":"script"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"button"},"a":{"0":"a","f":{"0":"v","l":"el"},"a":{"0":"s","v":"button"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"pre"},"a":{"0":"a","f":{"0":"v","l":"el"},"a":{"0":"s","v":"pre"}}},"a":{"0":"v","l":"basic"}}}}}}}}}}}}}},"t":{"0":"l","l":"layout","v":{"0":"l","l":"head","v":{"0":"s","v":"\n\n \n \n \n \n \n"},"t":{"0":"l","l":"attribute","v":{"0":"f","l":"name","b":{"0":"f","l":"value","b":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"v","l":"name"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"value"},"a":{"0":"v","l":"value"}},"a":{"0":"u"}}}}},"t":{"0":"l","l":"classes","v":{"0":"f","l":"classes","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"attribute"},"a":{"0":"s","v":"class"}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"join"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"classes"}},"a":{"0":"s","v":" "}}}},"t":{"0":"l","l":"vstack","v":{"0":"f","l":"extra","b":{"0":"f","l":"children","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"div"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"classes"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"vstack"}},"a":{"0":"v","l":"extra"}}}},"a":{"0":"ta"}}},"a":{"0":"v","l":"children"}}}},"t":{"0":"l","l":"hstack","v":{"0":"f","l":"children","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"div"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"s","v":"class"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"value"},"a":{"0":"s","v":"hstack"}},"a":{"0":"u"}}}},"a":{"0":"ta"}}},"a":{"0":"v","l":"children"}}},"t":{"0":"l","l":"expand","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"div"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"s","v":"class"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"value"},"a":{"0":"s","v":"expand"}},"a":{"0":"u"}}}},"a":{"0":"ta"}}},"a":{"0":"ta"}},"t":{"0":"l","l":"page","v":{"0":"f","l":"children","b":{"0":"l","l":"body","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"el"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"body"}},"a":{"0":"ta"}},"a":{"0":"v","l":"children"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"head"}},"a":{"0":"v","l":"body"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"hstack"},"a":{"0":"v","l":"hstack"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"vstack"},"a":{"0":"v","l":"vstack"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"expand"},"a":{"0":"v","l":"expand"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"page"},"a":{"0":"v","l":"page"}},"a":{"0":"u"}}}}}}}}}}}},"t":{"0":"l","l":"cli","v":{"0":"f","l":"args","b":{"0":"l","l":"sum","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"self","b":{"0":"f","l":"total","b":{"0":"f","l":"items","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"split","b":{"0":"l","l":"total","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"total"}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"split"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"total"}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"split"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"v","l":"total"}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}}}}}}},"a":{"0":"i","v":0}},"t":{"0":"l","l":"tests","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"std_test"}},"a":{"0":"a","f":{"0":"g","l":"tests"},"a":{"0":"v","l":"eygir"}}},"t":{"0":"l","l":"test","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"s","v":"test"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"exec"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"g","l":"run"},"a":{"0":"v","l":"legit"}},"a":{"0":"v","l":"tests"}}}},"a":{"0":"u"}}},"t":{"0":"l","l":"tasks","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"test"}},"a":{"0":"ta"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"l","l":"predicate","v":{"0":"f","l":"pair","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}},"a":{"0":"a","f":{"0":"g","l":"name"},"a":{"0":"v","l":"pair"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"task","b":{"0":"a","f":{"0":"a","f":{"0":"g","l":"exec"},"a":{"0":"v","l":"task"}},"a":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"No matching task"}},"t":{"0":"i","v":-1}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"find"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"predicate"}},"a":{"0":"v","l":"tasks"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"No cli task specified"}},"t":{"0":"i","v":-1}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"args"}}}}}}}},"t":{"0":"l","l":"web","v":{"0":"f","l":"req","b":{"0":"l","l":"response","v":{"0":"l","l":"ok","v":{"0":"f","l":"body","b":{"0":"a","f":{"0":"a","f":{"0":"e","l":"body"},"a":{"0":"v","l":"body"}},"a":{"0":"u"}}},"t":{"0":"l","l":"app","v":{"0":"f","l":"client","b":{"0":"l","l":"mount","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"div"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"attribute"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"id"}},"a":{"0":"s","v":"app"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"screen"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}}},"a":{"0":"ta"}},"t":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"script"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"attribute"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"type"}},"a":{"0":"s","v":"application/eygir"}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"encode_uri"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"serialize"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"client"}}}},"a":{"0":"ta"}}},"t":{"0":"l","l":"rendered","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"page"},"a":{"0":"v","l":"layout"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"mount"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"source"}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"v","l":"ok"},"a":{"0":"v","l":"rendered"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"ok"},"a":{"0":"v","l":"ok"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"app"},"a":{"0":"v","l":"app"}},"a":{"0":"u"}}}}},"t":{"0":"l","l":"language","v":{"0":"l","l":"view","v":{"0":"l","l":"p","v":{"0":"f","l":"content","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"p"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"max-w-2xl mx-auto"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"v","l":"content"}}},"t":{"0":"l","l":"h2","v":{"0":"f","l":"content","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"el"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"h2"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"text-lg max-w-2xl mx-auto"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"content"}},"a":{"0":"ta"}}}},"t":{"0":"l","l":"link","v":{"0":"f","l":"location","b":{"0":"f","l":"text","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"a"},"a":{"0":"v","l":"html"}},"a":{"0":"v","l":"location"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"text-blue-500 underline"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"text"}},"a":{"0":"ta"}}}}},"t":{"0":"l","l":"code","v":{"0":"f","l":"term","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"capture"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"term"}},"t":{"0":"l","l":"string","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"return","b":{"0":"a","f":{"0":"g","l":"text"},"a":{"0":"v","l":"return"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"s","v":"Error!"}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"render"},"a":{"0":"v","l":"eygir"}},"a":{"0":"v","l":"source"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pre"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"bg-gray-200"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"string"}},"a":{"0":"ta"}}}}}},"t":{"0":"l","l":"doc","v":{"0":"f","l":"path","b":{"0":"f","l":"sections","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"div"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"loose doc"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"v","l":"sections"}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"path"},"a":{"0":"v","l":"path"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"content"},"a":{"0":"v","l":"content"}},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"_","v":{"0":"s","v":"move content to content section"},"t":{"0":"l","l":"docs","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"doc"},"a":{"0":"s","v":"/"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"el"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"h1"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"text-2xl"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Language"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"link"},"a":{"0":"s","v":"/effects"}},"a":{"0":"s","v":"Effects"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"h2"},"a":{"0":"s","v":"Introduction"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"This language is an experiment in making a highly portable functional language. The syntax shown below only illustrates the features of the language, it is only one of many possible projections to view a program. Creating programs is not done by editing text files instead a structured editor is needed."}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"The language has both a compiler and interpreter, either or even both can be used in one program.\nAnonymous functions can be captured, serialised and sent to other computers. \nFor example a client and server app can be written as one function."}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"html","v":{"0":"z","c":""},"t":{"0":"f","l":"request","b":{"0":"f","l":"client","b":{"0":"l","l":"method","v":{"0":"a","f":{"0":"g","l":"method"},"a":{"0":"v","l":"request"}},"t":{"0":"l","l":"handle_click","v":{"0":"a","f":{"0":"p","l":"Alert"},"a":{"0":"v","l":"method"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"button"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"click"}},"a":{"0":"v","l":"handle_click"}}}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"A fully exhaustive type checker exists for the language. i.e. if the checks pass it is guaranteed not to crash.\nThis can be optionally run, it's not worth type checking a build script you get the same error anyway.\nIt's possible to type check a single function."}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Because the type system is complete and structural no type ever needs to be declared up front and no annotation is required, in fact annotation is not supported in the language.\nThis choice is to make programmers never need to think about types.\nType annotations are possible in the editor but they are only a debug tool and not committed to the source."}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"The type system contains extensible records and unions as well as an algebraic effect system. \nThese three components are all built on row types, using the same approach for each keeps the implementation simple.\n"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"All of the goals of the language are achieved by having the Abstract Syntax Tree (AST) of the language be the public interface and keeping that interface as small as possible.\nThere are currently only 19 different node types that make up the AST."}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"string","v":{"0":"z","c":"std.string"},"t":{"0":"l","l":"welcome","v":{"0":"f","l":"person","b":{"0":"l","l":"message","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"v","l":"string"}},"a":{"0":"s","v":"Hello "}},"a":{"0":"v","l":"person"}},"t":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"v","l":"message"}}}},"t":{"0":"a","f":{"0":"v","l":"welcome"},"a":{"0":"s","v":"Alan"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"h2"},"a":{"0":"s","v":"literal"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"i","v":{"0":"i","v":100},"t":{"0":"l","l":"s","v":{"0":"s","v":"hello"},"t":{"0":"l","l":"list","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"i","v":1}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"i","v":2}},"a":{"0":"ta"}}},"t":{"0":"u"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"h2"},"a":{"0":"s","v":"functions"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"All functions are anonymous.\nFunctions are first class an can be returned by other functions.\nThere is no support for multi-argument functions, to accept multiple arguments a function must return a function, and is therefore automatically curried"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"single","v":{"0":"f","l":"x","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"x"}},"a":{"0":"ta"}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"v","l":"single"},"a":{"0":"i","v":10}},"t":{"0":"l","l":"double","v":{"0":"f","l":"x","b":{"0":"f","l":"y","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"x"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"y"}},"a":{"0":"ta"}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"v","l":"double"},"a":{"0":"i","v":1}},"a":{"0":"i","v":2}},"t":{"0":"l","l":"start_with_one","v":{"0":"a","f":{"0":"v","l":"double"},"a":{"0":"i","v":1}},"t":{"0":"a","f":{"0":"v","l":"start_with_one"},"a":{"0":"i","v":7}}}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"h2"},"a":{"0":"s","v":"Let bindings"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"A value can be given a name using let. \nNames can be reused by later let bindings, but the values contained are immutable, meaning the values themselves cannot be changed."}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"a","v":{"0":"i","v":1},"t":{"0":"l","l":"b","v":{"0":"v","l":"a"},"t":{"0":"l","l":"a","v":{"0":"i","v":2},"t":{"0":"v","l":"b"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"h2"},"a":{"0":"s","v":"Records"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Records are used to store multiple values with a name. \nTyping is structural and so there is no need to define types a head of time.\nBecause typing is structural any record with the fields required by a function can be passed to that function"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"a","b":{"0":"l","l":"alice","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"s","v":"Alice"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"age"},"a":{"0":"i","v":10}},"a":{"0":"u"}}},"t":{"0":"l","l":"name","v":{"0":"a","f":{"0":"g","l":"name"},"a":{"0":"v","l":"alice"}},"t":{"0":"l","l":"alice","v":{"0":"a","f":{"0":"a","f":{"0":"o","l":"age"},"a":{"0":"i","v":11}},"a":{"0":"v","l":"alice"}},"t":{"0":"l","l":"age","v":{"0":"a","f":{"0":"g","l":"age"},"a":{"0":"v","l":"alice"}},"t":{"0":"l","l":"get_name","v":{"0":"f","l":"user","b":{"0":"a","f":{"0":"g","l":"name"},"a":{"0":"v","l":"user"}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"v","l":"get_name"},"a":{"0":"v","l":"alice"}},"t":{"0":"l","l":"bob","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"s","v":"Bob"}},"a":{"0":"u"}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"v","l":"get_name"},"a":{"0":"v","l":"bob"}},"t":{"0":"u"}}}}}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"h2"},"a":{"0":"s","v":"Unions"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Unions are tagged unions, they are extensible. Case statements are first class i.e. it is possible to compose them."}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"ok","v":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"i","v":5}},"t":{"0":"l","l":"unwrap","v":{"0":"f","l":"fallback","b":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"value","b":{"0":"v","l":"value"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"v","l":"fallback"}}},"a":{"0":"n"}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"v","l":"unwrap"},"a":{"0":"i","v":0}},"a":{"0":"v","l":"ok"}},"t":{"0":"u"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"matches can be open"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"multiline","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Let"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"True"},"a":{"0":"u"}}}},"a":{"0":"f","l":"_other","b":{"0":"a","f":{"0":"t","l":"False"},"a":{"0":"u"}}}},"t":{"0":"u"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"matches can be composed\n"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"pets","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Cat"},"a":{"0":"f","l":"_","b":{"0":"s","v":"felix"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Dog"},"a":{"0":"f","l":"_","b":{"0":"s","v":"fido"}}},"a":{"0":"n"}}},"t":{"0":"l","l":"animals","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Platypus"},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"special pet"}},"t":{"0":"s","v":"Alan"}}}},"a":{"0":"v","l":"pets"}},"t":{"0":"u"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":""}},"a":{"0":"ta"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"doc"},"a":{"0":"s","v":"/effects"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"el"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"h1"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"text-2xl"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Effects"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"h2"},"a":{"0":"s","v":"Choose"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"A random choice. \nImplementations can be handled to always return a fixed value or from a list or all.\n\nThe value passed when invoking the Choose effect is unit i.e. an empty record as behaviour is not defined by the caller of choose"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"choose","v":{"0":"f","l":"_","b":{"0":"a","f":{"0":"p","l":"Choose"},"a":{"0":"u"}}},"t":{"0":"l","l":"always","v":{"0":"f","l":"value","b":{"0":"a","f":{"0":"h","l":"Choose"},"a":{"0":"f","l":"_arg","b":{"0":"f","l":"resume","b":{"0":"a","f":{"0":"v","l":"resume"},"a":{"0":"v","l":"value"}}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"v","l":"always"},"a":{"0":"a","f":{"0":"t","l":"True"},"a":{"0":"u"}}},"a":{"0":"f","l":"_","b":{"0":"l","l":"first","v":{"0":"a","f":{"0":"v","l":"choose"},"a":{"0":"u"}},"t":{"0":"l","l":"second","v":{"0":"a","f":{"0":"v","l":"choose"},"a":{"0":"u"}},"t":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"first"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"second"}},"a":{"0":"ta"}}}}}}},"t":{"0":"l","l":"_","v":{"0":"s","v":"[True, True]"},"t":{"0":"z","c":""}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"choose both by resuming the exec function multiple times\n\nNeed to wrap the exec function to return a list of it's value so that it can be concatenated in the handler"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"concat","v":{"0":"z","c":""},"t":{"0":"l","l":"choose","v":{"0":"f","l":"_","b":{"0":"a","f":{"0":"p","l":"Choose"},"a":{"0":"u"}}},"t":{"0":"l","l":"both","v":{"0":"f","l":"exec","b":{"0":"l","l":"handler","v":{"0":"f","l":"_arg","b":{"0":"f","l":"resume","b":{"0":"l","l":"first","v":{"0":"a","f":{"0":"v","l":"resume"},"a":{"0":"a","f":{"0":"t","l":"True"},"a":{"0":"u"}}},"t":{"0":"l","l":"second","v":{"0":"a","f":{"0":"v","l":"resume"},"a":{"0":"a","f":{"0":"t","l":"False"},"a":{"0":"u"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"concat"},"a":{"0":"v","l":"first"}},"a":{"0":"v","l":"second"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"h","l":"Choose"},"a":{"0":"v","l":"handler"}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"exec"},"a":{"0":"u"}}},"a":{"0":"ta"}}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"v","l":"both"},"a":{"0":"f","l":"_","b":{"0":"l","l":"first","v":{"0":"a","f":{"0":"v","l":"choose"},"a":{"0":"u"}},"t":{"0":"l","l":"second","v":{"0":"a","f":{"0":"v","l":"choose"},"a":{"0":"u"}},"t":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"first"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"second"}},"a":{"0":"ta"}}}}}}},"t":{"0":"s","v":"[[True, True], [True, False], [False, True], [False, False]"}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"h2"},"a":{"0":"s","v":"Fail"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Short circuit execution with a failure.\n\nI'm not sure of naming here. Can I use Error for the union type i.e. in Ok | Error at the same time as it for the Effect"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"result","v":{"0":"l","l":"ok","v":{"0":"t","l":"Ok"},"t":{"0":"l","l":"error","v":{"0":"t","l":"Error"},"t":{"0":"l","l":"fail","v":{"0":"p","l":"Error"},"t":{"0":"l","l":"expect","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"value","b":{"0":"v","l":"value"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"reason","b":{"0":"a","f":{"0":"v","l":"fail"},"a":{"0":"v","l":"reason"}}}},"a":{"0":"z","c":""}}},"t":{"0":"l","l":"rescue","v":{"0":"f","l":"exec","b":{"0":"l","l":"handler","v":{"0":"f","l":"reason","b":{"0":"f","l":"_resume","b":{"0":"a","f":{"0":"v","l":"error"},"a":{"0":"v","l":"reason"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"h","l":"Error"},"a":{"0":"v","l":"handler"}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"ok"},"a":{"0":"a","f":{"0":"v","l":"exec"},"a":{"0":"u"}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"fail"},"a":{"0":"v","l":"fail"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"expect"},"a":{"0":"v","l":"expect"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"rescue"},"a":{"0":"v","l":"rescue"}},"a":{"0":"u"}}}}}}}}},"t":{"0":"z","c":""}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"h2"},"a":{"0":"s","v":"Log"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Logs are an effect\n"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"a","f":{"0":"g","l":"logs"},"a":{"0":"v","l":"std"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"h2"},"a":{"0":"s","v":"Async Await"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Both async and await are implemented as effects and can be caught for test purposes"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":""}},"a":{"0":"ta"}}}}}}}}}}}}}}}}}},"a":{"0":"ta"}}},"t":{"0":"l","l":"render","v":{"0":"f","l":"path","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"v","l":"path"}},"t":{"0":"l","l":"page","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"result","b":{"0":"a","f":{"0":"g","l":"content"},"a":{"0":"v","l":"result"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"h1"},"a":{"0":"v","l":"html"}},"a":{"0":"ta"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"not found "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"path"}},"a":{"0":"ta"}}}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"find"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"f","l":"d","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"path"},"a":{"0":"v","l":"d"}}},"a":{"0":"v","l":"path"}}}},"a":{"0":"v","l":"docs"}}},"t":{"0":"l","l":"vstack","v":{"0":"a","f":{"0":"g","l":"vstack"},"a":{"0":"v","l":"layout"}},"t":{"0":"l","l":"page","v":{"0":"a","f":{"0":"a","f":{"0":"v","l":"vstack"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"bg-gray-50 wrap"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"page"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"span"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"expand"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"el"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"footer"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"bg-gray-800"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"cover"}},"a":{"0":"ta"}}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"language"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}}}},"t":{"0":"v","l":"page"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"render"},"a":{"0":"v","l":"render"}},"a":{"0":"u"}}}}}}}}}},"t":{"0":"f","l":"request","b":{"0":"a","f":{"0":"a","f":{"0":"e","l":"body"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"page"},"a":{"0":"v","l":"layout"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"render"},"a":{"0":"v","l":"view"}},"a":{"0":"a","f":{"0":"g","l":"path"},"a":{"0":"v","l":"request"}}}},"a":{"0":"ta"}}}},"a":{"0":"u"}}}},"t":{"0":"l","l":"dashboard","v":{"0":"l","l":"http","v":{"0":"l","l":"get","v":{"0":"f","l":"h","b":{"0":"f","l":"p","b":{"0":"l","l":"scheme","v":{"0":"a","f":{"0":"t","l":"HTTPS"},"a":{"0":"u"}},"t":{"0":"l","l":"port","v":{"0":"a","f":{"0":"t","l":"None"},"a":{"0":"u"}},"t":{"0":"l","l":"query","v":{"0":"a","f":{"0":"t","l":"None"},"a":{"0":"u"}},"t":{"0":"l","l":"headers","v":{"0":"ta"},"t":{"0":"l","l":"body","v":{"0":"s","v":""},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"method"},"a":{"0":"a","f":{"0":"t","l":"Get"},"a":{"0":"u"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"scheme"},"a":{"0":"v","l":"scheme"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"host"},"a":{"0":"v","l":"h"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"port"},"a":{"0":"v","l":"port"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"path"},"a":{"0":"v","l":"p"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"query"},"a":{"0":"v","l":"query"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"headers"},"a":{"0":"v","l":"headers"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"body"},"a":{"0":"v","l":"body"}},"a":{"0":"u"}}}}}}}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"get"},"a":{"0":"v","l":"get"}},"a":{"0":"u"}}},"t":{"0":"l","l":"vstack","v":{"0":"a","f":{"0":"g","l":"vstack"},"a":{"0":"v","l":"layout"}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Await"},"a":{"0":"a","f":{"0":"p","l":"Wait"},"a":{"0":"i","v":1000}}},"t":{"0":"l","l":"promise","v":{"0":"a","f":{"0":"p","l":"HTTP"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"get"},"a":{"0":"v","l":"http"}},"a":{"0":"s","v":"api.sunrise-sunset.org"}},"a":{"0":"s","v":"/json"}}},"t":{"0":"l","l":"response","v":{"0":"a","f":{"0":"p","l":"Await"},"a":{"0":"v","l":"promise"}},"t":{"0":"l","l":"client","v":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"heres the response"}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"v","l":"response"}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Listen"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"event"},"a":{"0":"s","v":"click"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"handler"},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"There was a click"}},"t":{"0":"i","v":10}}}},"a":{"0":"u"}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"v","l":"async"},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"about to inner request"}},"t":{"0":"l","l":"promise","v":{"0":"a","f":{"0":"p","l":"HTTP"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"get"},"a":{"0":"v","l":"http"}},"a":{"0":"s","v":"api.sunrise-sunset.org"}},"a":{"0":"s","v":"/json"}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"have promise"}},"t":{"0":"l","l":"response","v":{"0":"a","f":{"0":"p","l":"Await"},"a":{"0":"v","l":"promise"}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"v","l":"response"}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"inner response"}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Await"},"a":{"0":"a","f":{"0":"p","l":"Wait"},"a":{"0":"i","v":5000}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Render"},"a":{"0":"s","v":"my new page2"}},"t":{"0":"s","v":"ok in async"}}}}}}}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"abc! "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"xyz"}},"a":{"0":"ta"}}}}},"t":{"0":"l","l":"_","v":{"0":"f","l":"comment","b":{"0":"a","f":{"0":"p","l":"Alert"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"Hello "}},"a":{"0":"a","f":{"0":"g","l":"query"},"a":{"0":"v","l":"req"}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Render"},"a":{"0":"s","v":"my new page"}},"t":{"0":"s","v":"ok"}}}}}}}}},"t":{"0":"l","l":"header","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"span"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"bg-gray-300"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"cover"}},"a":{"0":"ta"}}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"header"}},"a":{"0":"ta"}}},"t":{"0":"l","l":"main","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"span"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"expand"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"hello"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"response"}},"a":{"0":"ta"}}}},"t":{"0":"l","l":"app","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"div"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"attribute"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"id"}},"a":{"0":"s","v":"app"}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"header"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"main"}},"a":{"0":"ta"}}}},"t":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"script"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"attribute"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"type"}},"a":{"0":"s","v":"application/eygir"}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"serialize"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"client"}}},"a":{"0":"ta"}}},"t":{"0":"l","l":"runner","v":{"0":"s","v":"source should go outside vstack so need to do real append of strings"},"t":{"0":"l","l":"rendered","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"page"},"a":{"0":"v","l":"layout"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"app"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"source"}},"a":{"0":"ta"}}}},"t":{"0":"f","l":"request","b":{"0":"a","f":{"0":"a","f":{"0":"e","l":"body"},"a":{"0":"v","l":"rendered"}},"a":{"0":"u"}}}}}}}}}}}}}}},"t":{"0":"l","l":"universal","v":{"0":"f","l":"request","b":{"0":"l","l":"button","v":{"0":"f","l":"on_click","b":{"0":"f","l":"extra","b":{"0":"f","l":"children","b":{"0":"l","l":"attributes","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"attribute"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"data-click"}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"encode_uri"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"serialize"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"on_click"}}}}},"a":{"0":"v","l":"extra"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"button"},"a":{"0":"v","l":"html"}},"a":{"0":"v","l":"attributes"}},"a":{"0":"v","l":"children"}}}}}},"t":{"0":"l","l":"inc","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"i","v":1}},"t":{"0":"l","l":"dec","v":{"0":"f","l":"x","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"subtract"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"x"}},"a":{"0":"i","v":1}}},"t":{"0":"l","l":"initial","v":{"0":"i","v":2},"t":{"0":"l","l":"client","v":{"0":"f","l":"_","b":{"0":"l","l":"render","v":{"0":"f","l":"state","b":{"0":"l","l":"count","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"state"}},"t":{"0":"l","l":"inc_button","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"button"},"a":{"0":"a","f":{"0":"t","l":"Inc"},"a":{"0":"u"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"p-4"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Increment"}},"a":{"0":"ta"}}},"t":{"0":"l","l":"dec_button","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"button"},"a":{"0":"a","f":{"0":"t","l":"Dec"},"a":{"0":"u"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"bg-red-500"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Decrement"}},"a":{"0":"ta"}}},"t":{"0":"l","l":"page","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"div"},"a":{"0":"v","l":"html"}},"a":{"0":"ta"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"div"},"a":{"0":"v","l":"html"}},"a":{"0":"ta"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"count"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"inc_button"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"dec_button"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"p","l":"Render"},"a":{"0":"v","l":"page"}}}}}}},"t":{"0":"l","l":"handle_click","v":{"0":"f","l":"arg","b":{"0":"f","l":"state","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"debug"},"a":{"0":"a","f":{"0":"g","l":"log"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"arg"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Inc"},"a":{"0":"f","l":"_","b":{"0":"l","l":"state","v":{"0":"a","f":{"0":"v","l":"inc"},"a":{"0":"v","l":"state"}},"t":{"0":"v","l":"state"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Dec"},"a":{"0":"f","l":"_","b":{"0":"l","l":"state","v":{"0":"a","f":{"0":"v","l":"dec"},"a":{"0":"v","l":"state"}},"t":{"0":"v","l":"state"}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"arg"}}}}},"t":{"0":"l","l":"run","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"run","b":{"0":"f","l":"state","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"v","l":"render"},"a":{"0":"v","l":"state"}},"t":{"0":"a","f":{"0":"p","l":"OnClick"},"a":{"0":"f","l":"el","b":{"0":"a","f":{"0":"v","l":"run"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"handle_click"},"a":{"0":"v","l":"el"}},"a":{"0":"v","l":"state"}}}}}}}}},"t":{"0":"a","f":{"0":"v","l":"run"},"a":{"0":"v","l":"initial"}}}}}},"t":{"0":"l","l":"app","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"div"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"attribute"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"id"}},"a":{"0":"s","v":"app"}}},"a":{"0":"ta"}}},"a":{"0":"ta"}},"t":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"script"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"attribute"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"type"}},"a":{"0":"s","v":"application/eygir"}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"serialize"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"client"}}},"a":{"0":"ta"}}},"t":{"0":"l","l":"rendered","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"page"},"a":{"0":"v","l":"layout"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"app"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"source"}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"body"},"a":{"0":"v","l":"rendered"}},"a":{"0":"u"}}}}}}}}}}},"t":{"0":"l","l":"services","v":{"0":"l","l":"at","v":{"0":"f","l":"host","b":{"0":"f","l":"handler","b":{"0":"a","f":{"0":"a","f":{"0":"e","l":"host"},"a":{"0":"v","l":"host"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"handler"},"a":{"0":"v","l":"handler"}},"a":{"0":"u"}}}}},"t":{"0":"l","l":"s","v":{"0":"ta"},"t":{"0":"l","l":"s","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"at"},"a":{"0":"s","v":"localhost:5001"}},"a":{"0":"v","l":"language"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"at"},"a":{"0":"s","v":"language.web.petersaxton.uk"}},"a":{"0":"v","l":"language"}}},"a":{"0":"v","l":"s"}}},"t":{"0":"l","l":"laura","v":{"0":"f","l":"request","b":{"0":"l","l":"picture","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"el"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"img"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"s","v":"src"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"value"},"a":{"0":"s","v":"https://upload.wikimedia.org/wikipedia/commons/thumb/5/58/Schabrackentapir_Tapirus_indicus_Tiergarten-Nuernberg-1.jpg/1200px-Schabrackentapir_Tapirus_indicus_Tiergarten-Nuernberg-1.jpg"}},"a":{"0":"u"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"go to bbbc"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}},"t":{"0":"l","l":"link","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"el"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"a"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"s","v":"href"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"value"},"a":{"0":"s","v":"https://bbc.co.uk"}},"a":{"0":"u"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"go to bbbc"}},"a":{"0":"ta"}}}},"a":{"0":"v","l":"picture"}},"t":{"0":"l","l":"panels","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"hstack"},"a":{"0":"v","l":"layout"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"p"},"a":{"0":"v","l":"html"}},"a":{"0":"ta"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"barfoo"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"expand"},"a":{"0":"v","l":"layout"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"p"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"s","v":"class"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"value"},"a":{"0":"s","v":"text-indigo-500"}},"a":{"0":"u"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"bar"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}}}},"t":{"0":"l","l":"body","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"page"},"a":{"0":"v","l":"layout"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"vstack"},"a":{"0":"v","l":"layout"}},"a":{"0":"ta"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"p"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"s","v":"class"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"value"},"a":{"0":"s","v":"bg-green-400 cover"}},"a":{"0":"u"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Valhalla"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"panels"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"expand"},"a":{"0":"v","l":"layout"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"thor rocks"}},"a":{"0":"v","l":"link"}}}}}}},"a":{"0":"ta"}}},"t":{"0":"l","l":"response","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"body"},"a":{"0":"v","l":"body"}},"a":{"0":"u"}},"t":{"0":"v","l":"response"}}}}}}},"t":{"0":"l","l":"s","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"at"},"a":{"0":"s","v":"localhost:5002"}},"a":{"0":"v","l":"laura"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"at"},"a":{"0":"s","v":"laura.web.petersaxton.uk"}},"a":{"0":"v","l":"laura"}}},"a":{"0":"v","l":"s"}}},"t":{"0":"l","l":"s","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"at"},"a":{"0":"s","v":"localhost:5003"}},"a":{"0":"v","l":"dashboard"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"at"},"a":{"0":"s","v":"dashboard.web.petersaxton.uk"}},"a":{"0":"v","l":"dashboard"}}},"a":{"0":"v","l":"s"}}},"t":{"0":"l","l":"s","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"at"},"a":{"0":"s","v":"localhost:5004"}},"a":{"0":"v","l":"universal"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"at"},"a":{"0":"s","v":"universal.web.petersaxton.uk"}},"a":{"0":"v","l":"universal"}}},"a":{"0":"v","l":"s"}}},"t":{"0":"v","l":"s"}}}}}}}},"t":{"0":"l","l":"handler","v":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"g","l":"host"},"a":{"0":"v","l":"req"}}},"t":{"0":"l","l":"lookup","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"find"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"f","l":"item","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"host"},"a":{"0":"v","l":"item"}}},"a":{"0":"a","f":{"0":"g","l":"host"},"a":{"0":"v","l":"req"}}}}},"a":{"0":"v","l":"services"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"service","b":{"0":"a","f":{"0":"g","l":"handler"},"a":{"0":"v","l":"service"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"f","l":"_request","b":{"0":"a","f":{"0":"a","f":{"0":"e","l":"body"},"a":{"0":"s","v":"No service"}},"a":{"0":"u"}}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"lookup"}}}},"t":{"0":"a","f":{"0":"v","l":"handler"},"a":{"0":"v","l":"req"}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"cli"},"a":{"0":"v","l":"cli"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"web"},"a":{"0":"v","l":"web"}},"a":{"0":"u"}}}}}}}}}}}}}} \ No newline at end of file +{"0":"l","l":"std","v":{"0":"l","l":"equal","v":{"0":"b","l":"equal"},"t":{"0":"l","l":"debug","v":{"0":"b","l":"debug"},"t":{"0":"l","l":"fix","v":{"0":"b","l":"fix"},"t":{"0":"l","l":"capture","v":{"0":"b","l":"capture"},"t":{"0":"l","l":"serialize","v":{"0":"b","l":"serialize"},"t":{"0":"l","l":"encode_uri","v":{"0":"b","l":"encode_uri"},"t":{"0":"l","l":"boolean","v":{"0":"l","l":"and","v":{"0":"f","l":"a","b":{"0":"f","l":"b","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"True"},"a":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"False"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"b"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"False"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"a"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"and"},"a":{"0":"v","l":"and"}},"a":{"0":"u"}}},"t":{"0":"l","l":"result","v":{"0":"l","l":"unwrap","v":{"0":"f","l":"default","b":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"x","b":{"0":"v","l":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"v","l":"default"}}},"a":{"0":"n"}}}},"t":{"0":"u"}},"t":{"0":"l","l":"list","v":{"0":"l","l":"pop","v":{"0":"b","l":"list_pop"},"t":{"0":"l","l":"fold","v":{"0":"b","l":"list_fold"},"t":{"0":"l","l":"head","v":{"0":"f","l":"l","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"pop"},"a":{"0":"v","l":"l"}}}},"t":{"0":"l","l":"find","v":{"0":"a","f":{"0":"v","l":"fix"},"a":{"0":"f","l":"self","b":{"0":"f","l":"predicate","b":{"0":"f","l":"list","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}},"t":{"0":"l","l":"matched","v":{"0":"a","f":{"0":"v","l":"predicate"},"a":{"0":"v","l":"item"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"v","l":"item"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"predicate"}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"matched"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"t","l":"Error"}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"pop"},"a":{"0":"v","l":"list"}}}}}}},"t":{"0":"l","l":"reverse","v":{"0":"f","l":"list","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"fold"},"a":{"0":"v","l":"list"}},"a":{"0":"ta"}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"el"}},"a":{"0":"v","l":"acc"}}}}}},"t":{"0":"l","l":"append","v":{"0":"f","l":"first","b":{"0":"f","l":"second","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"fold"},"a":{"0":"a","f":{"0":"v","l":"reverse"},"a":{"0":"v","l":"first"}}},"a":{"0":"v","l":"second"}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"el"}},"a":{"0":"v","l":"acc"}}}}}}},"t":{"0":"l","l":"intersperse","v":{"0":"f","l":"list","b":{"0":"f","l":"element","b":{"0":"l","l":"reversed","v":{"0":"a","f":{"0":"v","l":"reverse"},"a":{"0":"v","l":"list"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"fold"},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}},"a":{"0":"ta"}}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"el"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"element"}},"a":{"0":"v","l":"acc"}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"ta"}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"pop"},"a":{"0":"v","l":"reversed"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"pop"},"a":{"0":"v","l":"pop"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"fold"},"a":{"0":"v","l":"fold"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"head"},"a":{"0":"v","l":"head"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"find"},"a":{"0":"v","l":"find"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"reverse"},"a":{"0":"v","l":"reverse"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"append"},"a":{"0":"v","l":"append"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"intersperse"},"a":{"0":"v","l":"intersperse"}},"a":{"0":"u"}}}}}}}}}}}}}}},"t":{"0":"l","l":"integer","v":{"0":"l","l":"add","v":{"0":"b","l":"int_add"},"t":{"0":"l","l":"subtract","v":{"0":"b","l":"int_subtract"},"t":{"0":"l","l":"to_string","v":{"0":"b","l":"int_to_string"},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"add"},"a":{"0":"v","l":"add"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"subtract"},"a":{"0":"v","l":"subtract"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"to_string"},"a":{"0":"v","l":"to_string"}},"a":{"0":"u"}}}}}}},"t":{"0":"l","l":"string","v":{"0":"l","l":"append","v":{"0":"b","l":"string_append"},"t":{"0":"l","l":"concat","v":{"0":"f","l":"l","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fold"},"a":{"0":"v","l":"list"}},"a":{"0":"v","l":"l"}},"a":{"0":"s","v":""}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"append"},"a":{"0":"v","l":"acc"}},"a":{"0":"v","l":"el"}}}}}},"t":{"0":"l","l":"join","v":{"0":"f","l":"strings","b":{"0":"f","l":"separator","b":{"0":"a","f":{"0":"v","l":"concat"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"v","l":"list"}},"a":{"0":"v","l":"strings"}},"a":{"0":"v","l":"separator"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"append"},"a":{"0":"v","l":"append"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"concat"},"a":{"0":"v","l":"concat"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"join"},"a":{"0":"v","l":"join"}},"a":{"0":"u"}}}}}}},"t":{"0":"l","l":"logs","v":{"0":"l","l":"log","v":{"0":"f","l":"term","b":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"v","l":"term"}}},"t":{"0":"l","l":"capture","v":{"0":"l","l":"handler","v":{"0":"f","l":"message","b":{"0":"f","l":"k","b":{"0":"l","l":"inner","v":{"0":"a","f":{"0":"v","l":"k"},"a":{"0":"u"}},"t":{"0":"a","f":{"0":"a","f":{"0":"o","l":"logs"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"message"}},"a":{"0":"a","f":{"0":"g","l":"logs"},"a":{"0":"v","l":"inner"}}}},"a":{"0":"v","l":"inner"}}}}},"t":{"0":"f","l":"run","b":{"0":"a","f":{"0":"a","f":{"0":"h","l":"Log"},"a":{"0":"v","l":"handler"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"return","v":{"0":"a","f":{"0":"v","l":"run"},"a":{"0":"u"}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"return"},"a":{"0":"v","l":"return"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"logs"},"a":{"0":"ta"}},"a":{"0":"u"}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"log"},"a":{"0":"v","l":"log"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"capture"},"a":{"0":"v","l":"capture"}},"a":{"0":"u"}}}}},"t":{"0":"l","l":"modules","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"boolean"},"a":{"0":"v","l":"boolean"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"result"},"a":{"0":"v","l":"result"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"list"},"a":{"0":"v","l":"list"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"integer"},"a":{"0":"v","l":"integer"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"string"},"a":{"0":"v","l":"string"}},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"modules","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"logs"},"a":{"0":"v","l":"logs"}},"a":{"0":"v","l":"modules"}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"equal"},"a":{"0":"v","l":"equal"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"debug"},"a":{"0":"v","l":"debug"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"fix"},"a":{"0":"v","l":"fix"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"capture"},"a":{"0":"v","l":"capture"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"serialize"},"a":{"0":"v","l":"serialize"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"encode_uri"},"a":{"0":"v","l":"encode_uri"}},"a":{"0":"v","l":"modules"}}}}}}}}}}}}}}}}}}}}},"t":{"0":"l","l":"should","v":{"0":"l","l":"equal","v":{"0":"f","l":"expected","b":{"0":"f","l":"given","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"u"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"l","l":"failure","v":{"0":"a","f":{"0":"t","l":"NotEqual"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"given"},"a":{"0":"v","l":"given"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"expected"},"a":{"0":"v","l":"expected"}},"a":{"0":"u"}}}},"t":{"0":"a","f":{"0":"p","l":"Fail"},"a":{"0":"v","l":"failure"}}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"expected"}},"a":{"0":"v","l":"given"}}}}},"t":{"0":"l","l":"be","v":{"0":"f","l":"match","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"match"},"a":{"0":"f","l":"value","b":{"0":"v","l":"value"}}},"a":{"0":"f","l":"other","b":{"0":"a","f":{"0":"p","l":"Abort"},"a":{"0":"s","v":"some other value"}}}}},"t":{"0":"l","l":"to_string","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"NotEqual"},"a":{"0":"f","l":"fail","b":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"expected: "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"debug"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"expected"},"a":{"0":"v","l":"fail"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" given: "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"debug"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"given"},"a":{"0":"v","l":"fail"}}}},"a":{"0":"ta"}}}}}}}},"a":{"0":"n"}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"equal"},"a":{"0":"v","l":"equal"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"be"},"a":{"0":"v","l":"be"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"to_string"},"a":{"0":"v","l":"to_string"}},"a":{"0":"u"}}}}}}},"t":{"0":"l","l":"legit","v":{"0":"l","l":"test","v":{"0":"f","l":"name","b":{"0":"f","l":"exec","b":{"0":"a","f":{"0":"a","f":{"0":"e","l":"exec"},"a":{"0":"v","l":"exec"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"v","l":"name"}},"a":{"0":"u"}}}}},"t":{"0":"l","l":"run_test","v":{"0":"f","l":"f","b":{"0":"a","f":{"0":"a","f":{"0":"h","l":"Fail"},"a":{"0":"f","l":"failure","b":{"0":"f","l":"_kont","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"v","l":"failure"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"a","f":{"0":"v","l":"f"},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"run","v":{"0":"f","l":"tests","b":{"0":"l","l":"initial","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"fails"},"a":{"0":"i","v":0}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"passes"},"a":{"0":"i","v":0}},"a":{"0":"u"}}},"t":{"0":"l","l":"acc","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fold"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"tests"}},"a":{"0":"v","l":"initial"}},"a":{"0":"f","l":"t","b":{"0":"f","l":"acc","b":{"0":"l","l":"result","v":{"0":"a","f":{"0":"v","l":"run_test"},"a":{"0":"a","f":{"0":"g","l":"exec"},"a":{"0":"v","l":"t"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"failure","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"❌ "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"name"},"a":{"0":"v","l":"t"}}},"a":{"0":"ta"}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"v","l":"should"}},"a":{"0":"v","l":"failure"}}},"t":{"0":"l","l":"fails","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"i","v":1}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"o","l":"fails"},"a":{"0":"v","l":"fails"}},"a":{"0":"v","l":"acc"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"_","b":{"0":"l","l":"passes","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"i","v":1}},"a":{"0":"a","f":{"0":"g","l":"passes"},"a":{"0":"v","l":"acc"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"o","l":"passes"},"a":{"0":"v","l":"passes"}},"a":{"0":"v","l":"acc"}}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"result"}}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"passes"},"a":{"0":"v","l":"acc"}}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" tests, "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" failures."}},"a":{"0":"ta"}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"i","v":0}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"i","v":-1}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}},"a":{"0":"i","v":0}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"run"},"a":{"0":"v","l":"run"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"test"},"a":{"0":"v","l":"test"}},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"expect","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"value","b":{"0":"v","l":"value"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"reason","b":{"0":"a","f":{"0":"p","l":"Error"},"a":{"0":"v","l":"reason"}}}},"a":{"0":"n"}}},"t":{"0":"l","l":"eygir","v":{"0":"l","l":"exp","v":{"0":"l","l":"variable","v":{"0":"t","l":"Variable"},"t":{"0":"l","l":"lambda","v":{"0":"t","l":"Lambda"},"t":{"0":"l","l":"apply","v":{"0":"a","f":{"0":"t","l":"Apply"},"a":{"0":"u"}},"t":{"0":"l","l":"let","v":{"0":"t","l":"Let"},"t":{"0":"l","l":"integer","v":{"0":"t","l":"Integer"},"t":{"0":"l","l":"string","v":{"0":"t","l":"Binary"},"t":{"0":"l","l":"tail","v":{"0":"a","f":{"0":"t","l":"Tail"},"a":{"0":"u"}},"t":{"0":"l","l":"cons","v":{"0":"a","f":{"0":"t","l":"Cons"},"a":{"0":"u"}},"t":{"0":"l","l":"empty","v":{"0":"a","f":{"0":"t","l":"Empty"},"a":{"0":"u"}},"t":{"0":"l","l":"extend","v":{"0":"t","l":"Extend"},"t":{"0":"l","l":"select","v":{"0":"t","l":"Select"},"t":{"0":"l","l":"overwrite","v":{"0":"t","l":"Overwrite"},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"variable"},"a":{"0":"v","l":"variable"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"lambda"},"a":{"0":"v","l":"lambda"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"apply"},"a":{"0":"v","l":"apply"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"let"},"a":{"0":"v","l":"let"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"integer"},"a":{"0":"v","l":"integer"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"tail"},"a":{"0":"v","l":"tail"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"cons"},"a":{"0":"v","l":"cons"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"string"},"a":{"0":"v","l":"string"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"empty"},"a":{"0":"v","l":"empty"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"extend"},"a":{"0":"v","l":"extend"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"select"},"a":{"0":"v","l":"select"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"overwrite"},"a":{"0":"v","l":"overwrite"}},"a":{"0":"u"}}}}}}}}}}}}}}}}}}}}}}}}},"t":{"0":"l","l":"render","v":{"0":"l","l":"expression","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"self","b":{"0":"f","l":"br","b":{"0":"f","l":"source","b":{"0":"l","l":"done","v":{"0":"f","l":"text","b":{"0":"f","l":"rest","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"text"},"a":{"0":"v","l":"text"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"rest"},"a":{"0":"v","l":"rest"}},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"then","v":{"0":"f","l":"renderer","b":{"0":"f","l":"then","b":{"0":"f","l":"rest","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"rendered","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"g","l":"text"},"a":{"0":"v","l":"rendered"}}},"a":{"0":"a","f":{"0":"g","l":"rest"},"a":{"0":"v","l":"rendered"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"reason","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"v","l":"reason"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"renderer"},"a":{"0":"v","l":"rest"}}}}}},"t":{"0":"l","l":"block","v":{"0":"f","l":"br","b":{"0":"f","l":"source","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Let"},"a":{"0":"f","l":"_","b":{"0":"l","l":"br_inner","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"br"}},"a":{"0":"s","v":" "}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"br_inner"}}},"a":{"0":"f","l":"value","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"{"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"br_inner"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"value"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"br"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"}"}},"a":{"0":"ta"}}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"debug"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"parts"}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"br"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"reason","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"v","l":"reason"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}},"t":{"0":"l","l":"spread","v":{"0":"f","l":"reversed","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"l","l":"tail","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":".."}},"a":{"0":"v","l":"tail"}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}}}},"t":{"0":"l","l":"gather_elements","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Tail"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Cons"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}}}},"t":{"0":"l","l":"gather_extend","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Extend"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Empty"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}}}},"t":{"0":"l","l":"gather_overwrite","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Empty"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Overwrite"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}}}},"t":{"0":"l","l":"gather_branches","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"br","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"NoCases"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Case"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"v","l":"br"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}}}}},"t":{"0":"l","l":"exp","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Variable"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"label"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Lambda"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"body","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" -> "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"body"}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"f","l":"source","b":{"0":"l","l":"default","v":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"func","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"arg","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"func"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"("}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"arg"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":")"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Extend"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"s","v":"{"},"t":{"0":"l","l":"post","v":{"0":"s","v":"}"},"t":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"gather_extend"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"s","v":", "}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Overwrite"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"s","v":"{"},"t":{"0":"l","l":"post","v":{"0":"s","v":"}"},"t":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"gather_overwrite"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"s","v":", "}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Case"},"a":{"0":"f","l":"label","b":{"0":"l","l":"br_inner","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"br"}},"a":{"0":"s","v":" "}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br_inner"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"match {"}},"a":{"0":"v","l":"br_inner"}},"t":{"0":"l","l":"post","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"br"}},"a":{"0":"s","v":"}"}},"t":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"gather_branches"},"a":{"0":"v","l":"br_inner"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"v","l":"br_inner"}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Cons"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"s","v":"["},"t":{"0":"l","l":"post","v":{"0":"s","v":"]"},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"gather_elements"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"s","v":", "}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Select"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"arg","b":{"0":"l","l":"rendered","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"arg"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"."}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"rendered"}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Let"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"value","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"rest_or_then","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"let "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" = "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"value"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"br"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"rest_or_then"}},"a":{"0":"ta"}}}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Integer"},"a":{"0":"f","l":"value","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"value"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Binary"},"a":{"0":"f","l":"value","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"\""}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"value"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"\""}},"a":{"0":"ta"}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Tail"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"[]"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Cons"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"cons"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Vacant"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"vacant"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Empty"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"{}"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Extend"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"+"}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Select"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"."}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Overwrite"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":":="}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Tag"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"label"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Case"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"match "}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"NoCases"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"--- no cases ---"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Perform"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"perform "}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Handle"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"handle "}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Builtin"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"TODO this shouldn't really be here"}}}},"a":{"0":"n"}}}}}}}}}}}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"exp"},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}}}}}}}}}}}}},"t":{"0":"a","f":{"0":"v","l":"expression"},"a":{"0":"s","v":"\n"}}},"t":{"0":"l","l":"t","v":{"0":"a","f":{"0":"g","l":"test"},"a":{"0":"v","l":"legit"}},"t":{"0":"l","l":"should_render","v":{"0":"f","l":"output","b":{"0":"f","l":"source","b":{"0":"l","l":"rendered","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"be"},"a":{"0":"v","l":"should"}},"a":{"0":"m","l":"Ok"}},"a":{"0":"a","f":{"0":"v","l":"render"},"a":{"0":"v","l":"source"}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"ta"}},"a":{"0":"a","f":{"0":"g","l":"rest"},"a":{"0":"v","l":"rendered"}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"v","l":"output"}},"a":{"0":"a","f":{"0":"g","l":"text"},"a":{"0":"v","l":"rendered"}}},"t":{"0":"u"}}}}}},"t":{"0":"l","l":"tests","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"empty"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"be"},"a":{"0":"v","l":"should"}},"a":{"0":"m","l":"Error"}},"a":{"0":"a","f":{"0":"v","l":"render"},"a":{"0":"ta"}}},"t":{"0":"u"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"variable"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"lambda"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"lambda"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"ta"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x -> 2"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"apply"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x(2)"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"let"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"let x = 2\nx"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"integer"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":5}}},"a":{"0":"ta"}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"5"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"string"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"hello"}}},"a":{"0":"ta"}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"\"hello\""}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"multiline lambda"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"lambda"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x -> {\n let y = x\n y\n}"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"multiline let"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"let x = {\n let y = 1\n y\n}\nx"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"extend list"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"exp"}}},"a":{"0":"ta"}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"[1, 2]"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"open list"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"[1, ..x]"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"open list fn application"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"ta"}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"[1, ..x(y)]"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"extend record"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"extend"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"foo"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"extend"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"bar"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"empty"},"a":{"0":"v","l":"exp"}}},"a":{"0":"ta"}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"{foo: 1, bar: 2}"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"select field from record"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"select"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"bar"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"select"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"foo"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x.foo.bar"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"ta"}}}}}}}}}}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"render"},"a":{"0":"v","l":"render"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"tests"},"a":{"0":"v","l":"tests"}},"a":{"0":"u"}}}}}}}},"t":{"0":"l","l":"cli","v":{"0":"z","c":""},"t":{"0":"l","l":"web","v":{"0":"z","c":""},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"cli"},"a":{"0":"v","l":"cli"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"web"},"a":{"0":"v","l":"web"}},"a":{"0":"u"}}}}}}}}}} \ No newline at end of file diff --git a/eyg/src/eyg/analysis/jm/incremental.gleam b/eyg/src/eyg/analysis/jm/incremental.gleam index eeb780bec..03fbd1a54 100644 --- a/eyg/src/eyg/analysis/jm/incremental.gleam +++ b/eyg/src/eyg/analysis/jm/incremental.gleam @@ -86,6 +86,13 @@ fn fetch(env, x, sub, next, types, ref, type_, k) { case map.get(env, x) { Ok(scheme) -> { let #(found, next) = instantiate(scheme, next) + case x == "should_render" { + False -> Nil + True -> { + io.debug(#(x, found, next)) + Nil + } + } Cont(unify_at(type_, found, sub, next, types, ref), k) } Error(Nil) -> { diff --git a/eyg/src/eyg/analysis/jm/infer.gleam b/eyg/src/eyg/analysis/jm/infer.gleam index 79f7ba965..b2349703a 100644 --- a/eyg/src/eyg/analysis/jm/infer.gleam +++ b/eyg/src/eyg/analysis/jm/infer.gleam @@ -93,12 +93,19 @@ pub fn builtins() { fn extend_b(env, key, t) { let scheme = generalise( map.new(), map.new(), t) + case key == "should_render" { + False -> Nil + True -> { + io.debug(#(key, scheme, t)) + Nil + } + } extend(env, key, scheme) } // THere could be part of std pub fn equal() { - t.Fun(t.Var(0), t.Var(1), t.Var(0)) + t.Fun(t.Var(0), t.Var(1), t.Fun(t.Var(0), t.Var(2), t.boolean)) } pub fn debug() { From 324d21f0e21caa325a2ec06331cfedd7e27958ea Mon Sep 17 00:00:00 2001 From: Peter Saxton Date: Mon, 24 Apr 2023 23:05:39 +0200 Subject: [PATCH 55/62] formatting --- eyg/saved/saved.json | 2 +- eyg/src/atelier/app.gleam | 75 ++++---- eyg/src/eyg/analysis/jm/env.gleam | 11 +- eyg/src/eyg/analysis/jm/error.gleam | 2 +- eyg/src/eyg/analysis/jm/incremental.gleam | 182 +++++++++++++------- eyg/src/eyg/analysis/jm/infer.gleam | 97 +++++------ eyg/src/eyg/analysis/jm/scheme.gleam | 5 +- eyg/src/eyg/analysis/jm/tree.gleam | 201 ++++++++++++++-------- eyg/src/eyg/analysis/jm/type_.gleam | 62 ++++--- eyg/src/eyg/analysis/jm/unify.gleam | 114 +++++++----- 10 files changed, 444 insertions(+), 307 deletions(-) diff --git a/eyg/saved/saved.json b/eyg/saved/saved.json index 36631bcb8..262a7eb74 100644 --- a/eyg/saved/saved.json +++ b/eyg/saved/saved.json @@ -1 +1 @@ -{"0":"l","l":"std","v":{"0":"l","l":"equal","v":{"0":"b","l":"equal"},"t":{"0":"l","l":"debug","v":{"0":"b","l":"debug"},"t":{"0":"l","l":"fix","v":{"0":"b","l":"fix"},"t":{"0":"l","l":"capture","v":{"0":"b","l":"capture"},"t":{"0":"l","l":"serialize","v":{"0":"b","l":"serialize"},"t":{"0":"l","l":"encode_uri","v":{"0":"b","l":"encode_uri"},"t":{"0":"l","l":"boolean","v":{"0":"l","l":"and","v":{"0":"f","l":"a","b":{"0":"f","l":"b","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"True"},"a":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"False"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"b"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"False"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"a"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"and"},"a":{"0":"v","l":"and"}},"a":{"0":"u"}}},"t":{"0":"l","l":"result","v":{"0":"l","l":"unwrap","v":{"0":"f","l":"default","b":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"x","b":{"0":"v","l":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"v","l":"default"}}},"a":{"0":"n"}}}},"t":{"0":"u"}},"t":{"0":"l","l":"list","v":{"0":"l","l":"pop","v":{"0":"b","l":"list_pop"},"t":{"0":"l","l":"fold","v":{"0":"b","l":"list_fold"},"t":{"0":"l","l":"head","v":{"0":"f","l":"l","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"pop"},"a":{"0":"v","l":"l"}}}},"t":{"0":"l","l":"find","v":{"0":"a","f":{"0":"v","l":"fix"},"a":{"0":"f","l":"self","b":{"0":"f","l":"predicate","b":{"0":"f","l":"list","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}},"t":{"0":"l","l":"matched","v":{"0":"a","f":{"0":"v","l":"predicate"},"a":{"0":"v","l":"item"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"v","l":"item"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"predicate"}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"matched"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"t","l":"Error"}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"pop"},"a":{"0":"v","l":"list"}}}}}}},"t":{"0":"l","l":"reverse","v":{"0":"f","l":"list","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"fold"},"a":{"0":"v","l":"list"}},"a":{"0":"ta"}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"el"}},"a":{"0":"v","l":"acc"}}}}}},"t":{"0":"l","l":"append","v":{"0":"f","l":"first","b":{"0":"f","l":"second","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"fold"},"a":{"0":"a","f":{"0":"v","l":"reverse"},"a":{"0":"v","l":"first"}}},"a":{"0":"v","l":"second"}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"el"}},"a":{"0":"v","l":"acc"}}}}}}},"t":{"0":"l","l":"intersperse","v":{"0":"f","l":"list","b":{"0":"f","l":"element","b":{"0":"l","l":"reversed","v":{"0":"a","f":{"0":"v","l":"reverse"},"a":{"0":"v","l":"list"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"fold"},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}},"a":{"0":"ta"}}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"el"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"element"}},"a":{"0":"v","l":"acc"}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"ta"}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"pop"},"a":{"0":"v","l":"reversed"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"pop"},"a":{"0":"v","l":"pop"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"fold"},"a":{"0":"v","l":"fold"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"head"},"a":{"0":"v","l":"head"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"find"},"a":{"0":"v","l":"find"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"reverse"},"a":{"0":"v","l":"reverse"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"append"},"a":{"0":"v","l":"append"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"intersperse"},"a":{"0":"v","l":"intersperse"}},"a":{"0":"u"}}}}}}}}}}}}}}},"t":{"0":"l","l":"integer","v":{"0":"l","l":"add","v":{"0":"b","l":"int_add"},"t":{"0":"l","l":"subtract","v":{"0":"b","l":"int_subtract"},"t":{"0":"l","l":"to_string","v":{"0":"b","l":"int_to_string"},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"add"},"a":{"0":"v","l":"add"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"subtract"},"a":{"0":"v","l":"subtract"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"to_string"},"a":{"0":"v","l":"to_string"}},"a":{"0":"u"}}}}}}},"t":{"0":"l","l":"string","v":{"0":"l","l":"append","v":{"0":"b","l":"string_append"},"t":{"0":"l","l":"concat","v":{"0":"f","l":"l","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fold"},"a":{"0":"v","l":"list"}},"a":{"0":"v","l":"l"}},"a":{"0":"s","v":""}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"append"},"a":{"0":"v","l":"acc"}},"a":{"0":"v","l":"el"}}}}}},"t":{"0":"l","l":"join","v":{"0":"f","l":"strings","b":{"0":"f","l":"separator","b":{"0":"a","f":{"0":"v","l":"concat"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"v","l":"list"}},"a":{"0":"v","l":"strings"}},"a":{"0":"v","l":"separator"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"append"},"a":{"0":"v","l":"append"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"concat"},"a":{"0":"v","l":"concat"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"join"},"a":{"0":"v","l":"join"}},"a":{"0":"u"}}}}}}},"t":{"0":"l","l":"logs","v":{"0":"l","l":"log","v":{"0":"f","l":"term","b":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"v","l":"term"}}},"t":{"0":"l","l":"capture","v":{"0":"l","l":"handler","v":{"0":"f","l":"message","b":{"0":"f","l":"k","b":{"0":"l","l":"inner","v":{"0":"a","f":{"0":"v","l":"k"},"a":{"0":"u"}},"t":{"0":"a","f":{"0":"a","f":{"0":"o","l":"logs"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"message"}},"a":{"0":"a","f":{"0":"g","l":"logs"},"a":{"0":"v","l":"inner"}}}},"a":{"0":"v","l":"inner"}}}}},"t":{"0":"f","l":"run","b":{"0":"a","f":{"0":"a","f":{"0":"h","l":"Log"},"a":{"0":"v","l":"handler"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"return","v":{"0":"a","f":{"0":"v","l":"run"},"a":{"0":"u"}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"return"},"a":{"0":"v","l":"return"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"logs"},"a":{"0":"ta"}},"a":{"0":"u"}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"log"},"a":{"0":"v","l":"log"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"capture"},"a":{"0":"v","l":"capture"}},"a":{"0":"u"}}}}},"t":{"0":"l","l":"modules","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"boolean"},"a":{"0":"v","l":"boolean"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"result"},"a":{"0":"v","l":"result"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"list"},"a":{"0":"v","l":"list"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"integer"},"a":{"0":"v","l":"integer"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"string"},"a":{"0":"v","l":"string"}},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"modules","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"logs"},"a":{"0":"v","l":"logs"}},"a":{"0":"v","l":"modules"}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"equal"},"a":{"0":"v","l":"equal"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"debug"},"a":{"0":"v","l":"debug"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"fix"},"a":{"0":"v","l":"fix"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"capture"},"a":{"0":"v","l":"capture"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"serialize"},"a":{"0":"v","l":"serialize"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"encode_uri"},"a":{"0":"v","l":"encode_uri"}},"a":{"0":"v","l":"modules"}}}}}}}}}}}}}}}}}}}}},"t":{"0":"l","l":"should","v":{"0":"l","l":"equal","v":{"0":"f","l":"expected","b":{"0":"f","l":"given","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"u"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"l","l":"failure","v":{"0":"a","f":{"0":"t","l":"NotEqual"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"given"},"a":{"0":"v","l":"given"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"expected"},"a":{"0":"v","l":"expected"}},"a":{"0":"u"}}}},"t":{"0":"a","f":{"0":"p","l":"Fail"},"a":{"0":"v","l":"failure"}}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"expected"}},"a":{"0":"v","l":"given"}}}}},"t":{"0":"l","l":"be","v":{"0":"f","l":"match","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"match"},"a":{"0":"f","l":"value","b":{"0":"v","l":"value"}}},"a":{"0":"f","l":"other","b":{"0":"a","f":{"0":"p","l":"Abort"},"a":{"0":"s","v":"some other value"}}}}},"t":{"0":"l","l":"to_string","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"NotEqual"},"a":{"0":"f","l":"fail","b":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"expected: "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"debug"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"expected"},"a":{"0":"v","l":"fail"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" given: "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"debug"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"given"},"a":{"0":"v","l":"fail"}}}},"a":{"0":"ta"}}}}}}}},"a":{"0":"n"}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"equal"},"a":{"0":"v","l":"equal"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"be"},"a":{"0":"v","l":"be"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"to_string"},"a":{"0":"v","l":"to_string"}},"a":{"0":"u"}}}}}}},"t":{"0":"l","l":"legit","v":{"0":"l","l":"test","v":{"0":"f","l":"name","b":{"0":"f","l":"exec","b":{"0":"a","f":{"0":"a","f":{"0":"e","l":"exec"},"a":{"0":"v","l":"exec"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"v","l":"name"}},"a":{"0":"u"}}}}},"t":{"0":"l","l":"run_test","v":{"0":"f","l":"f","b":{"0":"a","f":{"0":"a","f":{"0":"h","l":"Fail"},"a":{"0":"f","l":"failure","b":{"0":"f","l":"_kont","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"v","l":"failure"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"a","f":{"0":"v","l":"f"},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"run","v":{"0":"f","l":"tests","b":{"0":"l","l":"initial","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"fails"},"a":{"0":"i","v":0}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"passes"},"a":{"0":"i","v":0}},"a":{"0":"u"}}},"t":{"0":"l","l":"acc","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fold"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"tests"}},"a":{"0":"v","l":"initial"}},"a":{"0":"f","l":"t","b":{"0":"f","l":"acc","b":{"0":"l","l":"result","v":{"0":"a","f":{"0":"v","l":"run_test"},"a":{"0":"a","f":{"0":"g","l":"exec"},"a":{"0":"v","l":"t"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"failure","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"❌ "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"name"},"a":{"0":"v","l":"t"}}},"a":{"0":"ta"}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"v","l":"should"}},"a":{"0":"v","l":"failure"}}},"t":{"0":"l","l":"fails","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"i","v":1}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"o","l":"fails"},"a":{"0":"v","l":"fails"}},"a":{"0":"v","l":"acc"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"_","b":{"0":"l","l":"passes","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"i","v":1}},"a":{"0":"a","f":{"0":"g","l":"passes"},"a":{"0":"v","l":"acc"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"o","l":"passes"},"a":{"0":"v","l":"passes"}},"a":{"0":"v","l":"acc"}}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"result"}}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"passes"},"a":{"0":"v","l":"acc"}}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" tests, "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" failures."}},"a":{"0":"ta"}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"i","v":0}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"i","v":-1}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}},"a":{"0":"i","v":0}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"run"},"a":{"0":"v","l":"run"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"test"},"a":{"0":"v","l":"test"}},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"expect","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"value","b":{"0":"v","l":"value"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"reason","b":{"0":"a","f":{"0":"p","l":"Error"},"a":{"0":"v","l":"reason"}}}},"a":{"0":"n"}}},"t":{"0":"l","l":"eygir","v":{"0":"l","l":"exp","v":{"0":"l","l":"variable","v":{"0":"t","l":"Variable"},"t":{"0":"l","l":"lambda","v":{"0":"t","l":"Lambda"},"t":{"0":"l","l":"apply","v":{"0":"a","f":{"0":"t","l":"Apply"},"a":{"0":"u"}},"t":{"0":"l","l":"let","v":{"0":"t","l":"Let"},"t":{"0":"l","l":"integer","v":{"0":"t","l":"Integer"},"t":{"0":"l","l":"string","v":{"0":"t","l":"Binary"},"t":{"0":"l","l":"tail","v":{"0":"a","f":{"0":"t","l":"Tail"},"a":{"0":"u"}},"t":{"0":"l","l":"cons","v":{"0":"a","f":{"0":"t","l":"Cons"},"a":{"0":"u"}},"t":{"0":"l","l":"empty","v":{"0":"a","f":{"0":"t","l":"Empty"},"a":{"0":"u"}},"t":{"0":"l","l":"extend","v":{"0":"t","l":"Extend"},"t":{"0":"l","l":"select","v":{"0":"t","l":"Select"},"t":{"0":"l","l":"overwrite","v":{"0":"t","l":"Overwrite"},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"variable"},"a":{"0":"v","l":"variable"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"lambda"},"a":{"0":"v","l":"lambda"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"apply"},"a":{"0":"v","l":"apply"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"let"},"a":{"0":"v","l":"let"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"integer"},"a":{"0":"v","l":"integer"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"tail"},"a":{"0":"v","l":"tail"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"cons"},"a":{"0":"v","l":"cons"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"string"},"a":{"0":"v","l":"string"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"empty"},"a":{"0":"v","l":"empty"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"extend"},"a":{"0":"v","l":"extend"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"select"},"a":{"0":"v","l":"select"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"overwrite"},"a":{"0":"v","l":"overwrite"}},"a":{"0":"u"}}}}}}}}}}}}}}}}}}}}}}}}},"t":{"0":"l","l":"render","v":{"0":"l","l":"expression","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"self","b":{"0":"f","l":"br","b":{"0":"f","l":"source","b":{"0":"l","l":"done","v":{"0":"f","l":"text","b":{"0":"f","l":"rest","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"text"},"a":{"0":"v","l":"text"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"rest"},"a":{"0":"v","l":"rest"}},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"then","v":{"0":"f","l":"renderer","b":{"0":"f","l":"then","b":{"0":"f","l":"rest","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"rendered","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"g","l":"text"},"a":{"0":"v","l":"rendered"}}},"a":{"0":"a","f":{"0":"g","l":"rest"},"a":{"0":"v","l":"rendered"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"reason","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"v","l":"reason"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"renderer"},"a":{"0":"v","l":"rest"}}}}}},"t":{"0":"l","l":"block","v":{"0":"f","l":"br","b":{"0":"f","l":"source","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Let"},"a":{"0":"f","l":"_","b":{"0":"l","l":"br_inner","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"br"}},"a":{"0":"s","v":" "}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"br_inner"}}},"a":{"0":"f","l":"value","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"{"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"br_inner"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"value"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"br"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"}"}},"a":{"0":"ta"}}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"debug"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"parts"}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"br"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"reason","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"v","l":"reason"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}},"t":{"0":"l","l":"spread","v":{"0":"f","l":"reversed","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"l","l":"tail","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":".."}},"a":{"0":"v","l":"tail"}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}}}},"t":{"0":"l","l":"gather_elements","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Tail"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Cons"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}}}},"t":{"0":"l","l":"gather_extend","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Extend"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Empty"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}}}},"t":{"0":"l","l":"gather_overwrite","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Empty"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Overwrite"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}}}},"t":{"0":"l","l":"gather_branches","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"br","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"NoCases"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Case"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"v","l":"br"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}}}}},"t":{"0":"l","l":"exp","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Variable"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"label"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Lambda"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"body","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" -> "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"body"}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"f","l":"source","b":{"0":"l","l":"default","v":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"func","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"arg","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"func"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"("}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"arg"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":")"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Extend"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"s","v":"{"},"t":{"0":"l","l":"post","v":{"0":"s","v":"}"},"t":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"gather_extend"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"s","v":", "}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Overwrite"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"s","v":"{"},"t":{"0":"l","l":"post","v":{"0":"s","v":"}"},"t":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"gather_overwrite"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"s","v":", "}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Case"},"a":{"0":"f","l":"label","b":{"0":"l","l":"br_inner","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"br"}},"a":{"0":"s","v":" "}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br_inner"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"match {"}},"a":{"0":"v","l":"br_inner"}},"t":{"0":"l","l":"post","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"br"}},"a":{"0":"s","v":"}"}},"t":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"gather_branches"},"a":{"0":"v","l":"br_inner"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"v","l":"br_inner"}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Cons"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"s","v":"["},"t":{"0":"l","l":"post","v":{"0":"s","v":"]"},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"gather_elements"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"s","v":", "}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Select"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"arg","b":{"0":"l","l":"rendered","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"arg"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"."}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"rendered"}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Let"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"value","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"rest_or_then","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"let "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" = "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"value"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"br"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"rest_or_then"}},"a":{"0":"ta"}}}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Integer"},"a":{"0":"f","l":"value","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"value"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Binary"},"a":{"0":"f","l":"value","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"\""}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"value"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"\""}},"a":{"0":"ta"}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Tail"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"[]"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Cons"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"cons"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Vacant"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"vacant"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Empty"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"{}"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Extend"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"+"}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Select"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"."}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Overwrite"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":":="}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Tag"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"label"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Case"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"match "}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"NoCases"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"--- no cases ---"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Perform"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"perform "}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Handle"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"handle "}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Builtin"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"TODO this shouldn't really be here"}}}},"a":{"0":"n"}}}}}}}}}}}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"exp"},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}}}}}}}}}}}}},"t":{"0":"a","f":{"0":"v","l":"expression"},"a":{"0":"s","v":"\n"}}},"t":{"0":"l","l":"t","v":{"0":"a","f":{"0":"g","l":"test"},"a":{"0":"v","l":"legit"}},"t":{"0":"l","l":"should_render","v":{"0":"f","l":"output","b":{"0":"f","l":"source","b":{"0":"l","l":"rendered","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"be"},"a":{"0":"v","l":"should"}},"a":{"0":"m","l":"Ok"}},"a":{"0":"a","f":{"0":"v","l":"render"},"a":{"0":"v","l":"source"}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"ta"}},"a":{"0":"a","f":{"0":"g","l":"rest"},"a":{"0":"v","l":"rendered"}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"v","l":"output"}},"a":{"0":"a","f":{"0":"g","l":"text"},"a":{"0":"v","l":"rendered"}}},"t":{"0":"u"}}}}}},"t":{"0":"l","l":"tests","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"empty"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"be"},"a":{"0":"v","l":"should"}},"a":{"0":"m","l":"Error"}},"a":{"0":"a","f":{"0":"v","l":"render"},"a":{"0":"ta"}}},"t":{"0":"u"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"variable"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"lambda"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"lambda"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"ta"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x -> 2"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"apply"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x(2)"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"let"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"let x = 2\nx"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"integer"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":5}}},"a":{"0":"ta"}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"5"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"string"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"hello"}}},"a":{"0":"ta"}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"\"hello\""}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"multiline lambda"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"lambda"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x -> {\n let y = x\n y\n}"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"multiline let"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"let x = {\n let y = 1\n y\n}\nx"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"extend list"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"exp"}}},"a":{"0":"ta"}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"[1, 2]"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"open list"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"[1, ..x]"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"open list fn application"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"ta"}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"[1, ..x(y)]"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"extend record"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"extend"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"foo"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"extend"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"bar"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"empty"},"a":{"0":"v","l":"exp"}}},"a":{"0":"ta"}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"{foo: 1, bar: 2}"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"select field from record"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"select"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"bar"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"select"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"foo"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x.foo.bar"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"ta"}}}}}}}}}}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"render"},"a":{"0":"v","l":"render"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"tests"},"a":{"0":"v","l":"tests"}},"a":{"0":"u"}}}}}}}},"t":{"0":"l","l":"cli","v":{"0":"z","c":""},"t":{"0":"l","l":"web","v":{"0":"z","c":""},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"cli"},"a":{"0":"v","l":"cli"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"web"},"a":{"0":"v","l":"web"}},"a":{"0":"u"}}}}}}}}}} \ No newline at end of file +{"0":"l","l":"std","v":{"0":"l","l":"equal","v":{"0":"b","l":"equal"},"t":{"0":"l","l":"debug","v":{"0":"b","l":"debug"},"t":{"0":"l","l":"fix","v":{"0":"b","l":"fix"},"t":{"0":"l","l":"capture","v":{"0":"b","l":"capture"},"t":{"0":"l","l":"serialize","v":{"0":"b","l":"serialize"},"t":{"0":"l","l":"encode_uri","v":{"0":"b","l":"encode_uri"},"t":{"0":"l","l":"boolean","v":{"0":"l","l":"and","v":{"0":"f","l":"a","b":{"0":"f","l":"b","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"True"},"a":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"False"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"b"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"False"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"a"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"and"},"a":{"0":"v","l":"and"}},"a":{"0":"u"}}},"t":{"0":"l","l":"result","v":{"0":"l","l":"unwrap","v":{"0":"f","l":"default","b":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"x","b":{"0":"v","l":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"v","l":"default"}}},"a":{"0":"n"}}}},"t":{"0":"u"}},"t":{"0":"l","l":"list","v":{"0":"l","l":"pop","v":{"0":"b","l":"list_pop"},"t":{"0":"l","l":"fold","v":{"0":"b","l":"list_fold"},"t":{"0":"l","l":"head","v":{"0":"f","l":"l","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"pop"},"a":{"0":"v","l":"l"}}}},"t":{"0":"l","l":"find","v":{"0":"a","f":{"0":"v","l":"fix"},"a":{"0":"f","l":"self","b":{"0":"f","l":"predicate","b":{"0":"f","l":"list","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}},"t":{"0":"l","l":"matched","v":{"0":"a","f":{"0":"v","l":"predicate"},"a":{"0":"v","l":"item"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"v","l":"item"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"predicate"}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"matched"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"t","l":"Error"}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"pop"},"a":{"0":"v","l":"list"}}}}}}},"t":{"0":"l","l":"reverse","v":{"0":"f","l":"list","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"fold"},"a":{"0":"v","l":"list"}},"a":{"0":"ta"}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"el"}},"a":{"0":"v","l":"acc"}}}}}},"t":{"0":"l","l":"append","v":{"0":"f","l":"first","b":{"0":"f","l":"second","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"fold"},"a":{"0":"a","f":{"0":"v","l":"reverse"},"a":{"0":"v","l":"first"}}},"a":{"0":"v","l":"second"}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"el"}},"a":{"0":"v","l":"acc"}}}}}}},"t":{"0":"l","l":"intersperse","v":{"0":"f","l":"list","b":{"0":"f","l":"element","b":{"0":"l","l":"reversed","v":{"0":"a","f":{"0":"v","l":"reverse"},"a":{"0":"v","l":"list"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"fold"},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}},"a":{"0":"ta"}}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"el"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"element"}},"a":{"0":"v","l":"acc"}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"ta"}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"pop"},"a":{"0":"v","l":"reversed"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"pop"},"a":{"0":"v","l":"pop"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"fold"},"a":{"0":"v","l":"fold"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"head"},"a":{"0":"v","l":"head"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"find"},"a":{"0":"v","l":"find"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"reverse"},"a":{"0":"v","l":"reverse"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"append"},"a":{"0":"v","l":"append"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"intersperse"},"a":{"0":"v","l":"intersperse"}},"a":{"0":"u"}}}}}}}}}}}}}}},"t":{"0":"l","l":"integer","v":{"0":"l","l":"add","v":{"0":"b","l":"int_add"},"t":{"0":"l","l":"subtract","v":{"0":"b","l":"int_subtract"},"t":{"0":"l","l":"to_string","v":{"0":"b","l":"int_to_string"},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"add"},"a":{"0":"v","l":"add"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"subtract"},"a":{"0":"v","l":"subtract"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"to_string"},"a":{"0":"v","l":"to_string"}},"a":{"0":"u"}}}}}}},"t":{"0":"l","l":"string","v":{"0":"l","l":"append","v":{"0":"b","l":"string_append"},"t":{"0":"l","l":"concat","v":{"0":"f","l":"l","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fold"},"a":{"0":"v","l":"list"}},"a":{"0":"v","l":"l"}},"a":{"0":"s","v":""}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"append"},"a":{"0":"v","l":"acc"}},"a":{"0":"v","l":"el"}}}}}},"t":{"0":"l","l":"join","v":{"0":"f","l":"strings","b":{"0":"f","l":"separator","b":{"0":"a","f":{"0":"v","l":"concat"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"v","l":"list"}},"a":{"0":"v","l":"strings"}},"a":{"0":"v","l":"separator"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"append"},"a":{"0":"v","l":"append"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"concat"},"a":{"0":"v","l":"concat"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"join"},"a":{"0":"v","l":"join"}},"a":{"0":"u"}}}}}}},"t":{"0":"l","l":"logs","v":{"0":"l","l":"log","v":{"0":"f","l":"term","b":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"v","l":"term"}}},"t":{"0":"l","l":"capture","v":{"0":"l","l":"handler","v":{"0":"f","l":"message","b":{"0":"f","l":"k","b":{"0":"l","l":"inner","v":{"0":"a","f":{"0":"v","l":"k"},"a":{"0":"u"}},"t":{"0":"a","f":{"0":"a","f":{"0":"o","l":"logs"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"message"}},"a":{"0":"a","f":{"0":"g","l":"logs"},"a":{"0":"v","l":"inner"}}}},"a":{"0":"v","l":"inner"}}}}},"t":{"0":"f","l":"run","b":{"0":"a","f":{"0":"a","f":{"0":"h","l":"Log"},"a":{"0":"v","l":"handler"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"return","v":{"0":"a","f":{"0":"v","l":"run"},"a":{"0":"u"}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"return"},"a":{"0":"v","l":"return"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"logs"},"a":{"0":"ta"}},"a":{"0":"u"}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"log"},"a":{"0":"v","l":"log"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"capture"},"a":{"0":"v","l":"capture"}},"a":{"0":"u"}}}}},"t":{"0":"l","l":"modules","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"boolean"},"a":{"0":"v","l":"boolean"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"result"},"a":{"0":"v","l":"result"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"list"},"a":{"0":"v","l":"list"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"integer"},"a":{"0":"v","l":"integer"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"string"},"a":{"0":"v","l":"string"}},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"modules","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"logs"},"a":{"0":"v","l":"logs"}},"a":{"0":"v","l":"modules"}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"equal"},"a":{"0":"v","l":"equal"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"debug"},"a":{"0":"v","l":"debug"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"fix"},"a":{"0":"v","l":"fix"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"capture"},"a":{"0":"v","l":"capture"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"serialize"},"a":{"0":"v","l":"serialize"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"encode_uri"},"a":{"0":"v","l":"encode_uri"}},"a":{"0":"v","l":"modules"}}}}}}}}}}}}}}}}}}}}},"t":{"0":"l","l":"should","v":{"0":"l","l":"equal","v":{"0":"f","l":"expected","b":{"0":"f","l":"given","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"u"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"l","l":"failure","v":{"0":"a","f":{"0":"t","l":"NotEqual"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"given"},"a":{"0":"v","l":"given"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"expected"},"a":{"0":"v","l":"expected"}},"a":{"0":"u"}}}},"t":{"0":"a","f":{"0":"p","l":"Fail"},"a":{"0":"v","l":"failure"}}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"expected"}},"a":{"0":"v","l":"given"}}}}},"t":{"0":"l","l":"be","v":{"0":"f","l":"match","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"match"},"a":{"0":"f","l":"value","b":{"0":"v","l":"value"}}},"a":{"0":"f","l":"other","b":{"0":"a","f":{"0":"p","l":"Abort"},"a":{"0":"s","v":"some other value"}}}}},"t":{"0":"l","l":"to_string","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"NotEqual"},"a":{"0":"f","l":"fail","b":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"expected: "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"debug"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"expected"},"a":{"0":"v","l":"fail"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" given: "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"debug"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"given"},"a":{"0":"v","l":"fail"}}}},"a":{"0":"ta"}}}}}}}},"a":{"0":"n"}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"equal"},"a":{"0":"v","l":"equal"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"be"},"a":{"0":"v","l":"be"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"to_string"},"a":{"0":"v","l":"to_string"}},"a":{"0":"u"}}}}}}},"t":{"0":"l","l":"legit","v":{"0":"l","l":"test","v":{"0":"f","l":"name","b":{"0":"f","l":"exec","b":{"0":"a","f":{"0":"a","f":{"0":"e","l":"exec"},"a":{"0":"v","l":"exec"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"v","l":"name"}},"a":{"0":"u"}}}}},"t":{"0":"l","l":"run_test","v":{"0":"f","l":"f","b":{"0":"a","f":{"0":"a","f":{"0":"h","l":"Fail"},"a":{"0":"f","l":"failure","b":{"0":"f","l":"_kont","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"v","l":"failure"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"a","f":{"0":"v","l":"f"},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"run","v":{"0":"f","l":"tests","b":{"0":"l","l":"initial","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"fails"},"a":{"0":"i","v":0}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"passes"},"a":{"0":"i","v":0}},"a":{"0":"u"}}},"t":{"0":"l","l":"acc","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fold"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"tests"}},"a":{"0":"v","l":"initial"}},"a":{"0":"f","l":"t","b":{"0":"f","l":"acc","b":{"0":"l","l":"result","v":{"0":"a","f":{"0":"v","l":"run_test"},"a":{"0":"a","f":{"0":"g","l":"exec"},"a":{"0":"v","l":"t"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"failure","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"❌ "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"name"},"a":{"0":"v","l":"t"}}},"a":{"0":"ta"}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"v","l":"should"}},"a":{"0":"v","l":"failure"}}},"t":{"0":"l","l":"fails","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"i","v":1}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"o","l":"fails"},"a":{"0":"v","l":"fails"}},"a":{"0":"v","l":"acc"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"_","b":{"0":"l","l":"passes","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"i","v":1}},"a":{"0":"a","f":{"0":"g","l":"passes"},"a":{"0":"v","l":"acc"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"o","l":"passes"},"a":{"0":"v","l":"passes"}},"a":{"0":"v","l":"acc"}}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"result"}}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"passes"},"a":{"0":"v","l":"acc"}}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" tests, "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" failures."}},"a":{"0":"ta"}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"i","v":0}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"i","v":-1}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}},"a":{"0":"i","v":0}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"run"},"a":{"0":"v","l":"run"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"test"},"a":{"0":"v","l":"test"}},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"expect","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"value","b":{"0":"v","l":"value"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"reason","b":{"0":"a","f":{"0":"p","l":"Error"},"a":{"0":"v","l":"reason"}}}},"a":{"0":"n"}}},"t":{"0":"l","l":"eygir","v":{"0":"l","l":"exp","v":{"0":"l","l":"variable","v":{"0":"t","l":"Variable"},"t":{"0":"l","l":"lambda","v":{"0":"t","l":"Lambda"},"t":{"0":"l","l":"apply","v":{"0":"a","f":{"0":"t","l":"Apply"},"a":{"0":"u"}},"t":{"0":"l","l":"let","v":{"0":"t","l":"Let"},"t":{"0":"l","l":"integer","v":{"0":"t","l":"Integer"},"t":{"0":"l","l":"string","v":{"0":"t","l":"Binary"},"t":{"0":"l","l":"tail","v":{"0":"a","f":{"0":"t","l":"Tail"},"a":{"0":"u"}},"t":{"0":"l","l":"cons","v":{"0":"a","f":{"0":"t","l":"Cons"},"a":{"0":"u"}},"t":{"0":"l","l":"empty","v":{"0":"a","f":{"0":"t","l":"Empty"},"a":{"0":"u"}},"t":{"0":"l","l":"extend","v":{"0":"t","l":"Extend"},"t":{"0":"l","l":"select","v":{"0":"t","l":"Select"},"t":{"0":"l","l":"overwrite","v":{"0":"t","l":"Overwrite"},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"variable"},"a":{"0":"v","l":"variable"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"lambda"},"a":{"0":"v","l":"lambda"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"apply"},"a":{"0":"v","l":"apply"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"let"},"a":{"0":"v","l":"let"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"integer"},"a":{"0":"v","l":"integer"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"tail"},"a":{"0":"v","l":"tail"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"cons"},"a":{"0":"v","l":"cons"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"string"},"a":{"0":"v","l":"string"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"empty"},"a":{"0":"v","l":"empty"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"extend"},"a":{"0":"v","l":"extend"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"select"},"a":{"0":"v","l":"select"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"overwrite"},"a":{"0":"v","l":"overwrite"}},"a":{"0":"u"}}}}}}}}}}}}}}}}}}}}}}}}},"t":{"0":"l","l":"render","v":{"0":"l","l":"expression","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"self","b":{"0":"f","l":"br","b":{"0":"f","l":"source","b":{"0":"l","l":"done","v":{"0":"f","l":"text","b":{"0":"f","l":"rest","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"text"},"a":{"0":"v","l":"text"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"rest"},"a":{"0":"v","l":"rest"}},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"then","v":{"0":"f","l":"renderer","b":{"0":"f","l":"then","b":{"0":"f","l":"rest","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"rendered","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"g","l":"text"},"a":{"0":"v","l":"rendered"}}},"a":{"0":"a","f":{"0":"g","l":"rest"},"a":{"0":"v","l":"rendered"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"reason","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"v","l":"reason"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"renderer"},"a":{"0":"v","l":"rest"}}}}}},"t":{"0":"l","l":"block","v":{"0":"f","l":"br","b":{"0":"f","l":"source","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Let"},"a":{"0":"f","l":"_","b":{"0":"l","l":"br_inner","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"br"}},"a":{"0":"s","v":" "}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"br_inner"}}},"a":{"0":"f","l":"value","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"{"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"br_inner"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"value"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"br"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"}"}},"a":{"0":"ta"}}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"debug"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"parts"}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"br"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"reason","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"v","l":"reason"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}},"t":{"0":"l","l":"spread","v":{"0":"f","l":"reversed","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"l","l":"tail","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":".."}},"a":{"0":"v","l":"tail"}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}}}},"t":{"0":"l","l":"gather_elements","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Tail"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Cons"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}}}},"t":{"0":"l","l":"gather_extend","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Extend"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Empty"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}}}},"t":{"0":"l","l":"gather_overwrite","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Empty"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Overwrite"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}}}},"t":{"0":"l","l":"gather_branches","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"br","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"NoCases"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Case"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"v","l":"br"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}}}}},"t":{"0":"l","l":"exp","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Variable"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"label"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Lambda"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"body","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" -> "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"body"}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"f","l":"source","b":{"0":"l","l":"default","v":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"func","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"arg","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"func"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"("}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"arg"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":")"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Extend"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"s","v":"{"},"t":{"0":"l","l":"post","v":{"0":"s","v":"}"},"t":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"gather_extend"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"s","v":", "}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Overwrite"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"s","v":"{"},"t":{"0":"l","l":"post","v":{"0":"s","v":"}"},"t":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"gather_overwrite"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"s","v":", "}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Case"},"a":{"0":"f","l":"label","b":{"0":"l","l":"br_inner","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"br"}},"a":{"0":"s","v":" "}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br_inner"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"match {"}},"a":{"0":"v","l":"br_inner"}},"t":{"0":"l","l":"post","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"br"}},"a":{"0":"s","v":"}"}},"t":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"gather_branches"},"a":{"0":"v","l":"br_inner"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"v","l":"br_inner"}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Cons"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"s","v":"["},"t":{"0":"l","l":"post","v":{"0":"s","v":"]"},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"gather_elements"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"s","v":", "}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Select"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"arg","b":{"0":"l","l":"rendered","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"arg"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"."}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"rendered"}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Let"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"value","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"rest_or_then","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"let "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" = "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"value"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"br"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"rest_or_then"}},"a":{"0":"ta"}}}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Integer"},"a":{"0":"f","l":"value","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"value"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Binary"},"a":{"0":"f","l":"value","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"\""}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"value"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"\""}},"a":{"0":"ta"}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Tail"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"[]"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Cons"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"cons"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Vacant"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"vacant"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Empty"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"{}"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Extend"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"+"}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Select"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"."}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Overwrite"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":":="}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Tag"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"label"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Case"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"match "}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"NoCases"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"--- no cases ---"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Perform"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"perform "}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Handle"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"handle "}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Builtin"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"TODO this shouldn't really be here"}}}},"a":{"0":"n"}}}}}}}}}}}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"exp"},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}}}}}}}}}}}}},"t":{"0":"a","f":{"0":"v","l":"expression"},"a":{"0":"s","v":"\n"}}},"t":{"0":"l","l":"t","v":{"0":"a","f":{"0":"g","l":"test"},"a":{"0":"v","l":"legit"}},"t":{"0":"l","l":"should_render","v":{"0":"f","l":"output","b":{"0":"f","l":"source","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"output"}},"a":{"0":"s","v":"b"}},"t":{"0":"l","l":"rendered","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"be"},"a":{"0":"v","l":"should"}},"a":{"0":"m","l":"Ok"}},"a":{"0":"a","f":{"0":"v","l":"render"},"a":{"0":"v","l":"source"}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"ta"}},"a":{"0":"a","f":{"0":"g","l":"rest"},"a":{"0":"v","l":"rendered"}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"v","l":"output"}},"a":{"0":"a","f":{"0":"g","l":"text"},"a":{"0":"v","l":"rendered"}}},"t":{"0":"u"}}}}}}},"t":{"0":"l","l":"tests","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"empty"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"be"},"a":{"0":"v","l":"should"}},"a":{"0":"m","l":"Error"}},"a":{"0":"a","f":{"0":"v","l":"render"},"a":{"0":"ta"}}},"t":{"0":"u"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"variable"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"lambda"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"lambda"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"ta"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x -> 2"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"apply"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x(2)"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"let"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"let x = 2\nx"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"integer"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":5}}},"a":{"0":"ta"}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"5"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"string"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"hello"}}},"a":{"0":"ta"}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"\"hello\""}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"multiline lambda"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"lambda"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x -> {\n let y = x\n y\n}"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"multiline let"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"let x = {\n let y = 1\n y\n}\nx"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"extend list"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"exp"}}},"a":{"0":"ta"}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"[1, 2]"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"open list"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"[1, ..x]"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"open list fn application"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"ta"}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"[1, ..x(y)]"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"extend record"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"extend"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"foo"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"extend"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"bar"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"empty"},"a":{"0":"v","l":"exp"}}},"a":{"0":"ta"}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"{foo: 1, bar: 2}"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"select field from record"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"select"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"bar"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"select"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"foo"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x.foo.bar"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"ta"}}}}}}}}}}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"render"},"a":{"0":"v","l":"render"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"tests"},"a":{"0":"v","l":"tests"}},"a":{"0":"u"}}}}}}}},"t":{"0":"l","l":"cli","v":{"0":"z","c":""},"t":{"0":"l","l":"web","v":{"0":"z","c":""},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"cli"},"a":{"0":"v","l":"cli"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"web"},"a":{"0":"v","l":"web"}},"a":{"0":"u"}}}}}}}}}} \ No newline at end of file diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index 3fb82230e..a5e606be1 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -18,10 +18,8 @@ import eyg/runtime/standard import eyg/incremental/store import plinth/javascript/map as mutable_map import eyg/analysis/jm/incremental as jm -import eyg/analysis/jm/tree as jm_tree import eyg/analysis/jm/type_ as jmt - pub type WorkSpace { WorkSpace( selection: List(Int), @@ -71,16 +69,15 @@ pub fn init(source) { map.size(s.free), )) - let start = pnow() + let start = pnow() let doubled = store.ref_group(s) io.debug(#( "doubled took ms:", pnow() - start, map.size(doubled), - map.to_list(doubled) + map.to_list(doubled), )) - let start = pnow() let assert Ok(#(vars, s)) = store.free(s, root) io.debug(#( @@ -90,7 +87,7 @@ pub fn init(source) { map.size(s.free), )) - let start = pnow() + let start = pnow() let assert Ok(#(vars, s)) = store.free_mut(s, root) io.debug(#( "memoizing free mut took ms:", @@ -111,7 +108,6 @@ pub fn init(source) { // t, // )) - let _ = { let sub = map.new() let next = 0 @@ -119,53 +115,53 @@ pub fn init(source) { let source_map = s.source let ref = root let type_ = jmt.Var(-1) - let eff = jmt.Empty + let eff = jmt.Var(-2) let types = map.new() let start = pnow() - let #(sub, _next, typesjm) = jm.infer(sub, next, env, source_map, ref, type_, eff, types) - io.debug(#( - "typing jm took ms:", - pnow() - start, - map.size(typesjm), - )) + let #(sub, _next, typesjm) = + jm.infer(sub, next, env, source_map, ref, type_, eff, types) + io.debug(#("typing jm took ms:", pnow() - start, map.size(typesjm))) let assert Ok(Ok(t)) = map.get(typesjm, root) io.debug(jmt.resolve(t, sub)) - let assert Ok(Ok(t)) = map.get(typesjm, 0) - |> io.debug + let assert Ok(Ok(t)) = + map.get(typesjm, 0) + |> io.debug io.debug(jmt.resolve(t, sub)) let assert Ok(Ok(t)) = map.get(typesjm, 1) io.debug(jmt.resolve(t, sub)) let assert Ok(Ok(t)) = map.get(typesjm, 2) io.debug(jmt.resolve(t, sub)) - io.debug("================") - list.map(map.to_list(typesjm), fn(r) { - let #(id, r) = r - case r { - Ok(_) -> Nil - Error(reason) -> { - io.debug(map.get(s.source, id)) - // io.debug(reason) - io.debug(jmt.resolve_error(reason, sub)) - Nil + list.map( + map.to_list(typesjm), + fn(r) { + let #(id, r) = r + case r { + Ok(_) -> Nil + Error(reason) -> { + io.debug(map.get(s.source, id)) + // io.debug(reason) + io.debug(jmt.resolve_error(reason, sub)) + Nil + } } + }, + ) - } - }) io.debug("================") - - // // new map of types because non function not generic. - // // TODO should this be the case add to gleam explainers - // let types = map.new() - // let start = pnow() - // let #(sub, _next, typesjm) = jm_tree.infer(sub, next, env, source, [], type_, eff, types) - // io.debug(#( - // "typing jm took ms:", - // pnow() - start, - // map.size(typesjm), - // )) } + + // // new map of types because non function not generic. + // // TODO should this be the case add to gleam explainers + // let types = map.new() + // let start = pnow() + // let #(sub, _next, typesjm) = jm_tree.infer(sub, next, env, source, [], type_, eff, types) + // io.debug(#( + // "typing jm took ms:", + // pnow() - start, + // map.size(typesjm), + // )) // let start = pnow() // let assert Ok(c) = store.cursor(s, root, path) // io.debug(#("building store.cursor took ms:", pnow() - start)) @@ -243,7 +239,6 @@ pub fn init(source) { // let start = pnow() // let f2 = new_i.free(refs, f) // io.debug(#("f2 took ms:", pnow() - start)) - // let #(t, s, cache) = new_i.cached(root, refs, f, cache, env.empty(), s, count) // io.debug(#("partial type check took ms:", pnow() - start)) diff --git a/eyg/src/eyg/analysis/jm/env.gleam b/eyg/src/eyg/analysis/jm/env.gleam index 321103836..ca49ac9ab 100644 --- a/eyg/src/eyg/analysis/jm/env.gleam +++ b/eyg/src/eyg/analysis/jm/env.gleam @@ -1,12 +1,13 @@ - import gleam/map import gleam/set -import eyg/analysis/jm/type_ as t import eyg/analysis/jm/scheme -pub type Env = map.Map(String, scheme.Scheme) +pub type Env = + map.Map(String, scheme.Scheme) -fn ftv_for_key(state, _k, scheme) { set.union(state, scheme.ftv(scheme)) } +fn ftv_for_key(state, _k, scheme) { + set.union(state, scheme.ftv(scheme)) +} pub fn ftv(env: Env) { map.fold(env, set.new(), ftv_for_key) @@ -14,4 +15,4 @@ pub fn ftv(env: Env) { pub fn apply(sub, env) { map.map_values(env, fn(_k, scheme) { scheme.apply(sub, scheme) }) -} \ No newline at end of file +} diff --git a/eyg/src/eyg/analysis/jm/error.gleam b/eyg/src/eyg/analysis/jm/error.gleam index cb3a8e59b..e288cbfae 100644 --- a/eyg/src/eyg/analysis/jm/error.gleam +++ b/eyg/src/eyg/analysis/jm/error.gleam @@ -7,4 +7,4 @@ pub type Reason { RowMismatch(String) InvalidTail(t.Type) RecursiveType -} \ No newline at end of file +} diff --git a/eyg/src/eyg/analysis/jm/incremental.gleam b/eyg/src/eyg/analysis/jm/incremental.gleam index 03fbd1a54..31bd957dc 100644 --- a/eyg/src/eyg/analysis/jm/incremental.gleam +++ b/eyg/src/eyg/analysis/jm/incremental.gleam @@ -1,13 +1,11 @@ import gleam/io -import gleam/list import gleam/map -import gleam/set import eyg/incremental/source as e import eyg/analysis/jm/error import eyg/analysis/jm/type_ as t -import eyg/analysis/jm/env -import eyg/analysis/jm/unify -import eyg/analysis/jm/infer.{Cont, loop, instantiate, generalise, unify_at, extend, mono, Done, builtins} +import eyg/analysis/jm/infer.{ + Cont, Done, builtins, extend, generalise, instantiate, loop, mono, unify_at, +} pub fn infer(sub, next, env, source, ref, type_, eff, types) { loop(step(sub, next, env, source, ref, type_, eff, types, Done)) @@ -15,90 +13,146 @@ pub fn infer(sub, next, env, source, ref, type_, eff, types) { // TODO occurs in and recursive row check +// TODO acc = sub, nex, types +// step(acc, env, source, ref, t0, e0, k) fn step(sub, next, env, source, ref, type_, eff, types, k) { case map.get(source, ref) { - Error(Nil) -> Cont(#(sub, next, types), k) - Ok(exp) -> case exp { - e.Var(x) -> fetch(env, x, sub, next, types, ref, type_, k) - e.Call(e1, e2) -> { - // can't error - let types = map.insert(types, ref, Ok(type_)) - let #(arg, next) = t.fresh(next) - use #(sub, next, types) <- step(sub, next, env, source, e1, t.Fun(arg, eff, type_), eff, types) - use #(sub, next, types) <- step(sub, next, env, source, e2, arg, eff, types) - Cont(#(sub, next, types), k) - } - e.Fn(x, e1) -> { - let #(arg, next) = t.fresh(next) - let #(new_eff, next) = t.fresh(next) - let #(ret, next) = t.fresh(next) - let #(sub, next, types) = unify_at(type_, t.Fun(arg, new_eff, ret), sub, next, types, ref) - let env = extend(env, x, mono(arg)) - use #(sub, next, types) <- step(sub, next, env, source, e1, ret, new_eff, types) - Cont(#(sub, next, types), k) - } - e.Let(x, e1, e2) -> { - // can't error - let types = map.insert(types, ref, Ok(type_)) - let #(inner, next) = t.fresh(next) - use #(sub, next, types) <- step(sub, next, env, source, e1, inner, eff, types) - let env = extend(env, x, generalise(sub, env, inner)) - use #(sub, next, types) <- step(sub, next, env, source, e2, type_, eff, types) - Cont(#(sub, next, types), k) - } - e.Builtin(identifier) -> fetch(builtins(), identifier, sub, next, types, ref, type_, k) - literal -> { - let #(found, next) = primitive(literal, next) - Cont(unify_at(type_, found, sub, next, types, ref), k) + Error(Nil) -> Cont(#(sub, next, types), k) + Ok(exp) -> + case exp { + e.Var(x) -> fetch(env, x, sub, next, types, ref, type_, k) + e.Call(e1, e2) -> { + // can't error + let types = map.insert(types, ref, Ok(type_)) + let #(arg, next) = t.fresh(next) + use #(sub, next, types) <- step( + sub, + next, + env, + source, + e1, + t.Fun(arg, eff, type_), + eff, + types, + ) + use #(sub, next, types) <- step( + sub, + next, + env, + source, + e2, + arg, + eff, + types, + ) + Cont(#(sub, next, types), k) + } + e.Fn(x, e1) -> { + let #(arg, next) = t.fresh(next) + let #(new_eff, next) = t.fresh(next) + let #(ret, next) = t.fresh(next) + let #(sub, next, types) = + unify_at(type_, t.Fun(arg, new_eff, ret), sub, next, types, ref) + let env = extend(env, x, mono(arg)) + use #(sub, next, types) <- step( + sub, + next, + env, + source, + e1, + ret, + new_eff, + types, + ) + Cont(#(sub, next, types), k) + } + e.Let(x, e1, e2) -> { + // can't error + let types = map.insert(types, ref, Ok(type_)) + let #(inner, next) = t.fresh(next) + use #(sub, next, types) <- step( + sub, + next, + env, + source, + e1, + inner, + eff, + types, + ) + let env = extend(env, x, generalise(sub, env, inner)) + io.debug(#("gen", x)) + use #(sub, next, types) <- step( + sub, + next, + env, + source, + e2, + type_, + eff, + types, + ) + Cont(#(sub, next, types), k) + } + e.Builtin(identifier) -> + fetch(builtins(), identifier, sub, next, types, ref, type_, k) + literal -> { + let #(found, next) = primitive(literal, next) + Cont(unify_at(type_, found, sub, next, types, ref), k) + } } - } } } -fn primitive(exp, next) { - case exp { - e.Var(_) | e.Call(_,_) | e.Fn(_,_) | e.Let(_,_,_) | e.Builtin(_) -> panic("not a literal") - e.String(_) -> #(t.String, next) - e.Integer(_) -> #(t.Integer, next) +fn primitive(exp, next) { + case exp { + e.Var(_) | e.Call(_, _) | e.Fn(_, _) | e.Let(_, _, _) | e.Builtin(_) -> + panic("not a literal") + e.String(_) -> #(t.String, next) + e.Integer(_) -> #(t.Integer, next) - e.Tail -> t.tail(next) - e.Cons -> t.cons(next) - e.Vacant(_comment) -> t.fresh(next) + e.Tail -> t.tail(next) + e.Cons -> t.cons(next) + e.Vacant(_comment) -> t.fresh(next) - // Record - e.Empty -> t.empty(next) - e.Extend(label) -> t.extend(label, next) - e.Overwrite(label) -> t.overwrite(label, next) - e.Select(label) -> t.select(label, next) + // Record + e.Empty -> t.empty(next) + e.Extend(label) -> t.extend(label, next) + e.Overwrite(label) -> t.overwrite(label, next) + e.Select(label) -> t.select(label, next) - // Union - e.Tag(label) -> t.tag(label, next) - e.Case(label) -> t.case_(label, next) - e.NoCases -> t.nocases(next) + // Union + e.Tag(label) -> t.tag(label, next) + e.Case(label) -> t.case_(label, next) + e.NoCases -> t.nocases(next) - // Effect - e.Perform(label) -> t.perform(label, next) - e.Handle(label) -> t.handle(label, next) + // Effect + e.Perform(label) -> t.perform(label, next) + e.Handle(label) -> t.handle(label, next) } } fn fetch(env, x, sub, next, types, ref, type_, k) { case map.get(env, x) { - Ok(scheme) -> { + Ok(scheme) -> { let #(found, next) = instantiate(scheme, next) - case x == "should_render" { + case x == "equal" { False -> Nil True -> { - io.debug(#(x, found, next)) + io.debug(#("!!!!", scheme, x, found, next)) Nil } } Cont(unify_at(type_, found, sub, next, types, ref), k) } Error(Nil) -> { - let types = map.insert(types, ref, Error(#(error.MissingVariable(x), type_, t.Var(-100)))) + let types = + map.insert( + types, + ref, + Error(#(error.MissingVariable(x), type_, t.Var(-100))), + ) Cont(#(sub, next, types), k) } } } - diff --git a/eyg/src/eyg/analysis/jm/infer.gleam b/eyg/src/eyg/analysis/jm/infer.gleam index b2349703a..3b5d184db 100644 --- a/eyg/src/eyg/analysis/jm/infer.gleam +++ b/eyg/src/eyg/analysis/jm/infer.gleam @@ -2,25 +2,24 @@ import gleam/io import gleam/list import gleam/map import gleam/set -import eyg/incremental/source as e import eyg/analysis/jm/error import eyg/analysis/jm/type_ as t import eyg/analysis/jm/env import eyg/analysis/jm/unify + // import harness/ffi/core // import harness/ffi/integer // import harness/ffi/linked_list // import harness/ffi/string // import eyg/analysis/typ as old_t - -pub fn mono(type_) { +pub fn mono(type_) { #([], type_) } // reference substitution env and type. // causes circular dependencies to move to any other file -pub fn generalise(sub, env, t) { +pub fn generalise(sub, env, t) { let env = env.apply(sub, env) let t = t.apply(sub, t) let forall = set.drop(t.ftv(t), set.to_list(env.ftv(env))) @@ -29,25 +28,35 @@ pub fn generalise(sub, env, t) { pub fn instantiate(scheme, next) { let #(forall, type_) = scheme - let s = list.index_map(forall, fn(i, old) { #(old, t.Var(next + i))}) - |> map.from_list() + let s = + list.index_map(forall, fn(i, old) { #(old, t.Var(next + i)) }) + |> map.from_list() let next = next + list.length(forall) let type_ = t.apply(s, type_) #(type_, next) } -pub fn extend(env, label, scheme) { +pub fn extend(env, label, scheme) { map.insert(env, label, scheme) } pub fn unify_at(type_, found, sub, next, types, ref) { case unify.unify(type_, found, sub, next) { - Ok(#(s, next)) -> #(s, next, map.insert(types, ref, Ok(type_))) - Error(reason) -> #(sub, next, map.insert(types, ref, Error(#(reason, type_, found)))) + Ok(#(s, next)) -> #(s, next, map.insert(types, ref, Ok(type_))) + Error(reason) -> #( + sub, + next, + map.insert(types, ref, Error(#(reason, type_, found))), + ) } } -pub type State = #(t.Substitutions, Int, map.Map(Int, Result(t.Type, #(error.Reason, t.Type, t.Type)))) +pub type State = + #( + t.Substitutions, + Int, + map.Map(Int, Result(t.Type, #(error.Reason, t.Type, t.Type))), + ) pub type Run { Cont(State, fn(State) -> Run) @@ -62,7 +71,7 @@ pub fn loop(run) { } } -pub fn builtins() { +pub fn builtins() { map.new() |> extend_b("equal", equal()) |> extend_b("debug", debug()) @@ -89,14 +98,12 @@ pub fn builtins() { |> extend_b("list_fold", fold()) } - - -fn extend_b(env, key, t) { - let scheme = generalise( map.new(), map.new(), t) - case key == "should_render" { +fn extend_b(env, key, t) { + let scheme = generalise(map.new(), map.new(), t) + case key == "equal" { False -> Nil True -> { - io.debug(#(key, scheme, t)) + io.debug(#("------------>>>", key, scheme, t)) Nil } } @@ -104,79 +111,75 @@ fn extend_b(env, key, t) { } // THere could be part of std -pub fn equal() { +pub fn equal() { t.Fun(t.Var(0), t.Var(1), t.Fun(t.Var(0), t.Var(2), t.boolean)) } -pub fn debug() { +pub fn debug() { t.Fun(t.Var(0), t.Var(1), t.String) } -pub fn fix() { - t.Fun( - t.Fun(t.Var(0), t.Var(1), t.Var(0)), - t.Var(2), - t.Var(0), - ) +pub fn fix() { + t.Fun(t.Fun(t.Var(0), t.Var(1), t.Var(0)), t.Var(2), t.Var(0)) } -pub fn serialize() { +pub fn serialize() { t.Fun(t.Var(0), t.Var(1), t.String) } -pub fn capture() { +pub fn capture() { t.Fun(t.Var(0), t.Var(1), t.Var(2)) } -pub fn encode_uri() { +pub fn encode_uri() { t.Fun(t.String, t.Var(1), t.String) } // int // TODO fn2 taking a next would make handling curried fns easier -pub fn add() { +pub fn add() { t.Fun(t.Integer, t.Var(0), t.Fun(t.Integer, t.Var(1), t.Integer)) } -pub fn subtract() { +pub fn subtract() { t.Fun(t.Integer, t.Var(0), t.Fun(t.Integer, t.Var(1), t.Integer)) } -pub fn multiply() { +pub fn multiply() { t.Fun(t.Integer, t.Var(0), t.Fun(t.Integer, t.Var(1), t.Integer)) } -pub fn divide() { +pub fn divide() { t.Fun(t.Integer, t.Var(0), t.Fun(t.Integer, t.Var(1), t.Integer)) } -pub fn absolute() { +pub fn absolute() { t.Fun(t.Integer, t.Var(0), t.Integer) } // TODO parse -pub fn to_string() { +pub fn to_string() { t.Fun(t.Integer, t.Var(0), t.String) } -pub fn append() { +pub fn append() { t.Fun(t.String, t.Var(0), t.Fun(t.String, t.Var(1), t.String)) } -pub fn uppercase() { +pub fn uppercase() { t.Fun(t.String, t.Var(0), t.String) } -pub fn lowercase() { +pub fn lowercase() { t.Fun(t.String, t.Var(0), t.String) } -pub fn length() { +pub fn length() { t.Fun(t.String, t.Var(0), t.Integer) } -pub fn pop() { +pub fn pop() { let parts = t.Record(t.RowExtend( "head", @@ -198,18 +201,6 @@ pub fn fold() { t.Fun( t.LinkedList(item), eff1, - t.Fun( - acc, - eff2, - t.Fun( - t.Fun( - item, - eff3, - t.Fun(acc, eff4, acc), - ), - eff5, - acc, - ), - ), + t.Fun(acc, eff2, t.Fun(t.Fun(item, eff3, t.Fun(acc, eff4, acc)), eff5, acc)), ) -} \ No newline at end of file +} diff --git a/eyg/src/eyg/analysis/jm/scheme.gleam b/eyg/src/eyg/analysis/jm/scheme.gleam index 6833c84e5..576a5af75 100644 --- a/eyg/src/eyg/analysis/jm/scheme.gleam +++ b/eyg/src/eyg/analysis/jm/scheme.gleam @@ -2,7 +2,8 @@ import gleam/map import gleam/set import eyg/analysis/jm/type_ as t -pub type Scheme = #(List(Int), t.Type) +pub type Scheme = + #(List(Int), t.Type) pub fn ftv(scheme) { let #(forall, typ) = scheme @@ -12,4 +13,4 @@ pub fn ftv(scheme) { pub fn apply(sub, scheme) { let #(forall, typ) = scheme #(forall, t.apply(map.drop(sub, forall), typ)) -} \ No newline at end of file +} diff --git a/eyg/src/eyg/analysis/jm/tree.gleam b/eyg/src/eyg/analysis/jm/tree.gleam index 578ff1028..1146d1274 100644 --- a/eyg/src/eyg/analysis/jm/tree.gleam +++ b/eyg/src/eyg/analysis/jm/tree.gleam @@ -1,17 +1,15 @@ -import gleam/io -import gleam/list import gleam/map -import gleam/set import eygir/expression as e import eyg/analysis/jm/error import eyg/analysis/jm/type_ as t -import eyg/analysis/jm/env -import eyg/analysis/jm/unify -import eyg/analysis/jm/infer.{ instantiate, generalise, unify_at, extend, mono} -import eyg/analysis/typ as old_t +import eyg/analysis/jm/infer.{extend, generalise, instantiate, mono, unify_at} - -pub type State = #(t.Substitutions, Int, map.Map(List(Int), Result(t.Type, #(error.Reason, t.Type, t.Type)))) +pub type State = + #( + t.Substitutions, + Int, + map.Map(List(Int), Result(t.Type, #(error.Reason, t.Type, t.Type))), + ) pub type Run { Cont(State, fn(State) -> Run) @@ -31,81 +29,132 @@ pub fn infer(sub, next, env, exp, path, type_, eff, types) { } fn step(sub, next, env, exp, path, type_, eff, types, k) { - // io.debug(exp) - case exp { - e.Variable(x) -> { - case map.get(env, x) { - Ok(scheme) -> { - let #(found, next) = instantiate(scheme, next) - Cont(unify_at(type_, found, sub, next, types, path), k) - } - Error(Nil) -> { - let types = map.insert(types, path, Error(#(error.MissingVariable(x), type_, t.Var(-100)))) - Cont(#(sub, next, types), k) - } + // io.debug(exp) + case exp { + e.Variable(x) -> { + case map.get(env, x) { + Ok(scheme) -> { + let #(found, next) = instantiate(scheme, next) + Cont(unify_at(type_, found, sub, next, types, path), k) + } + Error(Nil) -> { + let types = + map.insert( + types, + path, + Error(#(error.MissingVariable(x), type_, t.Var(-100))), + ) + Cont(#(sub, next, types), k) } - } - e.Apply(e1, e2) -> { - // can't error - let types = map.insert(types, path, Ok(type_)) - let #(arg, next) = t.fresh(next) - use #(sub, next, types) <- step(sub, next, env, e1, [0,..path], t.Fun(arg, eff, type_), eff, types) - use #(sub, next, types) <- step(sub, next, env, e2, [1,..path], arg, eff, types) - Cont(#(sub, next, types), k) - } - e.Lambda(x, e1) -> { - let #(arg, next) = t.fresh(next) - let #(eff, next) = t.fresh(next) - let #(ret, next) = t.fresh(next) - let #(sub, next, types) = unify_at(type_, t.Fun(arg, eff, ret), sub, next, types, path) - let env = extend(env, x, mono(arg)) - use #(sub, next, types) <- step(sub, next, env, e1, [0, ..path], ret, eff, types) - Cont(#(sub, next, types), k) - } - e.Let(x, e1, e2) -> { - // can't error - let types = map.insert(types, path, Ok(type_)) - let #(inner, next) = t.fresh(next) - use #(sub, next, types) <- step(sub, next, env, e1, [0,..path], inner, eff, types) - let env = extend(env, x, generalise(sub, env, inner)) - use #(sub, next, types) <- step(sub, next, env, e2, [1,..path], type_, eff, types) - Cont(#(sub, next, types), k) - } - literal -> { - let #(found, next) = primitive(literal, next) - Cont(unify_at(type_, found, sub, next, types, path), k) } } - + e.Apply(e1, e2) -> { + // can't error + let types = map.insert(types, path, Ok(type_)) + let #(arg, next) = t.fresh(next) + use #(sub, next, types) <- step( + sub, + next, + env, + e1, + [0, ..path], + t.Fun(arg, eff, type_), + eff, + types, + ) + use #(sub, next, types) <- step( + sub, + next, + env, + e2, + [1, ..path], + arg, + eff, + types, + ) + Cont(#(sub, next, types), k) + } + e.Lambda(x, e1) -> { + let #(arg, next) = t.fresh(next) + let #(eff, next) = t.fresh(next) + let #(ret, next) = t.fresh(next) + let #(sub, next, types) = + unify_at(type_, t.Fun(arg, eff, ret), sub, next, types, path) + let env = extend(env, x, mono(arg)) + use #(sub, next, types) <- step( + sub, + next, + env, + e1, + [0, ..path], + ret, + eff, + types, + ) + Cont(#(sub, next, types), k) + } + e.Let(x, e1, e2) -> { + // can't error + let types = map.insert(types, path, Ok(type_)) + let #(inner, next) = t.fresh(next) + use #(sub, next, types) <- step( + sub, + next, + env, + e1, + [0, ..path], + inner, + eff, + types, + ) + let env = extend(env, x, generalise(sub, env, inner)) + use #(sub, next, types) <- step( + sub, + next, + env, + e2, + [1, ..path], + type_, + eff, + types, + ) + Cont(#(sub, next, types), k) + } + literal -> { + let #(found, next) = primitive(literal, next) + Cont(unify_at(type_, found, sub, next, types, path), k) + } + } } -fn primitive(exp, next) { - case exp { - e.Variable(_) | e.Apply(_,_) | e.Lambda(_,_) | e.Let(_,_,_) -> panic("not a literal") - e.Binary(_) -> #(t.String, next) - e.Integer(_) -> #(t.Integer, next) +fn primitive(exp, next) { + case exp { + e.Variable(_) | e.Apply(_, _) | e.Lambda(_, _) | e.Let(_, _, _) -> + panic("not a literal") + e.Binary(_) -> #(t.String, next) + e.Integer(_) -> #(t.Integer, next) - e.Tail -> t.tail(next) - e.Cons -> t.cons(next) - e.Vacant(_comment) -> t.fresh(next) + e.Tail -> t.tail(next) + e.Cons -> t.cons(next) + e.Vacant(_comment) -> t.fresh(next) - // Record - e.Empty -> t.empty(next) - e.Extend(label) -> t.extend(label, next) - e.Overwrite(label) -> t.overwrite(label, next) - e.Select(label) -> t.select(label, next) + // Record + e.Empty -> t.empty(next) + e.Extend(label) -> t.extend(label, next) + e.Overwrite(label) -> t.overwrite(label, next) + e.Select(label) -> t.select(label, next) - // Union - e.Tag(label) -> t.tag(label, next) - e.Case(label) -> t.case_(label, next) - e.NoCases -> t.nocases(next) + // Union + e.Tag(label) -> t.tag(label, next) + e.Case(label) -> t.case_(label, next) + e.NoCases -> t.nocases(next) - // Effect - e.Perform(label) -> t.perform(label, next) - e.Handle(label) -> t.handle(label, next) + // Effect + e.Perform(label) -> t.perform(label, next) + e.Handle(label) -> t.handle(label, next) - // TODO use real builtins - e.Builtin(identifier) -> t.fresh(next) - // _ -> todo("pull from old inference") - } + // TODO use real builtins + e.Builtin(identifier) -> t.fresh(next) + } + // _ -> todo("pull from old inference") } diff --git a/eyg/src/eyg/analysis/jm/type_.gleam b/eyg/src/eyg/analysis/jm/type_.gleam index 5bfb5491a..435229883 100644 --- a/eyg/src/eyg/analysis/jm/type_.gleam +++ b/eyg/src/eyg/analysis/jm/type_.gleam @@ -1,5 +1,4 @@ import gleam/map -import gleam/result import gleam/set import gleam/setx @@ -17,7 +16,8 @@ pub type Type { EffectExtend(String, #(Type, Type), Type) } -pub type Substitutions = map.Map(Int, Type) +pub type Substitutions = + map.Map(Int, Type) pub fn ftv(type_) { case type_ { @@ -30,17 +30,19 @@ pub fn ftv(type_) { Union(row) -> ftv(row) Empty -> set.new() RowExtend(_label, value, rest) -> set.union(ftv(value), ftv(rest)) - EffectExtend(_label, #(lift, reply), rest) -> set.union(set.union(ftv(lift), ftv(reply)), ftv(rest)) + EffectExtend(_label, #(lift, reply), rest) -> + set.union(set.union(ftv(lift), ftv(reply)), ftv(rest)) } } pub fn apply(s, type_) { case type_ { // This is recursive, get to the bottom of this - Var(a) -> case map.get(s, a) { - Ok(new) -> apply(s, new) - Error(Nil) -> type_ - } + Var(a) -> + case map.get(s, a) { + Ok(new) -> apply(s, new) + Error(Nil) -> type_ + } Fun(from, effects, to) -> Fun(apply(s, from), apply(s, effects), apply(s, to)) Integer | String -> type_ @@ -48,8 +50,10 @@ pub fn apply(s, type_) { Record(row) -> Record(apply(s, row)) Union(row) -> Union(apply(s, row)) Empty -> type_ - RowExtend(label, value, rest) -> RowExtend(label, apply(s, value), apply(s, rest)) - EffectExtend(label, #(lift, reply), rest) -> EffectExtend(label, #(apply(s, lift), apply(s, reply)), apply(s, rest)) + RowExtend(label, value, rest) -> + RowExtend(label, apply(s, value), apply(s, rest)) + EffectExtend(label, #(lift, reply), rest) -> + EffectExtend(label, #(apply(s, lift), apply(s, reply)), apply(s, rest)) } } @@ -58,18 +62,20 @@ pub fn resolve(t, s) { // Var(a) -> // map.get(s, a) // |> result.unwrap(t) - Var(a) -> case map.get(s, a) { - // recursive resolve needed for non direct unification - Ok(u) -> resolve(u, s) - Error(Nil) -> t - } + Var(a) -> + case map.get(s, a) { + // recursive resolve needed for non direct unification + Ok(u) -> resolve(u, s) + Error(Nil) -> t + } Fun(u, v, w) -> Fun(resolve(u, s), resolve(v, s), resolve(w, s)) String | Integer | Empty -> t LinkedList(element) -> LinkedList(resolve(element, s)) Record(u) -> Record(resolve(u, s)) Union(u) -> Union(resolve(u, s)) - RowExtend(label, u, v) -> RowExtend(label, resolve(u, s), resolve(v, s)) - EffectExtend(label, #(u, v), w) -> EffectExtend(label, #(resolve(u, s), resolve(v, s)), resolve(w, s)) + RowExtend(label, u, v) -> RowExtend(label, resolve(u, s), resolve(v, s)) + EffectExtend(label, #(u, v), w) -> + EffectExtend(label, #(resolve(u, s), resolve(v, s)), resolve(w, s)) } } @@ -78,11 +84,11 @@ pub fn resolve_error(reason, s) { #(x, resolve(t1, s), resolve(t2, s)) } -pub fn fresh(next) { +pub fn fresh(next) { #(Var(next), next + 1) } -pub fn tail(next) { +pub fn tail(next) { let #(item, next) = fresh(next) #(LinkedList(item), next) } @@ -104,7 +110,8 @@ pub fn extend(label, next) { let #(rest, next) = fresh(next) let #(e1, next) = fresh(next) let #(e2, next) = fresh(next) - let t = Fun(value, e1, Fun(Record(rest), e2, Record(RowExtend(label, value, rest)))) + let t = + Fun(value, e1, Fun(Record(rest), e2, Record(RowExtend(label, value, rest)))) #(t, next) } @@ -122,7 +129,16 @@ pub fn overwrite(label, next) { let #(rest, next) = fresh(next) let #(e1, next) = fresh(next) let #(e2, next) = fresh(next) - let t = Fun(new, e1, Fun(Record(RowExtend(label, old, rest)), e2, Record(RowExtend(label, new, rest)))) + let t = + Fun( + new, + e1, + Fun( + Record(RowExtend(label, old, rest)), + e2, + Record(RowExtend(label, new, rest)), + ), + ) #(t, next) } @@ -181,7 +197,9 @@ pub fn handle(label, next) { pub const unit = Record(Empty) -pub const boolean = Union(RowExtend("True", unit, RowExtend("False", unit, Empty))) +pub const boolean = Union( + RowExtend("True", unit, RowExtend("False", unit, Empty)), +) pub fn result(value, reason) { Union(RowExtend("Ok", value, RowExtend("Error", reason, Empty))) @@ -189,4 +207,4 @@ pub fn result(value, reason) { pub fn option(value) { Union(RowExtend("Some", value, RowExtend("None", unit, Empty))) -} \ No newline at end of file +} diff --git a/eyg/src/eyg/analysis/jm/unify.gleam b/eyg/src/eyg/analysis/jm/unify.gleam index c9845f09b..027300eef 100644 --- a/eyg/src/eyg/analysis/jm/unify.gleam +++ b/eyg/src/eyg/analysis/jm/unify.gleam @@ -1,62 +1,80 @@ -import gleam/io import gleam/map import gleam/result import gleam/set import eyg/analysis/jm/type_ as t import eyg/analysis/jm/error -pub fn unify(t1, t2, s, next) { - do_unify([#(t1, t2)], s, next) +pub fn unify(t1, t2, s, next) { + do_unify([#(t1, t2)], s, next) } + // I dont think this is the same as described because we don't keep lookup to original i. // s is a function from var -> t -fn do_unify(constraints, s, next) { +fn do_unify(constraints, s, next) { // Have to try and substitute at every point because new substitutions can come into existance // Because we don't replace for each new sub we need to apply at match time. // Do unify can introduce new subs and get called recursivly case constraints { [] -> Ok(#(s, next)) - [#(t1, t2), ..rest] -> case t.apply(s, t1), t.apply(s,t2) { - t.Var(i), t.Var(j) if i == j -> do_unify(rest, s, next) - t.Var(i), t1 | t1, t.Var(i) -> case set.contains(t.ftv(t1), i) { - True -> Error(error.RecursiveType) - False -> do_unify(rest, map.insert(s, i, t1), next) - } - t.Fun(a1, e1, r1), t.Fun(a2, e2, r2) -> do_unify([#(a1, a2), #(e1, e2), #(r1, r2), ..rest], s, next) - t.Integer, t.Integer -> do_unify(rest, s, next) - t.String, t.String -> do_unify(rest, s, next) - t.LinkedList(i1), t.LinkedList(i2) -> do_unify([#(i1, i2), ..rest], s, next) - t.Record(r1), t.Record(r2) -> do_unify([#(r1, r2), ..rest], s, next) - t.Union(r1), t.Union(r2) -> do_unify([#(r1, r2), ..rest], s, next) - t.Empty, t.Empty -> do_unify(rest, s, next) - t.RowExtend(label1, value1, tail1), t.RowExtend(_,_,_) as row2 -> { - use #(value2, tail2, s1, next) <- result.then(rewrite_row(label1, row2, s, next)) - // case tail1 { - // t.Var(x) -> { - // io.debug(#("---->", map.get(s, x))) - // Nil - // } - // _ -> Nil - // } - let s = s1 - do_unify([#(value1, value2), #(tail1, tail2), ..rest], s, next) - } - t.EffectExtend(label1, #(lift1, reply1), tail1), t.EffectExtend(_,_,_) as row2 -> { - use #(lift2, reply2, tail2, s, next) <- result.then(rewrite_effect(label1, row2, s, next)) - do_unify([#(lift1, lift2), #(reply1, reply2), #(tail1, tail2), ..rest], s, next) + [#(t1, t2), ..rest] -> + case t.apply(s, t1), t.apply(s, t2) { + t.Var(i), t.Var(j) if i == j -> do_unify(rest, s, next) + t.Var(i), t1 | t1, t.Var(i) -> + case set.contains(t.ftv(t1), i) { + True -> Error(error.RecursiveType) + False -> do_unify(rest, map.insert(s, i, t1), next) + } + t.Fun(a1, e1, r1), t.Fun(a2, e2, r2) -> + do_unify([#(a1, a2), #(e1, e2), #(r1, r2), ..rest], s, next) + t.Integer, t.Integer -> do_unify(rest, s, next) + t.String, t.String -> do_unify(rest, s, next) + t.LinkedList(i1), t.LinkedList(i2) -> + do_unify([#(i1, i2), ..rest], s, next) + t.Record(r1), t.Record(r2) -> do_unify([#(r1, r2), ..rest], s, next) + t.Union(r1), t.Union(r2) -> do_unify([#(r1, r2), ..rest], s, next) + t.Empty, t.Empty -> do_unify(rest, s, next) + t.RowExtend(label1, value1, tail1), t.RowExtend(_, _, _) as row2 -> { + use #(value2, tail2, s1, next) <- result.then(rewrite_row( + label1, + row2, + s, + next, + )) + // case tail1 { + // t.Var(x) -> { + // io.debug(#("---->", map.get(s, x))) + // Nil + // } + // _ -> Nil + // } + let s = s1 + do_unify([#(value1, value2), #(tail1, tail2), ..rest], s, next) + } + t.EffectExtend(label1, #(lift1, reply1), tail1), t.EffectExtend(_, _, _) as row2 -> { + use #(lift2, reply2, tail2, s, next) <- result.then(rewrite_effect( + label1, + row2, + s, + next, + )) + do_unify( + [#(lift1, lift2), #(reply1, reply2), #(tail1, tail2), ..rest], + s, + next, + ) + } + t1, t2 -> Error(error.TypeMismatch(t1, t2)) } - t1, t2 -> Error(error.TypeMismatch(t1, t2)) - } } } // alg J with rows is interesting // I think fsharp impl has bug of not accepting open rows at first pass -fn rewrite_row(new_label, row, s, next) { +fn rewrite_row(new_label, row, s, next) { case row { - t.Empty -> Error(error.RowMismatch(new_label)) - t.RowExtend(label, value, tail) if label == new_label -> + t.Empty -> Error(error.RowMismatch(new_label)) + t.RowExtend(label, value, tail) if label == new_label -> Ok(#(value, tail, s, next)) t.Var(a) -> { let #(value, next) = t.fresh(next) @@ -65,17 +83,22 @@ fn rewrite_row(new_label, row, s, next) { Ok(#(value, tail, s, next)) } t.RowExtend(label, value, tail) -> { - use #(value_new, tail_new, s, next) <- result.then(rewrite_row(new_label, tail, s, next)) + use #(value_new, tail_new, s, next) <- result.then(rewrite_row( + new_label, + tail, + s, + next, + )) Ok(#(value_new, t.RowExtend(label, value, tail_new), s, next)) } _ -> Error(error.InvalidTail(row)) } } -fn rewrite_effect(new_label, effect, s, next) { +fn rewrite_effect(new_label, effect, s, next) { case effect { - t.Empty -> Error(error.RowMismatch(new_label)) - t.EffectExtend(label, #(lift, reply), tail) if label == new_label -> + t.Empty -> Error(error.RowMismatch(new_label)) + t.EffectExtend(label, #(lift, reply), tail) if label == new_label -> Ok(#(lift, reply, tail, s, next)) t.Var(a) -> { let #(lift, next) = t.fresh(next) @@ -85,9 +108,14 @@ fn rewrite_effect(new_label, effect, s, next) { Ok(#(lift, reply, tail, s, next)) } t.EffectExtend(label, field, tail) -> { - use #(lift_new, reply_new, tail_new, s, next) <- result.then(rewrite_effect(new_label, tail, s, next)) + use #(lift_new, reply_new, tail_new, s, next) <- result.then(rewrite_effect( + new_label, + tail, + s, + next, + )) Ok(#(lift_new, reply_new, t.EffectExtend(label, field, tail_new), s, next)) } _ -> Error(error.InvalidTail(effect)) } -} \ No newline at end of file +} From 282909baa4a623d82523e699057ed63ff2202d2c Mon Sep 17 00:00:00 2001 From: Peter Saxton Date: Mon, 24 Apr 2023 23:20:09 +0200 Subject: [PATCH 56/62] notes --- eyg/test/eyg/analysis/typing_test.gleam | 52 +++++++++++++++++++------ 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/eyg/test/eyg/analysis/typing_test.gleam b/eyg/test/eyg/analysis/typing_test.gleam index a0fd665f8..35d4b9aa6 100644 --- a/eyg/test/eyg/analysis/typing_test.gleam +++ b/eyg/test/eyg/analysis/typing_test.gleam @@ -61,7 +61,7 @@ pub fn free_type_variables_test() { |> should.equal(set.from_list([t.Term(1), t.Term(2), t.Effect(3)])) } -fn jm(exp, type_, eff) { +fn jm(exp, type_, eff) { let #(root, store) = store.load(store.empty(), exp) let sub = map.new() @@ -71,15 +71,22 @@ fn jm(exp, type_, eff) { let ref = root let types = map.new() - let #(sub, _next, types) = jm.infer(sub, next, env, source, ref, type_, eff, types) + let #(sub, _next, types) = + jm.infer(sub, next, env, source, ref, type_, eff, types) case map.get(types, root) { Ok(Ok(t)) -> Ok(jmt.resolve(t, sub)) Ok(Error(reason)) -> Error(reason) // DOes panic expression print message Error(_) -> { io.debug(root) - io.debug(source |> map.to_list) - io.debug(types |> map.to_list) + io.debug( + source + |> map.to_list, + ) + io.debug( + types + |> map.to_list, + ) todo("no typr") } } @@ -107,7 +114,11 @@ pub fn binary_test() { let typ = t.Integer let sub = infer(env, exp, typ, eff) let assert Error(_) = type_of(sub, []) - let assert Error(#(jm_error.TypeMismatch(jmt.Integer, jmt.String), jmt.Integer, jmt.String)) = jm(exp, type_.Integer, type_.Empty) + let assert Error(#( + jm_error.TypeMismatch(jmt.Integer, jmt.String), + jmt.Integer, + jmt.String, + )) = jm(exp, type_.Integer, type_.Empty) } pub fn integer_test() { @@ -160,6 +171,8 @@ pub fn empty_list_test() { let typ = t.Binary let sub = infer(env, exp, typ, eff) let assert Error(_) = type_of(sub, []) + let assert Ok(type_.LinkedList(type_.Var(_))) = + jm(exp, type_.Var(-1), type_.Empty) } pub fn primitive_list_test() { @@ -170,7 +183,8 @@ pub fn primitive_list_test() { let eff = t.Closed let sub = infer(env, exp, typ, eff) let assert Ok(t.LinkedList(t.Binary)) = type_of(sub, []) - let assert Ok(type_.LinkedList(type_.Integer)) = jm(exp, type_.Var(-1), type_.Empty) + let assert Ok(type_.LinkedList(type_.Integer)) = + jm(exp, type_.Var(-1), type_.Empty) // THere is an error missing and the principle is wrong let assert Ok(t.Fun(t.LinkedList(t.Binary), t.Closed, t.LinkedList(t.Binary))) = @@ -213,7 +227,8 @@ pub fn function_test() { let typ = t.Unbound(-1) let sub = infer(env, exp, typ, eff) let assert t.Fun(t.Unbound(_), t.Open(_), t.Binary) = resolve(sub, typ) - let assert Ok(type_.Fun(type_.Var(_), type_.Var(_), type_.String)) = jm(exp, type_.Var(-1), type_.Empty) + let assert Ok(type_.Fun(type_.Var(_), type_.Var(_), type_.String)) = + jm(exp, type_.Var(-1), type_.Empty) } pub fn pure_function_test() { @@ -227,7 +242,8 @@ pub fn pure_function_test() { should.equal(x, y) let assert Ok(t.Unbound(z)) = type_of(sub, [0]) should.equal(x, z) - let assert Ok(type_.Fun(type_.Var(x), type_.Var(_), type_.Var(y))) = jm(exp, type_.Var(-1), type_.Empty) + let assert Ok(type_.Fun(type_.Var(x), type_.Var(_), type_.Var(y))) = + jm(exp, type_.Var(-1), type_.Empty) should.equal(x, y) } @@ -269,7 +285,12 @@ pub fn select_test() { resolve(sub, typ) should.equal(a, b) should.equal(l, "foo") - let assert Ok(type_.Fun(type_.Record(type_.RowExtend("foo", type_.Var(x), type_.Var(_y))), type_.Var(_z), type_.Var(a))) = jm(exp, type_.Var(-1), type_.Empty) + let assert Ok(type_.Fun( + type_.Record(type_.RowExtend("foo", type_.Var(x), type_.Var(_y))), + type_.Var(_z), + type_.Var(a), + )) = jm(exp, type_.Var(-1), type_.Empty) + should.equal(x, a) let exp = e.Apply(exp, e.Variable("x")) let env = env.empty() @@ -302,6 +323,14 @@ pub fn combine_select_test() { should.not_equal(x, y) let assert Ok(t.Unbound(z)) = field(row, "bar") should.equal(x, z) + let exp = e.Lambda("x", exp) + // TODO field fn that excepts Record only type_.field + // Proper double use in select statement test + // slim down saved.json + // All documentation of type systems in "mylang" + let assert Ok(type_.String) = + jm(exp, type_.Var(-1), type_.Empty) + |> io.debug } // Unions @@ -365,8 +394,9 @@ pub fn collect_effects_test() { should.equal(ret2, final) let exp = e.Lambda("_", exp) - let assert Ok(type_.String) = jm(exp, type_.Var(-1), type_.Empty) - |> io.debug + let assert Ok(type_.String) = + jm(exp, type_.Var(-1), type_.Empty) + |> io.debug } pub fn anony_test() { From bc27f4786d4b1071bec5bbabc5b710f1be6159c7 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 25 Apr 2023 21:17:29 +0200 Subject: [PATCH 57/62] chase out bug in apply --- eyg/saved/saved.json | 2 +- eyg/src/atelier/app.gleam | 895 +++++++++------------ eyg/src/atelier/view/pallet.gleam | 106 ++- eyg/src/atelier/view/root.gleam | 8 +- eyg/src/atelier/view/typ.gleam | 1 + eyg/src/eyg/analysis/jm/error.gleam | 1 - eyg/src/eyg/analysis/jm/incremental.gleam | 17 +- eyg/src/eyg/analysis/jm/infer.gleam | 39 +- eyg/src/eyg/analysis/jm/unify.gleam | 1 + eyg/src/eyg/incremental/continuation.gleam | 63 -- eyg/src/eyg/incremental/cursor.gleam | 39 +- eyg/src/eyg/incremental/source.gleam | 75 ++ eyg/src/eyg/incremental/state_monad.gleam | 129 --- eyg/src/eyg/incremental/store.gleam | 137 +--- eyg/test/atelier/ui_test.gleam | 112 +-- eyg/test/eyg/analysis/jm/infer_test.gleam | 48 +- eyg/test/eyg/incremental/store_test.gleam | 454 +++++------ 17 files changed, 937 insertions(+), 1190 deletions(-) delete mode 100644 eyg/src/eyg/incremental/continuation.gleam delete mode 100644 eyg/src/eyg/incremental/state_monad.gleam diff --git a/eyg/saved/saved.json b/eyg/saved/saved.json index 262a7eb74..0979c0a92 100644 --- a/eyg/saved/saved.json +++ b/eyg/saved/saved.json @@ -1 +1 @@ -{"0":"l","l":"std","v":{"0":"l","l":"equal","v":{"0":"b","l":"equal"},"t":{"0":"l","l":"debug","v":{"0":"b","l":"debug"},"t":{"0":"l","l":"fix","v":{"0":"b","l":"fix"},"t":{"0":"l","l":"capture","v":{"0":"b","l":"capture"},"t":{"0":"l","l":"serialize","v":{"0":"b","l":"serialize"},"t":{"0":"l","l":"encode_uri","v":{"0":"b","l":"encode_uri"},"t":{"0":"l","l":"boolean","v":{"0":"l","l":"and","v":{"0":"f","l":"a","b":{"0":"f","l":"b","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"True"},"a":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"False"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"b"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"False"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"a"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"and"},"a":{"0":"v","l":"and"}},"a":{"0":"u"}}},"t":{"0":"l","l":"result","v":{"0":"l","l":"unwrap","v":{"0":"f","l":"default","b":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"x","b":{"0":"v","l":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"v","l":"default"}}},"a":{"0":"n"}}}},"t":{"0":"u"}},"t":{"0":"l","l":"list","v":{"0":"l","l":"pop","v":{"0":"b","l":"list_pop"},"t":{"0":"l","l":"fold","v":{"0":"b","l":"list_fold"},"t":{"0":"l","l":"head","v":{"0":"f","l":"l","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"pop"},"a":{"0":"v","l":"l"}}}},"t":{"0":"l","l":"find","v":{"0":"a","f":{"0":"v","l":"fix"},"a":{"0":"f","l":"self","b":{"0":"f","l":"predicate","b":{"0":"f","l":"list","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}},"t":{"0":"l","l":"matched","v":{"0":"a","f":{"0":"v","l":"predicate"},"a":{"0":"v","l":"item"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"v","l":"item"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"predicate"}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"matched"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"t","l":"Error"}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"pop"},"a":{"0":"v","l":"list"}}}}}}},"t":{"0":"l","l":"reverse","v":{"0":"f","l":"list","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"fold"},"a":{"0":"v","l":"list"}},"a":{"0":"ta"}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"el"}},"a":{"0":"v","l":"acc"}}}}}},"t":{"0":"l","l":"append","v":{"0":"f","l":"first","b":{"0":"f","l":"second","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"fold"},"a":{"0":"a","f":{"0":"v","l":"reverse"},"a":{"0":"v","l":"first"}}},"a":{"0":"v","l":"second"}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"el"}},"a":{"0":"v","l":"acc"}}}}}}},"t":{"0":"l","l":"intersperse","v":{"0":"f","l":"list","b":{"0":"f","l":"element","b":{"0":"l","l":"reversed","v":{"0":"a","f":{"0":"v","l":"reverse"},"a":{"0":"v","l":"list"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"fold"},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}},"a":{"0":"ta"}}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"el"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"element"}},"a":{"0":"v","l":"acc"}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"ta"}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"pop"},"a":{"0":"v","l":"reversed"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"pop"},"a":{"0":"v","l":"pop"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"fold"},"a":{"0":"v","l":"fold"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"head"},"a":{"0":"v","l":"head"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"find"},"a":{"0":"v","l":"find"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"reverse"},"a":{"0":"v","l":"reverse"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"append"},"a":{"0":"v","l":"append"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"intersperse"},"a":{"0":"v","l":"intersperse"}},"a":{"0":"u"}}}}}}}}}}}}}}},"t":{"0":"l","l":"integer","v":{"0":"l","l":"add","v":{"0":"b","l":"int_add"},"t":{"0":"l","l":"subtract","v":{"0":"b","l":"int_subtract"},"t":{"0":"l","l":"to_string","v":{"0":"b","l":"int_to_string"},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"add"},"a":{"0":"v","l":"add"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"subtract"},"a":{"0":"v","l":"subtract"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"to_string"},"a":{"0":"v","l":"to_string"}},"a":{"0":"u"}}}}}}},"t":{"0":"l","l":"string","v":{"0":"l","l":"append","v":{"0":"b","l":"string_append"},"t":{"0":"l","l":"concat","v":{"0":"f","l":"l","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fold"},"a":{"0":"v","l":"list"}},"a":{"0":"v","l":"l"}},"a":{"0":"s","v":""}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"append"},"a":{"0":"v","l":"acc"}},"a":{"0":"v","l":"el"}}}}}},"t":{"0":"l","l":"join","v":{"0":"f","l":"strings","b":{"0":"f","l":"separator","b":{"0":"a","f":{"0":"v","l":"concat"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"v","l":"list"}},"a":{"0":"v","l":"strings"}},"a":{"0":"v","l":"separator"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"append"},"a":{"0":"v","l":"append"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"concat"},"a":{"0":"v","l":"concat"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"join"},"a":{"0":"v","l":"join"}},"a":{"0":"u"}}}}}}},"t":{"0":"l","l":"logs","v":{"0":"l","l":"log","v":{"0":"f","l":"term","b":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"v","l":"term"}}},"t":{"0":"l","l":"capture","v":{"0":"l","l":"handler","v":{"0":"f","l":"message","b":{"0":"f","l":"k","b":{"0":"l","l":"inner","v":{"0":"a","f":{"0":"v","l":"k"},"a":{"0":"u"}},"t":{"0":"a","f":{"0":"a","f":{"0":"o","l":"logs"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"message"}},"a":{"0":"a","f":{"0":"g","l":"logs"},"a":{"0":"v","l":"inner"}}}},"a":{"0":"v","l":"inner"}}}}},"t":{"0":"f","l":"run","b":{"0":"a","f":{"0":"a","f":{"0":"h","l":"Log"},"a":{"0":"v","l":"handler"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"return","v":{"0":"a","f":{"0":"v","l":"run"},"a":{"0":"u"}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"return"},"a":{"0":"v","l":"return"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"logs"},"a":{"0":"ta"}},"a":{"0":"u"}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"log"},"a":{"0":"v","l":"log"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"capture"},"a":{"0":"v","l":"capture"}},"a":{"0":"u"}}}}},"t":{"0":"l","l":"modules","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"boolean"},"a":{"0":"v","l":"boolean"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"result"},"a":{"0":"v","l":"result"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"list"},"a":{"0":"v","l":"list"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"integer"},"a":{"0":"v","l":"integer"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"string"},"a":{"0":"v","l":"string"}},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"modules","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"logs"},"a":{"0":"v","l":"logs"}},"a":{"0":"v","l":"modules"}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"equal"},"a":{"0":"v","l":"equal"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"debug"},"a":{"0":"v","l":"debug"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"fix"},"a":{"0":"v","l":"fix"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"capture"},"a":{"0":"v","l":"capture"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"serialize"},"a":{"0":"v","l":"serialize"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"encode_uri"},"a":{"0":"v","l":"encode_uri"}},"a":{"0":"v","l":"modules"}}}}}}}}}}}}}}}}}}}}},"t":{"0":"l","l":"should","v":{"0":"l","l":"equal","v":{"0":"f","l":"expected","b":{"0":"f","l":"given","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"u"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"l","l":"failure","v":{"0":"a","f":{"0":"t","l":"NotEqual"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"given"},"a":{"0":"v","l":"given"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"expected"},"a":{"0":"v","l":"expected"}},"a":{"0":"u"}}}},"t":{"0":"a","f":{"0":"p","l":"Fail"},"a":{"0":"v","l":"failure"}}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"expected"}},"a":{"0":"v","l":"given"}}}}},"t":{"0":"l","l":"be","v":{"0":"f","l":"match","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"match"},"a":{"0":"f","l":"value","b":{"0":"v","l":"value"}}},"a":{"0":"f","l":"other","b":{"0":"a","f":{"0":"p","l":"Abort"},"a":{"0":"s","v":"some other value"}}}}},"t":{"0":"l","l":"to_string","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"NotEqual"},"a":{"0":"f","l":"fail","b":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"expected: "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"debug"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"expected"},"a":{"0":"v","l":"fail"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" given: "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"debug"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"given"},"a":{"0":"v","l":"fail"}}}},"a":{"0":"ta"}}}}}}}},"a":{"0":"n"}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"equal"},"a":{"0":"v","l":"equal"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"be"},"a":{"0":"v","l":"be"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"to_string"},"a":{"0":"v","l":"to_string"}},"a":{"0":"u"}}}}}}},"t":{"0":"l","l":"legit","v":{"0":"l","l":"test","v":{"0":"f","l":"name","b":{"0":"f","l":"exec","b":{"0":"a","f":{"0":"a","f":{"0":"e","l":"exec"},"a":{"0":"v","l":"exec"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"v","l":"name"}},"a":{"0":"u"}}}}},"t":{"0":"l","l":"run_test","v":{"0":"f","l":"f","b":{"0":"a","f":{"0":"a","f":{"0":"h","l":"Fail"},"a":{"0":"f","l":"failure","b":{"0":"f","l":"_kont","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"v","l":"failure"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"a","f":{"0":"v","l":"f"},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"run","v":{"0":"f","l":"tests","b":{"0":"l","l":"initial","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"fails"},"a":{"0":"i","v":0}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"passes"},"a":{"0":"i","v":0}},"a":{"0":"u"}}},"t":{"0":"l","l":"acc","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fold"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"tests"}},"a":{"0":"v","l":"initial"}},"a":{"0":"f","l":"t","b":{"0":"f","l":"acc","b":{"0":"l","l":"result","v":{"0":"a","f":{"0":"v","l":"run_test"},"a":{"0":"a","f":{"0":"g","l":"exec"},"a":{"0":"v","l":"t"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"failure","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"❌ "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"name"},"a":{"0":"v","l":"t"}}},"a":{"0":"ta"}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"v","l":"should"}},"a":{"0":"v","l":"failure"}}},"t":{"0":"l","l":"fails","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"i","v":1}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"o","l":"fails"},"a":{"0":"v","l":"fails"}},"a":{"0":"v","l":"acc"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"_","b":{"0":"l","l":"passes","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"i","v":1}},"a":{"0":"a","f":{"0":"g","l":"passes"},"a":{"0":"v","l":"acc"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"o","l":"passes"},"a":{"0":"v","l":"passes"}},"a":{"0":"v","l":"acc"}}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"result"}}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"passes"},"a":{"0":"v","l":"acc"}}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" tests, "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" failures."}},"a":{"0":"ta"}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"i","v":0}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"i","v":-1}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}},"a":{"0":"i","v":0}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"run"},"a":{"0":"v","l":"run"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"test"},"a":{"0":"v","l":"test"}},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"expect","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"value","b":{"0":"v","l":"value"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"reason","b":{"0":"a","f":{"0":"p","l":"Error"},"a":{"0":"v","l":"reason"}}}},"a":{"0":"n"}}},"t":{"0":"l","l":"eygir","v":{"0":"l","l":"exp","v":{"0":"l","l":"variable","v":{"0":"t","l":"Variable"},"t":{"0":"l","l":"lambda","v":{"0":"t","l":"Lambda"},"t":{"0":"l","l":"apply","v":{"0":"a","f":{"0":"t","l":"Apply"},"a":{"0":"u"}},"t":{"0":"l","l":"let","v":{"0":"t","l":"Let"},"t":{"0":"l","l":"integer","v":{"0":"t","l":"Integer"},"t":{"0":"l","l":"string","v":{"0":"t","l":"Binary"},"t":{"0":"l","l":"tail","v":{"0":"a","f":{"0":"t","l":"Tail"},"a":{"0":"u"}},"t":{"0":"l","l":"cons","v":{"0":"a","f":{"0":"t","l":"Cons"},"a":{"0":"u"}},"t":{"0":"l","l":"empty","v":{"0":"a","f":{"0":"t","l":"Empty"},"a":{"0":"u"}},"t":{"0":"l","l":"extend","v":{"0":"t","l":"Extend"},"t":{"0":"l","l":"select","v":{"0":"t","l":"Select"},"t":{"0":"l","l":"overwrite","v":{"0":"t","l":"Overwrite"},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"variable"},"a":{"0":"v","l":"variable"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"lambda"},"a":{"0":"v","l":"lambda"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"apply"},"a":{"0":"v","l":"apply"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"let"},"a":{"0":"v","l":"let"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"integer"},"a":{"0":"v","l":"integer"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"tail"},"a":{"0":"v","l":"tail"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"cons"},"a":{"0":"v","l":"cons"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"string"},"a":{"0":"v","l":"string"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"empty"},"a":{"0":"v","l":"empty"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"extend"},"a":{"0":"v","l":"extend"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"select"},"a":{"0":"v","l":"select"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"overwrite"},"a":{"0":"v","l":"overwrite"}},"a":{"0":"u"}}}}}}}}}}}}}}}}}}}}}}}}},"t":{"0":"l","l":"render","v":{"0":"l","l":"expression","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"self","b":{"0":"f","l":"br","b":{"0":"f","l":"source","b":{"0":"l","l":"done","v":{"0":"f","l":"text","b":{"0":"f","l":"rest","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"text"},"a":{"0":"v","l":"text"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"rest"},"a":{"0":"v","l":"rest"}},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"then","v":{"0":"f","l":"renderer","b":{"0":"f","l":"then","b":{"0":"f","l":"rest","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"rendered","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"g","l":"text"},"a":{"0":"v","l":"rendered"}}},"a":{"0":"a","f":{"0":"g","l":"rest"},"a":{"0":"v","l":"rendered"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"reason","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"v","l":"reason"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"renderer"},"a":{"0":"v","l":"rest"}}}}}},"t":{"0":"l","l":"block","v":{"0":"f","l":"br","b":{"0":"f","l":"source","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Let"},"a":{"0":"f","l":"_","b":{"0":"l","l":"br_inner","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"br"}},"a":{"0":"s","v":" "}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"br_inner"}}},"a":{"0":"f","l":"value","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"{"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"br_inner"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"value"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"br"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"}"}},"a":{"0":"ta"}}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"debug"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"parts"}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"br"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"reason","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"v","l":"reason"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}},"t":{"0":"l","l":"spread","v":{"0":"f","l":"reversed","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"l","l":"tail","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":".."}},"a":{"0":"v","l":"tail"}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}}}},"t":{"0":"l","l":"gather_elements","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Tail"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Cons"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}}}},"t":{"0":"l","l":"gather_extend","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Extend"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Empty"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}}}},"t":{"0":"l","l":"gather_overwrite","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Empty"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Overwrite"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}}}},"t":{"0":"l","l":"gather_branches","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"br","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"NoCases"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Case"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"v","l":"br"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}}}}},"t":{"0":"l","l":"exp","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Variable"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"label"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Lambda"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"body","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" -> "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"body"}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"f","l":"source","b":{"0":"l","l":"default","v":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"func","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"arg","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"func"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"("}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"arg"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":")"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Extend"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"s","v":"{"},"t":{"0":"l","l":"post","v":{"0":"s","v":"}"},"t":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"gather_extend"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"s","v":", "}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Overwrite"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"s","v":"{"},"t":{"0":"l","l":"post","v":{"0":"s","v":"}"},"t":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"gather_overwrite"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"s","v":", "}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Case"},"a":{"0":"f","l":"label","b":{"0":"l","l":"br_inner","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"br"}},"a":{"0":"s","v":" "}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br_inner"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"match {"}},"a":{"0":"v","l":"br_inner"}},"t":{"0":"l","l":"post","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"br"}},"a":{"0":"s","v":"}"}},"t":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"gather_branches"},"a":{"0":"v","l":"br_inner"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"v","l":"br_inner"}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Cons"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"s","v":"["},"t":{"0":"l","l":"post","v":{"0":"s","v":"]"},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"gather_elements"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"s","v":", "}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Select"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"arg","b":{"0":"l","l":"rendered","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"arg"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"."}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"rendered"}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Let"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"value","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"rest_or_then","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"let "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" = "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"value"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"br"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"rest_or_then"}},"a":{"0":"ta"}}}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Integer"},"a":{"0":"f","l":"value","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"value"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Binary"},"a":{"0":"f","l":"value","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"\""}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"value"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"\""}},"a":{"0":"ta"}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Tail"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"[]"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Cons"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"cons"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Vacant"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"vacant"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Empty"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"{}"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Extend"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"+"}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Select"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"."}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Overwrite"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":":="}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Tag"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"label"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Case"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"match "}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"NoCases"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"--- no cases ---"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Perform"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"perform "}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Handle"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"handle "}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Builtin"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"TODO this shouldn't really be here"}}}},"a":{"0":"n"}}}}}}}}}}}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"exp"},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}}}}}}}}}}}}},"t":{"0":"a","f":{"0":"v","l":"expression"},"a":{"0":"s","v":"\n"}}},"t":{"0":"l","l":"t","v":{"0":"a","f":{"0":"g","l":"test"},"a":{"0":"v","l":"legit"}},"t":{"0":"l","l":"should_render","v":{"0":"f","l":"output","b":{"0":"f","l":"source","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"output"}},"a":{"0":"s","v":"b"}},"t":{"0":"l","l":"rendered","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"be"},"a":{"0":"v","l":"should"}},"a":{"0":"m","l":"Ok"}},"a":{"0":"a","f":{"0":"v","l":"render"},"a":{"0":"v","l":"source"}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"ta"}},"a":{"0":"a","f":{"0":"g","l":"rest"},"a":{"0":"v","l":"rendered"}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"v","l":"output"}},"a":{"0":"a","f":{"0":"g","l":"text"},"a":{"0":"v","l":"rendered"}}},"t":{"0":"u"}}}}}}},"t":{"0":"l","l":"tests","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"empty"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"be"},"a":{"0":"v","l":"should"}},"a":{"0":"m","l":"Error"}},"a":{"0":"a","f":{"0":"v","l":"render"},"a":{"0":"ta"}}},"t":{"0":"u"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"variable"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"lambda"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"lambda"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"ta"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x -> 2"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"apply"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x(2)"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"let"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"let x = 2\nx"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"integer"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":5}}},"a":{"0":"ta"}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"5"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"string"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"hello"}}},"a":{"0":"ta"}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"\"hello\""}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"multiline lambda"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"lambda"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x -> {\n let y = x\n y\n}"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"multiline let"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"let x = {\n let y = 1\n y\n}\nx"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"extend list"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"exp"}}},"a":{"0":"ta"}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"[1, 2]"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"open list"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"[1, ..x]"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"open list fn application"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"ta"}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"[1, ..x(y)]"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"extend record"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"extend"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"foo"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"extend"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"bar"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"empty"},"a":{"0":"v","l":"exp"}}},"a":{"0":"ta"}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"{foo: 1, bar: 2}"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"select field from record"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"select"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"bar"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"select"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"foo"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x.foo.bar"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"ta"}}}}}}}}}}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"render"},"a":{"0":"v","l":"render"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"tests"},"a":{"0":"v","l":"tests"}},"a":{"0":"u"}}}}}}}},"t":{"0":"l","l":"cli","v":{"0":"z","c":""},"t":{"0":"l","l":"web","v":{"0":"z","c":""},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"cli"},"a":{"0":"v","l":"cli"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"web"},"a":{"0":"v","l":"web"}},"a":{"0":"u"}}}}}}}}}} \ No newline at end of file +{"0":"l","l":"async","v":{"0":"f","l":"exec","b":{"0":"a","f":{"0":"p","l":"Async"},"a":{"0":"v","l":"exec"}}},"t":{"0":"l","l":"std","v":{"0":"l","l":"equal","v":{"0":"b","l":"equal"},"t":{"0":"l","l":"debug","v":{"0":"b","l":"debug"},"t":{"0":"l","l":"fix","v":{"0":"b","l":"fix"},"t":{"0":"l","l":"capture","v":{"0":"b","l":"capture"},"t":{"0":"l","l":"serialize","v":{"0":"b","l":"serialize"},"t":{"0":"l","l":"encode_uri","v":{"0":"b","l":"encode_uri"},"t":{"0":"l","l":"boolean","v":{"0":"l","l":"and","v":{"0":"f","l":"a","b":{"0":"f","l":"b","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"True"},"a":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"False"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"b"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"False"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"a"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"and"},"a":{"0":"v","l":"and"}},"a":{"0":"u"}}},"t":{"0":"l","l":"result","v":{"0":"l","l":"unwrap","v":{"0":"f","l":"default","b":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"x","b":{"0":"v","l":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"v","l":"default"}}},"a":{"0":"n"}}}},"t":{"0":"u"}},"t":{"0":"l","l":"list","v":{"0":"l","l":"pop","v":{"0":"b","l":"list_pop"},"t":{"0":"l","l":"fold","v":{"0":"b","l":"list_fold"},"t":{"0":"l","l":"head","v":{"0":"f","l":"l","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"pop"},"a":{"0":"v","l":"l"}}}},"t":{"0":"l","l":"find","v":{"0":"a","f":{"0":"v","l":"fix"},"a":{"0":"f","l":"self","b":{"0":"f","l":"predicate","b":{"0":"f","l":"list","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}},"t":{"0":"l","l":"matched","v":{"0":"a","f":{"0":"v","l":"predicate"},"a":{"0":"v","l":"item"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"v","l":"item"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"predicate"}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"matched"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"t","l":"Error"}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"pop"},"a":{"0":"v","l":"list"}}}}}}},"t":{"0":"l","l":"reverse","v":{"0":"f","l":"list","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"fold"},"a":{"0":"v","l":"list"}},"a":{"0":"ta"}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"el"}},"a":{"0":"v","l":"acc"}}}}}},"t":{"0":"l","l":"append","v":{"0":"f","l":"first","b":{"0":"f","l":"second","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"fold"},"a":{"0":"a","f":{"0":"v","l":"reverse"},"a":{"0":"v","l":"first"}}},"a":{"0":"v","l":"second"}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"el"}},"a":{"0":"v","l":"acc"}}}}}}},"t":{"0":"l","l":"intersperse","v":{"0":"f","l":"list","b":{"0":"f","l":"element","b":{"0":"l","l":"reversed","v":{"0":"a","f":{"0":"v","l":"reverse"},"a":{"0":"v","l":"list"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"fold"},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}},"a":{"0":"ta"}}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"el"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"element"}},"a":{"0":"v","l":"acc"}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"ta"}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"pop"},"a":{"0":"v","l":"reversed"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"pop"},"a":{"0":"v","l":"pop"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"fold"},"a":{"0":"v","l":"fold"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"head"},"a":{"0":"v","l":"head"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"find"},"a":{"0":"v","l":"find"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"reverse"},"a":{"0":"v","l":"reverse"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"append"},"a":{"0":"v","l":"append"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"intersperse"},"a":{"0":"v","l":"intersperse"}},"a":{"0":"u"}}}}}}}}}}}}}}},"t":{"0":"l","l":"integer","v":{"0":"l","l":"add","v":{"0":"b","l":"int_add"},"t":{"0":"l","l":"subtract","v":{"0":"b","l":"int_subtract"},"t":{"0":"l","l":"to_string","v":{"0":"b","l":"int_to_string"},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"add"},"a":{"0":"v","l":"add"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"subtract"},"a":{"0":"v","l":"subtract"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"to_string"},"a":{"0":"v","l":"to_string"}},"a":{"0":"u"}}}}}}},"t":{"0":"l","l":"string","v":{"0":"l","l":"append","v":{"0":"b","l":"string_append"},"t":{"0":"l","l":"concat","v":{"0":"f","l":"l","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fold"},"a":{"0":"v","l":"list"}},"a":{"0":"v","l":"l"}},"a":{"0":"s","v":""}},"a":{"0":"f","l":"el","b":{"0":"f","l":"acc","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"append"},"a":{"0":"v","l":"acc"}},"a":{"0":"v","l":"el"}}}}}},"t":{"0":"l","l":"join","v":{"0":"f","l":"strings","b":{"0":"f","l":"separator","b":{"0":"a","f":{"0":"v","l":"concat"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"v","l":"list"}},"a":{"0":"v","l":"strings"}},"a":{"0":"v","l":"separator"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"append"},"a":{"0":"v","l":"append"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"concat"},"a":{"0":"v","l":"concat"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"join"},"a":{"0":"v","l":"join"}},"a":{"0":"u"}}}}}}},"t":{"0":"l","l":"logs","v":{"0":"l","l":"log","v":{"0":"f","l":"term","b":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"v","l":"term"}}},"t":{"0":"l","l":"capture","v":{"0":"l","l":"handler","v":{"0":"f","l":"message","b":{"0":"f","l":"k","b":{"0":"l","l":"inner","v":{"0":"a","f":{"0":"v","l":"k"},"a":{"0":"u"}},"t":{"0":"a","f":{"0":"a","f":{"0":"o","l":"logs"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"message"}},"a":{"0":"a","f":{"0":"g","l":"logs"},"a":{"0":"v","l":"inner"}}}},"a":{"0":"v","l":"inner"}}}}},"t":{"0":"f","l":"run","b":{"0":"a","f":{"0":"a","f":{"0":"h","l":"Log"},"a":{"0":"v","l":"handler"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"return","v":{"0":"a","f":{"0":"v","l":"run"},"a":{"0":"u"}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"return"},"a":{"0":"v","l":"return"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"logs"},"a":{"0":"ta"}},"a":{"0":"u"}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"log"},"a":{"0":"v","l":"log"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"capture"},"a":{"0":"v","l":"capture"}},"a":{"0":"u"}}}}},"t":{"0":"l","l":"modules","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"boolean"},"a":{"0":"v","l":"boolean"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"result"},"a":{"0":"v","l":"result"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"list"},"a":{"0":"v","l":"list"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"integer"},"a":{"0":"v","l":"integer"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"string"},"a":{"0":"v","l":"string"}},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"modules","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"logs"},"a":{"0":"v","l":"logs"}},"a":{"0":"v","l":"modules"}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"equal"},"a":{"0":"v","l":"equal"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"debug"},"a":{"0":"v","l":"debug"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"fix"},"a":{"0":"v","l":"fix"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"capture"},"a":{"0":"v","l":"capture"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"serialize"},"a":{"0":"v","l":"serialize"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"encode_uri"},"a":{"0":"v","l":"encode_uri"}},"a":{"0":"v","l":"modules"}}}}}}}}}}}}}}}}}}}}},"t":{"0":"l","l":"should","v":{"0":"l","l":"equal","v":{"0":"f","l":"expected","b":{"0":"f","l":"given","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"u"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"l","l":"failure","v":{"0":"a","f":{"0":"t","l":"NotEqual"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"given"},"a":{"0":"v","l":"given"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"expected"},"a":{"0":"v","l":"expected"}},"a":{"0":"u"}}}},"t":{"0":"a","f":{"0":"p","l":"Fail"},"a":{"0":"v","l":"failure"}}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"expected"}},"a":{"0":"v","l":"given"}}}}},"t":{"0":"l","l":"be","v":{"0":"f","l":"match","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"match"},"a":{"0":"f","l":"value","b":{"0":"v","l":"value"}}},"a":{"0":"f","l":"other","b":{"0":"a","f":{"0":"p","l":"Abort"},"a":{"0":"s","v":"some other value"}}}}},"t":{"0":"l","l":"to_string","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"NotEqual"},"a":{"0":"f","l":"fail","b":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"expected: "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"debug"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"expected"},"a":{"0":"v","l":"fail"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" given: "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"debug"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"given"},"a":{"0":"v","l":"fail"}}}},"a":{"0":"ta"}}}}}}}},"a":{"0":"n"}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"equal"},"a":{"0":"v","l":"equal"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"be"},"a":{"0":"v","l":"be"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"to_string"},"a":{"0":"v","l":"to_string"}},"a":{"0":"u"}}}}}}},"t":{"0":"l","l":"legit","v":{"0":"l","l":"test","v":{"0":"f","l":"name","b":{"0":"f","l":"exec","b":{"0":"a","f":{"0":"a","f":{"0":"e","l":"exec"},"a":{"0":"v","l":"exec"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"v","l":"name"}},"a":{"0":"u"}}}}},"t":{"0":"l","l":"run_test","v":{"0":"f","l":"f","b":{"0":"a","f":{"0":"a","f":{"0":"h","l":"Fail"},"a":{"0":"f","l":"failure","b":{"0":"f","l":"_kont","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"v","l":"failure"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"a","f":{"0":"v","l":"f"},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"run","v":{"0":"f","l":"tests","b":{"0":"l","l":"initial","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"fails"},"a":{"0":"i","v":0}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"passes"},"a":{"0":"i","v":0}},"a":{"0":"u"}}},"t":{"0":"l","l":"acc","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fold"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"tests"}},"a":{"0":"v","l":"initial"}},"a":{"0":"f","l":"t","b":{"0":"f","l":"acc","b":{"0":"l","l":"result","v":{"0":"a","f":{"0":"v","l":"run_test"},"a":{"0":"a","f":{"0":"g","l":"exec"},"a":{"0":"v","l":"t"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"failure","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"❌ "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"name"},"a":{"0":"v","l":"t"}}},"a":{"0":"ta"}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"v","l":"should"}},"a":{"0":"v","l":"failure"}}},"t":{"0":"l","l":"fails","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"i","v":1}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"o","l":"fails"},"a":{"0":"v","l":"fails"}},"a":{"0":"v","l":"acc"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"_","b":{"0":"l","l":"passes","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"i","v":1}},"a":{"0":"a","f":{"0":"g","l":"passes"},"a":{"0":"v","l":"acc"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"o","l":"passes"},"a":{"0":"v","l":"passes"}},"a":{"0":"v","l":"acc"}}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"result"}}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"passes"},"a":{"0":"v","l":"acc"}}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" tests, "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" failures."}},"a":{"0":"ta"}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"True"},"a":{"0":"f","l":"_","b":{"0":"i","v":0}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"False"},"a":{"0":"f","l":"_","b":{"0":"i","v":-1}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"fails"},"a":{"0":"v","l":"acc"}}},"a":{"0":"i","v":0}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"run"},"a":{"0":"v","l":"run"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"test"},"a":{"0":"v","l":"test"}},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"std_test","v":{"0":"l","l":"t","v":{"0":"a","f":{"0":"g","l":"test"},"a":{"0":"v","l":"legit"}},"t":{"0":"l","l":"async_log","v":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"async log"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"captured","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"capture"},"a":{"0":"a","f":{"0":"g","l":"logs"},"a":{"0":"v","l":"std"}}},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"abc"}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Await"},"a":{"0":"a","f":{"0":"p","l":"Wait"},"a":{"0":"i","v":100}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"xyz"}},"t":{"0":"i","v":10}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"abc"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"xyz"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"g","l":"logs"},"a":{"0":"v","l":"captured"}}}}}},"t":{"0":"l","l":"_","v":{"0":"s","v":"todo we should have the same magic checking for catching effects"},"t":{"0":"l","l":"match_variant","v":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"match variant"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"term","v":{"0":"a","f":{"0":"t","l":"Some"},"a":{"0":"i","v":5}},"t":{"0":"l","l":"value","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"be"},"a":{"0":"v","l":"should"}},"a":{"0":"m","l":"Some"}},"a":{"0":"v","l":"term"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"i","v":5}},"a":{"0":"v","l":"value"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"`and`"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"a","f":{"0":"t","l":"True"},"a":{"0":"u"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"and"},"a":{"0":"a","f":{"0":"g","l":"boolean"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"t","l":"True"},"a":{"0":"u"}}},"a":{"0":"a","f":{"0":"t","l":"True"},"a":{"0":"u"}}}},"t":{"0":"u"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"`reverse`"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"i","v":2}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"i","v":1}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"i","v":1}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"i","v":2}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"ta"}},"a":{"0":"ta"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"`logs.capture`"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"captured","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"capture"},"a":{"0":"a","f":{"0":"g","l":"logs"},"a":{"0":"v","l":"std"}}},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"log"},"a":{"0":"a","f":{"0":"g","l":"logs"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"abc"}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"xyz"}},"t":{"0":"i","v":10}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"abc"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"xyz"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"g","l":"logs"},"a":{"0":"v","l":"captured"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"async_log"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"match_variant"}},"a":{"0":"ta"}}}}}}}}}},"t":{"0":"l","l":"expect","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"value","b":{"0":"v","l":"value"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"reason","b":{"0":"a","f":{"0":"p","l":"Error"},"a":{"0":"v","l":"reason"}}}},"a":{"0":"n"}}},"t":{"0":"l","l":"eygir","v":{"0":"l","l":"exp","v":{"0":"l","l":"variable","v":{"0":"t","l":"Variable"},"t":{"0":"l","l":"lambda","v":{"0":"t","l":"Lambda"},"t":{"0":"l","l":"apply","v":{"0":"a","f":{"0":"t","l":"Apply"},"a":{"0":"u"}},"t":{"0":"l","l":"let","v":{"0":"t","l":"Let"},"t":{"0":"l","l":"integer","v":{"0":"t","l":"Integer"},"t":{"0":"l","l":"string","v":{"0":"t","l":"Binary"},"t":{"0":"l","l":"tail","v":{"0":"a","f":{"0":"t","l":"Tail"},"a":{"0":"u"}},"t":{"0":"l","l":"cons","v":{"0":"a","f":{"0":"t","l":"Cons"},"a":{"0":"u"}},"t":{"0":"l","l":"empty","v":{"0":"a","f":{"0":"t","l":"Empty"},"a":{"0":"u"}},"t":{"0":"l","l":"extend","v":{"0":"t","l":"Extend"},"t":{"0":"l","l":"select","v":{"0":"t","l":"Select"},"t":{"0":"l","l":"overwrite","v":{"0":"t","l":"Overwrite"},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"variable"},"a":{"0":"v","l":"variable"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"lambda"},"a":{"0":"v","l":"lambda"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"apply"},"a":{"0":"v","l":"apply"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"let"},"a":{"0":"v","l":"let"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"integer"},"a":{"0":"v","l":"integer"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"tail"},"a":{"0":"v","l":"tail"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"cons"},"a":{"0":"v","l":"cons"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"string"},"a":{"0":"v","l":"string"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"empty"},"a":{"0":"v","l":"empty"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"extend"},"a":{"0":"v","l":"extend"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"select"},"a":{"0":"v","l":"select"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"overwrite"},"a":{"0":"v","l":"overwrite"}},"a":{"0":"u"}}}}}}}}}}}}}}}}}}}}}}}}},"t":{"0":"l","l":"render","v":{"0":"l","l":"expression","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"self","b":{"0":"f","l":"br","b":{"0":"f","l":"source","b":{"0":"l","l":"done","v":{"0":"f","l":"text","b":{"0":"f","l":"rest","b":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"text"},"a":{"0":"v","l":"text"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"rest"},"a":{"0":"v","l":"rest"}},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"then","v":{"0":"f","l":"renderer","b":{"0":"f","l":"then","b":{"0":"f","l":"rest","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"rendered","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"g","l":"text"},"a":{"0":"v","l":"rendered"}}},"a":{"0":"a","f":{"0":"g","l":"rest"},"a":{"0":"v","l":"rendered"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"reason","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"v","l":"reason"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"v","l":"renderer"},"a":{"0":"v","l":"rest"}}}}}},"t":{"0":"l","l":"block","v":{"0":"f","l":"br","b":{"0":"f","l":"source","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Let"},"a":{"0":"f","l":"_","b":{"0":"l","l":"br_inner","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"br"}},"a":{"0":"s","v":" "}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"br_inner"}}},"a":{"0":"f","l":"value","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"{"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"br_inner"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"value"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"br"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"}"}},"a":{"0":"ta"}}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"debug"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"parts"}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"br"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"reason","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"v","l":"reason"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}},"t":{"0":"l","l":"spread","v":{"0":"f","l":"reversed","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"l","l":"tail","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":".."}},"a":{"0":"v","l":"tail"}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}}}},"t":{"0":"l","l":"gather_elements","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Tail"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Cons"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}}}},"t":{"0":"l","l":"gather_extend","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Extend"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Empty"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}}}},"t":{"0":"l","l":"gather_overwrite","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Empty"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Overwrite"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"spread"},"a":{"0":"v","l":"reversed"}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}}}},"t":{"0":"l","l":"gather_branches","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"gather","b":{"0":"f","l":"br","b":{"0":"f","l":"reversed","b":{"0":"f","l":"source","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"NoCases"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"reversed"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"v","l":"expect"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Case"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"gather"},"a":{"0":"v","l":"br"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"v","l":"source"}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"tail","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"reverse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tail"}},"a":{"0":"v","l":"reversed"}}}}}},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}}}}}},"t":{"0":"l","l":"exp","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Variable"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"label"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Lambda"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"body","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" -> "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"body"}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"f","l":"source","b":{"0":"l","l":"default","v":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"func","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"arg","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"func"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"("}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"arg"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":")"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Apply"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Extend"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"s","v":"{"},"t":{"0":"l","l":"post","v":{"0":"s","v":"}"},"t":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"gather_extend"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"s","v":", "}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Overwrite"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"s","v":"{"},"t":{"0":"l","l":"post","v":{"0":"s","v":"}"},"t":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":": "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"gather_overwrite"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"s","v":", "}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Case"},"a":{"0":"f","l":"label","b":{"0":"l","l":"br_inner","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"br"}},"a":{"0":"s","v":" "}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br_inner"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"match {"}},"a":{"0":"v","l":"br_inner"}},"t":{"0":"l","l":"post","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"br"}},"a":{"0":"s","v":"}"}},"t":{"0":"l","l":"item","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"gather_branches"},"a":{"0":"v","l":"br_inner"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"v","l":"br_inner"}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Cons"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"item","b":{"0":"l","l":"pre","v":{"0":"s","v":"["},"t":{"0":"l","l":"post","v":{"0":"s","v":"]"},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"gather_elements"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"item"}},"a":{"0":"ta"}}}},"a":{"0":"f","l":"items","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"intersperse"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}},"a":{"0":"s","v":", "}},"t":{"0":"l","l":"printed","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"pre"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"content"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"post"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"printed"}}}}}}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Select"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"arg","b":{"0":"l","l":"rendered","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"arg"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"."}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"rendered"}}}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"default"},"a":{"0":"v","l":"source"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Let"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"block"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"value","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"then"},"a":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"br"}}},"a":{"0":"f","l":"rest_or_then","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"let "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"label"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" = "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"value"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"br"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"rest_or_then"}},"a":{"0":"ta"}}}}}}},"t":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}}}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Integer"},"a":{"0":"f","l":"value","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"value"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Binary"},"a":{"0":"f","l":"value","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"\""}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"value"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"\""}},"a":{"0":"ta"}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Tail"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"[]"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Cons"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"cons"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Vacant"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"vacant"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Empty"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"{}"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Extend"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"+"}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Select"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"."}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Overwrite"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":":="}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Tag"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"v","l":"label"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Case"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"match "}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"NoCases"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"--- no cases ---"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Perform"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"perform "}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Handle"},"a":{"0":"f","l":"label","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"handle "}},"a":{"0":"v","l":"label"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Builtin"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"done"},"a":{"0":"s","v":"TODO this shouldn't really be here"}}}},"a":{"0":"n"}}}}}}}}}}}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"exp"},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"parts"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"Error"},"a":{"0":"u"}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"source"}}}}}}}}}}}}}}}},"t":{"0":"a","f":{"0":"v","l":"expression"},"a":{"0":"s","v":"\n"}}},"t":{"0":"l","l":"t","v":{"0":"a","f":{"0":"g","l":"test"},"a":{"0":"v","l":"legit"}},"t":{"0":"l","l":"should_render","v":{"0":"f","l":"output","b":{"0":"f","l":"source","b":{"0":"l","l":"rendered","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"be"},"a":{"0":"v","l":"should"}},"a":{"0":"m","l":"Ok"}},"a":{"0":"a","f":{"0":"v","l":"render"},"a":{"0":"v","l":"source"}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"ta"}},"a":{"0":"a","f":{"0":"g","l":"rest"},"a":{"0":"v","l":"rendered"}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"should"}},"a":{"0":"v","l":"output"}},"a":{"0":"a","f":{"0":"g","l":"text"},"a":{"0":"v","l":"rendered"}}},"t":{"0":"u"}}}}}},"t":{"0":"l","l":"tests","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"empty"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"be"},"a":{"0":"v","l":"should"}},"a":{"0":"m","l":"Error"}},"a":{"0":"a","f":{"0":"v","l":"render"},"a":{"0":"ta"}}},"t":{"0":"u"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"variable"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"lambda"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"lambda"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"ta"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x -> 2"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"apply"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x(2)"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"let"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"let x = 2\nx"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"integer"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":5}}},"a":{"0":"ta"}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"5"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"string"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"hello"}}},"a":{"0":"ta"}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"\"hello\""}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"multiline lambda"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"lambda"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x -> {\n let y = x\n y\n}"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"multiline let"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"let"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"let x = {\n let y = 1\n y\n}\nx"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"extend list"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"exp"}}},"a":{"0":"ta"}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"[1, 2]"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"open list"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"[1, ..x]"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"open list fn application"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"cons"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"y"}}},"a":{"0":"ta"}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"[1, ..x(y)]"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"extend record"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"extend"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"foo"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":1}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"extend"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"bar"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"exp"}},"a":{"0":"i","v":2}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"empty"},"a":{"0":"v","l":"exp"}}},"a":{"0":"ta"}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"{foo: 1, bar: 2}"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"select field from record"}},"a":{"0":"f","l":"_","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"select"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"bar"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"apply"},"a":{"0":"v","l":"exp"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"select"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"foo"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"variable"},"a":{"0":"v","l":"exp"}},"a":{"0":"s","v":"x"}}},"a":{"0":"ta"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"should_render"},"a":{"0":"s","v":"x.foo.bar"}},"a":{"0":"v","l":"source"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"t"},"a":{"0":"s","v":"noop"}},"a":{"0":"f","l":"_","b":{"0":"u"}}}},"a":{"0":"ta"}}}}}}}}}}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"render"},"a":{"0":"v","l":"render"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"tests"},"a":{"0":"v","l":"tests"}},"a":{"0":"u"}}}}}}}},"t":{"0":"l","l":"html","v":{"0":"l","l":"el","v":{"0":"f","l":"tag","b":{"0":"f","l":"attrib","b":{"0":"f","l":"children","b":{"0":"l","l":"close","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":""}},"a":{"0":"ta"}}}}},"t":{"0":"l","l":"attributes","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fold"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"attrib"}},"a":{"0":"s","v":""}},"a":{"0":"f","l":"attribute","b":{"0":"f","l":"buffer","b":{"0":"l","l":"parts","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"name"},"a":{"0":"v","l":"attribute"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"=\""}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"value"},"a":{"0":"v","l":"attribute"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"\""}},"a":{"0":"ta"}}}}}},"t":{"0":"l","l":"str","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"parts"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"buffer"}},"a":{"0":"v","l":"str"}}}}}}},"t":{"0":"l","l":"tag_attributes","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tag"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":" "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"attributes"}},"a":{"0":"ta"}}}}},"t":{"0":"l","l":"open","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"<"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"tag_attributes"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":">"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"open"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"children"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"close"}},"a":{"0":"ta"}}}}}}}}}}}},"t":{"0":"l","l":"attribute","v":{"0":"f","l":"name","b":{"0":"f","l":"value","b":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"v","l":"name"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"value"},"a":{"0":"v","l":"value"}},"a":{"0":"u"}}}}},"t":{"0":"l","l":"classes","v":{"0":"f","l":"classes","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"attribute"},"a":{"0":"s","v":"class"}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"join"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"classes"}},"a":{"0":"s","v":" "}}}},"t":{"0":"l","l":"a","v":{"0":"f","l":"href","b":{"0":"f","l":"extra","b":{"0":"f","l":"children","b":{"0":"l","l":"attributes","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"attribute"},"a":{"0":"s","v":"href"}},"a":{"0":"v","l":"href"}}},"a":{"0":"v","l":"extra"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"el"},"a":{"0":"s","v":"a"}},"a":{"0":"v","l":"attributes"}},"a":{"0":"v","l":"children"}}}}}},"t":{"0":"l","l":"basic","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"el"},"a":{"0":"v","l":"el"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"attribute"},"a":{"0":"v","l":"attribute"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"classes"},"a":{"0":"v","l":"classes"}},"a":{"0":"u"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"div"},"a":{"0":"a","f":{"0":"v","l":"el"},"a":{"0":"s","v":"div"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"h1"},"a":{"0":"a","f":{"0":"v","l":"el"},"a":{"0":"s","v":"h1"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"p"},"a":{"0":"a","f":{"0":"v","l":"el"},"a":{"0":"s","v":"p"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"span"},"a":{"0":"a","f":{"0":"v","l":"el"},"a":{"0":"s","v":"span"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"a"},"a":{"0":"v","l":"a"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"script"},"a":{"0":"a","f":{"0":"v","l":"el"},"a":{"0":"s","v":"script"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"button"},"a":{"0":"a","f":{"0":"v","l":"el"},"a":{"0":"s","v":"button"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"pre"},"a":{"0":"a","f":{"0":"v","l":"el"},"a":{"0":"s","v":"pre"}}},"a":{"0":"v","l":"basic"}}}}}}}}}}}}}},"t":{"0":"l","l":"layout","v":{"0":"l","l":"head","v":{"0":"s","v":"\n\n \n \n \n \n \n"},"t":{"0":"l","l":"attribute","v":{"0":"f","l":"name","b":{"0":"f","l":"value","b":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"v","l":"name"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"value"},"a":{"0":"v","l":"value"}},"a":{"0":"u"}}}}},"t":{"0":"l","l":"classes","v":{"0":"f","l":"classes","b":{"0":"a","f":{"0":"a","f":{"0":"v","l":"attribute"},"a":{"0":"s","v":"class"}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"join"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"classes"}},"a":{"0":"s","v":" "}}}},"t":{"0":"l","l":"vstack","v":{"0":"f","l":"extra","b":{"0":"f","l":"children","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"div"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"classes"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"vstack"}},"a":{"0":"v","l":"extra"}}}},"a":{"0":"ta"}}},"a":{"0":"v","l":"children"}}}},"t":{"0":"l","l":"hstack","v":{"0":"f","l":"children","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"div"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"s","v":"class"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"value"},"a":{"0":"s","v":"hstack"}},"a":{"0":"u"}}}},"a":{"0":"ta"}}},"a":{"0":"v","l":"children"}}},"t":{"0":"l","l":"expand","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"div"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"s","v":"class"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"value"},"a":{"0":"s","v":"expand"}},"a":{"0":"u"}}}},"a":{"0":"ta"}}},"a":{"0":"ta"}},"t":{"0":"l","l":"page","v":{"0":"f","l":"children","b":{"0":"l","l":"body","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"el"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"body"}},"a":{"0":"ta"}},"a":{"0":"v","l":"children"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"head"}},"a":{"0":"v","l":"body"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"hstack"},"a":{"0":"v","l":"hstack"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"vstack"},"a":{"0":"v","l":"vstack"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"expand"},"a":{"0":"v","l":"expand"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"page"},"a":{"0":"v","l":"page"}},"a":{"0":"u"}}}}}}}}}}}},"t":{"0":"l","l":"cli","v":{"0":"f","l":"args","b":{"0":"l","l":"sum","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"self","b":{"0":"f","l":"total","b":{"0":"f","l":"items","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"split","b":{"0":"l","l":"total","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"total"}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"split"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"self"},"a":{"0":"v","l":"total"}},"a":{"0":"a","f":{"0":"g","l":"tail"},"a":{"0":"v","l":"split"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"v","l":"total"}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"items"}}}}}}},"a":{"0":"i","v":0}},"t":{"0":"l","l":"tests","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"std_test"}},"a":{"0":"a","f":{"0":"g","l":"tests"},"a":{"0":"v","l":"eygir"}}},"t":{"0":"l","l":"test","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"s","v":"test"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"exec"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"g","l":"run"},"a":{"0":"v","l":"legit"}},"a":{"0":"v","l":"tests"}}}},"a":{"0":"u"}}},"t":{"0":"l","l":"tasks","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"test"}},"a":{"0":"ta"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"parts","b":{"0":"l","l":"predicate","v":{"0":"f","l":"pair","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"head"},"a":{"0":"v","l":"parts"}}},"a":{"0":"a","f":{"0":"g","l":"name"},"a":{"0":"v","l":"pair"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"task","b":{"0":"a","f":{"0":"a","f":{"0":"g","l":"exec"},"a":{"0":"v","l":"task"}},"a":{"0":"u"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"No matching task"}},"t":{"0":"i","v":-1}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"find"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"predicate"}},"a":{"0":"v","l":"tasks"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"No cli task specified"}},"t":{"0":"i","v":-1}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pop"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"args"}}}}}}}},"t":{"0":"l","l":"web","v":{"0":"f","l":"req","b":{"0":"l","l":"response","v":{"0":"l","l":"ok","v":{"0":"f","l":"body","b":{"0":"a","f":{"0":"a","f":{"0":"e","l":"body"},"a":{"0":"v","l":"body"}},"a":{"0":"u"}}},"t":{"0":"l","l":"app","v":{"0":"f","l":"client","b":{"0":"l","l":"mount","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"div"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"attribute"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"id"}},"a":{"0":"s","v":"app"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"screen"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}}},"a":{"0":"ta"}},"t":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"script"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"attribute"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"type"}},"a":{"0":"s","v":"application/eygir"}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"encode_uri"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"serialize"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"client"}}}},"a":{"0":"ta"}}},"t":{"0":"l","l":"rendered","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"page"},"a":{"0":"v","l":"layout"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"mount"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"source"}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"v","l":"ok"},"a":{"0":"v","l":"rendered"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"ok"},"a":{"0":"v","l":"ok"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"app"},"a":{"0":"v","l":"app"}},"a":{"0":"u"}}}}},"t":{"0":"l","l":"language","v":{"0":"l","l":"view","v":{"0":"l","l":"p","v":{"0":"f","l":"content","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"p"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"max-w-2xl mx-auto"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"v","l":"content"}}},"t":{"0":"l","l":"h2","v":{"0":"f","l":"content","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"el"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"h2"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"text-lg max-w-2xl mx-auto"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"content"}},"a":{"0":"ta"}}}},"t":{"0":"l","l":"link","v":{"0":"f","l":"location","b":{"0":"f","l":"text","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"a"},"a":{"0":"v","l":"html"}},"a":{"0":"v","l":"location"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"text-blue-500 underline"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"text"}},"a":{"0":"ta"}}}}},"t":{"0":"l","l":"code","v":{"0":"f","l":"term","b":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"capture"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"term"}},"t":{"0":"l","l":"string","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"return","b":{"0":"a","f":{"0":"g","l":"text"},"a":{"0":"v","l":"return"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"s","v":"Error!"}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"render"},"a":{"0":"v","l":"eygir"}},"a":{"0":"v","l":"source"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"pre"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"bg-gray-200"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"string"}},"a":{"0":"ta"}}}}}},"t":{"0":"l","l":"doc","v":{"0":"f","l":"path","b":{"0":"f","l":"sections","b":{"0":"l","l":"content","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"div"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"loose doc"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"v","l":"sections"}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"path"},"a":{"0":"v","l":"path"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"content"},"a":{"0":"v","l":"content"}},"a":{"0":"u"}}}}}},"t":{"0":"l","l":"_","v":{"0":"s","v":"move content to content section"},"t":{"0":"l","l":"docs","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"doc"},"a":{"0":"s","v":"/"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"el"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"h1"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"text-2xl"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Language"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"link"},"a":{"0":"s","v":"/effects"}},"a":{"0":"s","v":"Effects"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"h2"},"a":{"0":"s","v":"Introduction"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"This language is an experiment in making a highly portable functional language. The syntax shown below only illustrates the features of the language, it is only one of many possible projections to view a program. Creating programs is not done by editing text files instead a structured editor is needed."}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"The language has both a compiler and interpreter, either or even both can be used in one program.\nAnonymous functions can be captured, serialised and sent to other computers. \nFor example a client and server app can be written as one function."}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"html","v":{"0":"z","c":""},"t":{"0":"f","l":"request","b":{"0":"f","l":"client","b":{"0":"l","l":"method","v":{"0":"a","f":{"0":"g","l":"method"},"a":{"0":"v","l":"request"}},"t":{"0":"l","l":"handle_click","v":{"0":"a","f":{"0":"p","l":"Alert"},"a":{"0":"v","l":"method"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"button"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"click"}},"a":{"0":"v","l":"handle_click"}}}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"A fully exhaustive type checker exists for the language. i.e. if the checks pass it is guaranteed not to crash.\nThis can be optionally run, it's not worth type checking a build script you get the same error anyway.\nIt's possible to type check a single function."}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Because the type system is complete and structural no type ever needs to be declared up front and no annotation is required, in fact annotation is not supported in the language.\nThis choice is to make programmers never need to think about types.\nType annotations are possible in the editor but they are only a debug tool and not committed to the source."}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"The type system contains extensible records and unions as well as an algebraic effect system. \nThese three components are all built on row types, using the same approach for each keeps the implementation simple.\n"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"All of the goals of the language are achieved by having the Abstract Syntax Tree (AST) of the language be the public interface and keeping that interface as small as possible.\nThere are currently only 19 different node types that make up the AST."}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"string","v":{"0":"z","c":"std.string"},"t":{"0":"l","l":"welcome","v":{"0":"f","l":"person","b":{"0":"l","l":"message","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"v","l":"string"}},"a":{"0":"s","v":"Hello "}},"a":{"0":"v","l":"person"}},"t":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"v","l":"message"}}}},"t":{"0":"a","f":{"0":"v","l":"welcome"},"a":{"0":"s","v":"Alan"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"h2"},"a":{"0":"s","v":"literal"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"i","v":{"0":"i","v":100},"t":{"0":"l","l":"s","v":{"0":"s","v":"hello"},"t":{"0":"l","l":"list","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"i","v":1}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"i","v":2}},"a":{"0":"ta"}}},"t":{"0":"u"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"h2"},"a":{"0":"s","v":"functions"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"All functions are anonymous.\nFunctions are first class an can be returned by other functions.\nThere is no support for multi-argument functions, to accept multiple arguments a function must return a function, and is therefore automatically curried"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"single","v":{"0":"f","l":"x","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"x"}},"a":{"0":"ta"}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"v","l":"single"},"a":{"0":"i","v":10}},"t":{"0":"l","l":"double","v":{"0":"f","l":"x","b":{"0":"f","l":"y","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"x"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"y"}},"a":{"0":"ta"}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"v","l":"double"},"a":{"0":"i","v":1}},"a":{"0":"i","v":2}},"t":{"0":"l","l":"start_with_one","v":{"0":"a","f":{"0":"v","l":"double"},"a":{"0":"i","v":1}},"t":{"0":"a","f":{"0":"v","l":"start_with_one"},"a":{"0":"i","v":7}}}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"h2"},"a":{"0":"s","v":"Let bindings"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"A value can be given a name using let. \nNames can be reused by later let bindings, but the values contained are immutable, meaning the values themselves cannot be changed."}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"a","v":{"0":"i","v":1},"t":{"0":"l","l":"b","v":{"0":"v","l":"a"},"t":{"0":"l","l":"a","v":{"0":"i","v":2},"t":{"0":"v","l":"b"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"h2"},"a":{"0":"s","v":"Records"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Records are used to store multiple values with a name. \nTyping is structural and so there is no need to define types a head of time.\nBecause typing is structural any record with the fields required by a function can be passed to that function"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"a","b":{"0":"l","l":"alice","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"s","v":"Alice"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"age"},"a":{"0":"i","v":10}},"a":{"0":"u"}}},"t":{"0":"l","l":"name","v":{"0":"a","f":{"0":"g","l":"name"},"a":{"0":"v","l":"alice"}},"t":{"0":"l","l":"alice","v":{"0":"a","f":{"0":"a","f":{"0":"o","l":"age"},"a":{"0":"i","v":11}},"a":{"0":"v","l":"alice"}},"t":{"0":"l","l":"age","v":{"0":"a","f":{"0":"g","l":"age"},"a":{"0":"v","l":"alice"}},"t":{"0":"l","l":"get_name","v":{"0":"f","l":"user","b":{"0":"a","f":{"0":"g","l":"name"},"a":{"0":"v","l":"user"}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"v","l":"get_name"},"a":{"0":"v","l":"alice"}},"t":{"0":"l","l":"bob","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"s","v":"Bob"}},"a":{"0":"u"}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"v","l":"get_name"},"a":{"0":"v","l":"bob"}},"t":{"0":"u"}}}}}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"h2"},"a":{"0":"s","v":"Unions"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Unions are tagged unions, they are extensible. Case statements are first class i.e. it is possible to compose them."}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"ok","v":{"0":"a","f":{"0":"t","l":"Ok"},"a":{"0":"i","v":5}},"t":{"0":"l","l":"unwrap","v":{"0":"f","l":"fallback","b":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"value","b":{"0":"v","l":"value"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"v","l":"fallback"}}},"a":{"0":"n"}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"v","l":"unwrap"},"a":{"0":"i","v":0}},"a":{"0":"v","l":"ok"}},"t":{"0":"u"}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"matches can be open"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"multiline","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Let"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"t","l":"True"},"a":{"0":"u"}}}},"a":{"0":"f","l":"_other","b":{"0":"a","f":{"0":"t","l":"False"},"a":{"0":"u"}}}},"t":{"0":"u"}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"matches can be composed\n"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"pets","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Cat"},"a":{"0":"f","l":"_","b":{"0":"s","v":"felix"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Dog"},"a":{"0":"f","l":"_","b":{"0":"s","v":"fido"}}},"a":{"0":"n"}}},"t":{"0":"l","l":"animals","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Platypus"},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"special pet"}},"t":{"0":"s","v":"Alan"}}}},"a":{"0":"v","l":"pets"}},"t":{"0":"u"}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":""}},"a":{"0":"ta"}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"doc"},"a":{"0":"s","v":"/effects"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"el"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"h1"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"text-2xl"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Effects"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"h2"},"a":{"0":"s","v":"Choose"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"A random choice. \nImplementations can be handled to always return a fixed value or from a list or all.\n\nThe value passed when invoking the Choose effect is unit i.e. an empty record as behaviour is not defined by the caller of choose"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"choose","v":{"0":"f","l":"_","b":{"0":"a","f":{"0":"p","l":"Choose"},"a":{"0":"u"}}},"t":{"0":"l","l":"always","v":{"0":"f","l":"value","b":{"0":"a","f":{"0":"h","l":"Choose"},"a":{"0":"f","l":"_arg","b":{"0":"f","l":"resume","b":{"0":"a","f":{"0":"v","l":"resume"},"a":{"0":"v","l":"value"}}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"v","l":"always"},"a":{"0":"a","f":{"0":"t","l":"True"},"a":{"0":"u"}}},"a":{"0":"f","l":"_","b":{"0":"l","l":"first","v":{"0":"a","f":{"0":"v","l":"choose"},"a":{"0":"u"}},"t":{"0":"l","l":"second","v":{"0":"a","f":{"0":"v","l":"choose"},"a":{"0":"u"}},"t":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"first"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"second"}},"a":{"0":"ta"}}}}}}},"t":{"0":"l","l":"_","v":{"0":"s","v":"[True, True]"},"t":{"0":"z","c":""}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"choose both by resuming the exec function multiple times\n\nNeed to wrap the exec function to return a list of it's value so that it can be concatenated in the handler"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"concat","v":{"0":"z","c":""},"t":{"0":"l","l":"choose","v":{"0":"f","l":"_","b":{"0":"a","f":{"0":"p","l":"Choose"},"a":{"0":"u"}}},"t":{"0":"l","l":"both","v":{"0":"f","l":"exec","b":{"0":"l","l":"handler","v":{"0":"f","l":"_arg","b":{"0":"f","l":"resume","b":{"0":"l","l":"first","v":{"0":"a","f":{"0":"v","l":"resume"},"a":{"0":"a","f":{"0":"t","l":"True"},"a":{"0":"u"}}},"t":{"0":"l","l":"second","v":{"0":"a","f":{"0":"v","l":"resume"},"a":{"0":"a","f":{"0":"t","l":"False"},"a":{"0":"u"}}},"t":{"0":"a","f":{"0":"a","f":{"0":"v","l":"concat"},"a":{"0":"v","l":"first"}},"a":{"0":"v","l":"second"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"h","l":"Choose"},"a":{"0":"v","l":"handler"}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"exec"},"a":{"0":"u"}}},"a":{"0":"ta"}}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"v","l":"both"},"a":{"0":"f","l":"_","b":{"0":"l","l":"first","v":{"0":"a","f":{"0":"v","l":"choose"},"a":{"0":"u"}},"t":{"0":"l","l":"second","v":{"0":"a","f":{"0":"v","l":"choose"},"a":{"0":"u"}},"t":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"first"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"second"}},"a":{"0":"ta"}}}}}}},"t":{"0":"s","v":"[[True, True], [True, False], [False, True], [False, False]"}}}}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"h2"},"a":{"0":"s","v":"Fail"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Short circuit execution with a failure.\n\nI'm not sure of naming here. Can I use Error for the union type i.e. in Ok | Error at the same time as it for the Effect"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"f","l":"_","b":{"0":"l","l":"result","v":{"0":"l","l":"ok","v":{"0":"t","l":"Ok"},"t":{"0":"l","l":"error","v":{"0":"t","l":"Error"},"t":{"0":"l","l":"fail","v":{"0":"p","l":"Error"},"t":{"0":"l","l":"expect","v":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"value","b":{"0":"v","l":"value"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"reason","b":{"0":"a","f":{"0":"v","l":"fail"},"a":{"0":"v","l":"reason"}}}},"a":{"0":"z","c":""}}},"t":{"0":"l","l":"rescue","v":{"0":"f","l":"exec","b":{"0":"l","l":"handler","v":{"0":"f","l":"reason","b":{"0":"f","l":"_resume","b":{"0":"a","f":{"0":"v","l":"error"},"a":{"0":"v","l":"reason"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"h","l":"Error"},"a":{"0":"v","l":"handler"}},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"v","l":"ok"},"a":{"0":"a","f":{"0":"v","l":"exec"},"a":{"0":"u"}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"fail"},"a":{"0":"v","l":"fail"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"expect"},"a":{"0":"v","l":"expect"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"rescue"},"a":{"0":"v","l":"rescue"}},"a":{"0":"u"}}}}}}}}},"t":{"0":"z","c":""}}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"h2"},"a":{"0":"s","v":"Log"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Logs are an effect\n"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"code"},"a":{"0":"a","f":{"0":"g","l":"logs"},"a":{"0":"v","l":"std"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"h2"},"a":{"0":"s","v":"Async Await"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"v","l":"p"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Both async and await are implemented as effects and can be caught for test purposes"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":""}},"a":{"0":"ta"}}}}}}}}}}}}}}}}}},"a":{"0":"ta"}}},"t":{"0":"l","l":"render","v":{"0":"f","l":"path","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"v","l":"path"}},"t":{"0":"l","l":"page","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"result","b":{"0":"a","f":{"0":"g","l":"content"},"a":{"0":"v","l":"result"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"h1"},"a":{"0":"v","l":"html"}},"a":{"0":"ta"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"not found "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"path"}},"a":{"0":"ta"}}}}}},"a":{"0":"n"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"find"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"f","l":"d","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"path"},"a":{"0":"v","l":"d"}}},"a":{"0":"v","l":"path"}}}},"a":{"0":"v","l":"docs"}}},"t":{"0":"l","l":"vstack","v":{"0":"a","f":{"0":"g","l":"vstack"},"a":{"0":"v","l":"layout"}},"t":{"0":"l","l":"page","v":{"0":"a","f":{"0":"a","f":{"0":"v","l":"vstack"},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"bg-gray-50 wrap"}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"page"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"span"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"expand"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"el"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"footer"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"bg-gray-800"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"cover"}},"a":{"0":"ta"}}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"language"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}}}},"t":{"0":"v","l":"page"}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"render"},"a":{"0":"v","l":"render"}},"a":{"0":"u"}}}}}}}}}},"t":{"0":"f","l":"request","b":{"0":"a","f":{"0":"a","f":{"0":"e","l":"body"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"page"},"a":{"0":"v","l":"layout"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"render"},"a":{"0":"v","l":"view"}},"a":{"0":"a","f":{"0":"g","l":"path"},"a":{"0":"v","l":"request"}}}},"a":{"0":"ta"}}}},"a":{"0":"u"}}}},"t":{"0":"l","l":"dashboard","v":{"0":"l","l":"http","v":{"0":"l","l":"get","v":{"0":"f","l":"h","b":{"0":"f","l":"p","b":{"0":"l","l":"scheme","v":{"0":"a","f":{"0":"t","l":"HTTPS"},"a":{"0":"u"}},"t":{"0":"l","l":"port","v":{"0":"a","f":{"0":"t","l":"None"},"a":{"0":"u"}},"t":{"0":"l","l":"query","v":{"0":"a","f":{"0":"t","l":"None"},"a":{"0":"u"}},"t":{"0":"l","l":"headers","v":{"0":"ta"},"t":{"0":"l","l":"body","v":{"0":"s","v":""},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"method"},"a":{"0":"a","f":{"0":"t","l":"Get"},"a":{"0":"u"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"scheme"},"a":{"0":"v","l":"scheme"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"host"},"a":{"0":"v","l":"h"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"port"},"a":{"0":"v","l":"port"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"path"},"a":{"0":"v","l":"p"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"query"},"a":{"0":"v","l":"query"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"headers"},"a":{"0":"v","l":"headers"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"body"},"a":{"0":"v","l":"body"}},"a":{"0":"u"}}}}}}}}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"get"},"a":{"0":"v","l":"get"}},"a":{"0":"u"}}},"t":{"0":"l","l":"vstack","v":{"0":"a","f":{"0":"g","l":"vstack"},"a":{"0":"v","l":"layout"}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Await"},"a":{"0":"a","f":{"0":"p","l":"Wait"},"a":{"0":"i","v":1000}}},"t":{"0":"l","l":"promise","v":{"0":"a","f":{"0":"p","l":"HTTP"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"get"},"a":{"0":"v","l":"http"}},"a":{"0":"s","v":"api.sunrise-sunset.org"}},"a":{"0":"s","v":"/json"}}},"t":{"0":"l","l":"response","v":{"0":"a","f":{"0":"p","l":"Await"},"a":{"0":"v","l":"promise"}},"t":{"0":"l","l":"client","v":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"heres the response"}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"v","l":"response"}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Listen"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"event"},"a":{"0":"s","v":"click"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"handler"},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"There was a click"}},"t":{"0":"i","v":10}}}},"a":{"0":"u"}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"v","l":"async"},"a":{"0":"f","l":"_","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"about to inner request"}},"t":{"0":"l","l":"promise","v":{"0":"a","f":{"0":"p","l":"HTTP"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"get"},"a":{"0":"v","l":"http"}},"a":{"0":"s","v":"api.sunrise-sunset.org"}},"a":{"0":"s","v":"/json"}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"have promise"}},"t":{"0":"l","l":"response","v":{"0":"a","f":{"0":"p","l":"Await"},"a":{"0":"v","l":"promise"}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"v","l":"response"}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"s","v":"inner response"}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Await"},"a":{"0":"a","f":{"0":"p","l":"Wait"},"a":{"0":"i","v":5000}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Render"},"a":{"0":"s","v":"my new page2"}},"t":{"0":"s","v":"ok in async"}}}}}}}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"concat"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"abc! "}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"xyz"}},"a":{"0":"ta"}}}}},"t":{"0":"l","l":"_","v":{"0":"f","l":"comment","b":{"0":"a","f":{"0":"p","l":"Alert"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"append"},"a":{"0":"a","f":{"0":"g","l":"string"},"a":{"0":"v","l":"std"}}},"a":{"0":"s","v":"Hello "}},"a":{"0":"a","f":{"0":"g","l":"query"},"a":{"0":"v","l":"req"}}}}},"t":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Render"},"a":{"0":"s","v":"my new page"}},"t":{"0":"s","v":"ok"}}}}}}}}},"t":{"0":"l","l":"header","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"span"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"bg-gray-300"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"cover"}},"a":{"0":"ta"}}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"header"}},"a":{"0":"ta"}}},"t":{"0":"l","l":"main","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"span"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"expand"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"hello"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"response"}},"a":{"0":"ta"}}}},"t":{"0":"l","l":"app","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"div"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"attribute"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"id"}},"a":{"0":"s","v":"app"}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"header"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"main"}},"a":{"0":"ta"}}}},"t":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"script"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"attribute"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"type"}},"a":{"0":"s","v":"application/eygir"}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"serialize"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"client"}}},"a":{"0":"ta"}}},"t":{"0":"l","l":"runner","v":{"0":"s","v":"source should go outside vstack so need to do real append of strings"},"t":{"0":"l","l":"rendered","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"page"},"a":{"0":"v","l":"layout"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"app"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"source"}},"a":{"0":"ta"}}}},"t":{"0":"f","l":"request","b":{"0":"a","f":{"0":"a","f":{"0":"e","l":"body"},"a":{"0":"v","l":"rendered"}},"a":{"0":"u"}}}}}}}}}}}}}}},"t":{"0":"l","l":"universal","v":{"0":"f","l":"request","b":{"0":"l","l":"button","v":{"0":"f","l":"on_click","b":{"0":"f","l":"extra","b":{"0":"f","l":"children","b":{"0":"l","l":"attributes","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"attribute"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"data-click"}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"encode_uri"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"serialize"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"on_click"}}}}},"a":{"0":"v","l":"extra"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"button"},"a":{"0":"v","l":"html"}},"a":{"0":"v","l":"attributes"}},"a":{"0":"v","l":"children"}}}}}},"t":{"0":"l","l":"inc","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"add"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"i","v":1}},"t":{"0":"l","l":"dec","v":{"0":"f","l":"x","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"subtract"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"x"}},"a":{"0":"i","v":1}}},"t":{"0":"l","l":"initial","v":{"0":"i","v":2},"t":{"0":"l","l":"client","v":{"0":"f","l":"_","b":{"0":"l","l":"render","v":{"0":"f","l":"state","b":{"0":"l","l":"count","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"to_string"},"a":{"0":"a","f":{"0":"g","l":"integer"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"state"}},"t":{"0":"l","l":"inc_button","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"button"},"a":{"0":"a","f":{"0":"t","l":"Inc"},"a":{"0":"u"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"p-4"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Increment"}},"a":{"0":"ta"}}},"t":{"0":"l","l":"dec_button","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"v","l":"button"},"a":{"0":"a","f":{"0":"t","l":"Dec"},"a":{"0":"u"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"classes"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"bg-red-500"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Decrement"}},"a":{"0":"ta"}}},"t":{"0":"l","l":"page","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"div"},"a":{"0":"v","l":"html"}},"a":{"0":"ta"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"div"},"a":{"0":"v","l":"html"}},"a":{"0":"ta"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"count"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"inc_button"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"dec_button"}},"a":{"0":"ta"}}}}},"t":{"0":"a","f":{"0":"p","l":"Render"},"a":{"0":"v","l":"page"}}}}}}},"t":{"0":"l","l":"handle_click","v":{"0":"f","l":"arg","b":{"0":"f","l":"state","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"debug"},"a":{"0":"a","f":{"0":"g","l":"log"},"a":{"0":"v","l":"std"}}},"a":{"0":"v","l":"arg"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Inc"},"a":{"0":"f","l":"_","b":{"0":"l","l":"state","v":{"0":"a","f":{"0":"v","l":"inc"},"a":{"0":"v","l":"state"}},"t":{"0":"v","l":"state"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Dec"},"a":{"0":"f","l":"_","b":{"0":"l","l":"state","v":{"0":"a","f":{"0":"v","l":"dec"},"a":{"0":"v","l":"state"}},"t":{"0":"v","l":"state"}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"arg"}}}}},"t":{"0":"l","l":"run","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"fix"},"a":{"0":"v","l":"std"}},"a":{"0":"f","l":"run","b":{"0":"f","l":"state","b":{"0":"l","l":"_","v":{"0":"a","f":{"0":"v","l":"render"},"a":{"0":"v","l":"state"}},"t":{"0":"a","f":{"0":"p","l":"OnClick"},"a":{"0":"f","l":"el","b":{"0":"a","f":{"0":"v","l":"run"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"handle_click"},"a":{"0":"v","l":"el"}},"a":{"0":"v","l":"state"}}}}}}}}},"t":{"0":"a","f":{"0":"v","l":"run"},"a":{"0":"v","l":"initial"}}}}}},"t":{"0":"l","l":"app","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"div"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"attribute"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"id"}},"a":{"0":"s","v":"app"}}},"a":{"0":"ta"}}},"a":{"0":"ta"}},"t":{"0":"l","l":"source","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"script"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"attribute"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"type"}},"a":{"0":"s","v":"application/eygir"}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"g","l":"serialize"},"a":{"0":"v","l":"std"}},"a":{"0":"v","l":"client"}}},"a":{"0":"ta"}}},"t":{"0":"l","l":"rendered","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"page"},"a":{"0":"v","l":"layout"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"app"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"source"}},"a":{"0":"ta"}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"body"},"a":{"0":"v","l":"rendered"}},"a":{"0":"u"}}}}}}}}}}},"t":{"0":"l","l":"services","v":{"0":"l","l":"at","v":{"0":"f","l":"host","b":{"0":"f","l":"handler","b":{"0":"a","f":{"0":"a","f":{"0":"e","l":"host"},"a":{"0":"v","l":"host"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"handler"},"a":{"0":"v","l":"handler"}},"a":{"0":"u"}}}}},"t":{"0":"l","l":"s","v":{"0":"ta"},"t":{"0":"l","l":"s","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"at"},"a":{"0":"s","v":"localhost:5001"}},"a":{"0":"v","l":"language"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"at"},"a":{"0":"s","v":"language.web.petersaxton.uk"}},"a":{"0":"v","l":"language"}}},"a":{"0":"v","l":"s"}}},"t":{"0":"l","l":"laura","v":{"0":"f","l":"request","b":{"0":"l","l":"picture","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"el"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"img"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"s","v":"src"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"value"},"a":{"0":"s","v":"https://upload.wikimedia.org/wikipedia/commons/thumb/5/58/Schabrackentapir_Tapirus_indicus_Tiergarten-Nuernberg-1.jpg/1200px-Schabrackentapir_Tapirus_indicus_Tiergarten-Nuernberg-1.jpg"}},"a":{"0":"u"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"go to bbbc"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}},"t":{"0":"l","l":"link","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"el"},"a":{"0":"v","l":"html"}},"a":{"0":"s","v":"a"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"s","v":"href"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"value"},"a":{"0":"s","v":"https://bbc.co.uk"}},"a":{"0":"u"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"go to bbbc"}},"a":{"0":"ta"}}}},"a":{"0":"v","l":"picture"}},"t":{"0":"l","l":"panels","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"hstack"},"a":{"0":"v","l":"layout"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"p"},"a":{"0":"v","l":"html"}},"a":{"0":"ta"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"barfoo"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"expand"},"a":{"0":"v","l":"layout"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"p"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"s","v":"class"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"value"},"a":{"0":"s","v":"text-indigo-500"}},"a":{"0":"u"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"bar"}},"a":{"0":"ta"}}}},"a":{"0":"ta"}}}}},"t":{"0":"l","l":"body","v":{"0":"a","f":{"0":"a","f":{"0":"g","l":"page"},"a":{"0":"v","l":"layout"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"vstack"},"a":{"0":"v","l":"layout"}},"a":{"0":"ta"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"p"},"a":{"0":"v","l":"html"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"name"},"a":{"0":"s","v":"class"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"value"},"a":{"0":"s","v":"bg-green-400 cover"}},"a":{"0":"u"}}}},"a":{"0":"ta"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"Valhalla"}},"a":{"0":"ta"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"v","l":"panels"}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"g","l":"expand"},"a":{"0":"v","l":"layout"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"s","v":"thor rocks"}},"a":{"0":"v","l":"link"}}}}}}},"a":{"0":"ta"}}},"t":{"0":"l","l":"response","v":{"0":"a","f":{"0":"a","f":{"0":"e","l":"body"},"a":{"0":"v","l":"body"}},"a":{"0":"u"}},"t":{"0":"v","l":"response"}}}}}}},"t":{"0":"l","l":"s","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"at"},"a":{"0":"s","v":"localhost:5002"}},"a":{"0":"v","l":"laura"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"at"},"a":{"0":"s","v":"laura.web.petersaxton.uk"}},"a":{"0":"v","l":"laura"}}},"a":{"0":"v","l":"s"}}},"t":{"0":"l","l":"s","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"at"},"a":{"0":"s","v":"localhost:5003"}},"a":{"0":"v","l":"dashboard"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"at"},"a":{"0":"s","v":"dashboard.web.petersaxton.uk"}},"a":{"0":"v","l":"dashboard"}}},"a":{"0":"v","l":"s"}}},"t":{"0":"l","l":"s","v":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"at"},"a":{"0":"s","v":"localhost:5004"}},"a":{"0":"v","l":"universal"}}},"a":{"0":"a","f":{"0":"a","f":{"0":"c"},"a":{"0":"a","f":{"0":"a","f":{"0":"v","l":"at"},"a":{"0":"s","v":"universal.web.petersaxton.uk"}},"a":{"0":"v","l":"universal"}}},"a":{"0":"v","l":"s"}}},"t":{"0":"v","l":"s"}}}}}}}},"t":{"0":"l","l":"handler","v":{"0":"l","l":"_","v":{"0":"a","f":{"0":"p","l":"Log"},"a":{"0":"a","f":{"0":"g","l":"host"},"a":{"0":"v","l":"req"}}},"t":{"0":"l","l":"lookup","v":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"find"},"a":{"0":"a","f":{"0":"g","l":"list"},"a":{"0":"v","l":"std"}}},"a":{"0":"f","l":"item","b":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"g","l":"equal"},"a":{"0":"v","l":"std"}},"a":{"0":"a","f":{"0":"g","l":"host"},"a":{"0":"v","l":"item"}}},"a":{"0":"a","f":{"0":"g","l":"host"},"a":{"0":"v","l":"req"}}}}},"a":{"0":"v","l":"services"}},"t":{"0":"a","f":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Ok"},"a":{"0":"f","l":"service","b":{"0":"a","f":{"0":"g","l":"handler"},"a":{"0":"v","l":"service"}}}},"a":{"0":"a","f":{"0":"a","f":{"0":"m","l":"Error"},"a":{"0":"f","l":"_","b":{"0":"f","l":"_request","b":{"0":"a","f":{"0":"a","f":{"0":"e","l":"body"},"a":{"0":"s","v":"No service"}},"a":{"0":"u"}}}}},"a":{"0":"n"}}},"a":{"0":"v","l":"lookup"}}}},"t":{"0":"a","f":{"0":"v","l":"handler"},"a":{"0":"v","l":"req"}}}}}}}}},"t":{"0":"a","f":{"0":"a","f":{"0":"e","l":"cli"},"a":{"0":"v","l":"cli"}},"a":{"0":"a","f":{"0":"a","f":{"0":"e","l":"web"},"a":{"0":"v","l":"web"}},"a":{"0":"u"}}}}}}}}}}}}}} \ No newline at end of file diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index a5e606be1..9a7a31e7b 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -11,7 +11,8 @@ import gleam/http import gleam/http/request import lustre/cmd import atelier/transform.{Act} -import eygir/expression as e +import eyg/incremental/source as e +import eyg/incremental/cursor import eygir/encode import eyg/analysis/inference import eyg/runtime/standard @@ -19,13 +20,18 @@ import eyg/incremental/store import plinth/javascript/map as mutable_map import eyg/analysis/jm/incremental as jm import eyg/analysis/jm/type_ as jmt +import eyg/analysis/jm/error pub type WorkSpace { WorkSpace( selection: List(Int), - source: e.Expression, - inferred: Option(inference.Infered), + source: e.Source, + root: Int, + // TODO call acc + inferred: #(map.Map(Int, jmt.Type), Int, Option(map.Map(Int, Result(jmt.Type, #(error.Reason, jmt.Type, jmt.Type))))), mode: Mode, + // copy pasting makes the id get reused that will change the type or have the type used more than once in a tree + // Need to not type things with free variables/types yanked: Option(e.Expression), error: Option(String), history: #( @@ -36,11 +42,11 @@ pub type WorkSpace { } pub type Mode { - Navigate(actions: transform.Act) - WriteLabel(value: String, commit: fn(String) -> e.Expression) - WriteText(value: String, commit: fn(String) -> e.Expression) - WriteNumber(value: Int, commit: fn(Int) -> e.Expression) - WriteTerm(value: String, commit: fn(e.Expression) -> e.Expression) + Navigate(cursor: cursor.Cursor) + WriteLabel(value: String, commit: fn(String) -> #(Int, e.Source)) + WriteText(value: String, commit: fn(String) -> #(Int, e.Source)) + WriteNumber(value: Int, commit: fn(Int) -> #(Int, e.Source)) + WriteTerm(value: String, commit: fn(e.Expression) -> #(Int, e.Source)) } pub type Action { @@ -54,13 +60,11 @@ pub type Action { external fn pnow() -> Int = "" "performance.now" -pub fn init(source) { - let assert Ok(act) = transform.prepare(source, []) - let mode = Navigate(act) - - let path = [1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0] +pub fn init(tree) { let start = pnow() - let #(root, s) = store.load(store.empty(), source) + // TODO don't use store with mutable ref typing and free is unused + let #(root, s) = store.load(store.empty(), tree) + let source = s.source io.debug(#( "loading store took ms:", pnow() - start, @@ -69,189 +73,40 @@ pub fn init(source) { map.size(s.free), )) - let start = pnow() - let doubled = store.ref_group(s) - io.debug(#( - "doubled took ms:", - pnow() - start, - map.size(doubled), - map.to_list(doubled), - )) + let sub = map.new() + let next = 0 + let env = map.new() + // TODO type for editor + let type_ = jmt.Var(-1) + let eff = jmt.Var(-2) + let types = map.new() let start = pnow() - let assert Ok(#(vars, s)) = store.free(s, root) - io.debug(#( - "memoizing free took ms:", - pnow() - start, - map.size(s.source), - map.size(s.free), - )) - - let start = pnow() - let assert Ok(#(vars, s)) = store.free_mut(s, root) - io.debug(#( - "memoizing free mut took ms:", - pnow() - start, - map.size(s.source), - mutable_map.size(s.free_mut), - )) - - // let start = pnow() - // let assert Ok(#(t, s)) = store.type_(s, root) - // // TODO i think should be same size - // io.debug(#( - // "typing took ms:", - // pnow() - start, - // map.size(s.source), - // map.size(s.free), - // map.size(s.types), - // t, - // )) - - let _ = { - let sub = map.new() - let next = 0 - let env = map.new() - let source_map = s.source - let ref = root - let type_ = jmt.Var(-1) - let eff = jmt.Var(-2) - let types = map.new() - let start = pnow() - let #(sub, _next, typesjm) = - jm.infer(sub, next, env, source_map, ref, type_, eff, types) - io.debug(#("typing jm took ms:", pnow() - start, map.size(typesjm))) - let assert Ok(Ok(t)) = map.get(typesjm, root) - io.debug(jmt.resolve(t, sub)) - let assert Ok(Ok(t)) = - map.get(typesjm, 0) - |> io.debug - io.debug(jmt.resolve(t, sub)) - let assert Ok(Ok(t)) = map.get(typesjm, 1) - io.debug(jmt.resolve(t, sub)) - let assert Ok(Ok(t)) = map.get(typesjm, 2) - io.debug(jmt.resolve(t, sub)) - - io.debug("================") - list.map( - map.to_list(typesjm), - fn(r) { - let #(id, r) = r - case r { - Ok(_) -> Nil - Error(reason) -> { - io.debug(map.get(s.source, id)) - // io.debug(reason) - io.debug(jmt.resolve_error(reason, sub)) - Nil - } + let #(sub, next, typesjm) as acc = + jm.infer(sub, next, env, source, root, type_, eff, types) + + io.debug(#("typing jm took ms:", pnow() - start, map.size(typesjm))) + list.map( + map.to_list(typesjm), + fn(r) { + let #(id, r) = r + case r { + Ok(_) -> Nil + Error(reason) -> { + io.debug("================ type error") + io.debug(map.get(s.source, id)) + // io.debug(reason) + io.debug(jmt.resolve_error(reason, sub)) + Nil } - }, - ) - - io.debug("================") - } - - // // new map of types because non function not generic. - // // TODO should this be the case add to gleam explainers - // let types = map.new() - // let start = pnow() - // let #(sub, _next, typesjm) = jm_tree.infer(sub, next, env, source, [], type_, eff, types) - // io.debug(#( - // "typing jm took ms:", - // pnow() - start, - // map.size(typesjm), - // )) - // let start = pnow() - // let assert Ok(c) = store.cursor(s, root, path) - // io.debug(#("building store.cursor took ms:", pnow() - start)) - // // io.debug(c) - // let start = pnow() - // TODO need to time new typing - // let assert Ok(#(root_, s)) = store.replace(s, c, incremental.String("hello")) - // io.debug(#( - // "updating store.replace took ms:", - // pnow() - start, - // map.size(s.source), - // map.size(s.free), - // map.size(s.types), - // )) - // let start = pnow() - // let assert Ok(#(t, s)) = store.type_(s, root_) - // io.debug(#( - // "typing took ms:", - // pnow() - start, - // map.size(s.source), - // map.size(s.free), - // map.size(s.types), - // t, - // )) - - // not helpful - // list.map(map.to_list(s.types), io.debug) - io.debug("------------------------") - - // let start = pnow() - // let #(root, refs) = incremental.from_tree(source) - // io.debug(#("building incremental took ms:", pnow() - start, list.length(refs))) - // let start = pnow() - // let #(root, refs_map) = incremental.from_tree_map(source) - // io.debug(#( - // "building incremental map took ms:", - // pnow() - start, - // map.size(refs_map), - // )) - - // let start = pnow() - // let f = new_i.free(refs, []) - // io.debug(#("finding free took ms:", pnow() - start)) - // let start = pnow() - // let fm = new_i.free_map(refs, map.new()) - // io.debug(#("finding free took ms:", pnow() - start)) - - // let count = javascript.make_reference(0) - // let start = pnow() - // let #(t, s, cache) = - // new_i.cached(root, refs, f, map.new(), env.empty(), sub.none(), count) - // io.debug(#("initial type check took ms:", pnow() - start)) - - // let start = pnow() - // let c = cursor.at(path, root, refs) - // io.debug(#("building cursor took ms:", pnow() - start)) - // io.debug(c) - - // let start = pnow() - // let refs_map = - // list.index_map(refs, fn(i, r) { #(i, r) }) - // |> map.from_list() - // io.debug(#("list to map took ms:", pnow() - start)) - - // let start = pnow() - // let #(x, refs) = cursor.replace(e.Binary("hello"), c, refs) - // io.debug(#("replacing at cursor took ms:", pnow() - start)) - // io.debug(x) - - // let start = pnow() - // let #(x, refs) = cursor.replace_map(e.Binary("hello"), c, refs_map) - // io.debug(#("replacing at cursor took ms:", pnow() - start)) - // io.debug(x) - - // let start = pnow() - // let f2 = new_i.free(refs, f) - // io.debug(#("f2 took ms:", pnow() - start)) - - // let #(t, s, cache) = new_i.cached(root, refs, f, cache, env.empty(), s, count) - // io.debug(#("partial type check took ms:", pnow() - start)) - // let start = pnow() - // let fm2 = new_i.free_map(refs, fm) - // io.debug(#("finding fm2 took ms:", pnow() - start)) - - let start = pnow() - let inferred = Some(standard.infer(source)) - io.debug(#("standard infer took ms:", pnow() - start)) - + } + }, + ) + // cusor at root doesn't ever error + let assert Ok(c) = cursor.at([], root, source) + let mode = Navigate(c) // Have inference work once for showing elements but need to also background this - WorkSpace([], source, inferred, mode, None, None, #([], [])) + WorkSpace([], source, root, #(sub, next, Some(typesjm)), mode, None, None, #([], [])) } pub fn update(state: WorkSpace, action) { @@ -292,8 +147,8 @@ pub fn update(state: WorkSpace, action) { } pub fn select_node(state, path) { - let WorkSpace(source: source, ..) = state - let assert Ok(act) = transform.prepare(source, path) + let WorkSpace(source: source, root: root, ..) = state + let assert Ok(act) = cursor.at(path, root, source) let mode = Navigate(act) let state = WorkSpace(..state, source: source, selection: path, mode: mode) @@ -308,35 +163,35 @@ pub fn keypress(key, state: WorkSpace) { let r = case state.mode, key { // save in this state only because q is a normal letter needed when entering text Navigate(_act), "q" -> save(state) - Navigate(act), "w" -> call_with(act, state) + // Navigate(act), "w" -> call_with(act, state) Navigate(act), "e" -> Ok(assign_to(act, state)) - Navigate(act), "r" -> record(act, state) - Navigate(act), "t" -> Ok(tag(act, state)) - Navigate(act), "y" -> Ok(copy(act, state)) - // copy paste quite rare so we use upper case. might be best as command - Navigate(act), "Y" -> paste(act, state) - Navigate(act), "u" -> unwrap(act, state) - Navigate(act), "i" -> insert(act, state) - Navigate(act), "o" -> overwrite(act, state) - Navigate(act), "p" -> Ok(perform(act, state)) + // Navigate(act), "r" -> record(act, state) + // Navigate(act), "t" -> Ok(tag(act, state)) + // Navigate(act), "y" -> Ok(copy(act, state)) + // // copy paste quite rare so we use upper case. might be best as command + // Navigate(act), "Y" -> paste(act, state) + // Navigate(act), "u" -> unwrap(act, state) + // Navigate(act), "i" -> insert(act, state) + // Navigate(act), "o" -> overwrite(act, state) + // Navigate(act), "p" -> Ok(perform(act, state)) Navigate(_act), "a" -> increase(state) Navigate(act), "s" -> decrease(act, state) Navigate(act), "d" -> delete(act, state) - Navigate(act), "f" -> Ok(abstract(act, state)) - Navigate(act), "g" -> select(act, state) - Navigate(act), "h" -> handle(act, state) - // Navigate(act), "j" -> ("down probably not") - // Navigate(act), "k" -> ("up probably not") - // Navigate(act), "l" -> ("right probably not") - Navigate(_act), "z" -> undo(state) - Navigate(_act), "Z" -> redo(state) - Navigate(act), "x" -> list(act, state) - Navigate(act), "c" -> call(act, state) - Navigate(act), "v" -> Ok(variable(act, state)) - Navigate(act), "b" -> Ok(binary(act, state)) - Navigate(act), "n" -> Ok(number(act, state)) - Navigate(act), "m" -> match(act, state) - Navigate(act), "M" -> nocases(act, state) + // Navigate(act), "f" -> Ok(abstract(act, state)) + // Navigate(act), "g" -> select(act, state) + // Navigate(act), "h" -> handle(act, state) + // // Navigate(act), "j" -> ("down probably not") + // // Navigate(act), "k" -> ("up probably not") + // // Navigate(act), "l" -> ("right probably not") + // Navigate(_act), "z" -> undo(state) + // Navigate(_act), "Z" -> redo(state) + // Navigate(act), "x" -> list(act, state) + // Navigate(act), "c" -> call(act, state) + // Navigate(act), "v" -> Ok(variable(act, state)) + // Navigate(act), "b" -> Ok(binary(act, state)) + // Navigate(act), "n" -> Ok(number(act, state)) + // Navigate(act), "m" -> match(act, state) + // Navigate(act), "M" -> nocases(act, state) // Navigate(act), " " -> ("space follow suggestion next error") Navigate(_), _ -> Error("no action for keypress") // Other mode @@ -353,12 +208,17 @@ pub fn keypress(key, state: WorkSpace) { WriteText(_, _), _k -> Ok(state) WriteTerm(new, commit), k if k == "Enter" -> { let assert [var, ..selects] = string.split(new, ".") + case selects { + [] -> Nil + _ -> todo("handle dot vars") + } let expression = - list.fold( - selects, - e.Variable(var), - fn(acc, select) { e.Apply(e.Select(select), acc) }, - ) + // list.fold( + // selects, + // e.Variable(var), + // fn(acc, select) { e.Apply(e.Select(select), acc) }, + // ) + e.Var(var) let source = commit(expression) update_source(state, source) } @@ -382,156 +242,170 @@ fn save(state: WorkSpace) { |> request.set_host("localhost:5000") |> request.set_path("/save") |> request.prepend_header("content-type", "application/json") - |> request.set_body(encode.to_json(state.source)) + todo("finish saving") + // |> request.set_body(encode.to_json(state.source)) fetch.send(request) |> io.debug Ok(state) } -fn call_with(act: Act, state) { - let source = act.update(e.Apply(e.Vacant(""), act.target)) - update_source(state, source) -} +// fn call_with(act: Act, state) { +// let source = act.update(e.Apply(e.Vacant(""), act.target)) +// update_source(state, source) +// } // e is essentially line above on a let statement. // nested lets can only be created from the value on the right. // moving something to a module might just have to be copy paste -fn assign_to(act: Act, state) { - let commit = case act.target { +fn assign_to(c, state: WorkSpace) { + let assert Ok(exp) = cursor.expression(c, state.source) + let #(hole, source) = e.insert(state.source, e.Vacant("")) + let commit = case exp { e.Let(_, _, _) -> fn(text) { - act.update(e.Let(text, e.Vacant(""), act.target)) + // TODO needs a tree replace + // easier to insert tree but only if no reference to the old stuff + let assert Ok(r) = store.replace(source, c, e.Let(text, hole, cursor.inner(c))) + r } // normally I want to add something above - exp -> fn(text) { act.update(e.Let(text, e.Vacant(""), exp)) } - } - WorkSpace(..state, mode: WriteLabel("", commit)) -} - -fn record(act: Act, state) { - case act.target { - e.Vacant(_comment) -> - act.update(e.Empty) - |> update_source(state, _) - e.Empty as exp | e.Apply(e.Apply(e.Extend(_), _), _) as exp -> { - let commit = fn(text) { - act.update(e.Apply(e.Apply(e.Extend(text), e.Vacant("")), exp)) - } - Ok(WorkSpace(..state, mode: WriteLabel("", commit))) - } - exp -> { - let commit = fn(text) { - act.update(e.Apply(e.Apply(e.Extend(text), exp), e.Empty)) - } - Ok(WorkSpace(..state, mode: WriteLabel("", commit))) + exp -> fn(text) { + // always the same + // act.update(e.Let(text, e.Vacant(""), exp)) } + let assert Ok(r) = + store.replace(source, c, e.Let(text, hole, cursor.inner(c))) + r } } -} - -fn tag(act: Act, state) { - let commit = case act.target { - e.Vacant(_comment) -> fn(text) { act.update(e.Tag(text)) } - exp -> fn(text) { act.update(e.Apply(e.Tag(text), exp)) } - } WorkSpace(..state, mode: WriteLabel("", commit)) } -fn copy(act: Act, state) { - WorkSpace(..state, yanked: Some(act.target)) -} - -fn paste(act: Act, state: WorkSpace) { - case state.yanked { - Some(snippet) -> { - let source = act.update(snippet) - update_source(state, source) - } - None -> Error("nothing on clipboard") - } -} - -fn unwrap(act: Act, state) { - case act.parent { - None -> Error("top level") - Some(#(_i, _list, _, parent_update)) -> { - let source = parent_update(act.target) - update_source(state, source) - } - } -} - -fn insert(act: Act, state) { - let write = fn(text, build) { - WriteLabel(text, fn(new) { act.update(build(new)) }) - } - use mode <- result.then(case act.target { - e.Variable(value) -> Ok(write(value, e.Variable(_))) - e.Lambda(param, body) -> Ok(write(param, e.Lambda(_, body))) - e.Apply(_, _) -> Error("no insert option for apply") - e.Let(var, body, then) -> Ok(write(var, e.Let(_, body, then))) - - e.Binary(value) -> - Ok(WriteText(value, fn(new) { act.update(e.Binary(new)) })) - e.Integer(value) -> - Ok(WriteNumber(value, fn(new) { act.update(e.Integer(new)) })) - e.Tail | e.Cons -> Error("there is no insert for lists") - e.Vacant(comment) -> Ok(write(comment, e.Vacant)) - e.Empty -> Error("empty record no insert") - e.Extend(label) -> Ok(write(label, e.Extend)) - e.Select(label) -> Ok(write(label, e.Select)) - e.Overwrite(label) -> Ok(write(label, e.Overwrite)) - e.Tag(label) -> Ok(write(label, e.Tag)) - e.Case(label) -> Ok(write(label, e.Case)) - e.NoCases -> Error("no cases") - e.Perform(label) -> Ok(write(label, e.Perform)) - e.Handle(label) -> Ok(write(label, e.Handle)) - e.Builtin(_) -> Error("no insert option for builtin, use stdlib references") - }) - - Ok(WorkSpace(..state, mode: mode)) -} - -fn overwrite(act: Act, state) { - case act.target { - e.Apply(e.Apply(e.Overwrite(_), _), _) as exp -> { - let commit = fn(text) { - act.update(e.Apply(e.Apply(e.Overwrite(text), e.Vacant("")), exp)) - } - Ok(WorkSpace(..state, mode: WriteLabel("", commit))) - } - exp -> { - let commit = fn(text) { - // This is the same as above - act.update(e.Apply(e.Apply(e.Overwrite(text), e.Vacant("")), exp)) - } - Ok(WorkSpace(..state, mode: WriteLabel("", commit))) - } - } -} +// fn record(act: Act, state) { +// case act.target { +// e.Vacant(_comment) -> +// act.update(e.Empty) +// |> update_source(state, _) +// e.Empty as exp | e.Apply(e.Apply(e.Extend(_), _), _) as exp -> { +// let commit = fn(text) { +// act.update(e.Apply(e.Apply(e.Extend(text), e.Vacant("")), exp)) +// } +// Ok(WorkSpace(..state, mode: WriteLabel("", commit))) +// } +// exp -> { +// let commit = fn(text) { +// act.update(e.Apply(e.Apply(e.Extend(text), exp), e.Empty)) +// } +// Ok(WorkSpace(..state, mode: WriteLabel("", commit))) +// } +// } +// } + +// fn tag(act: Act, state) { +// let commit = case act.target { +// e.Vacant(_comment) -> fn(text) { act.update(e.Tag(text)) } +// exp -> fn(text) { act.update(e.Apply(e.Tag(text), exp)) } +// } +// WorkSpace(..state, mode: WriteLabel("", commit)) +// } + +// fn copy(act: Act, state) { +// WorkSpace(..state, yanked: Some(act.target)) +// } + +// fn paste(act: Act, state: WorkSpace) { +// case state.yanked { +// Some(snippet) -> { +// let source = act.update(snippet) +// update_source(state, source) +// } +// None -> Error("nothing on clipboard") +// } +// } + +// fn unwrap(act: Act, state) { +// case act.parent { +// None -> Error("top level") +// Some(#(_i, _list, _, parent_update)) -> { +// let source = parent_update(act.target) +// update_source(state, source) +// } +// } +// } + +// fn insert(act: Act, state) { +// let write = fn(text, build) { +// WriteLabel(text, fn(new) { act.update(build(new)) }) +// } +// use mode <- result.then(case act.target { +// e.Variable(value) -> Ok(write(value, e.Variable(_))) +// e.Lambda(param, body) -> Ok(write(param, e.Lambda(_, body))) +// e.Apply(_, _) -> Error("no insert option for apply") +// e.Let(var, body, then) -> Ok(write(var, e.Let(_, body, then))) + +// e.Binary(value) -> +// Ok(WriteText(value, fn(new) { act.update(e.Binary(new)) })) +// e.Integer(value) -> +// Ok(WriteNumber(value, fn(new) { act.update(e.Integer(new)) })) +// e.Tail | e.Cons -> Error("there is no insert for lists") +// e.Vacant(comment) -> Ok(write(comment, e.Vacant)) +// e.Empty -> Error("empty record no insert") +// e.Extend(label) -> Ok(write(label, e.Extend)) +// e.Select(label) -> Ok(write(label, e.Select)) +// e.Overwrite(label) -> Ok(write(label, e.Overwrite)) +// e.Tag(label) -> Ok(write(label, e.Tag)) +// e.Case(label) -> Ok(write(label, e.Case)) +// e.NoCases -> Error("no cases") +// e.Perform(label) -> Ok(write(label, e.Perform)) +// e.Handle(label) -> Ok(write(label, e.Handle)) +// e.Builtin(_) -> Error("no insert option for builtin, use stdlib references") +// }) + +// Ok(WorkSpace(..state, mode: mode)) +// } + +// fn overwrite(act: Act, state) { +// case act.target { +// e.Apply(e.Apply(e.Overwrite(_), _), _) as exp -> { +// let commit = fn(text) { +// act.update(e.Apply(e.Apply(e.Overwrite(text), e.Vacant("")), exp)) +// } +// Ok(WorkSpace(..state, mode: WriteLabel("", commit))) +// } +// exp -> { +// let commit = fn(text) { +// // This is the same as above +// act.update(e.Apply(e.Apply(e.Overwrite(text), e.Vacant("")), exp)) +// } +// Ok(WorkSpace(..state, mode: WriteLabel("", commit))) +// } +// } +// } fn increase(state: WorkSpace) { use selection <- result.then(case list.reverse(state.selection) { [_, ..rest] -> Ok(list.reverse(rest)) [] -> Error("no increase") }) - let assert Ok(act) = transform.prepare(state.source, selection) - Ok(WorkSpace(..state, selection: selection, mode: Navigate(act))) + let assert Ok(c) = cursor.at(selection, state.root, state.source) + Ok(WorkSpace(..state, selection: selection, mode: Navigate(c))) } fn decrease(_act, state: WorkSpace) { let selection = list.append(state.selection, [0]) - use act <- result.then(transform.prepare(state.source, selection)) - Ok(WorkSpace(..state, selection: selection, mode: Navigate(act))) + use c <- result.then(cursor.at(selection, state.root, state.source) |> result.map_error(fn(_: Nil) { "no valid decrease"})) + Ok(WorkSpace(..state, selection: selection, mode: Navigate(c))) } -fn delete(act: Act, state) { +fn delete(c, state: WorkSpace) { // an assignment vacant or not is always deleted. // when deleting with a vacant as a target there is no change // we can instead bump up the path let start = pnow() - let source = case act.target { - e.Let(_label, _, then) -> act.update(then) - _ -> act.update(e.Vacant("")) + let assert Ok(exp) = cursor.expression(c, state.source) + let #(hole, source) = e.insert(state.source, e.Vacant("")) + let assert Ok(source) = case exp { + e.Let(_label, _, then) -> e.replace(source, c, then) + _ -> e.replace(source, c, hole) } let ret = update_source(state, source) io.debug(#("normal update took ms:", pnow() - start)) @@ -539,175 +413,192 @@ fn delete(act: Act, state) { ret } -fn abstract(act: Act, state) { - let commit = case act.target { - e.Let(label, value, then) -> fn(text) { - act.update(e.Let(label, e.Lambda(text, value), then)) - } - exp -> fn(text) { act.update(e.Lambda(text, exp)) } - } - WorkSpace(..state, mode: WriteLabel("", commit)) -} - -fn select(act: Act, state) { - case act.target { - e.Let(_label, _value, _then) -> Error("can't get on let") - exp -> { - let commit = fn(text) { act.update(e.Apply(e.Select(text), exp)) } - Ok(WorkSpace(..state, mode: WriteLabel("", commit))) - } - } -} - -fn handle(act: Act, state) { - case act.target { - e.Let(_label, _value, _then) -> Error("can't handle on let") - exp -> { - let commit = fn(text) { - act.update(e.Apply(e.Apply(e.Handle(text), e.Vacant("")), exp)) - } - Ok(WorkSpace(..state, mode: WriteLabel("", commit))) - } - } -} - -fn perform(act: Act, state) { - let commit = case act.target { - e.Let(label, _value, then) -> fn(text) { - act.update(e.Let(label, e.Perform(text), then)) - } - _exp -> fn(text) { act.update(e.Perform(text)) } - } - WorkSpace(..state, mode: WriteLabel("", commit)) -} - -fn undo(state: WorkSpace) { - case state.history { - #([], _) -> Error("No history") - #([#(source, selection), ..rest], forward) -> { - let history = #(rest, [#(state.source, state.selection), ..forward]) - use act <- result.then(transform.prepare(source, selection)) - // Has to already be in navigate mode to undo - let mode = Navigate(act) - Ok( - WorkSpace( - ..state, - source: source, - selection: selection, - mode: mode, - history: history, - ), - ) - } - } -} - -fn redo(state: WorkSpace) { - case state.history { - #(_, []) -> Error("No redo") - #(backward, [#(source, selection), ..rest]) -> { - let history = #([#(state.source, state.selection), ..backward], rest) - use act <- result.then(transform.prepare(source, selection)) - // Has to already be in navigate mode to undo - let mode = Navigate(act) - Ok( - WorkSpace( - ..state, - source: source, - selection: selection, - mode: mode, - history: history, - ), - ) - } - } -} - -fn list(act: Act, state) { - let new = case act.target { - e.Vacant(_comment) -> e.Tail - e.Tail | e.Apply(e.Apply(e.Cons, _), _) -> - e.Apply(e.Apply(e.Cons, e.Vacant("")), act.target) - _ -> e.Apply(e.Apply(e.Cons, act.target), e.Tail) - } - let source = act.update(new) - update_source(state, source) -} - -fn call(act: Act, state) { - let source = act.update(e.Apply(act.target, e.Vacant(""))) - update_source(state, source) -} - -fn variable(act: Act, state) { - let commit = case act.target { - e.Let(label, _value, then) -> fn(term) { - act.update(e.Let(label, term, then)) - } - _exp -> fn(term) { act.update(term) } - } - WorkSpace(..state, mode: WriteTerm("", commit)) -} - -fn binary(act: Act, state) { - let commit = case act.target { - e.Let(label, _value, then) -> fn(text) { - act.update(e.Let(label, e.Binary(text), then)) - } - _exp -> fn(text) { act.update(e.Binary(text)) } - } - WorkSpace(..state, mode: WriteText("", commit)) -} - -fn number(act: Act, state) { - let #(v, commit) = case act.target { - e.Let(label, _value, then) -> #( - 0, - fn(value) { act.update(e.Let(label, e.Integer(value), then)) }, - ) - e.Integer(value) -> #(value, fn(value) { act.update(e.Integer(value)) }) - _exp -> #(0, fn(value) { act.update(e.Integer(value)) }) - } - WorkSpace(..state, mode: WriteNumber(v, commit)) -} - -fn match(act: Act, state) { - let commit = case act.target { - // e.Let(label, value, then) -> fn(text) { - // act.update(e.Let(label, e.Binary(text), then)) - // } - // Match on original value should maybe be the arg? but I like promoting first class everything - exp -> fn(text) { - act.update(e.Apply(e.Apply(e.Case(text), e.Vacant("")), exp)) - } - } - Ok(WorkSpace(..state, mode: WriteLabel("", commit))) -} - -fn nocases(act: Act, state) { - update_source(state, act.update(e.NoCases)) -} +// fn abstract(act: Act, state) { +// let commit = case act.target { +// e.Let(label, value, then) -> fn(text) { +// act.update(e.Let(label, e.Lambda(text, value), then)) +// } +// exp -> fn(text) { act.update(e.Lambda(text, exp)) } +// } +// WorkSpace(..state, mode: WriteLabel("", commit)) +// } + +// fn select(act: Act, state) { +// case act.target { +// e.Let(_label, _value, _then) -> Error("can't get on let") +// exp -> { +// let commit = fn(text) { act.update(e.Apply(e.Select(text), exp)) } +// Ok(WorkSpace(..state, mode: WriteLabel("", commit))) +// } +// } +// } + +// fn handle(act: Act, state) { +// case act.target { +// e.Let(_label, _value, _then) -> Error("can't handle on let") +// exp -> { +// let commit = fn(text) { +// act.update(e.Apply(e.Apply(e.Handle(text), e.Vacant("")), exp)) +// } +// Ok(WorkSpace(..state, mode: WriteLabel("", commit))) +// } +// } +// } + +// fn perform(act: Act, state) { +// let commit = case act.target { +// e.Let(label, _value, then) -> fn(text) { +// act.update(e.Let(label, e.Perform(text), then)) +// } +// _exp -> fn(text) { act.update(e.Perform(text)) } +// } +// WorkSpace(..state, mode: WriteLabel("", commit)) +// } + +// fn undo(state: WorkSpace) { +// case state.history { +// #([], _) -> Error("No history") +// #([#(source, selection), ..rest], forward) -> { +// let history = #(rest, [#(state.source, state.selection), ..forward]) +// use act <- result.then(transform.prepare(source, selection)) +// // Has to already be in navigate mode to undo +// let mode = Navigate(act) +// Ok( +// WorkSpace( +// ..state, +// source: source, +// selection: selection, +// mode: mode, +// history: history, +// ), +// ) +// } +// } +// } + +// fn redo(state: WorkSpace) { +// case state.history { +// #(_, []) -> Error("No redo") +// #(backward, [#(source, selection), ..rest]) -> { +// let history = #([#(state.source, state.selection), ..backward], rest) +// use act <- result.then(transform.prepare(source, selection)) +// // Has to already be in navigate mode to undo +// let mode = Navigate(act) +// Ok( +// WorkSpace( +// ..state, +// source: source, +// selection: selection, +// mode: mode, +// history: history, +// ), +// ) +// } +// } +// } + +// fn list(act: Act, state) { +// let new = case act.target { +// e.Vacant(_comment) -> e.Tail +// e.Tail | e.Apply(e.Apply(e.Cons, _), _) -> +// e.Apply(e.Apply(e.Cons, e.Vacant("")), act.target) +// _ -> e.Apply(e.Apply(e.Cons, act.target), e.Tail) +// } +// let source = act.update(new) +// update_source(state, source) +// } + +// fn call(act: Act, state) { +// let source = act.update(e.Apply(act.target, e.Vacant(""))) +// update_source(state, source) +// } + +// fn variable(act: Act, state) { +// let commit = case act.target { +// e.Let(label, _value, then) -> fn(term) { +// act.update(e.Let(label, term, then)) +// } +// _exp -> fn(term) { act.update(term) } +// } +// WorkSpace(..state, mode: WriteTerm("", commit)) +// } + +// fn binary(act: Act, state) { +// let commit = case act.target { +// e.Let(label, _value, then) -> fn(text) { +// act.update(e.Let(label, e.Binary(text), then)) +// } +// _exp -> fn(text) { act.update(e.Binary(text)) } +// } +// WorkSpace(..state, mode: WriteText("", commit)) +// } + +// fn number(act: Act, state) { +// let #(v, commit) = case act.target { +// e.Let(label, _value, then) -> #( +// 0, +// fn(value) { act.update(e.Let(label, e.Integer(value), then)) }, +// ) +// e.Integer(value) -> #(value, fn(value) { act.update(e.Integer(value)) }) +// _exp -> #(0, fn(value) { act.update(e.Integer(value)) }) +// } +// WorkSpace(..state, mode: WriteNumber(v, commit)) +// } + +// fn match(act: Act, state) { +// let commit = case act.target { +// // e.Let(label, value, then) -> fn(text) { +// // act.update(e.Let(label, e.Binary(text), then)) +// // } +// // Match on original value should maybe be the arg? but I like promoting first class everything +// exp -> fn(text) { +// act.update(e.Apply(e.Apply(e.Case(text), e.Vacant("")), exp)) +// } +// } +// Ok(WorkSpace(..state, mode: WriteLabel("", commit))) +// } + +// fn nocases(act: Act, state) { +// update_source(state, act.update(e.NoCases)) +// } // app state actions maybe separate from ui but maybe ui files organised by mode // update source also ends the entry state -fn update_source(state: WorkSpace, source) { - use act <- result.then(transform.prepare(source, state.selection)) - let mode = Navigate(act) - let #(history, inferred) = case source == state.source { - True -> #(state.history, state.inferred) - False -> { - let #(backwards, _forwards) = state.history - let history = #([#(state.source, state.selection), ..backwards], []) - #(history, None) - } - } +fn update_source(state: WorkSpace, next) { + let #(root, source) = next + use cursor <- result.then(cursor.at(state.selection, root, source) |> result.map_error(fn(_:Nil) {"nope on the update"})) + + let mode = Navigate(cursor) + // let #(history, inferred) = case source == state.source { + // True -> #(state.history, state.inferred) + // False -> { + // let #(backwards, _forwards) = state.history + // let history = #([#(state.source, state.selection), ..backwards], []) + // #(history, None) + // } + // } + + let sub = map.new() + let next = 0 + let env = map.new() + // TODO type for editor + let type_ = jmt.Var(-1) + let eff = jmt.Var(-2) + let types = map.new() + + let start = pnow() + let #(sub, _next, typesjm) = + jm.infer(sub, next, env, source, root, type_, eff, types) + io.debug(#("typing jm took ms:", pnow() - start, map.size(typesjm))) + Ok( WorkSpace( ..state, source: source, + root: root, mode: mode, - history: history, - inferred: inferred, + // history: history, + // inferred: inferred, ), ) } diff --git a/eyg/src/atelier/view/pallet.gleam b/eyg/src/atelier/view/pallet.gleam index f706f5cd7..deeb4cb75 100644 --- a/eyg/src/atelier/view/pallet.gleam +++ b/eyg/src/atelier/view/pallet.gleam @@ -1,4 +1,5 @@ // command pallet +import gleam/io import gleam/dynamic import gleam/list import gleam/map @@ -8,19 +9,22 @@ import lustre/element.{div, input, span, text, textarea} import lustre/event.{on_click} import lustre/attribute.{class, classes} import eyg/analysis/inference +import eyg/incremental/cursor +import eyg/analysis/jm/error +import eyg/analysis/jm/type_ as t import atelier/app.{ClickOption, SelectNode} -import atelier/view/typ +import atelier/view/type_ import atelier/inventory -pub fn render(state: app.WorkSpace, inferred) { +pub fn render(state: app.WorkSpace) { div( [class("cover bg-gray-100")], case state.mode { app.WriteLabel(value, _) -> render_label(value) - app.WriteTerm(value, _) -> render_variable(value, inferred, state) + app.WriteTerm(value, _) -> render_variable(value, state) app.WriteNumber(number, _) -> render_number(number) app.WriteText(value, _) -> render_text(value) - _ -> render_navigate(inferred, state) + _ -> render_navigate(state) }, ) } @@ -37,37 +41,38 @@ fn render_label(value) { } fn render_variable( - value, - inferred: option.Option(inference.Infered), - state: app.WorkSpace, + value, state: app.WorkSpace, ) { [ div( [], - case inferred { - Some(inferred) -> - case inventory.variables_at(inferred.environments, state.selection) { - // using spaces because we are in pre tag and text based - // not in pre tag here - Ok(options) -> - list.map( - options, - fn(option) { - let #(t, term) = option - span( - [ - class("rounded bg-blue-100 p-1"), - on_click(ClickOption(term)), - ], - [text(t)], - ) - }, - ) - |> list.intersperse(text(" ")) - Error(_) -> [text("no env")] - } - None -> [] - }, + [] + // case inferred { + // Some(inferred) -> + // // TODO use inferred but we dont have the whole env map. + // [] + // // case inventory.variables_at(inferred.environments, state.selection) { + // // // using spaces because we are in pre tag and text based + // // // not in pre tag here + // // Ok(options) -> + // // list.map( + // // options, + // // fn(option) { + // // let #(t, term) = option + // // span( + // // [ + // // class("rounded bg-blue-100 p-1"), + // // on_click(ClickOption(term)), + // // ], + // // [text(t)], + // // ) + // // }, + // // ) + // // |> list.intersperse(text(" ")) + // // Error(_) -> [text("no env")] + // // } + // None -> [] + // }, ), input([ class("border w-full"), @@ -114,10 +119,11 @@ fn render_text(value) { ] } -fn render_navigate(inferred, state: app.WorkSpace) { +fn render_navigate(state: app.WorkSpace) { + let #(sub, _next, types) = state.inferred [ - case inferred { - Some(inferred) -> render_errors(inferred) + case types { + Some(types) -> render_errors(types) None -> span([], []) }, div( @@ -126,13 +132,19 @@ fn render_navigate(inferred, state: app.WorkSpace) { span( [], [ - case inferred { - Some(inferred) -> + case types { + Some(types) -> text(string.append( ":", - inferred - |> inference.type_of(state.selection) - |> typ.render(), + { + let assert Ok(c) = cursor.at(state.selection, state.root, state.source) + let id = cursor.inner(c) + let assert Ok(type_) = map.get(types, id) + case type_ { + Ok(type_) -> type_.render_type(t.resolve( type_, sub)) + Error(#(reason, t1, t2)) -> type_.render_failure(reason, t.resolve(t1, sub), t.resolve(t2, sub)) + } + } )) None -> span([], [text("type checking")]) }, @@ -151,10 +163,10 @@ fn render_navigate(inferred, state: app.WorkSpace) { ] } -fn render_errors(inferred: inference.Infered) { +fn render_errors(types) { let errors = list.filter_map( - map.to_list(inferred.types), + map.to_list(types), fn(el) { let #(k, v) = el case v { @@ -173,12 +185,22 @@ fn render_errors(inferred: inference.Infered) { errors, fn(err) { let #(path, reason) = err + // TODO real path + let path = [] div( [classes([#("cursor-pointer", True)]), on_click(SelectNode(path))], - [text(typ.render_failure(reason))], + [text(render_failure(reason))], ) }, ), ) } } + +pub fn render_failure(reason) { + let #(reason, _,_) = reason + case reason { + error.RecursiveType -> "recursive type" + _ -> "other error" + } +} \ No newline at end of file diff --git a/eyg/src/atelier/view/root.gleam b/eyg/src/atelier/view/root.gleam index 36e635d1e..fe49f6511 100644 --- a/eyg/src/atelier/view/root.gleam +++ b/eyg/src/atelier/view/root.gleam @@ -1,13 +1,16 @@ import gleam/io +import gleam/option import lustre/element.{div} import lustre/attribute.{attribute, autofocus, class} import lustre/event.{on_keydown} +import eyg/incremental/source import atelier/app import atelier/view/projection import atelier/view/pallet // maybe belongs in procejection .render pub fn render(state: app.WorkSpace) { + let assert Ok(tree) = source.to_tree(state.source, state.root) div( [ on_keydown(app.Keypress), @@ -19,9 +22,10 @@ pub fn render(state: app.WorkSpace) { ], [ div([class("expand")], []), - projection.render(state.source, state.selection, state.inferred), + // pass through inferred + projection.render(tree, state.selection, option.None), div([class("expand")], []), - pallet.render(state, state.inferred), + pallet.render(state), ], ) } diff --git a/eyg/src/atelier/view/typ.gleam b/eyg/src/atelier/view/typ.gleam index 61a039a99..988cda837 100644 --- a/eyg/src/atelier/view/typ.gleam +++ b/eyg/src/atelier/view/typ.gleam @@ -6,6 +6,7 @@ import eyg/analysis/typ as t import eyg/analysis/unification import eyg/analysis/substitutions as sub +// Keep for old kinded version // Do we have a general need for type debug functionality pub fn render(type_info) { case type_info { diff --git a/eyg/src/eyg/analysis/jm/error.gleam b/eyg/src/eyg/analysis/jm/error.gleam index e288cbfae..56a23e43a 100644 --- a/eyg/src/eyg/analysis/jm/error.gleam +++ b/eyg/src/eyg/analysis/jm/error.gleam @@ -2,7 +2,6 @@ import eyg/analysis/jm/type_ as t pub type Reason { MissingVariable(String) - // unification TypeMismatch(t.Type, t.Type) RowMismatch(String) InvalidTail(t.Type) diff --git a/eyg/src/eyg/analysis/jm/incremental.gleam b/eyg/src/eyg/analysis/jm/incremental.gleam index 31bd957dc..4c3d34fe7 100644 --- a/eyg/src/eyg/analysis/jm/incremental.gleam +++ b/eyg/src/eyg/analysis/jm/incremental.gleam @@ -81,7 +81,6 @@ fn step(sub, next, env, source, ref, type_, eff, types, k) { types, ) let env = extend(env, x, generalise(sub, env, inner)) - io.debug(#("gen", x)) use #(sub, next, types) <- step( sub, next, @@ -135,14 +134,16 @@ fn primitive(exp, next) { fn fetch(env, x, sub, next, types, ref, type_, k) { case map.get(env, x) { Ok(scheme) -> { + // io.debug("found") let #(found, next) = instantiate(scheme, next) - case x == "equal" { - False -> Nil - True -> { - io.debug(#("!!!!", scheme, x, found, next)) - Nil - } - } + // io.debug("instanted") + // case x == "equal" { + // False -> Nil + // True -> { + // io.debug(#("!!!!", scheme, x, found, next)) + // Nil + // } + // } Cont(unify_at(type_, found, sub, next, types, ref), k) } Error(Nil) -> { diff --git a/eyg/src/eyg/analysis/jm/infer.gleam b/eyg/src/eyg/analysis/jm/infer.gleam index 3b5d184db..2ee5799bd 100644 --- a/eyg/src/eyg/analysis/jm/infer.gleam +++ b/eyg/src/eyg/analysis/jm/infer.gleam @@ -27,15 +27,45 @@ pub fn generalise(sub, env, t) { } pub fn instantiate(scheme, next) { + let next = next + 1000 let #(forall, type_) = scheme + // io.debug(next) let s = list.index_map(forall, fn(i, old) { #(old, t.Var(next + i)) }) |> map.from_list() let next = next + list.length(forall) - let type_ = t.apply(s, type_) + // io.debug(#(next, forall, type_)) + // io.debug("applying") + // io.debug(s |> map.to_list) + // Apply is actually on a recursive substitution, composing SHOULD update all values to make it a single call + let type_ = apply_once(s, type_) + // io.debug("applyed") + #(type_, next) } +fn apply_once(s, type_) { + case type_ { + // This is recursive, get to the bottom of this + t.Var(a) -> + case map.get(s, a) { + Ok(new) -> new + Error(Nil) -> type_ + } + t.Fun(from, effects, to) -> + t.Fun(apply_once(s, from), apply_once(s, effects), apply_once(s, to)) + t.Integer | t.String -> type_ + t.LinkedList(element) -> t.LinkedList(apply_once(s, element)) + t.Record(row) -> t.Record(apply_once(s, row)) + t.Union(row) -> t.Union(apply_once(s, row)) + t.Empty -> type_ + t.RowExtend(label, value, rest) -> + t.RowExtend(label, apply_once(s, value), apply_once(s, rest)) + t.EffectExtend(label, #(lift, reply), rest) -> + t.EffectExtend(label, #(apply_once(s, lift), apply_once(s, reply)), apply_once(s, rest)) + } +} + pub fn extend(env, label, scheme) { map.insert(env, label, scheme) } @@ -100,13 +130,6 @@ pub fn builtins() { fn extend_b(env, key, t) { let scheme = generalise(map.new(), map.new(), t) - case key == "equal" { - False -> Nil - True -> { - io.debug(#("------------>>>", key, scheme, t)) - Nil - } - } extend(env, key, scheme) } diff --git a/eyg/src/eyg/analysis/jm/unify.gleam b/eyg/src/eyg/analysis/jm/unify.gleam index 027300eef..cbdef7d6a 100644 --- a/eyg/src/eyg/analysis/jm/unify.gleam +++ b/eyg/src/eyg/analysis/jm/unify.gleam @@ -1,3 +1,4 @@ +import gleam/io import gleam/map import gleam/result import gleam/set diff --git a/eyg/src/eyg/incremental/continuation.gleam b/eyg/src/eyg/incremental/continuation.gleam deleted file mode 100644 index 9fecdcf06..000000000 --- a/eyg/src/eyg/incremental/continuation.gleam +++ /dev/null @@ -1,63 +0,0 @@ -// import gleam/io -// import gleam/list -// import gleam/map.{Map} -// import gleam/result -// import gleam/set.{Set} -// import gleam/setx -// import gleam/javascript -// import eygir/expression as e - -// // TODO source -> ref -// import eyg/analysis/typ as t -// import eyg/analysis/substitutions as sub -// import eyg/analysis/scheme.{Scheme} -// import eyg/analysis/unification -// import eyg/incremental/source -// import eyg/analysis/env -// import eyg/incremental/inference -// import eyg/incremental/cursor -// import plinth/javascript/map as mutable_map - -// // type Continuation(arg, ret) = -// // fn(fn(arg) -> ret) -> ret - -// // fn do(st: Continuation(a, r), f: fn(r) -> Continuation(a1, r2)) -> Continuation(a1, r2) { -// // fn(env) { -// // let #(env, a) = st(env) -// // let next = f(a) -// // next(env) -// // } -// // } -// // TODO continuation monad - -// pub fn do(arg, k) { -// // separate Cont from all other effects -// case arg { -// // Push(env, exp) -> { -// // cache_lookup -// // // call do(push()) = > infer -// // } -// _ -> todo -// } -// } - -// pub fn run() { -// todo -// } - - - -// pub fn step(env, exp) { -// case exp { -// e.Apply(e1, e2) -> { -// use #(s1, t1) <- do(push(env, e1)) -// use #(s2, t2) <- do(push(env.apply(s1, env), e2)) -// let tv = t.Unbound(0) -// let ref = todo -// use s3 <- result.then(unification.unify(sub.apply(s2, t1), t.Fun(t2, t.Closed, tv), ref)) -// Ok(#(sub.compose(sub.compose(s3, s2), s2), sub.apply(s3, tv))) -// } -// e.Integer(_) -> Ok(#(sub.none(), t.Integer)) -// _ -> todo -// } -// } \ No newline at end of file diff --git a/eyg/src/eyg/incremental/cursor.gleam b/eyg/src/eyg/incremental/cursor.gleam index b7d07763c..8310bc684 100644 --- a/eyg/src/eyg/incremental/cursor.gleam +++ b/eyg/src/eyg/incremental/cursor.gleam @@ -1,42 +1,39 @@ -import gleam/io import gleam/map import gleam/result -import eyg/incremental/source +import eyg/incremental/source as e -pub fn zip_match(node, path_element) { +pub type Cursor = #(List(Int), Int) + +fn zip_match(node, path_element) { case node, path_element { - source.Let(_, index, _), 0 -> index - source.Let(_, _, index), 1 -> index - source.Fn(_, index), 0 -> index - source.Call(index, _), 0 -> index - source.Call(_, index), 1 -> index - _, _ -> { - io.debug(#(node, path_element)) - panic("no_zip_match") - } + e.Let(_, index, _), 0 -> Ok(index) + e.Let(_, _, index), 1 -> Ok(index) + e.Fn(_, index), 0 -> Ok(index) + e.Call(index, _), 0 -> Ok(index) + e.Call(_, index), 1 -> Ok(index) + _, _ -> Error(Nil) } } -fn do_at_map(path, refs, current, zoom, root) { +fn do_at(path, refs, current, zoom, root) { case path { [] -> Ok(#([current, ..zoom], root)) [path_element, ..path] -> { use node <- result.then(map.get(refs, current)) let zoom = [current, ..zoom] - let current = zip_match(node, path_element) - do_at_map(path, refs, current, zoom, root) + use current <- result.then(zip_match(node, path_element)) + do_at(path, refs, current, zoom, root) } } } -// root and refs together from tree -pub fn at_map(path, root, refs) { +pub fn at(path, root, refs) { case path { [] -> Ok(#([], root)) [path_element, ..path] -> { use node <- result.then(map.get(refs, root)) - let current = zip_match(node, path_element) - do_at_map(path, refs, current, [], root) + use current <- result.then(zip_match(node, path_element)) + do_at(path, refs, current, [], root) } } } @@ -47,3 +44,7 @@ pub fn inner(c) { #([ref, ..], _) -> ref } } + +pub fn expression(c, source) { + map.get(source, inner(c)) +} \ No newline at end of file diff --git a/eyg/src/eyg/incremental/source.gleam b/eyg/src/eyg/incremental/source.gleam index e1bd12e2a..f9126fce0 100644 --- a/eyg/src/eyg/incremental/source.gleam +++ b/eyg/src/eyg/incremental/source.gleam @@ -1,5 +1,6 @@ import gleam/list import gleam/map +import gleam/result import gleam/javascript import eygir/expression as e @@ -25,6 +26,8 @@ pub type Expression { Builtin(identifier: String) } +pub type Source = map.Map(Int, Expression) + pub fn do_from_tree(tree, acc) { case tree { e.Variable(label) -> #(Var(label), acc) @@ -127,3 +130,75 @@ pub fn from_tree_map(tree) { let #(index, source) = do_from_tree_map(tree, map.new(), javascript.make_reference(0)) #(index, source) } + +pub fn to_tree(source, root) { + use exp <- result.then(map.get(source, root)) + case exp { + Var(x) -> Ok(e.Variable(x)) + Fn(x, ref) -> { + use exp <- result.then(to_tree(source, ref)) + Ok(e.Lambda(x, exp)) + } + Let(x, ref1, ref2) -> { + use exp1 <- result.then(to_tree(source, ref1)) + use exp2 <- result.then(to_tree(source, ref2)) + Ok(e.Let(x, exp1, exp2)) + } + Call(ref1, ref2) -> { + use exp1 <- result.then(to_tree(source, ref1)) + use exp2 <- result.then(to_tree(source, ref2)) + Ok(e.Apply(exp1, exp2)) + } + String(value) -> Ok(e.Binary(value) ) + Integer(value) -> Ok(e.Integer(value) ) + Tail -> Ok(e.Tail ) + Cons -> Ok(e.Cons ) + Vacant(comment) -> Ok(e.Vacant(comment)) + Empty -> Ok(e.Empty) + Extend(label) -> Ok(e.Extend(label)) + Select(label) -> Ok(e.Select(label)) + Overwrite(label) -> Ok(e.Overwrite(label)) + Tag(label) -> Ok(e.Tag(label)) + Case(label) -> Ok(e.Case(label)) + NoCases -> Ok(e.NoCases ) + Perform(label) -> Ok(e.Perform(label)) + Handle(label) -> Ok(e.Handle(label)) + Builtin(identifier) -> Ok(e.Builtin(identifier)) + } +} + +pub fn insert(acc, exp) { + let id = map.size(acc) + #(id, map.insert(acc, id, exp)) +} + +fn do_replace(old_id, new_id, zoom, source) { + case zoom { + [] -> Ok(#(new_id, source)) + [next, ..zoom] -> { + use node <- result.then(map.get(source, next)) + let exp = case node { + Let(label, value, then) if value == old_id -> + Let(label, new_id, then) + Let(label, value, then) if then == old_id -> + Let(label, value, new_id) + Fn(param, body) if body == old_id -> Fn(param, new_id) + Call(func, arg) if func == old_id -> Call(new_id, arg) + Call(func, arg) if arg == old_id -> Call(func, new_id) + _ -> panic("Can't have a path into literal") + } + let new_id = map.size(source) + let source = map.insert(source, new_id, exp) + do_replace(next, new_id, zoom, source) + } + } +} + +pub fn replace(source, cursor, new_id) { + + case cursor { + #([], old) -> do_replace(old, new_id, [], source) + #([old, ..zoom], root) -> + do_replace(old, new_id, list.append(zoom, [root]), source) + } +} \ No newline at end of file diff --git a/eyg/src/eyg/incremental/state_monad.gleam b/eyg/src/eyg/incremental/state_monad.gleam deleted file mode 100644 index 8d2c93ab3..000000000 --- a/eyg/src/eyg/incremental/state_monad.gleam +++ /dev/null @@ -1,129 +0,0 @@ -import gleam/io -import gleam/list -import gleam/map.{Map} -import gleam/result -import gleam/set.{Set} -import gleam/setx -import gleam/javascript -// TODO source -> ref -import eyg/analysis/typ as t -import eyg/analysis/substitutions as sub -import eyg/analysis/scheme.{Scheme} -import eyg/analysis/unification -import eyg/incremental/source -import eyg/analysis/env -import eyg/incremental/inference -import eyg/incremental/cursor -import plinth/javascript/map as mutable_map - - -type State(a, env) = - fn(env) -> #(env, a) - -fn do(st: State(a, env), f: fn(a) -> State(b, env)) -> State(b, env) { - fn(env) { - let #(env, a) = st(env) - let next = f(a) - next(env) - } -} - -fn return(a: a) -> State(a, env) { - fn(env) { - #(env, a) - } -} - -fn run(st: State(a, env), env: env) -> a { - st(env).1 -} - - -// you can write: - - - - -// fn lookup(pointer) { -// fn(infer: Infer) { -// #(infer, source.String("temp")) -// } -// } - - -// fn w_(env, pointer) { -// // do_w(env, do()) -// // run the internal one -// // fn(infer) {#(infer,run(do_w(env, todo), todo))} -// fn(infer) { -// do_w(env, todo)(infer) -// } -// } - -// fn unbound(k) { -// do(fn(infer) { -// use var <- do(fresh()) -// return(t.Unbound(var)) -// }, k) -// } - -pub type Infer { - Infer(counter: Int, source: Map(Int, source.Expression)) -} - -fn fresh() -> State(Int, Infer) { - fn(infer: Infer) { - let count = infer.counter - #(Infer(..infer, counter: count + 1), count) - } -} - -fn w(env, pointer, k) { - do(fn(infer: Infer) { - let assert Ok(exp) = map.get(infer.source, pointer) - do_w(env, exp)(infer) - }, k) -} - - -fn do_w(env, exp) { - case exp { - source.Fn(x, exp1) -> { - use tv <- do(fresh()) - use #(s1, t1) <- w(env, exp1) - return(#(s1, t.Fun(sub.apply(s1, t.Unbound(tv)), t.Closed, t1))) - } - source.String(_) -> return(#(sub.none(), t.Binary)) - _ -> todo - } -} - - -// pub fn run(step, k) { -// case step { -// Return(s, t) -> k(s,t) -// Continue(p,f)-> todo -// } -// } - -// pub fn w(env, pointer, k) { -// Continue(pointer, fn(exp) { -// // TODO need k -// run(do_w(env, exp), k) -// }) -// } - -// pub type Effect { -// Continue(Int, fn(source.Expression) -> Effect) -// Return(sub.Substitutions, t.Term) -// } - -// fn do_w(env, exp) { -// case exp { -// source.Fn(x, exp1) -> { -// use #(s1, t1) <- w(env, exp1) -// } -// source.String(_) -> Return(sub.none(), t.Binary) -// _ -> todo -// } -// } \ No newline at end of file diff --git a/eyg/src/eyg/incremental/store.gleam b/eyg/src/eyg/incremental/store.gleam index 63255bffa..910ca46f0 100644 --- a/eyg/src/eyg/incremental/store.gleam +++ b/eyg/src/eyg/incremental/store.gleam @@ -19,6 +19,7 @@ import plinth/javascript/map as mutable_map pub type Store { Store( source: Map(Int, source.Expression), + // Not used. do map size instead source_id_tracker: javascript.Reference(Int), free: Map(Int, Set(String)), free_mut: mutable_map.MutableMap(Int, Set(String)), @@ -109,141 +110,17 @@ pub fn free_mut(store: Store, root) -> Result(#(Set(String), Store), Nil) { } } - -pub fn type_(store: Store, root) { - use #(unresolved, store) <- result.then(do_type(map.new(), root, store)) - let t = unification.resolve(store.substitutions, unresolved) - Ok(#(t, store)) -} - -// Error only for invalid ref -pub fn do_type(env, ref, store: Store) -> Result(_, _) { - use #(vars, store) <- result.then(free(store, ref)) - let required = map.take(env, set.to_list(vars)) - case inference.cache_lookup(store.types, ref, required) { - Ok(t) -> Ok(#(t, store)) - Error(Nil) -> { - use node <- result.then(map.get(store.source, ref)) - use #(t, store) <- result.then(case node { - source.Var(x) -> { - case map.get(env, x) { - Ok(scheme) -> { - let t = unification.instantiate(scheme, store.counter) - Ok(#(t, store)) - } - Error(Nil) -> - panic( - "no var in env, this should return an ok value from do_type function but needs to add an error to the list type info", - ) - } - } - source.Let(x, value, then) -> { - // Alg J single substitutions no what we have - // Should I throw away caching when there are free type variables, because they wont be the same - // however std will always be free - // all of std and other projects should trivially remain. and without free variables - // changing std if only extending types should have no changes in project - use #(t1, store) <- result.then(do_type(env, value, store)) - let store: Store = store - let scheme = unification.generalise(env.apply(store.substitutions, env), sub.apply(store.substitutions,t1)) - // is this env.apply twice necessary - let env = env.apply(store.substitutions, map.insert(env, x, scheme)) - do_type(env, then, store) - } - source.Fn(x, body) -> { - let param = unification.fresh(store.counter) - let env = map.insert(env, x, Scheme([], t.Unbound(param))) - use #(body, store) <- result.then(do_type(env, body, store)) - let t = t.Fun(t.Unbound(param), t.Closed, body) - Ok(#(t, store)) - } - source.Call(func, arg) -> { - let ret = unification.fresh(store.counter) - use #(t1, store) <- result.then(do_type(env, func, store)) - use #(t2, store) <- result.then(do_type(env, arg, store)) - let unified = - unification.unify( - t.Fun(t2, t.Closed, t.Unbound(ret)), - t1, - store.counter, - ) - let store = case unified { - Ok(s) -> - Store(..store, substitutions: sub.compose(store.substitutions, s)) - Error(_reason) -> { - io.debug("unifiy failed") - // TODO handle failure - store - } - } - - Ok(#(t.Unbound(ret), store)) - } - source.Integer(_) -> Ok(#(t.Integer, store)) - source.String(_) -> Ok(#(t.Binary, store)) - source.Tail -> Ok(#(t.tail(store.counter), store)) - source.Cons -> Ok(#(t.cons(store.counter), store)) - source.Vacant(_) -> - Ok(#(t.Unbound(unification.fresh(store.counter)), store)) - source.Empty -> Ok(#(t.empty(), store)) - source.Extend(label) -> Ok(#(t.extend(label, store.counter), store)) - source.Select(label) -> Ok(#(t.select(label, store.counter), store)) - source.Overwrite(label) -> - Ok(#(t.overwrite(label, store.counter), store)) - source.Tag(label) -> Ok(#(t.tag(label, store.counter), store)) - source.Case(label) -> Ok(#(t.case_(label, store.counter), store)) - source.NoCases -> Ok(#(t.nocases(store.counter), store)) - source.Perform(label) -> Ok(#(t.perform(label, store.counter), store)) - source.Handle(label) -> Ok(#(t.handle(label, store.counter), store)) - source.Builtin(_) -> - Ok(#(t.Unbound(unification.fresh(store.counter)), store)) - }) - // TODO lookup builtins - // Ok(#(t.builtin(store.counter), store)) - let types = inference.cache_update(store.types, ref, required, t) - let store = Store(..store, types: types) - Ok(#(t, store)) - } - } -} - pub fn cursor(store: Store, root, path) { - cursor.at_map(path, root, store.source) + cursor.at(path, root, store.source) } -fn do_replace(old_id, new_id, zoom, store: Store) { - case zoom { - [] -> Ok(#(new_id, store)) - [next, ..zoom] -> { - use node <- result.then(map.get(store.source, next)) - let exp = case node { - source.Let(label, value, then) if value == old_id -> - source.Let(label, new_id, then) - source.Let(label, value, then) if then == old_id -> - source.Let(label, value, new_id) - source.Fn(param, body) if body == old_id -> source.Fn(param, new_id) - source.Call(func, arg) if func == old_id -> source.Call(new_id, arg) - source.Call(func, arg) if arg == old_id -> source.Call(func, new_id) - _ -> panic("Can't have a path into literal") - } - let new_id = map.size(store.source) - let source = map.insert(store.source, new_id, exp) - let store = Store(..store, source: source) - do_replace(next, new_id, zoom, store) - } - } -} +// Move to source or cursor // could separate pushing one item from fn and pass in new index here -pub fn replace(store: Store, cursor, exp) { - let new_id = map.size(store.source) - let source = map.insert(store.source, new_id, exp) - let store = Store(..store, source: source) - case cursor { - #([], old) -> do_replace(old, new_id, [], store) - #([old, ..zoom], root) -> - do_replace(old, new_id, list.append(zoom, [root]), store) - } +pub fn replace(source, cursor, exp) { + let new_id = map.size(source) + let source = map.insert(source, new_id, exp) + source.replace(source, cursor, new_id) } pub fn focus(store: Store, c) { diff --git a/eyg/test/atelier/ui_test.gleam b/eyg/test/atelier/ui_test.gleam index 7063f22be..48acbf69f 100644 --- a/eyg/test/atelier/ui_test.gleam +++ b/eyg/test/atelier/ui_test.gleam @@ -1,56 +1,56 @@ -import gleeunit/should -import eygir/expression as e -import atelier/app - -pub fn call_test() { - let source = e.Let("x", e.Binary("initial"), e.Variable("x")) - let initial = app.init(source) - - // update value of let - let #(state, _cmd) = app.select_node(initial, [0]) - let #(state, _cmd) = app.keypress("w", state) - e.Let("x", e.Apply(e.Vacant(""), e.Binary("initial")), e.Variable("x")) - |> should.equal(state.source) - - // update final statement - let #(state, _cmd) = app.select_node(initial, [1]) - let #(state, _cmd) = app.keypress("w", state) - e.Let("x", e.Binary("initial"), e.Apply(e.Vacant(""), e.Variable("x"))) - |> should.equal(state.source) -} - -pub fn insert_parameter_test() { - // test variable - let source = e.Let("_", e.Variable("x"), e.Vacant("")) - let initial = app.init(source) - - let #(state, _cmd) = app.select_node(initial, [0]) - let #(state, _cmd) = app.keypress("i", state) - let assert app.WriteLabel(initial, commit) = state.mode - should.equal(initial, "x") - e.Let("_", e.Variable("foo"), e.Vacant("")) - |> should.equal(commit("foo")) - - // test lambdanested to test step and zip - let source = e.Lambda("x", e.Lambda("y", e.Vacant(""))) - let initial = app.init(source) - - let #(state, _cmd) = app.select_node(initial, [0]) - let #(state, _cmd) = app.keypress("i", state) - let assert app.WriteLabel(initial, commit) = state.mode - should.equal(initial, "y") - e.Lambda("x", e.Lambda("foo", e.Vacant(""))) - |> should.equal(commit("foo")) - - // test let - let source = - e.Let("_", e.Let("x", e.Binary("stuff"), e.Vacant("")), e.Vacant("")) - let initial = app.init(source) - - let #(state, _cmd) = app.select_node(initial, [0]) - let #(state, _cmd) = app.keypress("i", state) - let assert app.WriteLabel(initial, commit) = state.mode - should.equal(initial, "x") - e.Let("_", e.Let("foo", e.Binary("stuff"), e.Vacant("")), e.Vacant("")) - |> should.equal(commit("foo")) -} +// import gleeunit/should +// import eygir/expression as e +// import atelier/app + +// pub fn call_test() { +// let source = e.Let("x", e.Binary("initial"), e.Variable("x")) +// let initial = app.init(source) + +// // update value of let +// let #(state, _cmd) = app.select_node(initial, [0]) +// let #(state, _cmd) = app.keypress("w", state) +// e.Let("x", e.Apply(e.Vacant(""), e.Binary("initial")), e.Variable("x")) +// |> should.equal(state.source) + +// // update final statement +// let #(state, _cmd) = app.select_node(initial, [1]) +// let #(state, _cmd) = app.keypress("w", state) +// e.Let("x", e.Binary("initial"), e.Apply(e.Vacant(""), e.Variable("x"))) +// |> should.equal(state.source) +// } + +// pub fn insert_parameter_test() { +// // test variable +// let source = e.Let("_", e.Variable("x"), e.Vacant("")) +// let initial = app.init(source) + +// let #(state, _cmd) = app.select_node(initial, [0]) +// let #(state, _cmd) = app.keypress("i", state) +// let assert app.WriteLabel(initial, commit) = state.mode +// should.equal(initial, "x") +// e.Let("_", e.Variable("foo"), e.Vacant("")) +// |> should.equal(commit("foo")) + +// // test lambdanested to test step and zip +// let source = e.Lambda("x", e.Lambda("y", e.Vacant(""))) +// let initial = app.init(source) + +// let #(state, _cmd) = app.select_node(initial, [0]) +// let #(state, _cmd) = app.keypress("i", state) +// let assert app.WriteLabel(initial, commit) = state.mode +// should.equal(initial, "y") +// e.Lambda("x", e.Lambda("foo", e.Vacant(""))) +// |> should.equal(commit("foo")) + +// // test let +// let source = +// e.Let("_", e.Let("x", e.Binary("stuff"), e.Vacant("")), e.Vacant("")) +// let initial = app.init(source) + +// let #(state, _cmd) = app.select_node(initial, [0]) +// let #(state, _cmd) = app.keypress("i", state) +// let assert app.WriteLabel(initial, commit) = state.mode +// should.equal(initial, "x") +// e.Let("_", e.Let("foo", e.Binary("stuff"), e.Vacant("")), e.Vacant("")) +// |> should.equal(commit("foo")) +// } diff --git a/eyg/test/eyg/analysis/jm/infer_test.gleam b/eyg/test/eyg/analysis/jm/infer_test.gleam index 4edf9516c..09725adce 100644 --- a/eyg/test/eyg/analysis/jm/infer_test.gleam +++ b/eyg/test/eyg/analysis/jm/infer_test.gleam @@ -1,3 +1,47 @@ +import gleam/io +import gleam/map +import gleam/set +import gleam/setx +import eygir/expression as e +import eyg/analysis/typ.{ftv} as t +import eyg/analysis/jm/type_ +import eyg/analysis/env +import eyg/analysis/inference.{infer, type_of} +// top level analysis +import eyg/analysis/scheme.{Scheme} +import eyg/analysis/unification +import gleeunit/should +import eyg/incremental/store +import eyg/analysis/jm/incremental as jm +import eyg/analysis/jm/type_ as jmt +import eyg/analysis/jm/error as jm_error + +fn call2(f,a,b) { + e.Apply(e.Apply(f, a), b) + } + pub fn example_test() { - todo -} \ No newline at end of file + let exp = e.Let( + "equal", e.Builtin("equal"), + e.Let("_", call2(e.Variable("equal"), e.Binary(""), e.Binary("")), + e.Let("_", call2(e.Variable("equal"), e.Integer(1), e.Integer(1)), + e.Empty))) + + let #(root, store) = store.load(store.empty(), exp) + + let sub = map.new() + let next = 0 + let env = map.new() + let source = store.source + let ref = root + let types = map.new() + + io.debug("loaded") + let #(sub, _next, types) = + jm.infer(sub, next, env, source, ref, jmt.Var(-1), jmt.Var(-2), types) + map.get(types, root) + // |> io.debug + // io.debug(types |> map.to_list) +} + +// TODO try and have test for recursive types in rows/effects \ No newline at end of file diff --git a/eyg/test/eyg/incremental/store_test.gleam b/eyg/test/eyg/incremental/store_test.gleam index 6d828fe80..e2f862a80 100644 --- a/eyg/test/eyg/incremental/store_test.gleam +++ b/eyg/test/eyg/incremental/store_test.gleam @@ -1,230 +1,230 @@ -import gleam/io -import gleam/map -import gleam/set -import eygir/expression as e -import eyg/analysis/typ as t -import eyg/analysis/inference -import eyg/incremental/source -import eyg/incremental/store -import gleeunit/should - -// TODO printing map in node -// TODO binary-size in JS match - -pub fn literal_test() { - let s = store.empty() - - let tree = e.Binary("hello") - let #(ref_binary, s) = store.load(s, tree) - should.equal(ref_binary, 0) - // should.equal(store.tree(s, ref_binary), Ok(tree)) - let assert Ok(#(free, s)) = store.free(s, ref_binary) - should.equal(map.size(s.free), 1) - should.equal(free, set.new()) - let assert Ok(#(t, s)) = store.type_(s, ref_binary) - should.equal(map.size(s.types), 1) - should.equal(t, t.Binary) - - let #(ref_integer, s) = store.load(s, e.Integer(5)) - should.equal(ref_integer, 1) - let assert Ok(#(free, s)) = store.free(s, ref_integer) - should.equal(map.size(s.free), 2) - should.equal(free, set.new()) - let assert Ok(#(t, s)) = store.type_(s, ref_integer) - should.equal(map.size(s.types), 2) - should.equal(t, t.Integer) -} - -pub fn function_unification_test() { - let s = store.empty() - - let tree = e.Apply(e.Lambda("x", e.Variable("x")), e.Binary("hey")) - let #(root, s) = store.load(s, tree) - should.equal(root, 3) - should.equal(map.size(s.source), 4) - - let assert Ok(#(t, s)) = store.type_(s, root) - should.equal(t, t.Binary) - should.equal(map.size(s.free), 4) - should.equal(map.size(s.types), 4) - - let assert Ok(c) = store.cursor(s, root, [1]) - let assert Ok(node) = store.focus(s, c) - should.equal(node, source.String("hey")) - let assert Ok(#(root1, s)) = store.replace(s, c, source.Integer(10)) - should.equal(map.size(s.source), 6) - - let assert Ok(c) = store.cursor(s, root, [0, 0]) - let assert Ok(node) = store.focus(s, c) - should.equal(node, source.Var("x")) - let assert Ok(#(root2, s)) = store.replace(s, c, source.Empty) - should.equal(map.size(s.source), 9) - // source increase by path length + 1 - // free and types are lazy so stay at 4 - should.equal(map.size(s.free), 4) - should.equal(map.size(s.types), 4) - - let assert Ok(#(t, s)) = store.type_(s, root1) - should.equal(t, t.Integer) - let assert Ok(#(t, s)) = store.type_(s, root2) - should.equal(t, t.unit) - - should.equal(map.size(s.free), 9) - should.equal(map.size(s.types), 9) -} - -pub fn let_literal_test() { - let s = store.empty() - - let tree = e.Let("x", e.Binary("hey"), e.Variable("x")) - let #(root, s) = store.load(s, tree) - should.equal(root, 2) - should.equal(map.size(s.source), 3) - - let assert Ok(#(t, s)) = store.type_(s, root) - should.equal(t, t.Binary) - should.equal(map.size(s.free), 3) - should.equal(map.size(s.types), 3) - - let assert Ok(c) = store.cursor(s, root, [0]) - let assert Ok(node) = store.focus(s, c) - should.equal(node, source.String("hey")) - let assert Ok(#(root1, s)) = store.replace(s, c, source.Integer(10)) - should.equal(map.size(s.source), 5) - - let assert Ok(c) = store.cursor(s, root, [1]) - let assert Ok(node) = store.focus(s, c) - should.equal(node, source.Var("x")) - let assert Ok(#(root2, s)) = store.replace(s, c, source.Empty) - should.equal(map.size(s.source), 7) - // source increase by path length + 1 - // free and types are lazy so stay at previous value - should.equal(map.size(s.free), 3) - should.equal(map.size(s.types), 3) - - let assert Ok(#(t, s)) = store.type_(s, root1) - should.equal(t, t.Integer) - let assert Ok(#(t, s)) = store.type_(s, root2) - should.equal(t, t.unit) - - should.equal(map.size(s.free), 7) - should.equal(map.size(s.types), 7) -} - -pub fn fn_poly_test() { - let s = store.empty() - - let tree = - e.Let( - "id", - e.Lambda("x", e.Variable("x")), - e.Apply(e.Variable("id"), e.Integer(10)), - ) - let #(root, s) = store.load(s, tree) - should.equal(root, 5) - should.equal(map.size(s.source), 6) - - let assert Ok(#(t, s)) = store.type_(s, root) - should.equal(t, t.Integer) - should.equal(map.size(s.free), 6) - should.equal(map.size(s.types), 6) -} - -pub fn nested_fn_test() { - let s = store.empty() - - let tree = e.Lambda("x", e.Lambda("y", e.Empty)) - let #(root, s) = store.load(s, tree) - should.equal(root, 2) - should.equal(map.size(s.source), 3) - - let assert Ok(#(t, s)) = store.type_(s, root) - should.equal( - t, - t.Fun( - t.Unbound(0), - t.Closed, - t.Fun(t.Unbound(1), t.Closed, t.Record(t.Closed)), - ), - ) - should.equal(map.size(s.free), 3) - should.equal(map.size(s.types), 3) - - let assert Ok(c) = store.cursor(s, root, [0, 0]) - let assert Ok(node) = store.focus(s, c) - should.equal(node, source.Empty) - let assert Ok(#(root1, s)) = store.replace(s, c, source.Integer(10)) - should.equal(map.size(s.source), 6) - - let assert Ok(node) = store.focus(s, c) - // same cursor points to same item, store replace gives new root - should.equal(node, source.Empty) - let assert Ok(#(root2, s)) = store.replace(s, c, source.Var("y")) - should.equal(map.size(s.source), 9) - // source increase by path length + 1 - // free and types are lazy so stay at 4 - should.equal(map.size(s.free), 3) - should.equal(map.size(s.types), 3) - - let assert Ok(#(t, s)) = store.type_(s, root1) - should.equal( - t, - t.Fun(t.Unbound(2), t.Closed, t.Fun(t.Unbound(3), t.Closed, t.Integer)), - ) - let assert Ok(#(t, s)) = store.type_(s, root2) - should.equal( - t, - t.Fun(t.Unbound(4), t.Closed, t.Fun(t.Unbound(5), t.Closed, t.Unbound(5))), - ) - - should.equal(map.size(s.free), 9) - should.equal(map.size(s.types), 9) -} - -pub fn branched_apply_test() { - let s = store.empty() - - let tree = - e.Let( - "id", - e.Lambda("x", e.Variable("x")), - e.Apply( - e.Apply(e.Variable("id"), e.Variable("id")), - e.Apply(e.Variable("id"), e.Integer(1)), - ), - ) - - let #(root, s) = store.load(s, tree) - should.equal(root, 9) - should.equal(map.size(s.source), 10) - - let assert Ok(c) = store.cursor(s, root, []) - let assert Ok(node) = store.focus(s, c) - should.equal(node, source.Let("id", 8, 6)) - let assert Ok(#(vars, s)) = store.free(s, root) - should.equal(vars, set.new()) - should.equal(map.size(s.free), 10) - should.equal(map.size(s.types), 0) - - let assert Ok(#(t, s)) = store.type_(s, root) - should.equal(map.size(s.types), 10) - io.debug( - s.substitutions.terms - |> map.to_list, - ) - - let sub = inference.infer(map.new(), tree, t.Unbound(-1), t.Open(-2)) - io.debug(sub.substitutions.terms |> map.to_list) - - inference.sound(sub) - |> should.equal(Ok(Nil)) - - inference.type_of(sub, []) - |> io.debug - - should.equal(t, t.Integer) - panic -} +// import gleam/io +// import gleam/map +// import gleam/set +// import eygir/expression as e +// import eyg/analysis/typ as t +// import eyg/analysis/inference +// import eyg/incremental/source +// import eyg/incremental/store +// import gleeunit/should + +// // TODO printing map in node +// // TODO binary-size in JS match + +// pub fn literal_test() { +// let s = store.empty() + +// let tree = e.Binary("hello") +// let #(ref_binary, s) = store.load(s, tree) +// should.equal(ref_binary, 0) +// // should.equal(store.tree(s, ref_binary), Ok(tree)) +// let assert Ok(#(free, s)) = store.free(s, ref_binary) +// should.equal(map.size(s.free), 1) +// should.equal(free, set.new()) +// let assert Ok(#(t, s)) = store.type_(s, ref_binary) +// should.equal(map.size(s.types), 1) +// should.equal(t, t.Binary) + +// let #(ref_integer, s) = store.load(s, e.Integer(5)) +// should.equal(ref_integer, 1) +// let assert Ok(#(free, s)) = store.free(s, ref_integer) +// should.equal(map.size(s.free), 2) +// should.equal(free, set.new()) +// let assert Ok(#(t, s)) = store.type_(s, ref_integer) +// should.equal(map.size(s.types), 2) +// should.equal(t, t.Integer) +// } + +// pub fn function_unification_test() { +// let s = store.empty() + +// let tree = e.Apply(e.Lambda("x", e.Variable("x")), e.Binary("hey")) +// let #(root, s) = store.load(s, tree) +// should.equal(root, 3) +// should.equal(map.size(s.source), 4) + +// let assert Ok(#(t, s)) = store.type_(s, root) +// should.equal(t, t.Binary) +// should.equal(map.size(s.free), 4) +// should.equal(map.size(s.types), 4) + +// let assert Ok(c) = store.cursor(s, root, [1]) +// let assert Ok(node) = store.focus(s, c) +// should.equal(node, source.String("hey")) +// let assert Ok(#(root1, s)) = store.replace(s, c, source.Integer(10)) +// should.equal(map.size(s.source), 6) + +// let assert Ok(c) = store.cursor(s, root, [0, 0]) +// let assert Ok(node) = store.focus(s, c) +// should.equal(node, source.Var("x")) +// let assert Ok(#(root2, s)) = store.replace(s, c, source.Empty) +// should.equal(map.size(s.source), 9) +// // source increase by path length + 1 +// // free and types are lazy so stay at 4 +// should.equal(map.size(s.free), 4) +// should.equal(map.size(s.types), 4) + +// let assert Ok(#(t, s)) = store.type_(s, root1) +// should.equal(t, t.Integer) +// let assert Ok(#(t, s)) = store.type_(s, root2) +// should.equal(t, t.unit) + +// should.equal(map.size(s.free), 9) +// should.equal(map.size(s.types), 9) +// } + +// pub fn let_literal_test() { +// let s = store.empty() + +// let tree = e.Let("x", e.Binary("hey"), e.Variable("x")) +// let #(root, s) = store.load(s, tree) +// should.equal(root, 2) +// should.equal(map.size(s.source), 3) + +// let assert Ok(#(t, s)) = store.type_(s, root) +// should.equal(t, t.Binary) +// should.equal(map.size(s.free), 3) +// should.equal(map.size(s.types), 3) + +// let assert Ok(c) = store.cursor(s, root, [0]) +// let assert Ok(node) = store.focus(s, c) +// should.equal(node, source.String("hey")) +// let assert Ok(#(root1, s)) = store.replace(s, c, source.Integer(10)) +// should.equal(map.size(s.source), 5) + +// let assert Ok(c) = store.cursor(s, root, [1]) +// let assert Ok(node) = store.focus(s, c) +// should.equal(node, source.Var("x")) +// let assert Ok(#(root2, s)) = store.replace(s, c, source.Empty) +// should.equal(map.size(s.source), 7) +// // source increase by path length + 1 +// // free and types are lazy so stay at previous value +// should.equal(map.size(s.free), 3) +// should.equal(map.size(s.types), 3) + +// let assert Ok(#(t, s)) = store.type_(s, root1) +// should.equal(t, t.Integer) +// let assert Ok(#(t, s)) = store.type_(s, root2) +// should.equal(t, t.unit) + +// should.equal(map.size(s.free), 7) +// should.equal(map.size(s.types), 7) +// } + +// pub fn fn_poly_test() { +// let s = store.empty() + +// let tree = +// e.Let( +// "id", +// e.Lambda("x", e.Variable("x")), +// e.Apply(e.Variable("id"), e.Integer(10)), +// ) +// let #(root, s) = store.load(s, tree) +// should.equal(root, 5) +// should.equal(map.size(s.source), 6) + +// let assert Ok(#(t, s)) = store.type_(s, root) +// should.equal(t, t.Integer) +// should.equal(map.size(s.free), 6) +// should.equal(map.size(s.types), 6) +// } + +// pub fn nested_fn_test() { +// let s = store.empty() + +// let tree = e.Lambda("x", e.Lambda("y", e.Empty)) +// let #(root, s) = store.load(s, tree) +// should.equal(root, 2) +// should.equal(map.size(s.source), 3) + +// let assert Ok(#(t, s)) = store.type_(s, root) +// should.equal( +// t, +// t.Fun( +// t.Unbound(0), +// t.Closed, +// t.Fun(t.Unbound(1), t.Closed, t.Record(t.Closed)), +// ), +// ) +// should.equal(map.size(s.free), 3) +// should.equal(map.size(s.types), 3) + +// let assert Ok(c) = store.cursor(s, root, [0, 0]) +// let assert Ok(node) = store.focus(s, c) +// should.equal(node, source.Empty) +// let assert Ok(#(root1, s)) = store.replace(s, c, source.Integer(10)) +// should.equal(map.size(s.source), 6) + +// let assert Ok(node) = store.focus(s, c) +// // same cursor points to same item, store replace gives new root +// should.equal(node, source.Empty) +// let assert Ok(#(root2, s)) = store.replace(s, c, source.Var("y")) +// should.equal(map.size(s.source), 9) +// // source increase by path length + 1 +// // free and types are lazy so stay at 4 +// should.equal(map.size(s.free), 3) +// should.equal(map.size(s.types), 3) + +// let assert Ok(#(t, s)) = store.type_(s, root1) +// should.equal( +// t, +// t.Fun(t.Unbound(2), t.Closed, t.Fun(t.Unbound(3), t.Closed, t.Integer)), +// ) +// let assert Ok(#(t, s)) = store.type_(s, root2) +// should.equal( +// t, +// t.Fun(t.Unbound(4), t.Closed, t.Fun(t.Unbound(5), t.Closed, t.Unbound(5))), +// ) + +// should.equal(map.size(s.free), 9) +// should.equal(map.size(s.types), 9) +// } + +// pub fn branched_apply_test() { +// let s = store.empty() + +// let tree = +// e.Let( +// "id", +// e.Lambda("x", e.Variable("x")), +// e.Apply( +// e.Apply(e.Variable("id"), e.Variable("id")), +// e.Apply(e.Variable("id"), e.Integer(1)), +// ), +// ) + +// let #(root, s) = store.load(s, tree) +// should.equal(root, 9) +// should.equal(map.size(s.source), 10) + +// let assert Ok(c) = store.cursor(s, root, []) +// let assert Ok(node) = store.focus(s, c) +// should.equal(node, source.Let("id", 8, 6)) +// let assert Ok(#(vars, s)) = store.free(s, root) +// should.equal(vars, set.new()) +// should.equal(map.size(s.free), 10) +// should.equal(map.size(s.types), 0) + +// let assert Ok(#(t, s)) = store.type_(s, root) +// should.equal(map.size(s.types), 10) +// io.debug( +// s.substitutions.terms +// |> map.to_list, +// ) + +// let sub = inference.infer(map.new(), tree, t.Unbound(-1), t.Open(-2)) +// io.debug(sub.substitutions.terms |> map.to_list) + +// inference.sound(sub) +// |> should.equal(Ok(Nil)) + +// inference.type_of(sub, []) +// |> io.debug + +// should.equal(t, t.Integer) +// panic +// } From bae14590fef928685281f91d150d41ae8da668b8 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 27 Apr 2023 19:20:13 +0200 Subject: [PATCH 58/62] typ rendering for new types --- eyg/src/atelier/view/type_.gleam | 95 +++++++++++++++++++ .../eyg/analysis/jm/incremental_test.gleam | 26 +++++ 2 files changed, 121 insertions(+) create mode 100644 eyg/src/atelier/view/type_.gleam create mode 100644 eyg/test/eyg/analysis/jm/incremental_test.gleam diff --git a/eyg/src/atelier/view/type_.gleam b/eyg/src/atelier/view/type_.gleam new file mode 100644 index 000000000..91446ebd9 --- /dev/null +++ b/eyg/src/atelier/view/type_.gleam @@ -0,0 +1,95 @@ +// for flat types +import gleam/int +import gleam/list +import gleam/string +import eyg/analysis/jm/type_ as t +import eyg/analysis/jm/error + +pub fn render_failure(reason, t1, t2) { + case reason { + error.TypeMismatch(a, b) -> + // need to shrink errors together + string.concat(["Type Missmatch: ", render_type(a), " vs ", render_type(b)]) + error.RowMismatch(label) -> string.append("Row Missmatch: ", label) + error.MissingVariable(x) -> string.append("missing variable: ", x) + error.RecursiveType -> "Recursive type" + error.InvalidTail(_) -> "invalid tail" + } +} + +pub fn render_type(typ) { + case typ { + t.Var(i) -> int.to_string(i) + t.Integer -> "Integer" + t.String -> "String" + t.LinkedList(el) -> string.concat(["List(", render_type(el), ")"]) + t.Fun(from, effects, to) -> + string.concat([ + "(", + render_type(from), + ") ->", + render_effects(effects), + " ", + render_type(to), + ]) + t.Union(row) -> + string.concat([ + "[", + string.concat( + render_row(row) + |> list.intersperse(" | "), + ), + "]", + ]) + t.Record(row) -> + string.concat([ + "{", + string.concat( + render_row(row) + |> list.intersperse(", "), + ), + "}", + ]) + _ -> "invalid should not be raw type" + } +} + +fn render_row(r) -> List(String) { + case r { + t.Empty -> [] + t.Var(i) -> [string.append("..", int.to_string(i))] + t.RowExtend(label, value, tail) -> { + let field = string.concat([label, ": ", render_type(value)]) + [field, ..render_row(tail)] + } + _ -> ["not a valid row"] + } +} + +fn render_effects(effects) { + case effects { + t.Var(_) | t.Empty -> "" + t.EffectExtend(label, #(lift, resume), tail) -> + string.concat([ + " <", + string.join( + collect_effect(tail, [render_effect(label, lift, resume)]), + ", ", + ), + ">", + ]) + _ -> "not a valid effect" + } +} + +fn render_effect(label, lift, resume) { + string.concat([label, "(", render_type(lift), ", ", render_type(resume), ")"]) +} + +fn collect_effect(eff, acc) { + case eff { + t.EffectExtend(label, #(lift, resume), tail) -> + collect_effect(tail, [render_effect(label, lift, resume), ..acc]) + _ -> acc + } +} \ No newline at end of file diff --git a/eyg/test/eyg/analysis/jm/incremental_test.gleam b/eyg/test/eyg/analysis/jm/incremental_test.gleam new file mode 100644 index 000000000..79897f559 --- /dev/null +++ b/eyg/test/eyg/analysis/jm/incremental_test.gleam @@ -0,0 +1,26 @@ + +import eyg/incremental/source as e + +// constant folding and refernce + +pub fn foo_test(exp) -> Nil { + // case exp { + // e.Var(Term(hash)) + // e.Var(Brujin(index)) + // e.Var(Index(index)) + // e.Let -> + // e.Fn(x) -> { + // let vars = [x,..var] + // } + // } +} +// i -> free vars + + +// let y = 1 +// let x = y -> x = hash(1) + + +// let f x -> +// let y = x + 1 + From 592d66f62399d0c0eab65f101db9fab459f82fe4 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 27 Apr 2023 20:04:40 +0200 Subject: [PATCH 59/62] tidy up jm inference --- eyg/src/atelier/app.gleam | 21 ++++++ eyg/src/eyg/analysis/jm/tree.gleam | 106 ++++++++++++----------------- 2 files changed, 64 insertions(+), 63 deletions(-) diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index 9a7a31e7b..327b1bab2 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -21,6 +21,8 @@ import plinth/javascript/map as mutable_map import eyg/analysis/jm/incremental as jm import eyg/analysis/jm/type_ as jmt import eyg/analysis/jm/error +import eyg/analysis/jm/tree + pub type WorkSpace { WorkSpace( @@ -102,6 +104,25 @@ pub fn init(tree) { } }, ) + + let _ = { + + // TODO type for editor + let type_ = jmt.Var(-1) + let eff = jmt.Var(-2) + + let start = pnow() + let #(sub, next, types) = tree.infer(tree, type_, eff) + io.debug(#("typing jm took ms:", pnow() - start, map.size(types))) + types |> map.to_list |> list.filter_map(fn(z) { + let #(p, r) = z + case r { + Ok(_) -> Error(Nil) + Error(reason) -> Ok(io.debug(reason)) + } + }) + } + io.debug("d000---") // cusor at root doesn't ever error let assert Ok(c) = cursor.at([], root, source) let mode = Navigate(c) diff --git a/eyg/src/eyg/analysis/jm/tree.gleam b/eyg/src/eyg/analysis/jm/tree.gleam index 1146d1274..0b1eb1a98 100644 --- a/eyg/src/eyg/analysis/jm/tree.gleam +++ b/eyg/src/eyg/analysis/jm/tree.gleam @@ -2,7 +2,7 @@ import gleam/map import eygir/expression as e import eyg/analysis/jm/error import eyg/analysis/jm/type_ as t -import eyg/analysis/jm/infer.{extend, generalise, instantiate, mono, unify_at} +import eyg/analysis/jm/infer.{extend, generalise, instantiate, mono} pub type State = #( @@ -24,20 +24,34 @@ pub fn loop(run) { } } -pub fn infer(sub, next, env, exp, path, type_, eff, types) { - loop(step(sub, next, env, exp, path, type_, eff, types, Done)) +pub fn infer(exp, type_, eff) { + let sub = map.new() + let next = 0 + let types = map.new() + let env = map.new() + // Switching path to integer took ~ 20% off the inference time 600ms to 500ms for 6000 nodes + let path = [] + let acc = #(sub, next, types) + loop(step(acc, env, exp, path, type_, eff, Done)) } -fn step(sub, next, env, exp, path, type_, eff, types, k) { - // io.debug(exp) +pub fn unify_at(acc, path, expected, found) { + let #(sub, next, types)= acc + infer.unify_at(expected, found, sub, next, types, path) +} + +fn step(acc, env, exp, path, type_, eff, k) { case exp { e.Variable(x) -> { case map.get(env, x) { Ok(scheme) -> { + let #(sub, next, types) = acc let #(found, next) = instantiate(scheme, next) - Cont(unify_at(type_, found, sub, next, types, path), k) + let acc = #(sub, next, types) + Cont(unify_at(acc, path, type_, found), k) } Error(Nil) -> { + let #(sub, next, types) = acc let types = map.insert( types, @@ -50,79 +64,45 @@ fn step(sub, next, env, exp, path, type_, eff, types, k) { } e.Apply(e1, e2) -> { // can't error + let #(sub, next, types) = acc let types = map.insert(types, path, Ok(type_)) let #(arg, next) = t.fresh(next) - use #(sub, next, types) <- step( - sub, - next, - env, - e1, - [0, ..path], - t.Fun(arg, eff, type_), - eff, - types, - ) - use #(sub, next, types) <- step( - sub, - next, - env, - e2, - [1, ..path], - arg, - eff, - types, - ) - Cont(#(sub, next, types), k) + let acc = #(sub, next, types) + let func = t.Fun(arg, eff, type_) + use acc <- step(acc, env, e1, [0, ..path], func, eff) + use acc <- step(acc, env, e2, [1, ..path], arg, eff) + Cont(acc, k) } e.Lambda(x, e1) -> { + let #(sub, next, types) = acc let #(arg, next) = t.fresh(next) let #(eff, next) = t.fresh(next) let #(ret, next) = t.fresh(next) - let #(sub, next, types) = - unify_at(type_, t.Fun(arg, eff, ret), sub, next, types, path) + let acc = #(sub, next, types) + + let func = t.Fun(arg, eff, ret) + let acc = unify_at(acc, path, type_, func) let env = extend(env, x, mono(arg)) - use #(sub, next, types) <- step( - sub, - next, - env, - e1, - [0, ..path], - ret, - eff, - types, - ) - Cont(#(sub, next, types), k) + use acc <- step(acc, env, e1, [0, ..path], ret, eff) + Cont(acc, k) } e.Let(x, e1, e2) -> { // can't error + let #(sub, next, types) = acc let types = map.insert(types, path, Ok(type_)) let #(inner, next) = t.fresh(next) - use #(sub, next, types) <- step( - sub, - next, - env, - e1, - [0, ..path], - inner, - eff, - types, - ) - let env = extend(env, x, generalise(sub, env, inner)) - use #(sub, next, types) <- step( - sub, - next, - env, - e2, - [1, ..path], - type_, - eff, - types, - ) - Cont(#(sub, next, types), k) + let acc = #(sub, next, types) + + use acc <- step(acc, env, e1, [0, ..path], inner, eff) + let env = extend(env, x, generalise(acc.0, env, inner)) + use acc <- step(acc, env, e2, [1, ..path], type_, eff) + Cont(acc, k) } literal -> { + let #(sub, next, types) = acc let #(found, next) = primitive(literal, next) - Cont(unify_at(type_, found, sub, next, types, path), k) + let acc = #(sub, next, types) + Cont(unify_at(acc, path, type_, found), k) } } } From 14c3c92b29294aaeb63a144de8ef7d08a73ece6d Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 27 Apr 2023 20:14:43 +0200 Subject: [PATCH 60/62] add builtins to j --- eyg/src/eyg/analysis/jm/incremental.gleam | 28 +--------- eyg/src/eyg/analysis/jm/infer.gleam | 20 ++++++++ eyg/src/eyg/analysis/jm/tree.gleam | 62 ++++++++++++----------- 3 files changed, 54 insertions(+), 56 deletions(-) diff --git a/eyg/src/eyg/analysis/jm/incremental.gleam b/eyg/src/eyg/analysis/jm/incremental.gleam index 4c3d34fe7..819ab0d21 100644 --- a/eyg/src/eyg/analysis/jm/incremental.gleam +++ b/eyg/src/eyg/analysis/jm/incremental.gleam @@ -4,7 +4,7 @@ import eyg/incremental/source as e import eyg/analysis/jm/error import eyg/analysis/jm/type_ as t import eyg/analysis/jm/infer.{ - Cont, Done, builtins, extend, generalise, instantiate, loop, mono, unify_at, + Cont, Done, builtins, extend, generalise, instantiate, loop, mono, unify_at, fetch } pub fn infer(sub, next, env, source, ref, type_, eff, types) { @@ -131,29 +131,3 @@ fn primitive(exp, next) { } } -fn fetch(env, x, sub, next, types, ref, type_, k) { - case map.get(env, x) { - Ok(scheme) -> { - // io.debug("found") - let #(found, next) = instantiate(scheme, next) - // io.debug("instanted") - // case x == "equal" { - // False -> Nil - // True -> { - // io.debug(#("!!!!", scheme, x, found, next)) - // Nil - // } - // } - Cont(unify_at(type_, found, sub, next, types, ref), k) - } - Error(Nil) -> { - let types = - map.insert( - types, - ref, - Error(#(error.MissingVariable(x), type_, t.Var(-100))), - ) - Cont(#(sub, next, types), k) - } - } -} diff --git a/eyg/src/eyg/analysis/jm/infer.gleam b/eyg/src/eyg/analysis/jm/infer.gleam index 2ee5799bd..67ade3494 100644 --- a/eyg/src/eyg/analysis/jm/infer.gleam +++ b/eyg/src/eyg/analysis/jm/infer.gleam @@ -101,6 +101,26 @@ pub fn loop(run) { } } +pub fn fetch(env, x, sub, next, types, ref, type_, k) { + case map.get(env, x) { + Ok(scheme) -> { + let #(found, next) = instantiate(scheme, next) + Cont(unify_at(type_, found, sub, next, types, ref), k) + } + Error(Nil) -> { + let #(unmatched, next) = t.fresh(next) + let types = + map.insert( + types, + ref, + Error(#(error.MissingVariable(x), type_, unmatched)), + ) + Cont(#(sub, next, types), k) + } + } +} + + pub fn builtins() { map.new() |> extend_b("equal", equal()) diff --git a/eyg/src/eyg/analysis/jm/tree.gleam b/eyg/src/eyg/analysis/jm/tree.gleam index 0b1eb1a98..4516b2627 100644 --- a/eyg/src/eyg/analysis/jm/tree.gleam +++ b/eyg/src/eyg/analysis/jm/tree.gleam @@ -2,7 +2,7 @@ import gleam/map import eygir/expression as e import eyg/analysis/jm/error import eyg/analysis/jm/type_ as t -import eyg/analysis/jm/infer.{extend, generalise, instantiate, mono} +import eyg/analysis/jm/infer.{extend, generalise, instantiate, mono, builtins} pub type State = #( @@ -35,33 +35,11 @@ pub fn infer(exp, type_, eff) { loop(step(acc, env, exp, path, type_, eff, Done)) } -pub fn unify_at(acc, path, expected, found) { - let #(sub, next, types)= acc - infer.unify_at(expected, found, sub, next, types, path) -} + fn step(acc, env, exp, path, type_, eff, k) { case exp { - e.Variable(x) -> { - case map.get(env, x) { - Ok(scheme) -> { - let #(sub, next, types) = acc - let #(found, next) = instantiate(scheme, next) - let acc = #(sub, next, types) - Cont(unify_at(acc, path, type_, found), k) - } - Error(Nil) -> { - let #(sub, next, types) = acc - let types = - map.insert( - types, - path, - Error(#(error.MissingVariable(x), type_, t.Var(-100))), - ) - Cont(#(sub, next, types), k) - } - } - } + e.Variable(x) -> fetch(acc, path, env, x, type_, k) e.Apply(e1, e2) -> { // can't error let #(sub, next, types) = acc @@ -98,6 +76,7 @@ fn step(acc, env, exp, path, type_, eff, k) { use acc <- step(acc, env, e2, [1, ..path], type_, eff) Cont(acc, k) } + e.Builtin(x) -> fetch(acc, path, builtins(), x, type_, k) literal -> { let #(sub, next, types) = acc let #(found, next) = primitive(literal, next) @@ -109,7 +88,7 @@ fn step(acc, env, exp, path, type_, eff, k) { fn primitive(exp, next) { case exp { - e.Variable(_) | e.Apply(_, _) | e.Lambda(_, _) | e.Let(_, _, _) -> + e.Variable(_) | e.Apply(_, _) | e.Lambda(_, _) | e.Let(_, _, _) | e.Builtin(_) -> panic("not a literal") e.Binary(_) -> #(t.String, next) e.Integer(_) -> #(t.Integer, next) @@ -132,9 +111,34 @@ fn primitive(exp, next) { // Effect e.Perform(label) -> t.perform(label, next) e.Handle(label) -> t.handle(label, next) + } +} + + +pub fn unify_at(acc, path, expected, found) { + let #(sub, next, types) = acc + infer.unify_at(expected, found, sub, next, types, path) +} - // TODO use real builtins - e.Builtin(identifier) -> t.fresh(next) +pub fn fetch(acc, path, env, x, type_, k) { + case map.get(env, x) { + Ok(scheme) -> { + let #(sub, next, types) = acc + let #(found, next) = instantiate(scheme, next) + let acc = #(sub, next, types) + Cont(unify_at(acc, path, type_, found), k) + } + Error(Nil) -> { + let #(sub, next, types) = acc + let #(unmatched, next) = t.fresh(next) + let types = + map.insert( + types, + path, + Error(#(error.MissingVariable(x), type_, unmatched)), + ) + let acc = #(sub, next, types) + Cont(acc, k) + } } - // _ -> todo("pull from old inference") } From b734f41095f0bd3db7f62dea7985378d33afcf38 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 27 Apr 2023 20:35:24 +0200 Subject: [PATCH 61/62] run formatter --- eyg/src/atelier/app.gleam | 75 +++--- eyg/src/atelier/view/pallet.gleam | 85 +++--- eyg/src/atelier/view/type_.gleam | 2 +- eyg/src/eyg/analysis/jm/incremental.gleam | 4 +- eyg/src/eyg/analysis/jm/infer.gleam | 9 +- eyg/src/eyg/analysis/jm/tree.gleam | 14 +- eyg/src/eyg/incremental/cursor.gleam | 5 +- eyg/src/eyg/incremental/inference.gleam | 4 +- eyg/src/eyg/incremental/source.gleam | 40 +-- eyg/src/eyg/incremental/store.gleam | 3 +- eyg/src/eyg/runtime/interpreter.gleam | 4 +- eyg/src/harness/ffi/integer.gleam | 2 +- eyg/src/platforms/browser.gleam | 5 +- eyg/test/examples/algorithm_j_test.gleam | 125 ++++----- eyg/test/examples/algorithm_w.gleam | 6 +- eyg/test/examples/algorithm_w_test.gleam | 4 +- eyg/test/examples/j_cont_test.gleam | 251 +++++++++--------- .../eyg/analysis/jm/incremental_test.gleam | 5 +- eyg/test/eyg/analysis/jm/infer_test.gleam | 26 +- eyg/test/eyg/analysis/jm/unify_test.gleam | 15 +- eyg/test/eyg/incremental/store_test.gleam | 5 - eyg/test/hash_test.gleam | 1 - eyg/test/plinth/map_test.gleam | 40 +-- 23 files changed, 384 insertions(+), 346 deletions(-) diff --git a/eyg/src/atelier/app.gleam b/eyg/src/atelier/app.gleam index 327b1bab2..5a84f5f0a 100644 --- a/eyg/src/atelier/app.gleam +++ b/eyg/src/atelier/app.gleam @@ -23,14 +23,19 @@ import eyg/analysis/jm/type_ as jmt import eyg/analysis/jm/error import eyg/analysis/jm/tree - pub type WorkSpace { WorkSpace( selection: List(Int), source: e.Source, root: Int, // TODO call acc - inferred: #(map.Map(Int, jmt.Type), Int, Option(map.Map(Int, Result(jmt.Type, #(error.Reason, jmt.Type, jmt.Type))))), + inferred: #( + map.Map(Int, jmt.Type), + Int, + Option( + map.Map(Int, Result(jmt.Type, #(error.Reason, jmt.Type, jmt.Type))), + ), + ), mode: Mode, // copy pasting makes the id get reused that will change the type or have the type used more than once in a tree // Need to not type things with free variables/types @@ -105,8 +110,7 @@ pub fn init(tree) { }, ) - let _ = { - + let _ = { // TODO type for editor let type_ = jmt.Var(-1) let eff = jmt.Var(-2) @@ -114,7 +118,9 @@ pub fn init(tree) { let start = pnow() let #(sub, next, types) = tree.infer(tree, type_, eff) io.debug(#("typing jm took ms:", pnow() - start, map.size(types))) - types |> map.to_list |> list.filter_map(fn(z) { + types + |> map.to_list + |> list.filter_map(fn(z) { let #(p, r) = z case r { Ok(_) -> Error(Nil) @@ -127,7 +133,16 @@ pub fn init(tree) { let assert Ok(c) = cursor.at([], root, source) let mode = Navigate(c) // Have inference work once for showing elements but need to also background this - WorkSpace([], source, root, #(sub, next, Some(typesjm)), mode, None, None, #([], [])) + WorkSpace( + [], + source, + root, + #(sub, next, Some(typesjm)), + mode, + None, + None, + #([], []), + ) } pub fn update(state: WorkSpace, action) { @@ -229,10 +244,10 @@ pub fn keypress(key, state: WorkSpace) { WriteText(_, _), _k -> Ok(state) WriteTerm(new, commit), k if k == "Enter" -> { let assert [var, ..selects] = string.split(new, ".") - case selects { - [] -> Nil - _ -> todo("handle dot vars") - } + case selects { + [] -> Nil + _ -> todo("handle dot vars") + } let expression = // list.fold( // selects, @@ -263,8 +278,8 @@ fn save(state: WorkSpace) { |> request.set_host("localhost:5000") |> request.set_path("/save") |> request.prepend_header("content-type", "application/json") - todo("finish saving") - // |> request.set_body(encode.to_json(state.source)) + todo("finish saving") + // |> request.set_body(encode.to_json(state.source)) fetch.send(request) |> io.debug @@ -286,15 +301,16 @@ fn assign_to(c, state: WorkSpace) { e.Let(_, _, _) -> fn(text) { // TODO needs a tree replace // easier to insert tree but only if no reference to the old stuff - let assert Ok(r) = store.replace(source, c, e.Let(text, hole, cursor.inner(c))) + let assert Ok(r) = + store.replace(source, c, e.Let(text, hole, cursor.inner(c))) r } // normally I want to add something above - exp -> fn(text) { + exp -> fn(text) { // always the same // act.update(e.Let(text, e.Vacant(""), exp)) } - let assert Ok(r) = - store.replace(source, c, e.Let(text, hole, cursor.inner(c))) + let assert Ok(r) = + store.replace(source, c, e.Let(text, hole, cursor.inner(c))) r } } @@ -413,7 +429,10 @@ fn increase(state: WorkSpace) { fn decrease(_act, state: WorkSpace) { let selection = list.append(state.selection, [0]) - use c <- result.then(cursor.at(selection, state.root, state.source) |> result.map_error(fn(_: Nil) { "no valid decrease"})) + use c <- result.then( + cursor.at(selection, state.root, state.source) + |> result.map_error(fn(_: Nil) { "no valid decrease" }), + ) Ok(WorkSpace(..state, selection: selection, mode: Navigate(c))) } @@ -587,8 +606,11 @@ fn delete(c, state: WorkSpace) { // update source also ends the entry state fn update_source(state: WorkSpace, next) { let #(root, source) = next - use cursor <- result.then(cursor.at(state.selection, root, source) |> result.map_error(fn(_:Nil) {"nope on the update"})) - + use cursor <- result.then( + cursor.at(state.selection, root, source) + |> result.map_error(fn(_: Nil) { "nope on the update" }), + ) + let mode = Navigate(cursor) // let #(history, inferred) = case source == state.source { // True -> #(state.history, state.inferred) @@ -611,15 +633,8 @@ fn update_source(state: WorkSpace, next) { let #(sub, _next, typesjm) = jm.infer(sub, next, env, source, root, type_, eff, types) io.debug(#("typing jm took ms:", pnow() - start, map.size(typesjm))) - - Ok( - WorkSpace( - ..state, - source: source, - root: root, - mode: mode, - // history: history, - // inferred: inferred, - ), - ) + + Ok(WorkSpace(..state, source: source, root: root, mode: mode)) + // history: history, + // inferred: inferred, } diff --git a/eyg/src/atelier/view/pallet.gleam b/eyg/src/atelier/view/pallet.gleam index deeb4cb75..f0ba601b1 100644 --- a/eyg/src/atelier/view/pallet.gleam +++ b/eyg/src/atelier/view/pallet.gleam @@ -40,40 +40,35 @@ fn render_label(value) { ] } -fn render_variable( - value, state: app.WorkSpace, -) { +fn render_variable(value, state: app.WorkSpace) { [ - div( - [], - [] - // case inferred { - // Some(inferred) -> - // // TODO use inferred but we dont have the whole env map. - // [] - // // case inventory.variables_at(inferred.environments, state.selection) { - // // // using spaces because we are in pre tag and text based - // // // not in pre tag here - // // Ok(options) -> - // // list.map( - // // options, - // // fn(option) { - // // let #(t, term) = option - // // span( - // // [ - // // class("rounded bg-blue-100 p-1"), - // // on_click(ClickOption(term)), - // // ], - // // [text(t)], - // // ) - // // }, - // // ) - // // |> list.intersperse(text(" ")) - // // Error(_) -> [text("no env")] - // // } - // None -> [] - // }, - ), + div([], []), + // case inferred { + // Some(inferred) -> + // // TODO use inferred but we dont have the whole env map. + // [] + // // case inventory.variables_at(inferred.environments, state.selection) { + // // // using spaces because we are in pre tag and text based + // // // not in pre tag here + // // Ok(options) -> + // // list.map( + // // options, + // // fn(option) { + // // let #(t, term) = option + // // span( + // // [ + // // class("rounded bg-blue-100 p-1"), + // // on_click(ClickOption(term)), + // // ], + // // [text(t)], + // // ) + // // }, + // // ) + // // |> list.intersperse(text(" ")) + // // Error(_) -> [text("no env")] + // // } + // None -> [] + // }, input([ class("border w-full"), attribute.autofocus(True), @@ -120,7 +115,7 @@ fn render_text(value) { } fn render_navigate(state: app.WorkSpace) { - let #(sub, _next, types) = state.inferred + let #(sub, _next, types) = state.inferred [ case types { Some(types) -> render_errors(types) @@ -137,14 +132,20 @@ fn render_navigate(state: app.WorkSpace) { text(string.append( ":", { - let assert Ok(c) = cursor.at(state.selection, state.root, state.source) + let assert Ok(c) = + cursor.at(state.selection, state.root, state.source) let id = cursor.inner(c) let assert Ok(type_) = map.get(types, id) case type_ { - Ok(type_) -> type_.render_type(t.resolve( type_, sub)) - Error(#(reason, t1, t2)) -> type_.render_failure(reason, t.resolve(t1, sub), t.resolve(t2, sub)) + Ok(type_) -> type_.render_type(t.resolve(type_, sub)) + Error(#(reason, t1, t2)) -> + type_.render_failure( + reason, + t.resolve(t1, sub), + t.resolve(t2, sub), + ) } - } + }, )) None -> span([], [text("type checking")]) }, @@ -197,10 +198,10 @@ fn render_errors(types) { } } -pub fn render_failure(reason) { - let #(reason, _,_) = reason +pub fn render_failure(reason) { + let #(reason, _, _) = reason case reason { - error.RecursiveType -> "recursive type" + error.RecursiveType -> "recursive type" _ -> "other error" } -} \ No newline at end of file +} diff --git a/eyg/src/atelier/view/type_.gleam b/eyg/src/atelier/view/type_.gleam index 91446ebd9..45239191e 100644 --- a/eyg/src/atelier/view/type_.gleam +++ b/eyg/src/atelier/view/type_.gleam @@ -92,4 +92,4 @@ fn collect_effect(eff, acc) { collect_effect(tail, [render_effect(label, lift, resume), ..acc]) _ -> acc } -} \ No newline at end of file +} diff --git a/eyg/src/eyg/analysis/jm/incremental.gleam b/eyg/src/eyg/analysis/jm/incremental.gleam index 819ab0d21..6ca5ff065 100644 --- a/eyg/src/eyg/analysis/jm/incremental.gleam +++ b/eyg/src/eyg/analysis/jm/incremental.gleam @@ -4,7 +4,8 @@ import eyg/incremental/source as e import eyg/analysis/jm/error import eyg/analysis/jm/type_ as t import eyg/analysis/jm/infer.{ - Cont, Done, builtins, extend, generalise, instantiate, loop, mono, unify_at, fetch + Cont, Done, builtins, extend, fetch, generalise, instantiate, loop, mono, + unify_at, } pub fn infer(sub, next, env, source, ref, type_, eff, types) { @@ -130,4 +131,3 @@ fn primitive(exp, next) { e.Handle(label) -> t.handle(label, next) } } - diff --git a/eyg/src/eyg/analysis/jm/infer.gleam b/eyg/src/eyg/analysis/jm/infer.gleam index 67ade3494..b9b6d4356 100644 --- a/eyg/src/eyg/analysis/jm/infer.gleam +++ b/eyg/src/eyg/analysis/jm/infer.gleam @@ -39,7 +39,7 @@ pub fn instantiate(scheme, next) { // io.debug(s |> map.to_list) // Apply is actually on a recursive substitution, composing SHOULD update all values to make it a single call let type_ = apply_once(s, type_) - // io.debug("applyed") + // io.debug("applyed") #(type_, next) } @@ -62,7 +62,11 @@ fn apply_once(s, type_) { t.RowExtend(label, value, rest) -> t.RowExtend(label, apply_once(s, value), apply_once(s, rest)) t.EffectExtend(label, #(lift, reply), rest) -> - t.EffectExtend(label, #(apply_once(s, lift), apply_once(s, reply)), apply_once(s, rest)) + t.EffectExtend( + label, + #(apply_once(s, lift), apply_once(s, reply)), + apply_once(s, rest), + ) } } @@ -120,7 +124,6 @@ pub fn fetch(env, x, sub, next, types, ref, type_, k) { } } - pub fn builtins() { map.new() |> extend_b("equal", equal()) diff --git a/eyg/src/eyg/analysis/jm/tree.gleam b/eyg/src/eyg/analysis/jm/tree.gleam index 4516b2627..cc5df285c 100644 --- a/eyg/src/eyg/analysis/jm/tree.gleam +++ b/eyg/src/eyg/analysis/jm/tree.gleam @@ -2,7 +2,7 @@ import gleam/map import eygir/expression as e import eyg/analysis/jm/error import eyg/analysis/jm/type_ as t -import eyg/analysis/jm/infer.{extend, generalise, instantiate, mono, builtins} +import eyg/analysis/jm/infer.{builtins, extend, generalise, instantiate, mono} pub type State = #( @@ -35,8 +35,6 @@ pub fn infer(exp, type_, eff) { loop(step(acc, env, exp, path, type_, eff, Done)) } - - fn step(acc, env, exp, path, type_, eff, k) { case exp { e.Variable(x) -> fetch(acc, path, env, x, type_, k) @@ -88,8 +86,11 @@ fn step(acc, env, exp, path, type_, eff, k) { fn primitive(exp, next) { case exp { - e.Variable(_) | e.Apply(_, _) | e.Lambda(_, _) | e.Let(_, _, _) | e.Builtin(_) -> - panic("not a literal") + e.Variable(_) + | e.Apply(_, _) + | e.Lambda(_, _) + | e.Let(_, _, _) + | e.Builtin(_) -> panic("not a literal") e.Binary(_) -> #(t.String, next) e.Integer(_) -> #(t.Integer, next) @@ -114,8 +115,7 @@ fn primitive(exp, next) { } } - -pub fn unify_at(acc, path, expected, found) { +pub fn unify_at(acc, path, expected, found) { let #(sub, next, types) = acc infer.unify_at(expected, found, sub, next, types, path) } diff --git a/eyg/src/eyg/incremental/cursor.gleam b/eyg/src/eyg/incremental/cursor.gleam index 8310bc684..15274a472 100644 --- a/eyg/src/eyg/incremental/cursor.gleam +++ b/eyg/src/eyg/incremental/cursor.gleam @@ -2,7 +2,8 @@ import gleam/map import gleam/result import eyg/incremental/source as e -pub type Cursor = #(List(Int), Int) +pub type Cursor = + #(List(Int), Int) fn zip_match(node, path_element) { case node, path_element { @@ -47,4 +48,4 @@ pub fn inner(c) { pub fn expression(c, source) { map.get(source, inner(c)) -} \ No newline at end of file +} diff --git a/eyg/src/eyg/incremental/inference.gleam b/eyg/src/eyg/incremental/inference.gleam index f45fbe1c6..76179e7b4 100644 --- a/eyg/src/eyg/incremental/inference.gleam +++ b/eyg/src/eyg/incremental/inference.gleam @@ -11,7 +11,6 @@ import eyg/analysis/scheme.{Scheme} import eyg/analysis/unification import eyg/incremental/source - fn from_end(items, i) { list.at(items, list.length(items) - 1 - i) } @@ -128,7 +127,8 @@ pub fn cached( let t = unification.instantiate(scheme, count) #(t, subs, types) } - Error(Nil) -> panic("no var in env need to add errors but return normal type") + Error(Nil) -> + panic("no var in env need to add errors but return normal type") } source.Let(x, value, then) -> { let #(t1, subs, types) = diff --git a/eyg/src/eyg/incremental/source.gleam b/eyg/src/eyg/incremental/source.gleam index f9126fce0..6085f8a4a 100644 --- a/eyg/src/eyg/incremental/source.gleam +++ b/eyg/src/eyg/incremental/source.gleam @@ -26,7 +26,8 @@ pub type Expression { Builtin(identifier: String) } -pub type Source = map.Map(Int, Expression) +pub type Source = + map.Map(Int, Expression) pub fn do_from_tree(tree, acc) { case tree { @@ -79,16 +80,17 @@ pub fn from_tree(tree) { let source = list.reverse([exp, ..acc]) #(index, source) } + fn next(ref) { javascript.update_reference(ref, fn(x) { x + 1 }) } -fn push(x, ref) { +fn push(x, ref) { let #(node, source) = x let index = next(ref) let source = map.insert(source, index, node) #(index, source) - } +} pub fn do_from_tree_map(tree, acc, ref) -> #(Int, map.Map(Int, Expression)) { case tree { @@ -127,7 +129,8 @@ pub fn do_from_tree_map(tree, acc, ref) -> #(Int, map.Map(Int, Expression)) { } pub fn from_tree_map(tree) { - let #(index, source) = do_from_tree_map(tree, map.new(), javascript.make_reference(0)) + let #(index, source) = + do_from_tree_map(tree, map.new(), javascript.make_reference(0)) #(index, source) } @@ -149,25 +152,25 @@ pub fn to_tree(source, root) { use exp2 <- result.then(to_tree(source, ref2)) Ok(e.Apply(exp1, exp2)) } - String(value) -> Ok(e.Binary(value) ) - Integer(value) -> Ok(e.Integer(value) ) - Tail -> Ok(e.Tail ) - Cons -> Ok(e.Cons ) + String(value) -> Ok(e.Binary(value)) + Integer(value) -> Ok(e.Integer(value)) + Tail -> Ok(e.Tail) + Cons -> Ok(e.Cons) Vacant(comment) -> Ok(e.Vacant(comment)) - Empty -> Ok(e.Empty) + Empty -> Ok(e.Empty) Extend(label) -> Ok(e.Extend(label)) Select(label) -> Ok(e.Select(label)) Overwrite(label) -> Ok(e.Overwrite(label)) Tag(label) -> Ok(e.Tag(label)) Case(label) -> Ok(e.Case(label)) - NoCases -> Ok(e.NoCases ) - Perform(label) -> Ok(e.Perform(label)) - Handle(label) -> Ok(e.Handle(label)) - Builtin(identifier) -> Ok(e.Builtin(identifier)) + NoCases -> Ok(e.NoCases) + Perform(label) -> Ok(e.Perform(label)) + Handle(label) -> Ok(e.Handle(label)) + Builtin(identifier) -> Ok(e.Builtin(identifier)) } } -pub fn insert(acc, exp) { +pub fn insert(acc, exp) { let id = map.size(acc) #(id, map.insert(acc, id, exp)) } @@ -178,10 +181,8 @@ fn do_replace(old_id, new_id, zoom, source) { [next, ..zoom] -> { use node <- result.then(map.get(source, next)) let exp = case node { - Let(label, value, then) if value == old_id -> - Let(label, new_id, then) - Let(label, value, then) if then == old_id -> - Let(label, value, new_id) + Let(label, value, then) if value == old_id -> Let(label, new_id, then) + Let(label, value, then) if then == old_id -> Let(label, value, new_id) Fn(param, body) if body == old_id -> Fn(param, new_id) Call(func, arg) if func == old_id -> Call(new_id, arg) Call(func, arg) if arg == old_id -> Call(func, new_id) @@ -195,10 +196,9 @@ fn do_replace(old_id, new_id, zoom, source) { } pub fn replace(source, cursor, new_id) { - case cursor { #([], old) -> do_replace(old, new_id, [], source) #([old, ..zoom], root) -> do_replace(old, new_id, list.append(zoom, [root]), source) } -} \ No newline at end of file +} diff --git a/eyg/src/eyg/incremental/store.gleam b/eyg/src/eyg/incremental/store.gleam index 910ca46f0..259b0ed57 100644 --- a/eyg/src/eyg/incremental/store.gleam +++ b/eyg/src/eyg/incremental/store.gleam @@ -42,7 +42,8 @@ pub fn empty() { } pub fn load(store: Store, tree) { - let #(index, source) = source.do_from_tree_map(tree, store.source, store.source_id_tracker) + let #(index, source) = + source.do_from_tree_map(tree, store.source, store.source_id_tracker) #(index, Store(..store, source: source)) } diff --git a/eyg/src/eyg/runtime/interpreter.gleam b/eyg/src/eyg/runtime/interpreter.gleam index cdbeb0b10..ac98927fb 100644 --- a/eyg/src/eyg/runtime/interpreter.gleam +++ b/eyg/src/eyg/runtime/interpreter.gleam @@ -38,7 +38,9 @@ pub fn run(source, env, term, extrinsic) { Cont(_, _) -> panic("should have evaluated and not be a Cont at all") // other runtime errors return error, maybe this should be the same Async(_, _) -> - panic("cannot return async value some sync run. This effect would not be allowed by type system") + panic( + "cannot return async value some sync run. This effect would not be allowed by type system", + ) } } diff --git a/eyg/src/harness/ffi/integer.gleam b/eyg/src/harness/ffi/integer.gleam index ad96570c9..8b0e1f5b9 100644 --- a/eyg/src/harness/ffi/integer.gleam +++ b/eyg/src/harness/ffi/integer.gleam @@ -5,7 +5,7 @@ import harness/ffi/cast pub fn add() { let type_ = - // TODO not same effect + // TODO not same effect t.Fun(t.Integer, t.Open(0), t.Fun(t.Integer, t.Open(0), t.Integer)) #(type_, r.Arity2(do_add)) } diff --git a/eyg/src/platforms/browser.gleam b/eyg/src/platforms/browser.gleam index 5772d1bbd..be84f3f5c 100644 --- a/eyg/src/platforms/browser.gleam +++ b/eyg/src/platforms/browser.gleam @@ -78,7 +78,10 @@ fn render() { let assert r.Binary(page) = page case document.query_selector("#app") { Ok(Some(element)) -> document.set_html(element, page) - _ -> panic("could not render as no app element found, the reference to the app element should exist from start time and not be checked on every render") + _ -> + panic( + "could not render as no app element found, the reference to the app element should exist from start time and not be checked on every render", + ) } r.continue(k, r.unit) }, diff --git a/eyg/test/examples/algorithm_j_test.gleam b/eyg/test/examples/algorithm_j_test.gleam index eb3bee65c..b5ab2d2ed 100644 --- a/eyg/test/examples/algorithm_j_test.gleam +++ b/eyg/test/examples/algorithm_j_test.gleam @@ -2,89 +2,92 @@ import gleam/map.{get, insert as extend} import gleam/result.{then as try_} pub type Literal { - Integer - String + Integer + String } pub type Exp { - Var(String) - App(Exp, Exp) - Abs(String, Exp) - Let(String, Exp, Exp) - Lit(Literal) + Var(String) + App(Exp, Exp) + Abs(String, Exp) + Let(String, Exp, Exp) + Lit(Literal) } pub type Type { - TInt - // TString - Unbound(Int) - Fn(Type,Type) + TInt + // TString + Unbound(Int) + Fn(Type, Type) } -pub type Scheme = #(List(Int), Type) +pub type Scheme = + #(List(Int), Type) -pub fn fresh(next) { - #(Unbound(next), next + 1) +pub fn fresh(next) { + #(Unbound(next), next + 1) } -pub fn instantiate(scheme, next) { - todo +pub fn instantiate(scheme, next) { + todo } -pub fn mono(t) { - #([], t) +pub fn mono(t) { + #([], t) } -pub fn generalise(env, t) { - todo +pub fn generalise(env, t) { + todo } -pub fn unify(t1, t2, s) { - do_unify([#(t1, t2)], s) +pub fn unify(t1, t2, s) { + do_unify([#(t1, t2)], s) } // s is a function from var -> t -pub fn do_unify(constraints, s) { - // Have to try and substitute at every point because new substitutions can come into existance - case constraints { - [] -> Ok(s) - [#(Unbound(i), Unbound(j)), ..constraints] -> do_unify(constraints, s) - [#(Unbound(i), t1), ..constraints] | [#(t1, Unbound(i)), ..constraints] -> case map.get(s, i) { - Ok(t2) -> do_unify([#(t1, t2),..constraints], s) - Error(Nil) -> do_unify(constraints, map.insert(s, i, t1)) - } - [#(Fn(a1, r1), Fn(a2, r2)), ..cs] -> do_unify([#(a1, a2), #(r1, r2), ..cs], s) - _ -> Error(Nil) - } +pub fn do_unify(constraints, s) { + // Have to try and substitute at every point because new substitutions can come into existance + case constraints { + [] -> Ok(s) + [#(Unbound(i), Unbound(j)), ..constraints] -> do_unify(constraints, s) + [#(Unbound(i), t1), ..constraints] | [#(t1, Unbound(i)), ..constraints] -> + case map.get(s, i) { + Ok(t2) -> do_unify([#(t1, t2), ..constraints], s) + Error(Nil) -> do_unify(constraints, map.insert(s, i, t1)) + } + [#(Fn(a1, r1), Fn(a2, r2)), ..cs] -> + do_unify([#(a1, a2), #(r1, r2), ..cs], s) + _ -> Error(Nil) + } } // In exercise a type can be type err pub fn j(env, exp, sub, next) { - case exp { - Var(x) -> { - use scheme <- try_(get(env, x)) - let #(type_, next) = instantiate(scheme, next) - Ok(#(sub, next, type_)) - } - App(e1, e2) -> { - use #(sub1, next, t1) <- try_(j(env, e1, sub, next)) - use #(sub2, next, t2) <- try_(j(env, e2, sub1, next)) - let #(beta, next) = fresh(next) - use sub3 <- try_(unify(t1, Fn(t2, beta), sub2)) - Ok(#(sub, next, beta)) - } - Abs(x, e1) -> { - let #(beta, next) = fresh(next) - let env1 = extend(env, x, mono(beta)) - use #(sub1, next, t1) <- try_(j(env, e1, sub, next)) - Ok(#(sub1, next, Fn(beta, t1))) - } - Let(x, e1, e2) -> { - use #(sub1, next, t1) <- try_(j(env, e1, sub, next)) - // generalise needs sub applied tot1 - let env1 = extend(env, x, generalise(env, t1)) - use #(sub2, next, t2) <- try_(j(env, e2, sub1, next)) - } - Lit(l) -> todo + case exp { + Var(x) -> { + use scheme <- try_(get(env, x)) + let #(type_, next) = instantiate(scheme, next) + Ok(#(sub, next, type_)) + } + App(e1, e2) -> { + use #(sub1, next, t1) <- try_(j(env, e1, sub, next)) + use #(sub2, next, t2) <- try_(j(env, e2, sub1, next)) + let #(beta, next) = fresh(next) + use sub3 <- try_(unify(t1, Fn(t2, beta), sub2)) + Ok(#(sub, next, beta)) + } + Abs(x, e1) -> { + let #(beta, next) = fresh(next) + let env1 = extend(env, x, mono(beta)) + use #(sub1, next, t1) <- try_(j(env, e1, sub, next)) + Ok(#(sub1, next, Fn(beta, t1))) } -} \ No newline at end of file + Let(x, e1, e2) -> { + use #(sub1, next, t1) <- try_(j(env, e1, sub, next)) + // generalise needs sub applied tot1 + let env1 = extend(env, x, generalise(env, t1)) + use #(sub2, next, t2) <- try_(j(env, e2, sub1, next)) + } + Lit(l) -> todo + } +} diff --git a/eyg/test/examples/algorithm_w.gleam b/eyg/test/examples/algorithm_w.gleam index 1070abc01..e05215725 100644 --- a/eyg/test/examples/algorithm_w.gleam +++ b/eyg/test/examples/algorithm_w.gleam @@ -1,3 +1,3 @@ -pub fn w() { - "" -} \ No newline at end of file +pub fn w() { + "" +} diff --git a/eyg/test/examples/algorithm_w_test.gleam b/eyg/test/examples/algorithm_w_test.gleam index 948e7457a..84f7b379c 100644 --- a/eyg/test/examples/algorithm_w_test.gleam +++ b/eyg/test/examples/algorithm_w_test.gleam @@ -1,5 +1,5 @@ import examples/algorithm_w.{w} pub fn function_name_test() -> Nil { - todo -} \ No newline at end of file + todo +} diff --git a/eyg/test/examples/j_cont_test.gleam b/eyg/test/examples/j_cont_test.gleam index 4388a762f..45bf87ce8 100644 --- a/eyg/test/examples/j_cont_test.gleam +++ b/eyg/test/examples/j_cont_test.gleam @@ -3,68 +3,72 @@ import gleam/map.{get, insert as extend} import gleam/result.{then as try_} pub type Literal { - Integer - String + Integer + String } pub type Exp { - Var(String) - App(Exp, Exp) - Abs(String, Exp) - Let(String, Exp, Exp) - Lit(Literal) + Var(String) + App(Exp, Exp) + Abs(String, Exp) + Let(String, Exp, Exp) + Lit(Literal) } pub type Type { - TInt - TString - Unbound(Int) - Fn(Type,Type) - TErr(String) + TInt + TString + Unbound(Int) + Fn(Type, Type) + TErr(String) } -pub type Scheme = #(List(Int), Type) +pub type Scheme = + #(List(Int), Type) -pub fn fresh(next) { - #(Unbound(next), next + 1) +pub fn fresh(next) { + #(Unbound(next), next + 1) } -pub fn instantiate(scheme, next) { - todo +pub fn instantiate(scheme, next) { + todo } -pub fn mono(t) { - #([], t) +pub fn mono(t) { + #([], t) } -pub fn generalise(env, t) { - todo +pub fn generalise(env, t) { + todo } -pub fn unify(t1, t2, s) { - do_unify([#(t1, t2)], s) +pub fn unify(t1, t2, s) { + do_unify([#(t1, t2)], s) } // s is a function from var -> t -pub fn do_unify(constraints, s) { - // Have to try and substitute at every point because new substitutions can come into existance - case constraints { - [] -> Ok(s) - [#(Unbound(i), Unbound(j)), ..constraints] -> do_unify(constraints, s) - [#(Unbound(i), t1), ..constraints] | [#(t1, Unbound(i)), ..constraints] -> case map.get(s, i) { - Ok(t2) -> do_unify([#(t1, t2),..constraints], s) - Error(Nil) -> do_unify(constraints, map.insert(s, i, t1)) - } - [#(Fn(a1, r1), Fn(a2, r2)), ..cs] -> do_unify([#(a1, a2), #(r1, r2), ..cs], s) - _ -> Error(Nil) - } +pub fn do_unify(constraints, s) { + // Have to try and substitute at every point because new substitutions can come into existance + case constraints { + [] -> Ok(s) + [#(Unbound(i), Unbound(j)), ..constraints] -> do_unify(constraints, s) + [#(Unbound(i), t1), ..constraints] | [#(t1, Unbound(i)), ..constraints] -> + case map.get(s, i) { + Ok(t2) -> do_unify([#(t1, t2), ..constraints], s) + Error(Nil) -> do_unify(constraints, map.insert(s, i, t1)) + } + [#(Fn(a1, r1), Fn(a2, r2)), ..cs] -> + do_unify([#(a1, a2), #(r1, r2), ..cs], s) + _ -> Error(Nil) + } } - - pub type Run { - Done(#(map.Map(Int, Type), Int, #(List(Int), Type))) - Continue(#(map.Map(Int, Type), Int, #(List(Int), Type)), fn(#(map.Map(Int, Type), Int, #(List(Int), Type))) -> Run) + Done(#(map.Map(Int, Type), Int, #(List(Int), Type))) + Continue( + #(map.Map(Int, Type), Int, #(List(Int), Type)), + fn(#(map.Map(Int, Type), Int, #(List(Int), Type))) -> Run, + ) } // J gi @@ -88,97 +92,102 @@ pub type Run { // let's do j with effects and follow BUT the id's are NOT unique i.e. the types depend on the environment. // let's try global inference and see if it's faster pub fn step(env, exp, sub, next, path, k) { - case exp { - Var(x) -> { - let scheme = result.unwrap(get(env, x), #([], TErr("missing var"))) - let #(type_, next) = instantiate(scheme, next) - Continue(#(sub, next, #(path,type_)), k) - } - App(e1, e2) -> { - use #(sub1, next, #(_, t1)) <- step(env, e1, sub, next, [0,..path]) - use #(sub2, next, #(_, t2)) <- step(env, e2, sub1, next, [1,..path]) - let #(beta, next) = fresh(next) - // returns t error - let sub3 = case unify(t1, Fn(t2, beta), sub2) { - Ok(sub3) -> sub3 - // TODO record error - Error(_) -> sub - } - // let assert Ok(sub3) = - Continue(#(sub3, next, #(path,beta)), k) - } - Abs(x, e1) -> { - let #(beta, next) = fresh(next) - let env1 = extend(env, x, mono(beta)) - use #(sub1, next, #(_, t1)) <- step(env1, e1, sub, next, [0,..path]) - Continue(#(sub1, next, #(path,Fn(beta, t1))), k) - } - Let(x, e1, e2) -> { - use #(sub1, next, #(_, t1)) <- step(env, e1, sub, next, [0,..path]) - // generalise needs sub applied tot1 - let env1 = extend(env, x, generalise(env, t1)) - use #(sub2, next, #(_, t2)) <- step(env, e2, sub1, next, [1,..path]) - Continue(#(sub2, next, #(path,t2)), k) - } - Lit(Integer) -> Continue(#(sub, next, #(path,TInt)), k) - Lit(String) -> Continue(#(sub, next, #(path,TString)), k) + case exp { + Var(x) -> { + let scheme = result.unwrap(get(env, x), #([], TErr("missing var"))) + let #(type_, next) = instantiate(scheme, next) + Continue(#(sub, next, #(path, type_)), k) } - -} -pub fn loop(run) { - case run { - Done(r) -> r - Continue(r, k) -> { - io.debug(r) - loop(k(r)) - } + App(e1, e2) -> { + use #(sub1, next, #(_, t1)) <- step(env, e1, sub, next, [0, ..path]) + use #(sub2, next, #(_, t2)) <- step(env, e2, sub1, next, [1, ..path]) + let #(beta, next) = fresh(next) + // returns t error + let sub3 = case unify(t1, Fn(t2, beta), sub2) { + Ok(sub3) -> sub3 + // TODO record error + Error(_) -> sub + } + // let assert Ok(sub3) = + Continue(#(sub3, next, #(path, beta)), k) } -} - -pub fn j(env, exp, sub, next) { - loop(step(env, exp, sub, next, [], Done)) -} - -pub fn demo(items, k) { - case items { - [] -> k("done") - [g, ..rest] -> demo(rest, fn(x) { - // io.debug(g) - g + 1 - k(x) - }) + Abs(x, e1) -> { + let #(beta, next) = fresh(next) + let env1 = extend(env, x, mono(beta)) + use #(sub1, next, #(_, t1)) <- step(env1, e1, sub, next, [0, ..path]) + Continue(#(sub1, next, #(path, Fn(beta, t1))), k) + } + Let(x, e1, e2) -> { + use #(sub1, next, #(_, t1)) <- step(env, e1, sub, next, [0, ..path]) + // generalise needs sub applied tot1 + let env1 = extend(env, x, generalise(env, t1)) + use #(sub2, next, #(_, t2)) <- step(env, e2, sub1, next, [1, ..path]) + Continue(#(sub2, next, #(path, t2)), k) } + Lit(Integer) -> Continue(#(sub, next, #(path, TInt)), k) + Lit(String) -> Continue(#(sub, next, #(path, TString)), k) + } } -pub fn demo2(items, k) { - case items { - [] -> k("done") - [g, ..rest] -> { - use x <- demo2(rest) - // io.debug(g) - g + 1 - k(x) - } +pub fn loop(run) { + case run { + Done(r) -> r + Continue(r, k) -> { + io.debug(r) + loop(k(r)) + } + } +} + +pub fn j(env, exp, sub, next) { + loop(step(env, exp, sub, next, [], Done)) +} + +pub fn demo(items, k) { + case items { + [] -> k("done") + [g, ..rest] -> + demo( + rest, + fn(x) { + // io.debug(g) + g + 1 + k(x) + }, + ) + } +} + +pub fn demo2(items, k) { + case items { + [] -> k("done") + [g, ..rest] -> { + use x <- demo2(rest) + // io.debug(g) + g + 1 + k(x) } + } } // use twice makes reference to demo3, that blows the stack. Document this // TODO plinth library -pub fn demo3(items, k) { - case items { - [] -> k("done") - [g, ..rest] -> { - use x <- demo3(rest) - use y <- demo3(rest) - - // io.debug(g) - g + 1 - k(x) - } +pub fn demo3(items, k) { + case items { + [] -> k("done") + [g, ..rest] -> { + use x <- demo3(rest) + use y <- demo3(rest) + + // io.debug(g) + g + 1 + k(x) } + } +} + +pub fn order_test() { + j(map.new(), App(Lit(Integer), Lit(String)), map.new(), 0) + |> io.debug + todo } -pub fn order_test() { - j(map.new(), App(Lit(Integer),Lit(String)), map.new(), 0) - |> io.debug - todo -} \ No newline at end of file diff --git a/eyg/test/eyg/analysis/jm/incremental_test.gleam b/eyg/test/eyg/analysis/jm/incremental_test.gleam index 79897f559..e5cd6ad1a 100644 --- a/eyg/test/eyg/analysis/jm/incremental_test.gleam +++ b/eyg/test/eyg/analysis/jm/incremental_test.gleam @@ -1,9 +1,9 @@ - import eyg/incremental/source as e // constant folding and refernce pub fn foo_test(exp) -> Nil { + todo // case exp { // e.Var(Term(hash)) // e.Var(Brujin(index)) @@ -16,11 +16,8 @@ pub fn foo_test(exp) -> Nil { } // i -> free vars - // let y = 1 // let x = y -> x = hash(1) - // let f x -> // let y = x + 1 - diff --git a/eyg/test/eyg/analysis/jm/infer_test.gleam b/eyg/test/eyg/analysis/jm/infer_test.gleam index 09725adce..656416de5 100644 --- a/eyg/test/eyg/analysis/jm/infer_test.gleam +++ b/eyg/test/eyg/analysis/jm/infer_test.gleam @@ -16,16 +16,25 @@ import eyg/analysis/jm/incremental as jm import eyg/analysis/jm/type_ as jmt import eyg/analysis/jm/error as jm_error -fn call2(f,a,b) { +fn call2(f, a, b) { e.Apply(e.Apply(f, a), b) - } +} pub fn example_test() { - let exp = e.Let( - "equal", e.Builtin("equal"), - e.Let("_", call2(e.Variable("equal"), e.Binary(""), e.Binary("")), - e.Let("_", call2(e.Variable("equal"), e.Integer(1), e.Integer(1)), - e.Empty))) + let exp = + e.Let( + "equal", + e.Builtin("equal"), + e.Let( + "_", + call2(e.Variable("equal"), e.Binary(""), e.Binary("")), + e.Let( + "_", + call2(e.Variable("equal"), e.Integer(1), e.Integer(1)), + e.Empty, + ), + ), + ) let #(root, store) = store.load(store.empty(), exp) @@ -43,5 +52,4 @@ pub fn example_test() { // |> io.debug // io.debug(types |> map.to_list) } - -// TODO try and have test for recursive types in rows/effects \ No newline at end of file +// TODO try and have test for recursive types in rows/effects diff --git a/eyg/test/eyg/analysis/jm/unify_test.gleam b/eyg/test/eyg/analysis/jm/unify_test.gleam index 3ca8c3e2c..d29cc9d6b 100644 --- a/eyg/test/eyg/analysis/jm/unify_test.gleam +++ b/eyg/test/eyg/analysis/jm/unify_test.gleam @@ -4,14 +4,15 @@ import eyg/analysis/jm/type_ as t import eyg/analysis/jm/unify pub fn other_test() { - let assert Ok(#(s, _next)) = unify.unify( - t.Fun(t.Var(1), t.Empty, t.Var(1)), - t.Fun(t.Var(2), t.Empty, t.String), - map.new(), - 600 - ) + let assert Ok(#(s, _next)) = + unify.unify( + t.Fun(t.Var(1), t.Empty, t.Var(1)), + t.Fun(t.Var(2), t.Empty, t.String), + map.new(), + 600, + ) s |> map.to_list - |> io.debug + |> io.debug todo } diff --git a/eyg/test/eyg/incremental/store_test.gleam b/eyg/test/eyg/incremental/store_test.gleam index e2f862a80..29f081f7b 100644 --- a/eyg/test/eyg/incremental/store_test.gleam +++ b/eyg/test/eyg/incremental/store_test.gleam @@ -225,8 +225,3 @@ // should.equal(t, t.Integer) // panic // } - - - - - diff --git a/eyg/test/hash_test.gleam b/eyg/test/hash_test.gleam index 50296f612..0638915f4 100644 --- a/eyg/test/hash_test.gleam +++ b/eyg/test/hash_test.gleam @@ -107,7 +107,6 @@ pub fn round_trip_test() -> Nil { let source = linear(tree) decode(source) |> should.equal(Ok(#(tree, <<>>))) - // gather_hash(<<1, 1, "ab":utf8>>) // gather_hash(source) // TODO not really useful diff --git a/eyg/test/plinth/map_test.gleam b/eyg/test/plinth/map_test.gleam index 85f19b987..70bc261c7 100644 --- a/eyg/test/plinth/map_test.gleam +++ b/eyg/test/plinth/map_test.gleam @@ -2,26 +2,26 @@ import plinth/javascript/map import gleeunit/should pub fn map_size_test() { - let m = map.new() - should.equal(map.size(m), 0) + let m = map.new() + should.equal(map.size(m), 0) - map.set(m, "a", 1) - should.equal(map.size(m), 1) - - map.set(m, "b", 1) - should.equal(map.size(m), 2) - - map.set(m, "b", 10) - should.equal(map.size(m), 2) + map.set(m, "a", 1) + should.equal(map.size(m), 1) + + map.set(m, "b", 1) + should.equal(map.size(m), 2) + + map.set(m, "b", 10) + should.equal(map.size(m), 2) } -pub fn map_retrieve_test() { - let m = map.new() - should.equal(map.get(m, "a"), Error(Nil)) - - map.set(m, "a", 1) - should.equal(map.get(m, "a"), Ok(1)) - - map.set(m, "a", 2) - should.equal(map.get(m, "a"), Ok(2)) -} \ No newline at end of file +pub fn map_retrieve_test() { + let m = map.new() + should.equal(map.get(m, "a"), Error(Nil)) + + map.set(m, "a", 1) + should.equal(map.get(m, "a"), Ok(1)) + + map.set(m, "a", 2) + should.equal(map.get(m, "a"), Ok(2)) +} From e7f969fc93fd83b9bf4a6d79739d291aea304ea2 Mon Sep 17 00:00:00 2001 From: Peter Date: Thu, 27 Apr 2023 20:58:54 +0200 Subject: [PATCH 62/62] remove really useless tests --- eyg/test/examples/algorithm_w.gleam | 3 --- eyg/test/examples/algorithm_w_test.gleam | 5 ---- .../eyg/analysis/jm/incremental_test.gleam | 23 ------------------- eyg/test/eyg/analysis/jm/unify_test.gleam | 18 --------------- 4 files changed, 49 deletions(-) delete mode 100644 eyg/test/examples/algorithm_w.gleam delete mode 100644 eyg/test/examples/algorithm_w_test.gleam delete mode 100644 eyg/test/eyg/analysis/jm/incremental_test.gleam delete mode 100644 eyg/test/eyg/analysis/jm/unify_test.gleam diff --git a/eyg/test/examples/algorithm_w.gleam b/eyg/test/examples/algorithm_w.gleam deleted file mode 100644 index e05215725..000000000 --- a/eyg/test/examples/algorithm_w.gleam +++ /dev/null @@ -1,3 +0,0 @@ -pub fn w() { - "" -} diff --git a/eyg/test/examples/algorithm_w_test.gleam b/eyg/test/examples/algorithm_w_test.gleam deleted file mode 100644 index 84f7b379c..000000000 --- a/eyg/test/examples/algorithm_w_test.gleam +++ /dev/null @@ -1,5 +0,0 @@ -import examples/algorithm_w.{w} - -pub fn function_name_test() -> Nil { - todo -} diff --git a/eyg/test/eyg/analysis/jm/incremental_test.gleam b/eyg/test/eyg/analysis/jm/incremental_test.gleam deleted file mode 100644 index e5cd6ad1a..000000000 --- a/eyg/test/eyg/analysis/jm/incremental_test.gleam +++ /dev/null @@ -1,23 +0,0 @@ -import eyg/incremental/source as e - -// constant folding and refernce - -pub fn foo_test(exp) -> Nil { - todo - // case exp { - // e.Var(Term(hash)) - // e.Var(Brujin(index)) - // e.Var(Index(index)) - // e.Let -> - // e.Fn(x) -> { - // let vars = [x,..var] - // } - // } -} -// i -> free vars - -// let y = 1 -// let x = y -> x = hash(1) - -// let f x -> -// let y = x + 1 diff --git a/eyg/test/eyg/analysis/jm/unify_test.gleam b/eyg/test/eyg/analysis/jm/unify_test.gleam deleted file mode 100644 index d29cc9d6b..000000000 --- a/eyg/test/eyg/analysis/jm/unify_test.gleam +++ /dev/null @@ -1,18 +0,0 @@ -import gleam/io -import gleam/map -import eyg/analysis/jm/type_ as t -import eyg/analysis/jm/unify - -pub fn other_test() { - let assert Ok(#(s, _next)) = - unify.unify( - t.Fun(t.Var(1), t.Empty, t.Var(1)), - t.Fun(t.Var(2), t.Empty, t.String), - map.new(), - 600, - ) - s - |> map.to_list - |> io.debug - todo -}