Skip to content
This repository has been archived by the owner on Dec 5, 2022. It is now read-only.

Commit

Permalink
Allow selecting ranges for watches
Browse files Browse the repository at this point in the history
  • Loading branch information
jamii committed Sep 2, 2021
1 parent 3182898 commit 798215d
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 21 deletions.
8 changes: 4 additions & 4 deletions lib/imp/lang.zig
Expand Up @@ -85,7 +85,7 @@ pub const InterpretResult = struct {
pub fn interpret(
arena: *ArenaAllocator,
source: []const u8,
watch_position: usize,
watch_selection: Store.SourceSelection,
interrupter: Interrupter,
error_info: *?InterpretErrorInfo,
) InterpretError!InterpretResult {
Expand Down Expand Up @@ -115,7 +115,7 @@ pub fn interpret(
return err;
};

const watch_expr_o = store.findCoreExprAt(watch_position);
const watch_expr_o = store.findCoreExprAt(watch_selection);
var watch_range: ?[2]usize = null;
if (watch_expr_o) |watch_expr| {
const watch_meta = Store.getSyntaxMeta(Store.getCoreMeta(watch_expr).from);
Expand Down Expand Up @@ -164,7 +164,7 @@ pub const Worker = struct {
pub const Request = struct {
id: usize,
text: []const u8,
position: usize,
selection: Store.SourceSelection,
};

pub const Response = struct {
Expand Down Expand Up @@ -281,7 +281,7 @@ pub const Worker = struct {
.desired_id = &self.desired_id,
};
var error_info: ?imp.lang.InterpretErrorInfo = null;
const result = imp.lang.interpret(&arena, new_request.text, new_request.position, interrupter, &error_info);
const result = imp.lang.interpret(&arena, new_request.text, new_request.selection, interrupter, &error_info);

// print result
var response_buffer = ArrayList(u8).init(self.allocator);
Expand Down
10 changes: 9 additions & 1 deletion lib/imp/lang/pass/interpret.zig
Expand Up @@ -8,7 +8,15 @@ const value = imp.lang.repr.value;
/// Guarantees:
/// * If expr typechecks then this will not return InterpretError
/// * If expr has a finite type then this will return a value.Set.Finite
pub fn interpret(store: *const Store, arena: *ArenaAllocator, expr: *const core.Expr, watch_expr_o: ?*const core.Expr, watch_results: *ArrayList(value.Set), interrupter: imp.lang.Interrupter, error_info: *?ErrorInfo) Error!value.Set {
pub fn interpret(
store: *const Store,
arena: *ArenaAllocator,
expr: *const core.Expr,
watch_expr_o: ?*const core.Expr,
watch_results: *ArrayList(value.Set),
interrupter: imp.lang.Interrupter,
error_info: *?ErrorInfo,
) Error!value.Set {
var interpreter = Interpreter{
.store = store,
.arena = arena,
Expand Down
51 changes: 36 additions & 15 deletions lib/imp/lang/store.zig
Expand Up @@ -68,28 +68,49 @@ pub const Store = struct {
return &@fieldParentPtr(ExprAndMeta(core.Expr, CoreMeta), "expr", expr).meta;
}

fn betterMatchForPosition(position: usize, a: *const core.Expr, b: *const core.Expr) bool {
pub const SourceSelection = union(enum) {
Point: usize,
Range: [2]usize,
};
fn betterMatchForPosition(selection: SourceSelection, a: *const core.Expr, b: *const core.Expr) bool {
const a_core_meta = Store.getCoreMeta(a);
const a_syntax_meta = Store.getSyntaxMeta(a_core_meta.from);
const b_core_meta = Store.getCoreMeta(b);
const b_syntax_meta = Store.getSyntaxMeta(b_core_meta.from);
// anything past position is not a match
if (a_syntax_meta.end > position) return false;
if (b_syntax_meta.end > position) return true;
// the expr that ends closest to position is the best match
if (a_syntax_meta.end > b_syntax_meta.end) return true;
if (a_syntax_meta.end < b_syntax_meta.end) return false;
// if both end at the same point, the expr that is longest is the best match
if (a_syntax_meta.start < b_syntax_meta.start) return true;
if (a_syntax_meta.start > b_syntax_meta.start) return false;
// if both have same length, return the outermost expr in the tree
return a_core_meta.id > b_core_meta.id;
switch (selection) {
.Point => |point| {
// anything past point is not a match
if (a_syntax_meta.end > point) return false;
if (b_syntax_meta.end > point) return true;
// the expr that ends closest to point is the best match
if (a_syntax_meta.end > b_syntax_meta.end) return true;
if (a_syntax_meta.end < b_syntax_meta.end) return false;
// if both end at the same point, the expr that is longest is the best match
if (a_syntax_meta.start < b_syntax_meta.start) return true;
if (a_syntax_meta.start > b_syntax_meta.start) return false;
// if both have same length, return the outermost expr in the tree
return a_core_meta.id > b_core_meta.id;
},
.Range => |range| {
// anything outside range is not a match
if (a_syntax_meta.start < range[0] or a_syntax_meta.end > range[1]) return false;
if (b_syntax_meta.start < range[0] or b_syntax_meta.end > range[1]) return true;
// the expr that is longest is the best match
if (a_syntax_meta.end - a_syntax_meta.start > b_syntax_meta.end - b_syntax_meta.start) return true;
if (a_syntax_meta.end - a_syntax_meta.start < b_syntax_meta.end - b_syntax_meta.start) return false;
// if both have the same length, return the outermost expr in the tree
return a_core_meta.id > b_core_meta.id;
},
}
}

pub fn findCoreExprAt(self: Store, position: usize) ?*const core.Expr {
if (std.sort.min(*const core.Expr, self.core_exprs.items, position, betterMatchForPosition)) |best_match| {
pub fn findCoreExprAt(self: Store, selection: SourceSelection) ?*const core.Expr {
if (std.sort.min(*const core.Expr, self.core_exprs.items, selection, betterMatchForPosition)) |best_match| {
const match_meta = Store.getSyntaxMeta(Store.getCoreMeta(best_match).from);
if (match_meta.end <= position) return best_match;
switch (selection) {
.Point => |point| if (match_meta.end <= point) return best_match,
.Range => |range| if (match_meta.start >= range[0] and match_meta.end <= range[1]) return best_match,
}
}
return null;
}
Expand Down
2 changes: 1 addition & 1 deletion test/end_to_end.zig
Expand Up @@ -49,7 +49,7 @@ pub fn main() anyerror!void {
.desired_id = &desired_id,
};
var error_info: ?imp.lang.InterpretErrorInfo = null;
const result = imp.lang.interpret(&arena, input, 0, interrupter, &error_info);
const result = imp.lang.interpret(&arena, input, .{ .Point = 0 }, interrupter, &error_info);

var bytes = ArrayList(u8).init(allocator);
defer bytes.deinit();
Expand Down

0 comments on commit 798215d

Please sign in to comment.