add the anyframe and anyframe->T types

This commit is contained in:
Andrew Kelley
2019-07-26 19:52:35 -04:00
parent 018a89c7a1
commit ee64a22045
19 changed files with 337 additions and 50 deletions

View File

@@ -540,6 +540,7 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type
.Undefined,
.ArgTuple,
.Frame,
.AnyFrame,
=> @compileError("cannot hash this type"),
.Void,

View File

@@ -30,6 +30,7 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
.ArgTuple,
.Opaque,
.Frame,
.AnyFrame,
=> @compileError("value of type " ++ @typeName(@typeOf(actual)) ++ " encountered"),
.Undefined,

View File

@@ -400,7 +400,7 @@ pub const Node = struct {
VarType,
ErrorType,
FnProto,
PromiseType,
AnyFrameType,
// Primary expressions
IntegerLiteral,
@@ -952,9 +952,9 @@ pub const Node = struct {
}
};
pub const PromiseType = struct {
pub const AnyFrameType = struct {
base: Node,
promise_token: TokenIndex,
anyframe_token: TokenIndex,
result: ?Result,
pub const Result = struct {
@@ -962,7 +962,7 @@ pub const Node = struct {
return_type: *Node,
};
pub fn iterate(self: *PromiseType, index: usize) ?*Node {
pub fn iterate(self: *AnyFrameType, index: usize) ?*Node {
var i = index;
if (self.result) |result| {
@@ -973,13 +973,13 @@ pub const Node = struct {
return null;
}
pub fn firstToken(self: *const PromiseType) TokenIndex {
return self.promise_token;
pub fn firstToken(self: *const AnyFrameType) TokenIndex {
return self.anyframe_token;
}
pub fn lastToken(self: *const PromiseType) TokenIndex {
pub fn lastToken(self: *const AnyFrameType) TokenIndex {
if (self.result) |result| return result.return_type.lastToken();
return self.promise_token;
return self.anyframe_token;
}
};

View File

@@ -1201,7 +1201,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
/// / KEYWORD_error DOT IDENTIFIER
/// / KEYWORD_false
/// / KEYWORD_null
/// / KEYWORD_promise
/// / KEYWORD_anyframe
/// / KEYWORD_true
/// / KEYWORD_undefined
/// / KEYWORD_unreachable
@@ -1256,11 +1256,11 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
}
if (eatToken(it, .Keyword_false)) |token| return createLiteral(arena, Node.BoolLiteral, token);
if (eatToken(it, .Keyword_null)) |token| return createLiteral(arena, Node.NullLiteral, token);
if (eatToken(it, .Keyword_promise)) |token| {
const node = try arena.create(Node.PromiseType);
node.* = Node.PromiseType{
.base = Node{ .id = .PromiseType },
.promise_token = token,
if (eatToken(it, .Keyword_anyframe)) |token| {
const node = try arena.create(Node.AnyFrameType);
node.* = Node.AnyFrameType{
.base = Node{ .id = .AnyFrameType },
.anyframe_token = token,
.result = null,
};
return &node.base;
@@ -2194,7 +2194,7 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
/// PrefixTypeOp
/// <- QUESTIONMARK
/// / KEYWORD_promise MINUSRARROW
/// / KEYWORD_anyframe MINUSRARROW
/// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
/// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
@@ -2209,20 +2209,20 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
return &node.base;
}
// TODO: Returning a PromiseType instead of PrefixOp makes casting and setting .rhs or
// TODO: Returning a AnyFrameType instead of PrefixOp makes casting and setting .rhs or
// .return_type more difficult for the caller (see parsePrefixOpExpr helper).
// Consider making the PromiseType a member of PrefixOp and add a
// PrefixOp.PromiseType variant?
if (eatToken(it, .Keyword_promise)) |token| {
// Consider making the AnyFrameType a member of PrefixOp and add a
// PrefixOp.AnyFrameType variant?
if (eatToken(it, .Keyword_anyframe)) |token| {
const arrow = eatToken(it, .Arrow) orelse {
putBackToken(it, token);
return null;
};
const node = try arena.create(Node.PromiseType);
node.* = Node.PromiseType{
.base = Node{ .id = .PromiseType },
.promise_token = token,
.result = Node.PromiseType.Result{
const node = try arena.create(Node.AnyFrameType);
node.* = Node.AnyFrameType{
.base = Node{ .id = .AnyFrameType },
.anyframe_token = token,
.result = Node.AnyFrameType.Result{
.arrow_token = arrow,
.return_type = undefined, // set by caller
},
@@ -2903,8 +2903,8 @@ fn parsePrefixOpExpr(
rightmost_op = rhs;
} else break;
},
.PromiseType => {
const prom = rightmost_op.cast(Node.PromiseType).?;
.AnyFrameType => {
const prom = rightmost_op.cast(Node.AnyFrameType).?;
if (try opParseFn(arena, it, tree)) |rhs| {
prom.result.?.return_type = rhs;
rightmost_op = rhs;
@@ -2922,8 +2922,8 @@ fn parsePrefixOpExpr(
.InvalidToken = AstError.InvalidToken{ .token = it.index },
});
},
.PromiseType => {
const prom = rightmost_op.cast(Node.PromiseType).?;
.AnyFrameType => {
const prom = rightmost_op.cast(Node.AnyFrameType).?;
prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, AstError{
.InvalidToken = AstError.InvalidToken{ .token = it.index },
});

View File

@@ -2111,12 +2111,12 @@ test "zig fmt: coroutines" {
\\ suspend;
\\ x += 1;
\\ suspend;
\\ const p: promise->void = async simpleAsyncFn() catch unreachable;
\\ const p: anyframe->void = async simpleAsyncFn() catch unreachable;
\\ await p;
\\}
\\
\\test "coroutine suspend, resume, cancel" {
\\ const p: promise = try async<std.debug.global_allocator> testAsyncSeq();
\\ const p: anyframe = try async<std.debug.global_allocator> testAsyncSeq();
\\ resume p;
\\ cancel p;
\\}

View File

@@ -1205,15 +1205,15 @@ fn renderExpression(
}
},
ast.Node.Id.PromiseType => {
const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);
ast.Node.Id.AnyFrameType => {
const anyframe_type = @fieldParentPtr(ast.Node.AnyFrameType, "base", base);
if (promise_type.result) |result| {
try renderToken(tree, stream, promise_type.promise_token, indent, start_col, Space.None); // promise
if (anyframe_type.result) |result| {
try renderToken(tree, stream, anyframe_type.anyframe_token, indent, start_col, Space.None); // anyframe
try renderToken(tree, stream, result.arrow_token, indent, start_col, Space.None); // ->
return renderExpression(allocator, stream, tree, indent, start_col, result.return_type, space);
} else {
return renderToken(tree, stream, promise_type.promise_token, indent, start_col, space); // promise
return renderToken(tree, stream, anyframe_type.anyframe_token, indent, start_col, space); // anyframe
}
},

View File

@@ -15,6 +15,7 @@ pub const Token = struct {
Keyword{ .bytes = "align", .id = Id.Keyword_align },
Keyword{ .bytes = "allowzero", .id = Id.Keyword_allowzero },
Keyword{ .bytes = "and", .id = Id.Keyword_and },
Keyword{ .bytes = "anyframe", .id = Id.Keyword_anyframe },
Keyword{ .bytes = "asm", .id = Id.Keyword_asm },
Keyword{ .bytes = "async", .id = Id.Keyword_async },
Keyword{ .bytes = "await", .id = Id.Keyword_await },
@@ -42,7 +43,6 @@ pub const Token = struct {
Keyword{ .bytes = "or", .id = Id.Keyword_or },
Keyword{ .bytes = "orelse", .id = Id.Keyword_orelse },
Keyword{ .bytes = "packed", .id = Id.Keyword_packed },
Keyword{ .bytes = "promise", .id = Id.Keyword_promise },
Keyword{ .bytes = "pub", .id = Id.Keyword_pub },
Keyword{ .bytes = "resume", .id = Id.Keyword_resume },
Keyword{ .bytes = "return", .id = Id.Keyword_return },
@@ -174,7 +174,7 @@ pub const Token = struct {
Keyword_or,
Keyword_orelse,
Keyword_packed,
Keyword_promise,
Keyword_anyframe,
Keyword_pub,
Keyword_resume,
Keyword_return,