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

Commit

Permalink
First pass at watches
Browse files Browse the repository at this point in the history
  • Loading branch information
jamii committed Sep 2, 2021
1 parent a6171cd commit 3182898
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 18 deletions.
2 changes: 1 addition & 1 deletion bin/run.zig
Expand Up @@ -35,7 +35,7 @@ pub fn main() anyerror!void {
.desired_id = &desired_id,
};
var error_info: ?imp.lang.InterpretErrorInfo = null;
const result = imp.lang.interpret(&arena, source.items, interrupter, &error_info);
const result = imp.lang.interpret(&arena, source.items, 0, interrupter, &error_info);
const writer = std.io.getStdOut().writer();
if (result) |type_and_set| {
try type_and_set.dumpInto(allocator, writer);
Expand Down
48 changes: 36 additions & 12 deletions lib/imp/lang.zig
Expand Up @@ -61,20 +61,34 @@ pub const InterpretError = pass.parse.Error ||
pass.analyze.Error ||
pass.interpret.Error;

pub const TypeAndSet = struct {
pub const InterpretResult = struct {
set_type: repr.type_.SetType,
set: repr.value.Set,
watch_results: []const repr.value.Set,
watch_range: ?[2]usize,

pub fn dumpInto(self: TypeAndSet, allocator: *Allocator, out_stream: anytype) anyerror!void {
pub fn dumpInto(self: InterpretResult, allocator: *Allocator, out_stream: anytype) anyerror!void {
try out_stream.writeAll("type:\n");
try self.set_type.dumpInto(out_stream);
try out_stream.writeAll("\nvalue:\n");
try self.set.dumpInto(allocator, out_stream);
try out_stream.writeAll("\n");
if (self.watch_range) |_| {
try out_stream.writeAll("\nwatch values:\n");
for (self.watch_results) |set| {
try set.dumpInto(allocator, out_stream);
try out_stream.writeAll("\n");
}
}
}
};

pub fn interpret(arena: *ArenaAllocator, source: []const u8, interrupter: Interrupter, error_info: *?InterpretErrorInfo) InterpretError!TypeAndSet {
pub fn interpret(
arena: *ArenaAllocator,
source: []const u8,
watch_position: usize,
interrupter: Interrupter,
error_info: *?InterpretErrorInfo,
) InterpretError!InterpretResult {
var store = Store.init(arena);

var parse_error_info: ?pass.parse.ErrorInfo = null;
Expand All @@ -101,17 +115,26 @@ pub fn interpret(arena: *ArenaAllocator, source: []const u8, interrupter: Interr
return err;
};

const watch_expr_o = store.findCoreExprAt(watch_position);
var watch_range: ?[2]usize = null;
if (watch_expr_o) |watch_expr| {
const watch_meta = Store.getSyntaxMeta(Store.getCoreMeta(watch_expr).from);
watch_range = .{ watch_meta.start, watch_meta.end };
}
var watch_results = ArrayList(repr.value.Set).init(&arena.allocator);
var interpret_error_info: ?pass.interpret.ErrorInfo = null;
const set = pass.interpret.interpret(&store, arena, core_expr, interrupter, &interpret_error_info) catch |err| {
const set = pass.interpret.interpret(&store, arena, core_expr, watch_expr_o, &watch_results, interrupter, &interpret_error_info) catch |err| {
if (err == error.InterpretError or err == error.NativeError) {
error_info.* = .{ .Interpret = interpret_error_info.? };
}
return err;
};

return TypeAndSet{
return InterpretResult{
.set_type = set_type,
.set = set,
.watch_results = watch_results.toOwnedSlice(),
.watch_range = watch_range,
};
}

Expand Down Expand Up @@ -141,6 +164,7 @@ pub const Worker = struct {
pub const Request = struct {
id: usize,
text: []const u8,
position: usize,
};

pub const Response = struct {
Expand All @@ -150,7 +174,7 @@ pub const Worker = struct {
};

pub const ResponseKind = union(enum) {
Ok,
Ok: ?[2]usize,
Err: ?[2]usize,
};

Expand Down Expand Up @@ -252,20 +276,20 @@ pub const Worker = struct {
defer _ = gpa.deinit();
var arena = ArenaAllocator.init(&gpa.allocator);
defer arena.deinit();
var error_info: ?imp.lang.InterpretErrorInfo = null;
const interrupter = Interrupter{
.current_id = new_request.id,
.desired_id = &self.desired_id,
};
const result = imp.lang.interpret(&arena, new_request.text, interrupter, &error_info);
var error_info: ?imp.lang.InterpretErrorInfo = null;
const result = imp.lang.interpret(&arena, new_request.text, new_request.position, interrupter, &error_info);

// print result
var response_buffer = ArrayList(u8).init(self.allocator);
defer response_buffer.deinit();
var response_kind: ResponseKind = undefined;
if (result) |type_and_set| {
try type_and_set.dumpInto(&arena.allocator, response_buffer.writer());
response_kind = .Ok;
if (result) |ok| {
try ok.dumpInto(&arena.allocator, response_buffer.writer());
response_kind = .{ .Ok = ok.watch_range };
} else |err| {
try InterpretErrorInfo.dumpInto(error_info, err, response_buffer.writer());
response_kind = .{ .Err = InterpretErrorInfo.error_range(error_info, err) };
Expand Down
16 changes: 15 additions & 1 deletion lib/imp/lang/pass/interpret.zig
Expand Up @@ -8,10 +8,12 @@ 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, 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,
.watch_expr_o = watch_expr_o,
.watch_results = watch_results,
.scope = ArrayList(value.Scalar).init(&store.arena.allocator),
.time = ArrayList(value.Time).init(&store.arena.allocator),
.boxes = DeepHashMap(value.LazySet, value.Set).init(&store.arena.allocator),
Expand Down Expand Up @@ -41,6 +43,8 @@ pub const ErrorInfo = struct {
const Interpreter = struct {
store: *const Store,
arena: *ArenaAllocator,
watch_expr_o: ?*const core.Expr,
watch_results: *ArrayList(value.Set),
scope: ArrayList(value.Scalar),
time: ArrayList(value.Time),
boxes: DeepHashMap(value.LazySet, value.Set),
Expand All @@ -66,6 +70,16 @@ const Interpreter = struct {
}

fn interpret(self: *Interpreter, expr: *const core.Expr, hint: value.Tuple) Error!value.Set {
const result = self.interpretInner(expr, hint);
if (self.watch_expr_o) |watch_expr|
if (expr == watch_expr)
if (result) |set|
try self.watch_results.append(set)
else |_| {};
return result;
}

fn interpretInner(self: *Interpreter, expr: *const core.Expr, hint: value.Tuple) Error!value.Set {
try self.interrupter.check();
switch (expr.*) {
.None => {
Expand Down
4 changes: 2 additions & 2 deletions lib/imp/lang/repr/value.zig
Expand Up @@ -60,9 +60,9 @@ pub const FiniteSet = struct {
}
}.lessThan);
if (tuples.items.len == 0) {
try out_stream.writeAll("none");
try out_stream.writeAll("none\n");
} else if (tuples.items.len == 1 and tuples.items[0].len == 0) {
try out_stream.writeAll("some");
try out_stream.writeAll("some\n");
} else {
for (tuples.items) |tuple| {
try out_stream.writeAll("| ");
Expand Down
31 changes: 30 additions & 1 deletion lib/imp/lang/store.zig
Expand Up @@ -19,13 +19,15 @@ pub const CoreMeta = struct {
pub const Store = struct {
arena: *ArenaAllocator,
next_expr_id: usize,
core_exprs: ArrayList(*const core.Expr),
specializations: DeepHashMap(type_.LazySetType, ArrayList(Specialization)),

pub fn init(arena: *ArenaAllocator) Store {
return Store{
.arena = arena,
.specializations = DeepHashMap(type_.LazySetType, ArrayList(Specialization)).init(&arena.allocator),
.next_expr_id = 0,
.core_exprs = ArrayList(*const core.Expr).init(&arena.allocator),
.specializations = DeepHashMap(type_.LazySetType, ArrayList(Specialization)).init(&arena.allocator),
};
}

Expand All @@ -52,6 +54,7 @@ pub const Store = struct {
.id = id,
},
};
try self.core_exprs.append(&expr_and_meta.expr);
return &expr_and_meta.expr;
}

Expand All @@ -65,6 +68,32 @@ 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 {
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;
}

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| {
const match_meta = Store.getSyntaxMeta(Store.getCoreMeta(best_match).from);
if (match_meta.end <= position) return best_match;
}
return null;
}

pub fn putSpecialization(self: *Store, lazy: type_.LazySetType, hint: []const type_.ScalarType, set_type: type_.SetType) !void {
const used_hint = switch (set_type) {
// always empty so can't say how much of the hint was used
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, interrupter, &error_info);
const result = imp.lang.interpret(&arena, input, 0, interrupter, &error_info);

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

0 comments on commit 3182898

Please sign in to comment.