Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Live Projectors #1420

Open
wants to merge 63 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
881a086
projectors live init: an attempt at extracing vals for projectors: in…
disconcision Nov 20, 2024
1d07174
clarify live projector statics
disconcision Nov 20, 2024
08c21d1
live projectors view layer. minimal poc complete
disconcision Nov 20, 2024
535ec65
merge
disconcision Nov 25, 2024
dfbd034
rename Dynamics
disconcision Nov 25, 2024
376f411
dynamics probes for live projectors. experiment with ExpToSegment
disconcision Nov 25, 2024
09d08e9
projector probes have access to values and reference environments
disconcision Nov 30, 2024
4ce84f1
surface projector probe reference environment display on hover
disconcision Dec 4, 2024
323338f
typo
disconcision Dec 6, 2024
34b27e4
Merge branch 'editor-output' of github.com:hazelgrove/hazel into proj…
disconcision Dec 6, 2024
48ee429
basic value abbreviator
disconcision Dec 7, 2024
ce355ab
drag to resize value abbreviations
disconcision Dec 9, 2024
4415b81
simple persistent closure cursor
disconcision Dec 10, 2024
5e93bc6
closureenv cleanup. probe style tweaks
disconcision Dec 10, 2024
18c4751
live projectors cleanup
disconcision Dec 10, 2024
2f94e7a
live projectors view cleanup
disconcision Dec 11, 2024
0ee836b
live projectors in exercises mode
disconcision Dec 11, 2024
0af9929
alt/option-v to toggle probes. partial fix to projector panel desync bug
disconcision Dec 11, 2024
8dd2f78
probe projectors: better logic for closure co-inhabitation. better style
disconcision Dec 13, 2024
fffd013
clean up live projectors maketerm
disconcision Dec 16, 2024
dc8ebfe
projectors live cleanup
disconcision Dec 16, 2024
d64e739
projectors live cleanup
disconcision Dec 16, 2024
18ceb80
accidentally a dir
disconcision Dec 16, 2024
1ea2ac4
live projectors cleanup
disconcision Dec 16, 2024
31c8e72
merge fix
disconcision Dec 16, 2024
953e4a2
truncate probe projector closures lists after 30 items, controls to s…
disconcision Dec 19, 2024
6da6244
probe projectors on patterns
disconcision Dec 22, 2024
bfe13af
fixed bug with wrong env being passed to live projectors on function …
disconcision Dec 22, 2024
8ea387e
better styling for live pat probe
disconcision Dec 22, 2024
6fb7a52
probe projector ap descent indication
disconcision Dec 28, 2024
8640845
probe projector ap indication in patterns. css cleanup
disconcision Dec 28, 2024
9ce7709
style deeper stack ap indications differently than first degree
disconcision Dec 29, 2024
10c3a35
projector API flag for dynamics collection
disconcision Dec 29, 2024
527d392
all probe cells now individually resizable
disconcision Dec 29, 2024
b4ddee2
fix binding not found bug
disconcision Jan 2, 2025
d6d4b20
telescope (ap) probes style
disconcision Jan 6, 2025
4ae4695
fix issue with projector metrics being misaligned in stepper. fix pro…
disconcision Jan 13, 2025
d5125cf
merge fix
disconcision Jan 13, 2025
04c9fbc
rename Parens to Wrap, which includes as sub-cases both Parens and Probe
disconcision Jan 14, 2025
6fc30f3
upgrade projector shape API
disconcision Jan 14, 2025
9243224
cleanup
disconcision Jan 14, 2025
69fb87e
cleanup
disconcision Jan 14, 2025
2bda1f7
incorporate probe projector offside view into projectors API
disconcision Jan 14, 2025
4b84511
give projectors access to maketerm through utility
disconcision Jan 14, 2025
e843e6b
indicate the 'outer ap' a closure was created by
disconcision Jan 14, 2025
639d0b5
projector probe state refactor
disconcision Jan 14, 2025
28fb563
fixed ap tracking bug. added probe doc slide
disconcision Jan 14, 2025
2c211dd
better probe doc slide
disconcision Jan 15, 2025
65cc47a
merge dev
disconcision Jan 15, 2025
71cf598
group probe cells according to call
disconcision Jan 15, 2025
474fe84
cleanup
disconcision Jan 15, 2025
3925e0a
probe css cleanup
disconcision Jan 15, 2025
0325d22
pin aps for probe projector
disconcision Jan 15, 2025
9d4852f
clicking on probe projector now selects first cell. improved nav arro…
disconcision Jan 16, 2025
63b8368
dev merge
disconcision Jan 16, 2025
e592948
projector update functions now have access to the semantic info pack
disconcision Jan 16, 2025
c2668c9
add icon license readme. probe cleanup
disconcision Jan 16, 2025
4c48765
projector api addition: overlay view (view which is rendered above th…
disconcision Jan 17, 2025
de876b5
added optional underlay view to projectors API
disconcision Jan 17, 2025
620fcff
equals sign for projectors. fix pin deco somewhat. better value abbre…
disconcision Jan 17, 2025
60e980d
probe style tweaks
disconcision Jan 17, 2025
127f6f1
refactor projector view data flow
disconcision Jan 17, 2025
b603c56
cleanup
disconcision Jan 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions licenses/Icons.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The icons used in Hazel, including the Hazel icon, are from The Noun Project (https://thenounproject.com/) under the Icon Pro license (https://thenounproject.com/legal/terms-of-use/#icon-licenses).
25 changes: 25 additions & 0 deletions src/haz3lcore/FontMetrics.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
open Util;
open Js_of_ocaml;

[@deriving (show({with_path: false}), sexp, yojson)]
type t = {
row_height: float,
col_width: float,
};

let init = {row_height: 10., col_width: 10.};

let get_goal =
(
~font_metrics: t,
text_box: Js.t(Dom_html.element),
e: Js.t(Dom_html.mouseEvent),
)
: Point.t => {
open Float;
let x_rel = of_int(e##.clientX) -. text_box##getBoundingClientRect##.left;
let y_rel = of_int(e##.clientY) -. text_box##getBoundingClientRect##.top;
let row = to_int(y_rel /. font_metrics.row_height);
let col = to_int(round(x_rel /. font_metrics.col_width));
{row, col};
};
45 changes: 29 additions & 16 deletions src/haz3lcore/Measured.re
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ type t = {
secondary: Id.Map.t(measurement),
projectors: Id.Map.t(measurement),
rows: Rows.t,
linebreaks: Id.Map.t(rel_indent),
};

let empty = {
Expand All @@ -65,7 +64,6 @@ let empty = {
secondary: Id.Map.empty,
projectors: Id.Map.empty,
rows: Rows.empty,
linebreaks: Id.Map.empty,
};

let add_s = (id: Id.t, i: int, m, map) => {
Expand Down Expand Up @@ -131,11 +129,6 @@ let rec add_n_rows = (origin: Point.t, row_indent, n: abs_indent, map: t): t =>
|> add_row(origin.row + n - 1, {indent: row_indent, max_col: origin.col})
};

let add_lb = (id, indent, map) => {
...map,
linebreaks: Id.Map.add(id, indent, map.linebreaks),
};

let singleton_w = (w, m) => empty |> add_w(w, m);
let singleton_g = (g, m) => empty |> add_g(g, m);
let singleton_s = (id, shard, m) => empty |> add_s(id, shard, m);
Expand All @@ -147,8 +140,6 @@ let find_shards = (~msg="", t: Tile.t, map) =>
| _ => failwith("find_shards: " ++ msg)
};

let find_opt_lb = (id, map) => Id.Map.find_opt(id, map.linebreaks);

let find_shards' = (id: Id.t, map) =>
switch (Id.Map.find_opt(id, map.tiles)) {
| None => []
Expand Down Expand Up @@ -282,7 +273,8 @@ let last_of_token = (token: string, origin: Point.t): Point.t =>
row: origin.row + StringUtil.num_linebreaks(token),
};

let of_segment = (seg: Segment.t, info_map: Statics.Map.t): t => {
let of_segment =
(seg: Segment.t, shape_of_proj: Base.projector => ProjectorShape.t): t => {
let is_indented = is_indented_map(seg);

// recursive across seg's bidelimited containers
Expand Down Expand Up @@ -340,7 +332,7 @@ let of_segment = (seg: Segment.t, info_map: Statics.Map.t): t => {
origin.row,
{indent: row_indent, max_col: origin.col},
)
|> add_lb(w.id, indent);
|> add_n_rows(origin, row_indent, 1);
(indent, last, map);
| Secondary(w) =>
let wspace_length =
Expand All @@ -353,11 +345,25 @@ let of_segment = (seg: Segment.t, info_map: Statics.Map.t): t => {
let map = map |> add_g(g, {origin, last});
(contained_indent, last, map);
| Projector(p) =>
let token =
Projector.placeholder(p, Id.Map.find_opt(p.id, info_map));
let last = last_of_token(token, origin);
let map = extra_rows(token, origin, map);
let map = add_pr(p, {origin, last}, map);
let row_indent = container_indent + contained_indent;
let shape = shape_of_proj(p);
let num_extra_rows =
switch (shape.vertical) {
| Inline => 0
| Block(num_lbs) => num_lbs
};
let last = {
col: origin.col + shape.horizontal,
row:
switch (shape.vertical) {
| Inline => origin.row
| Block(num_lb) => origin.row + num_lb
},
};
let map =
map
|> add_n_rows(origin, row_indent, num_extra_rows)
|> add_pr(p, {origin, last});
(contained_indent, last, map);
| Tile(t) =>
let add_shard = (origin, shard, map) => {
Expand Down Expand Up @@ -403,3 +409,10 @@ let length = (seg: Segment.t, map: t): int =>
let last = find_p(ListUtil.last(tl), map);
last.last.col - first.origin.col;
};

/* Width in characters of row at measurement.origin */
let start_row_width = (measurement: measurement, measured: t): int =>
switch (IntMap.find_opt(measurement.origin.row, measured.rows)) {
| None => 0
| Some(row) => row.max_col
};
2 changes: 1 addition & 1 deletion src/haz3lcore/dynamics/Casts.re
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ let rec ground_cases_of = (ty: Typ.t): ground_cases => {
| Forall(_, {term: Unknown(_), _})
| Arrow({term: Unknown(_), _}, {term: Unknown(_), _})
| List({term: Unknown(_), _}) => Ground
| Parens(ty) => ground_cases_of(ty)
| Wrap(ty) => ground_cases_of(ty)
| Prod(tys) =>
if (List.for_all(
fun
Expand Down
4 changes: 2 additions & 2 deletions src/haz3lcore/dynamics/DHExp.re
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ let rec strip_casts =
| UnOp(_)
| BinOp(_)
| Match(_)
| Parens(_)
| Wrap(_)
| EmptyHole
| Invalid(_)
| Var(_)
Expand Down Expand Up @@ -161,7 +161,7 @@ let ty_subst = (s: Typ.t, tpat: TPat.t, exp: t): t => {
| Deferral(_)
| TyAlias(_)
| DeferredAp(_)
| Parens(_)
| Wrap(_)
| UnOp(_) => continue(exp)
},
exp,
Expand Down
4 changes: 4 additions & 0 deletions src/haz3lcore/dynamics/EvalCtx.re
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type term =
| BinOp2(Operators.op_bin, DHExp.t, t)
| Tuple(t, (list(DHExp.t), list(DHExp.t)))
| Test(t)
| Wrap(t, Probe.tag)
| ListLit(t, (list(DHExp.t), list(DHExp.t)))
| MultiHole(t, (list(Any.t), list(Any.t)))
| Cons1(t, DHExp.t)
Expand Down Expand Up @@ -88,6 +89,9 @@ let rec compose = (ctx: t, d: DHExp.t): DHExp.t => {
| Test(ctx) =>
let d1 = compose(ctx, d);
Test(d1) |> wrap;
| Wrap(ctx, tag) =>
let d1 = compose(ctx, d);
Wrap(d1, tag) |> wrap;
| UnOp(op, ctx) =>
let d1 = compose(ctx, d);
UnOp(op, d1) |> wrap;
Expand Down
3 changes: 3 additions & 0 deletions src/haz3lcore/dynamics/Evaluator.re
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ module EvaluatorEVMode: {
let update_test = (state, id, v) =>
state := EvaluatorState.add_test(state^, id, v);

let update_probe = (state, id, v) =>
disconcision marked this conversation as resolved.
Show resolved Hide resolved
state := EvaluatorState.add_closure(state^, id, v);

let req_final = (f, _, x) => {
let.trampoline x' = Next(() => f(x));
Trampoline.return(x' |> snd);
Expand Down
14 changes: 12 additions & 2 deletions src/haz3lcore/dynamics/EvaluatorState.re
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@
type t = {
stats: EvaluatorStats.t,
tests: TestMap.t,
probes: Dynamics.Probe.Map.t,
};

let init = {stats: EvaluatorStats.initial, tests: TestMap.empty};
let init = {
stats: EvaluatorStats.initial,
tests: TestMap.empty,
probes: Dynamics.Probe.Map.empty,
};

let take_step = ({stats, _} as es) => {
...es,
Expand All @@ -22,4 +27,9 @@ let add_test = ({tests, _} as es, id, report) => {

let get_tests = ({tests, _}) => tests;

let put_tests = (tests, es) => {...es, tests};
let add_closure = ({probes, _} as es, id: Id.t, v: Dynamics.Probe.Closure.t) => {
...es,
probes: Dynamics.Probe.Map.extend(id, v, probes),
};

let get_probes = ({probes, _}) => probes;
4 changes: 3 additions & 1 deletion src/haz3lcore/dynamics/EvaluatorState.rei
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,6 @@ let add_test: (t, Id.t, TestMap.instance_report) => t;

let get_tests: t => TestMap.t;

let put_tests: (TestMap.t, t) => t;
let add_closure: (t, Id.t, Dynamics.Probe.Closure.t) => t;

let get_probes: t => Dynamics.Probe.Map.t;
8 changes: 8 additions & 0 deletions src/haz3lcore/dynamics/EvaluatorStep.re
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ let rec matches =
| Test(ctx) =>
let+ ctx = matches(env, flt, ctx, exp, act, idx);
Test(ctx) |> rewrap;
| Wrap(ctx, tag) =>
let+ ctx = matches(env, flt, ctx, exp, act, idx);
Wrap(ctx, tag) |> rewrap;
| ListLit(ctx, ds) =>
let+ ctx = matches(env, flt, ctx, exp, act, idx);
ListLit(ctx, ds) |> rewrap;
Expand Down Expand Up @@ -298,6 +301,8 @@ module Decompose = {
let otherwise = (env, o) => (o, Result.BoxedValue, env, ());
let update_test = (state, id, v) =>
state := EvaluatorState.add_test(state^, id, v);
let update_probe = (state, id, info) =>
state := EvaluatorState.add_closure(state^, id, info);
};

module Decomp = Transition(DecomposeEVMode);
Expand Down Expand Up @@ -339,6 +344,9 @@ module TakeStep = {

let update_test = (state, id, v) =>
state := EvaluatorState.add_test(state^, id, v);

let update_probe = (state, id, info) =>
state := EvaluatorState.add_closure(state^, id, info);
};

module TakeStepEV = Transition(TakeStepEVMode);
Expand Down
13 changes: 3 additions & 10 deletions src/haz3lcore/dynamics/FilterMatcher.re
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
let evaluate_extend_env =
(new_bindings: Environment.t, to_extend: ClosureEnvironment.t)
: ClosureEnvironment.t => {
to_extend
|> ClosureEnvironment.map_of
|> Environment.union(new_bindings)
|> ClosureEnvironment.of_environment;
};
let evaluate_extend_env = ClosureEnvironment.extend_eval;

let evaluate_extend_env_with_pat =
(
Expand Down Expand Up @@ -104,8 +97,8 @@ let rec matches_exp =
true;
} else {
switch (d |> DHExp.term_of, f |> DHExp.term_of) {
| (Parens(d), _) => matches_exp(d, f)
| (_, Parens(f)) => matches_exp(d, f)
| (Wrap(d, _), _) => matches_exp(d, f)
| (_, Wrap(f, _)) => matches_exp(d, f)

| (Constructor("$e", _), _) => failwith("$e in matched expression")
| (Constructor("$v", _), _) => failwith("$v in matched expression")
Expand Down
38 changes: 37 additions & 1 deletion src/haz3lcore/dynamics/PatternMatch.re
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,26 @@ let combine_result = (r1: match_result, r2: match_result): match_result =>
Matches(Environment.union(env1, env2))
};

type closure_closures =
list((Probe.stack, Probe.stack) => (Id.t, Dynamics.Probe.Closure.t));
let closure_closures: ref(closure_closures) = ref([]);

let capture_closure = (pr, id: Id.t, d, inner_match: match_result): unit =>
switch (inner_match) {
| DoesNotMatch => ()
| IndetMatch => ()
| Matches(env) =>
closure_closures :=
List.cons(
(stack, dyn_stack) =>
(
id,
Dynamics.Probe.Closure.mk(d, {env, stack, dyn_stack, id}, pr),
),
closure_closures^,
)
};

let rec matches = (dp: Pat.t, d: DHExp.t): match_result =>
switch (DHPat.term_of(dp)) {
| Invalid(_)
Expand Down Expand Up @@ -55,7 +75,23 @@ let rec matches = (dp: Pat.t, d: DHExp.t): match_result =>
let* ds = Unboxing.unbox(Tuple(List.length(ps)), d);
List.map2(matches, ps, ds)
|> List.fold_left(combine_result, Matches(Environment.empty));
| Parens(p) => matches(p, d)
| Wrap(p, Paren) => matches(p, d)
| Wrap(p, Probe(pr)) =>
let inner_match = matches(p, d);
capture_closure(pr, Term.Pat.rep_id(dp), d, inner_match);
inner_match;
| Cast(p, t1, t2) =>
matches(p, Cast(d, t2, t1) |> DHExp.fresh |> Casts.transition_multiple)
};

type matches_and_closures = {
matches: match_result,
closures: closure_closures,
};

// wrap matches but do stateful thing (closure capture)
let matches = (dp: Pat.t, d: DHExp.t): matches_and_closures => {
closure_closures := [];
let res = matches(dp, d);
{matches: res, closures: closure_closures^};
};
38 changes: 38 additions & 0 deletions src/haz3lcore/dynamics/Probe.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
open Util;

/* A syntax probe is inserted into syntax to capture
* information during evaluation. The tag type below,
* for the probe case, is used to collect binding ids
* which are used to faciltate capturing the values
* of certain variables in the environment. This captured
* information is, for a given closure, encoded in
* the `frame` type. */

[@deriving (show({with_path: false}), sexp, yojson)]
type t = {
refs: Binding.s,
stem: Binding.stem,
};

[@deriving (show({with_path: false}), sexp, yojson)]
type tag =
| Paren
| Probe(t);

/* Information about the evaluation of an ap */
[@deriving (show({with_path: false}), sexp, yojson)]
type frame = {
ap_id: Id.t, /* Syntax ID of the ap */
env_id: Id.t /* ID of env in which ap was applied */
};

/* List of applications prior to some evaluation */
[@deriving (show({with_path: false}), sexp, yojson)]
type stack = list(frame);

let empty: t = {refs: [], stem: []};

let env_stack: list(frame) => list(Id.t) =
List.map((en: frame) => en.env_id);

let mk_frame = (~env_id: Id.t, ~ap_id: Id.t): frame => {env_id, ap_id};
Loading
Loading