Address spaces: addrspace(A) parsing

The grammar for function prototypes, (global) variable declarations, and
pointer types now accepts an optional addrspace(A) modifier.
This commit is contained in:
Robin Voetter 2021-09-02 14:45:00 +02:00
parent 9fa723ee50
commit ccc7f9987d
4 changed files with 139 additions and 34 deletions

View File

@ -262,6 +262,9 @@ pub fn renderError(tree: Tree, parse_error: Error, stream: anytype) !void {
token_tags[parse_error.token].symbol(),
});
},
.extra_addrspace_qualifier => {
return stream.writeAll("extra addrspace qualifier");
},
.extra_align_qualifier => {
return stream.writeAll("extra align qualifier");
},
@ -1021,7 +1024,7 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex {
},
.fn_proto_one => {
const extra = tree.extraData(datas[n].lhs, Node.FnProtoOne);
// linksection, callconv, align can appear in any order, so we
// addrspace, linksection, callconv, align can appear in any order, so we
// find the last one here.
var max_node: Node.Index = datas[n].rhs;
var max_start = token_starts[main_tokens[max_node]];
@ -1034,6 +1037,14 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex {
max_offset = 1; // for the rparen
}
}
if (extra.addrspace_expr != 0) {
const start = token_starts[main_tokens[extra.addrspace_expr]];
if (start > max_start) {
max_node = extra.addrspace_expr;
max_start = start;
max_offset = 1; // for the rparen
}
}
if (extra.section_expr != 0) {
const start = token_starts[main_tokens[extra.section_expr]];
if (start > max_start) {
@ -1055,7 +1066,7 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex {
},
.fn_proto => {
const extra = tree.extraData(datas[n].lhs, Node.FnProto);
// linksection, callconv, align can appear in any order, so we
// addrspace, linksection, callconv, align can appear in any order, so we
// find the last one here.
var max_node: Node.Index = datas[n].rhs;
var max_start = token_starts[main_tokens[max_node]];
@ -1068,6 +1079,14 @@ pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex {
max_offset = 1; // for the rparen
}
}
if (extra.addrspace_expr != 0) {
const start = token_starts[main_tokens[extra.addrspace_expr]];
if (start > max_start) {
max_node = extra.addrspace_expr;
max_start = start;
max_offset = 1; // for the rparen
}
}
if (extra.section_expr != 0) {
const start = token_starts[main_tokens[extra.section_expr]];
if (start > max_start) {
@ -1138,6 +1157,7 @@ pub fn globalVarDecl(tree: Tree, node: Node.Index) full.VarDecl {
return tree.fullVarDecl(.{
.type_node = extra.type_node,
.align_node = extra.align_node,
.addrspace_node = extra.addrspace_node,
.section_node = extra.section_node,
.init_node = data.rhs,
.mut_token = tree.nodes.items(.main_token)[node],
@ -1151,6 +1171,7 @@ pub fn localVarDecl(tree: Tree, node: Node.Index) full.VarDecl {
return tree.fullVarDecl(.{
.type_node = extra.type_node,
.align_node = extra.align_node,
.addrspace_node = 0,
.section_node = 0,
.init_node = data.rhs,
.mut_token = tree.nodes.items(.main_token)[node],
@ -1163,6 +1184,7 @@ pub fn simpleVarDecl(tree: Tree, node: Node.Index) full.VarDecl {
return tree.fullVarDecl(.{
.type_node = data.lhs,
.align_node = 0,
.addrspace_node = 0,
.section_node = 0,
.init_node = data.rhs,
.mut_token = tree.nodes.items(.main_token)[node],
@ -1175,6 +1197,7 @@ pub fn alignedVarDecl(tree: Tree, node: Node.Index) full.VarDecl {
return tree.fullVarDecl(.{
.type_node = 0,
.align_node = data.lhs,
.addrspace_node = 0,
.section_node = 0,
.init_node = data.rhs,
.mut_token = tree.nodes.items(.main_token)[node],
@ -1249,6 +1272,7 @@ pub fn fnProtoSimple(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.
.return_type = data.rhs,
.params = params,
.align_expr = 0,
.addrspace_expr = 0,
.section_expr = 0,
.callconv_expr = 0,
});
@ -1265,6 +1289,7 @@ pub fn fnProtoMulti(tree: Tree, node: Node.Index) full.FnProto {
.return_type = data.rhs,
.params = params,
.align_expr = 0,
.addrspace_expr = 0,
.section_expr = 0,
.callconv_expr = 0,
});
@ -1282,6 +1307,7 @@ pub fn fnProtoOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.FnP
.return_type = data.rhs,
.params = params,
.align_expr = extra.align_expr,
.addrspace_expr = extra.addrspace_expr,
.section_expr = extra.section_expr,
.callconv_expr = extra.callconv_expr,
});
@ -1298,6 +1324,7 @@ pub fn fnProto(tree: Tree, node: Node.Index) full.FnProto {
.return_type = data.rhs,
.params = params,
.align_expr = extra.align_expr,
.addrspace_expr = extra.addrspace_expr,
.section_expr = extra.section_expr,
.callconv_expr = extra.callconv_expr,
});
@ -1453,6 +1480,7 @@ pub fn ptrTypeAligned(tree: Tree, node: Node.Index) full.PtrType {
return tree.fullPtrType(.{
.main_token = tree.nodes.items(.main_token)[node],
.align_node = data.lhs,
.addrspace_node = 0,
.sentinel = 0,
.bit_range_start = 0,
.bit_range_end = 0,
@ -1466,6 +1494,7 @@ pub fn ptrTypeSentinel(tree: Tree, node: Node.Index) full.PtrType {
return tree.fullPtrType(.{
.main_token = tree.nodes.items(.main_token)[node],
.align_node = 0,
.addrspace_node = 0,
.sentinel = data.lhs,
.bit_range_start = 0,
.bit_range_end = 0,
@ -1480,6 +1509,7 @@ pub fn ptrType(tree: Tree, node: Node.Index) full.PtrType {
return tree.fullPtrType(.{
.main_token = tree.nodes.items(.main_token)[node],
.align_node = extra.align_node,
.addrspace_node = extra.addrspace_node,
.sentinel = extra.sentinel,
.bit_range_start = 0,
.bit_range_end = 0,
@ -1494,6 +1524,7 @@ pub fn ptrTypeBitRange(tree: Tree, node: Node.Index) full.PtrType {
return tree.fullPtrType(.{
.main_token = tree.nodes.items(.main_token)[node],
.align_node = extra.align_node,
.addrspace_node = extra.addrspace_node,
.sentinel = extra.sentinel,
.bit_range_start = extra.bit_range_start,
.bit_range_end = extra.bit_range_end,
@ -2063,6 +2094,7 @@ pub const full = struct {
mut_token: TokenIndex,
type_node: Node.Index,
align_node: Node.Index,
addrspace_node: Node.Index,
section_node: Node.Index,
init_node: Node.Index,
};
@ -2130,6 +2162,7 @@ pub const full = struct {
return_type: Node.Index,
params: []const Node.Index,
align_expr: Node.Index,
addrspace_expr: Node.Index,
section_expr: Node.Index,
callconv_expr: Node.Index,
};
@ -2288,6 +2321,7 @@ pub const full = struct {
pub const Components = struct {
main_token: TokenIndex,
align_node: Node.Index,
addrspace_node: Node.Index,
sentinel: Node.Index,
bit_range_start: Node.Index,
bit_range_end: Node.Index,
@ -2397,6 +2431,7 @@ pub const Error = struct {
expected_var_decl_or_fn,
expected_loop_payload,
expected_container,
extra_addrspace_qualifier,
extra_align_qualifier,
extra_allowzero_qualifier,
extra_const_qualifier,
@ -2723,13 +2758,13 @@ pub const Node = struct {
/// main_token is the `fn` keyword.
/// extern function declarations use this tag.
fn_proto_multi,
/// `fn(a: b) rhs linksection(e) callconv(f)`. `FnProtoOne[lhs]`.
/// `fn(a: b) rhs addrspace(e) linksection(f) callconv(g)`. `FnProtoOne[lhs]`.
/// zero or one parameters.
/// anytype and ... parameters are omitted from the AST tree.
/// main_token is the `fn` keyword.
/// extern function declarations use this tag.
fn_proto_one,
/// `fn(a: b, c: d) rhs linksection(e) callconv(f)`. `FnProto[lhs]`.
/// `fn(a: b, c: d) rhs addrspace(e) linksection(f) callconv(g)`. `FnProto[lhs]`.
/// anytype and ... parameters are omitted from the AST tree.
/// main_token is the `fn` keyword.
/// extern function declarations use this tag.
@ -2893,11 +2928,13 @@ pub const Node = struct {
pub const PtrType = struct {
sentinel: Index,
align_node: Index,
addrspace_node: Index,
};
pub const PtrTypeBitRange = struct {
sentinel: Index,
align_node: Index,
addrspace_node: Index,
bit_range_start: Index,
bit_range_end: Index,
};
@ -2920,8 +2957,13 @@ pub const Node = struct {
};
pub const GlobalVarDecl = struct {
/// Populated if there is an explicit type ascription.
type_node: Index,
/// Populated if align(A) is present.
align_node: Index,
/// Populated if linksection(A) is present.
addrspace_node: Index,
/// Populated if addrspace(A) is present.
section_node: Index,
};
@ -2954,6 +2996,8 @@ pub const Node = struct {
/// Populated if align(A) is present.
align_expr: Index,
/// Populated if linksection(A) is present.
addrspace_expr: Index,
/// Populated if addrspace(A) is present.
section_expr: Index,
/// Populated if callconv(A) is present.
callconv_expr: Index,
@ -2964,6 +3008,8 @@ pub const Node = struct {
params_end: Index,
/// Populated if align(A) is present.
align_expr: Index,
/// Populated if addrspace(A) is present.
addrspace_expr: Index,
/// Populated if linksection(A) is present.
section_expr: Index,
/// Populated if callconv(A) is present.

View File

@ -629,7 +629,7 @@ const Parser = struct {
};
}
/// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr
/// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? AddrSpace? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr
fn parseFnProto(p: *Parser) !Node.Index {
const fn_token = p.eatToken(.keyword_fn) orelse return null_node;
@ -639,6 +639,7 @@ const Parser = struct {
_ = p.eatToken(.identifier);
const params = try p.parseParamDeclList();
const align_expr = try p.parseByteAlign();
const addrspace_expr = try p.parseAddrSpace();
const section_expr = try p.parseLinkSection();
const callconv_expr = try p.parseCallconv();
_ = p.eatToken(.bang);
@ -650,7 +651,7 @@ const Parser = struct {
try p.warn(.expected_return_type);
}
if (align_expr == 0 and section_expr == 0 and callconv_expr == 0) {
if (align_expr == 0 and section_expr == 0 and callconv_expr == 0 and addrspace_expr == 0) {
switch (params) {
.zero_or_one => |param| return p.setNode(fn_proto_index, .{
.tag = .fn_proto_simple,
@ -683,6 +684,7 @@ const Parser = struct {
.lhs = try p.addExtra(Node.FnProtoOne{
.param = param,
.align_expr = align_expr,
.addrspace_expr = addrspace_expr,
.section_expr = section_expr,
.callconv_expr = callconv_expr,
}),
@ -698,6 +700,7 @@ const Parser = struct {
.params_start = span.start,
.params_end = span.end,
.align_expr = align_expr,
.addrspace_expr = addrspace_expr,
.section_expr = section_expr,
.callconv_expr = callconv_expr,
}),
@ -708,7 +711,7 @@ const Parser = struct {
}
}
/// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON
/// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? AddrSpace? LinkSection? (EQUAL Expr)? SEMICOLON
fn parseVarDecl(p: *Parser) !Node.Index {
const mut_token = p.eatToken(.keyword_const) orelse
p.eatToken(.keyword_var) orelse
@ -717,9 +720,10 @@ const Parser = struct {
_ = try p.expectToken(.identifier);
const type_node: Node.Index = if (p.eatToken(.colon) == null) 0 else try p.expectTypeExpr();
const align_node = try p.parseByteAlign();
const addrspace_node = try p.parseAddrSpace();
const section_node = try p.parseLinkSection();
const init_node: Node.Index = if (p.eatToken(.equal) == null) 0 else try p.expectExpr();
if (section_node == 0) {
if (section_node == 0 and addrspace_node == 0) {
if (align_node == 0) {
return p.addNode(.{
.tag = .simple_var_decl,
@ -759,6 +763,7 @@ const Parser = struct {
.lhs = try p.addExtra(Node.GlobalVarDecl{
.type_node = type_node,
.align_node = align_node,
.addrspace_node = addrspace_node,
.section_node = section_node,
}),
.rhs = init_node,
@ -1440,8 +1445,8 @@ const Parser = struct {
/// PrefixTypeOp
/// <- QUESTIONMARK
/// / KEYWORD_anyframe MINUSRARROW
/// / SliceTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
/// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
/// / SliceTypeStart (ByteAlign / AddrSpace / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
/// / PtrTypeStart (AddrSpace / KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
/// / ArrayTypeStart
/// SliceTypeStart <- LBRACKET (COLON Expr)? RBRACKET
/// PtrTypeStart
@ -1474,16 +1479,7 @@ const Parser = struct {
const asterisk = p.nextToken();
const mods = try p.parsePtrModifiers();
const elem_type = try p.expectTypeExpr();
if (mods.bit_range_start == 0) {
return p.addNode(.{
.tag = .ptr_type_aligned,
.main_token = asterisk,
.data = .{
.lhs = mods.align_node,
.rhs = elem_type,
},
});
} else {
if (mods.bit_range_start != 0) {
return p.addNode(.{
.tag = .ptr_type_bit_range,
.main_token = asterisk,
@ -1491,12 +1487,35 @@ const Parser = struct {
.lhs = try p.addExtra(Node.PtrTypeBitRange{
.sentinel = 0,
.align_node = mods.align_node,
.addrspace_node = mods.addrspace_node,
.bit_range_start = mods.bit_range_start,
.bit_range_end = mods.bit_range_end,
}),
.rhs = elem_type,
},
});
} else if (mods.addrspace_node != 0) {
return p.addNode(.{
.tag = .ptr_type,
.main_token = asterisk,
.data = .{
.lhs = try p.addExtra(Node.PtrType{
.sentinel = 0,
.align_node = mods.align_node,
.addrspace_node = mods.addrspace_node,
}),
.rhs = elem_type,
},
});
} else {
return p.addNode(.{
.tag = .ptr_type_aligned,
.main_token = asterisk,
.data = .{
.lhs = mods.align_node,
.rhs = elem_type,
},
});
}
},
.asterisk_asterisk => {
@ -1504,16 +1523,7 @@ const Parser = struct {
const mods = try p.parsePtrModifiers();
const elem_type = try p.expectTypeExpr();
const inner: Node.Index = inner: {
if (mods.bit_range_start == 0) {
break :inner try p.addNode(.{
.tag = .ptr_type_aligned,
.main_token = asterisk,
.data = .{
.lhs = mods.align_node,
.rhs = elem_type,
},
});
} else {
if (mods.bit_range_start != 0) {
break :inner try p.addNode(.{
.tag = .ptr_type_bit_range,
.main_token = asterisk,
@ -1521,12 +1531,35 @@ const Parser = struct {
.lhs = try p.addExtra(Node.PtrTypeBitRange{
.sentinel = 0,
.align_node = mods.align_node,
.addrspace_node = mods.addrspace_node,
.bit_range_start = mods.bit_range_start,
.bit_range_end = mods.bit_range_end,
}),
.rhs = elem_type,
},
});
} else if (mods.addrspace_node != 0) {
break :inner try p.addNode(.{
.tag = .ptr_type,
.main_token = asterisk,
.data = .{
.lhs = try p.addExtra(Node.PtrType{
.sentinel = 0,
.align_node = mods.align_node,
.addrspace_node = mods.addrspace_node,
}),
.rhs = elem_type,
},
});
} else {
break :inner try p.addNode(.{
.tag = .ptr_type_aligned,
.main_token = asterisk,
.data = .{
.lhs = mods.align_node,
.rhs = elem_type,
},
});
}
};
return p.addNode(.{
@ -1560,7 +1593,7 @@ const Parser = struct {
const mods = try p.parsePtrModifiers();
const elem_type = try p.expectTypeExpr();
if (mods.bit_range_start == 0) {
if (sentinel == 0) {
if (sentinel == 0 and mods.addrspace_node == 0) {
return p.addNode(.{
.tag = .ptr_type_aligned,
.main_token = asterisk,
@ -1569,7 +1602,7 @@ const Parser = struct {
.rhs = elem_type,
},
});
} else if (mods.align_node == 0) {
} else if (mods.align_node == 0 and mods.addrspace_node == 0) {
return p.addNode(.{
.tag = .ptr_type_sentinel,
.main_token = asterisk,
@ -1586,6 +1619,7 @@ const Parser = struct {
.lhs = try p.addExtra(Node.PtrType{
.sentinel = sentinel,
.align_node = mods.align_node,
.addrspace_node = mods.addrspace_node,
}),
.rhs = elem_type,
},
@ -1599,6 +1633,7 @@ const Parser = struct {
.lhs = try p.addExtra(Node.PtrTypeBitRange{
.sentinel = sentinel,
.align_node = mods.align_node,
.addrspace_node = mods.addrspace_node,
.bit_range_start = mods.bit_range_start,
.bit_range_end = mods.bit_range_end,
}),
@ -1624,7 +1659,7 @@ const Parser = struct {
.token = p.nodes.items(.main_token)[mods.bit_range_start],
});
}
if (sentinel == 0) {
if (sentinel == 0 and mods.addrspace_node == 0) {
return p.addNode(.{
.tag = .ptr_type_aligned,
.main_token = lbracket,
@ -1633,7 +1668,7 @@ const Parser = struct {
.rhs = elem_type,
},
});
} else if (mods.align_node == 0) {
} else if (mods.align_node == 0 and mods.addrspace_node == 0) {
return p.addNode(.{
.tag = .ptr_type_sentinel,
.main_token = lbracket,
@ -1650,6 +1685,7 @@ const Parser = struct {
.lhs = try p.addExtra(Node.PtrType{
.sentinel = sentinel,
.align_node = mods.align_node,
.addrspace_node = mods.addrspace_node,
}),
.rhs = elem_type,
},
@ -1661,6 +1697,7 @@ const Parser = struct {
.keyword_const,
.keyword_volatile,
.keyword_allowzero,
.keyword_addrspace,
=> return p.fail(.ptr_mod_on_array_child_type),
else => {},
}
@ -2879,6 +2916,15 @@ const Parser = struct {
return expr_node;
}
/// AddrSpace <- KEYWORD_addrspace LPAREN Expr RPAREN
fn parseAddrSpace(p: *Parser) !Node.Index {
_ = p.eatToken(.keyword_addrspace) orelse return null_node;
_ = try p.expectToken(.l_paren);
const expr_node = try p.expectExpr();
_ = try p.expectToken(.r_paren);
return expr_node;
}
/// ParamDecl
/// <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType
/// / DOT3
@ -3011,6 +3057,7 @@ const Parser = struct {
const PtrModifiers = struct {
align_node: Node.Index,
addrspace_node: Node.Index,
bit_range_start: Node.Index,
bit_range_end: Node.Index,
};
@ -3018,12 +3065,14 @@ const Parser = struct {
fn parsePtrModifiers(p: *Parser) !PtrModifiers {
var result: PtrModifiers = .{
.align_node = 0,
.addrspace_node = 0,
.bit_range_start = 0,
.bit_range_end = 0,
};
var saw_const = false;
var saw_volatile = false;
var saw_allowzero = false;
var saw_addrspace = false;
while (true) {
switch (p.token_tags[p.tok_i]) {
.keyword_align => {
@ -3063,6 +3112,12 @@ const Parser = struct {
p.tok_i += 1;
saw_allowzero = true;
},
.keyword_addrspace => {
if (saw_addrspace) {
try p.warn(.extra_addrspace_qualifier);
}
result.addrspace_node = try p.parseAddrSpace();
},
else => return result,
}
}

View File

@ -11,6 +11,7 @@ pub const Token = struct {
};
pub const keywords = std.ComptimeStringMap(Tag, .{
.{ "addrspace", .keyword_addrspace },
.{ "align", .keyword_align },
.{ "allowzero", .keyword_allowzero },
.{ "and", .keyword_and },
@ -132,6 +133,7 @@ pub const Token = struct {
float_literal,
doc_comment,
container_doc_comment,
keyword_addrspace,
keyword_align,
keyword_allowzero,
keyword_and,
@ -251,6 +253,7 @@ pub const Token = struct {
.angle_bracket_angle_bracket_right => ">>",
.angle_bracket_angle_bracket_right_equal => ">>=",
.tilde => "~",
.keyword_addrspace => "addrspace",
.keyword_align => "align",
.keyword_allowzero => "allowzero",
.keyword_and => "and",

View File

@ -2614,6 +2614,7 @@ fn renderVar(c: *Context, node: Node) !NodeIndex {
.type_node = type_node,
.align_node = align_node,
.section_node = section_node,
.addrspace_node = 0,
}),
.rhs = init_node,
},