Skip to content

Commit ba7870b

Browse files
committed
Add option type handling: drop Nones and provide default values in column menu
1 parent b2acebd commit ba7870b

File tree

1 file changed

+111
-1
lines changed

1 file changed

+111
-1
lines changed

src/haz3lcore/projectors/implementations/TableRenderer.re

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,13 @@ let get_columns = (ty: Typ.t): option(list(string)) => {
153153
};
154154
};
155155

156+
/* Check if a type is an Option type (+None +Some(?)) */
157+
let is_option_type = (ty: Typ.t): bool => {
158+
let ctx = Builtins.ctx_init(Some(Int));
159+
Typ.is_consistent(ctx, ty, BuiltinsADT.Option.t)
160+
&& Typ.is_more_precise(ctx, ty, BuiltinsADT.Option.t);
161+
};
162+
156163
let strip_parens =
157164
Exp.map_term(~f_exp=(continue, e) =>
158165
switch (e.term) {
@@ -343,6 +350,81 @@ let filter_by_column = (op, info: info, column: string): Base.segment => {
343350
);
344351
};
345352

353+
/* Drop rows where the option column is None, unwrapping Some values */
354+
let drop_nones_column = (info: info, column: string): Base.segment => {
355+
IdTagged.FreshGrammar.(
356+
apply_transformation(
357+
info,
358+
Exp.(
359+
ap(
360+
Forward,
361+
var("filter_map"),
362+
tuple([
363+
deferral(InAp),
364+
fn(
365+
Pat.var("row"),
366+
ap(
367+
Forward,
368+
var("option_map"),
369+
tuple([
370+
dot(var("row"), label(column)),
371+
fn(
372+
Pat.var("v"),
373+
tuple_extension(
374+
var("row"),
375+
tuple([tup_label(label(column), var("v"))]),
376+
),
377+
None,
378+
None,
379+
),
380+
]),
381+
),
382+
None,
383+
None,
384+
),
385+
]),
386+
)
387+
),
388+
)
389+
);
390+
};
391+
392+
/* Replace None values with an expression hole for user to fill in default */
393+
let provide_default_column = (info: info, column: string): Base.segment => {
394+
IdTagged.FreshGrammar.(
395+
apply_rowwise_transformation(
396+
info,
397+
Exp.(
398+
fn(
399+
Pat.var("row"),
400+
tuple_extension(
401+
var("row"),
402+
tuple([
403+
tup_label(
404+
label(column),
405+
match(
406+
dot(var("row"), label(column)),
407+
[
408+
/* None => hole for user to fill in */
409+
(BuiltinsADT.Option.pat_none, empty_hole()),
410+
/* Some(x) => x */
411+
(
412+
Pat.ap(BuiltinsADT.Option.pat_some, Pat.var("v")),
413+
var("v"),
414+
),
415+
],
416+
),
417+
),
418+
]),
419+
),
420+
None,
421+
None,
422+
)
423+
),
424+
)
425+
);
426+
};
427+
346428
let get_dynamic_type = (exp: Exp.t): option(Typ.t) => {
347429
let statics = Statics.mk(CoreSettings.on, Builtins.ctx_init(Some(Int)));
348430
IdTagged.rep_id(exp)
@@ -807,6 +889,33 @@ let build_column_menu =
807889
| None => []
808890
};
809891

892+
/* Option type actions: Drop Nones and Provide Default */
893+
let option_items =
894+
switch (column_type) {
895+
| Some(ty) =>
896+
is_option_type(ty)
897+
? [
898+
Action({
899+
text: "Drop Nones",
900+
action: () =>
901+
Effect.Many([
902+
local(CloseMenu),
903+
parent(SetSyntax(drop_nones_column(info, h))),
904+
]),
905+
}),
906+
Action({
907+
text: "Provide Default",
908+
action: () =>
909+
Effect.Many([
910+
local(CloseMenu),
911+
parent(SetSyntax(provide_default_column(info, h))),
912+
]),
913+
}),
914+
]
915+
: []
916+
| None => []
917+
};
918+
810919
base_items
811920
@ [
812921
Action({
@@ -821,7 +930,8 @@ let build_column_menu =
821930
@ conversion_submenu
822931
@ move_items
823932
@ sort_submenu
824-
@ filter_submenu;
933+
@ filter_submenu
934+
@ option_items;
825935
| _ => [] // Unknown menu path
826936
};
827937
};

0 commit comments

Comments
 (0)