authorgravatar for fncontroloption@noreply.codeberg.orgFnControlOption <fncontroloption@noreply.codeberg.org> 2021-10-04 15:46:55-07:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-01-17 17:16:48+02:00
logd46973ee4fc2a2eff5b5e0ef78368419546ee6f9
tree86a3354a3fb9dbeae945cea375972dcc9b1f3c85
parent4a92f42ed755a1c30ef2aa3842b7efe7e5725e17

translate-c: improve error messages when expecting specific tokens

Old: unable to translate C expr: expected ')' New: unable to translate C expr: expected ')' instead got '...'

2 files changed, 41 insertions(+), 71 deletions(-)

src/translate_c.zig+40-70
...@@ -5281,6 +5281,18 @@ const MacroCtx = struct {...@@ -5281,6 +5281,18 @@ const MacroCtx = struct {
5281 return self.list[self.i].id;5281 return self.list[self.i].id;
5282 }5282 }
52835283
5284 fn skip(self: *MacroCtx, c: *Context, expected_id: std.meta.Tag(CToken.Id)) ParseError!void {
5285 const next_id = self.next().?;
5286 if (next_id != expected_id) {
5287 try self.fail(
5288 c,
5289 "unable to translate C expr: expected '{s}' instead got '{s}'",
5290 .{ CToken.Id.symbol(expected_id), next_id.symbol() },
5291 );
5292 return error.ParseError;
5293 }
5294 }
5295
5284 fn slice(self: *MacroCtx) []const u8 {5296 fn slice(self: *MacroCtx) []const u8 {
5285 const tok = self.list[self.i];5297 const tok = self.list[self.i];
5286 return self.source[tok.start..tok.end];5298 return self.source[tok.start..tok.end];
...@@ -5418,7 +5430,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {...@@ -5418,7 +5430,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
5418 const init_node = try parseCExpr(c, m, scope);5430 const init_node = try parseCExpr(c, m, scope);
5419 const last = m.next().?;5431 const last = m.next().?;
5420 if (last != .Eof and last != .Nl)5432 if (last != .Eof and last != .Nl)
5421 return m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(last)});5433 return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()});
54225434
5423 const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node });5435 const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node });
5424 try c.global_scope.macro_table.put(m.name, var_decl);5436 try c.global_scope.macro_table.put(m.name, var_decl);
...@@ -5439,9 +5451,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {...@@ -5439,9 +5451,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
5439 defer block_scope.deinit();5451 defer block_scope.deinit();
5440 const scope = &block_scope.base;5452 const scope = &block_scope.base;
54415453
5442 if (m.next().? != .LParen) {5454 try m.skip(c, .LParen);
5443 return m.fail(c, "unable to translate C expr: expected '('", .{});
5444 }
54455455
5446 var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa);5456 var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa);
5447 defer fn_params.deinit();5457 defer fn_params.deinit();
...@@ -5461,9 +5471,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {...@@ -5461,9 +5471,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
5461 _ = m.next();5471 _ = m.next();
5462 }5472 }
54635473
5464 if (m.next().? != .RParen) {5474 try m.skip(c, .RParen);
5465 return m.fail(c, "unable to translate C expr: expected ')'", .{});
5466 }
54675475
5468 if (m.containsUndefinedIdentifier(scope, fn_params.items)) |ident|5476 if (m.containsUndefinedIdentifier(scope, fn_params.items)) |ident|
5469 return m.fail(c, "unable to translate macro: undefined identifier `{s}`", .{ident});5477 return m.fail(c, "unable to translate macro: undefined identifier `{s}`", .{ident});
...@@ -5471,7 +5479,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {...@@ -5471,7 +5479,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
5471 const expr = try parseCExpr(c, m, scope);5479 const expr = try parseCExpr(c, m, scope);
5472 const last = m.next().?;5480 const last = m.next().?;
5473 if (last != .Eof and last != .Nl)5481 if (last != .Eof and last != .Nl)
5474 return m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(last)});5482 return m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{last.symbol()});
54755483
5476 const typeof_arg = if (expr.castTag(.block)) |some| blk: {5484 const typeof_arg = if (expr.castTag(.block)) |some| blk: {
5477 const stmts = some.data.stmts;5485 const stmts = some.data.stmts;
...@@ -5837,11 +5845,7 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N...@@ -5837,11 +5845,7 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
5837 .LParen => {5845 .LParen => {
5838 const inner_node = try parseCExpr(c, m, scope);5846 const inner_node = try parseCExpr(c, m, scope);
58395847
5840 const next_id = m.next().?;5848 try m.skip(c, .RParen);
5841 if (next_id != .RParen) {
5842 try m.fail(c, "unable to translate C expr: expected ')' instead got: {s}", .{@tagName(next_id)});
5843 return error.ParseError;
5844 }
5845 return inner_node;5849 return inner_node;
5846 },5850 },
5847 else => {5851 else => {
...@@ -5851,7 +5855,7 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N...@@ -5851,7 +5855,7 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N
5851 if (try parseCTypeName(c, m, scope, true)) |type_name| {5855 if (try parseCTypeName(c, m, scope, true)) |type_name| {
5852 return type_name;5856 return type_name;
5853 }5857 }
5854 try m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(tok)});5858 try m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{tok.symbol()});
5855 return error.ParseError;5859 return error.ParseError;
5856 },5860 },
5857 }5861 }
...@@ -5896,10 +5900,7 @@ fn parseCCondExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -5896,10 +5900,7 @@ fn parseCCondExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
5896 _ = m.next();5900 _ = m.next();
58975901
5898 const then_body = try parseCOrExpr(c, m, scope);5902 const then_body = try parseCOrExpr(c, m, scope);
5899 if (m.next().? != .Colon) {5903 try m.skip(c, .Colon);
5900 try m.fail(c, "unable to translate C expr: expected ':'", .{});
5901 return error.ParseError;
5902 }
5903 const else_body = try parseCCondExpr(c, m, scope);5904 const else_body = try parseCCondExpr(c, m, scope);
5904 return Tag.@"if".create(c.arena, .{ .cond = node, .then = then_body, .@"else" = else_body });5905 return Tag.@"if".create(c.arena, .{ .cond = node, .then = then_body, .@"else" = else_body });
5905}5906}
...@@ -6086,10 +6087,7 @@ fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -6086,10 +6087,7 @@ fn parseCCastExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6086 switch (m.next().?) {6087 switch (m.next().?) {
6087 .LParen => {6088 .LParen => {
6088 if (try parseCTypeName(c, m, scope, true)) |type_name| {6089 if (try parseCTypeName(c, m, scope, true)) |type_name| {
6089 if (m.next().? != .RParen) {6090 try m.skip(c, .RParen);
6090 try m.fail(c, "unable to translate C expr: expected ')'", .{});
6091 return error.ParseError;
6092 }
6093 if (m.peek().? == .LBrace) {6091 if (m.peek().? == .LBrace) {
6094 // initializer list6092 // initializer list
6095 return parseCPostfixExpr(c, m, scope, type_name);6093 return parseCPostfixExpr(c, m, scope, type_name);
...@@ -6141,11 +6139,7 @@ fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_...@@ -6141,11 +6139,7 @@ fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_
6141 .Keyword_enum, .Keyword_struct, .Keyword_union => {6139 .Keyword_enum, .Keyword_struct, .Keyword_union => {
6142 // struct Foo will be declared as struct_Foo by transRecordDecl6140 // struct Foo will be declared as struct_Foo by transRecordDecl
6143 const slice = m.slice();6141 const slice = m.slice();
6144 const next_id = m.next().?;6142 try m.skip(c, .Identifier);
6145 if (next_id != .Identifier) {
6146 try m.fail(c, "unable to translate C expr: expected Identifier instead got: {s}", .{@tagName(next_id)});
6147 return error.ParseError;
6148 }
61496143
6150 const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() });6144 const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() });
6151 return try Tag.identifier.create(c.arena, name);6145 return try Tag.identifier.create(c.arena, name);
...@@ -6157,7 +6151,7 @@ fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_...@@ -6157,7 +6151,7 @@ fn parseCSpecifierQualifierList(c: *Context, m: *MacroCtx, scope: *Scope, allow_
6157 m.i -= 1;6151 m.i -= 1;
6158 return null;6152 return null;
6159 } else {6153 } else {
6160 try m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(tok)});6154 try m.fail(c, "unable to translate C expr: unexpected token '{s}'", .{tok.symbol()});
6161 return error.ParseError;6155 return error.ParseError;
6162 }6156 }
6163}6157}
...@@ -6298,18 +6292,12 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)...@@ -6298,18 +6292,12 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
6298 while (true) {6292 while (true) {
6299 switch (m.next().?) {6293 switch (m.next().?) {
6300 .Period => {6294 .Period => {
6301 if (m.next().? != .Identifier) {6295 try m.skip(c, .Identifier);
6302 try m.fail(c, "unable to translate C expr: expected identifier", .{});
6303 return error.ParseError;
6304 }
63056296
6306 node = try Tag.field_access.create(c.arena, .{ .lhs = node, .field_name = m.slice() });6297 node = try Tag.field_access.create(c.arena, .{ .lhs = node, .field_name = m.slice() });
6307 },6298 },
6308 .Arrow => {6299 .Arrow => {
6309 if (m.next().? != .Identifier) {6300 try m.skip(c, .Identifier);
6310 try m.fail(c, "unable to translate C expr: expected identifier", .{});
6311 return error.ParseError;
6312 }
63136301
6314 const deref = try Tag.deref.create(c.arena, node);6302 const deref = try Tag.deref.create(c.arena, node);
6315 node = try Tag.field_access.create(c.arena, .{ .lhs = deref, .field_name = m.slice() });6303 node = try Tag.field_access.create(c.arena, .{ .lhs = deref, .field_name = m.slice() });
...@@ -6317,10 +6305,7 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)...@@ -6317,10 +6305,7 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
6317 .LBracket => {6305 .LBracket => {
6318 const index = try macroBoolToInt(c, try parseCExpr(c, m, scope));6306 const index = try macroBoolToInt(c, try parseCExpr(c, m, scope));
6319 node = try Tag.array_access.create(c.arena, .{ .lhs = node, .rhs = index });6307 node = try Tag.array_access.create(c.arena, .{ .lhs = node, .rhs = index });
6320 if (m.next().? != .RBracket) {6308 try m.skip(c, .RBracket);
6321 try m.fail(c, "unable to translate C expr: expected ']'", .{});
6322 return error.ParseError;
6323 }
6324 },6309 },
6325 .LParen => {6310 .LParen => {
6326 if (m.peek().? == .RParen) {6311 if (m.peek().? == .RParen) {
...@@ -6332,11 +6317,12 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)...@@ -6332,11 +6317,12 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
6332 while (true) {6317 while (true) {
6333 const arg = try parseCCondExpr(c, m, scope);6318 const arg = try parseCCondExpr(c, m, scope);
6334 try args.append(arg);6319 try args.append(arg);
6335 switch (m.next().?) {6320 const next_id = m.next().?;
6321 switch (next_id) {
6336 .Comma => {},6322 .Comma => {},
6337 .RParen => break,6323 .RParen => break,
6338 else => {6324 else => {
6339 try m.fail(c, "unable to translate C expr: expected ',' or ')'", .{});6325 try m.fail(c, "unable to translate C expr: expected ',' or ')' instead got '{s}'", .{next_id.symbol()});
6340 return error.ParseError;6326 return error.ParseError;
6341 },6327 },
6342 }6328 }
...@@ -6351,27 +6337,19 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)...@@ -6351,27 +6337,19 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
6351 defer init_vals.deinit();6337 defer init_vals.deinit();
63526338
6353 while (true) {6339 while (true) {
6354 if (m.next().? != .Period) {6340 try m.skip(c, .Period);
6355 try m.fail(c, "unable to translate C expr: expected '.'", .{});6341 try m.skip(c, .Identifier);
6356 return error.ParseError;
6357 }
6358 if (m.next().? != .Identifier) {
6359 try m.fail(c, "unable to translate C expr: expected identifier", .{});
6360 return error.ParseError;
6361 }
6362 const name = m.slice();6342 const name = m.slice();
6363 if (m.next().? != .Equal) {6343 try m.skip(c, .Equal);
6364 try m.fail(c, "unable to translate C expr: expected '='", .{});
6365 return error.ParseError;
6366 }
63676344
6368 const val = try parseCCondExpr(c, m, scope);6345 const val = try parseCCondExpr(c, m, scope);
6369 try init_vals.append(.{ .name = name, .value = val });6346 try init_vals.append(.{ .name = name, .value = val });
6370 switch (m.next().?) {6347 const next_id = m.next().?;
6348 switch (next_id) {
6371 .Comma => {},6349 .Comma => {},
6372 .RBrace => break,6350 .RBrace => break,
6373 else => {6351 else => {
6374 try m.fail(c, "unable to translate C expr: expected ',' or '}}'", .{});6352 try m.fail(c, "unable to translate C expr: expected ',' or '}}' instead got '{s}'", .{next_id.symbol()});
6375 return error.ParseError;6353 return error.ParseError;
6376 },6354 },
6377 }6355 }
...@@ -6387,11 +6365,12 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)...@@ -6387,11 +6365,12 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope, type_name: ?Node)
6387 while (true) {6365 while (true) {
6388 const val = try parseCCondExpr(c, m, scope);6366 const val = try parseCCondExpr(c, m, scope);
6389 try init_vals.append(val);6367 try init_vals.append(val);
6390 switch (m.next().?) {6368 const next_id = m.next().?;
6369 switch (next_id) {
6391 .Comma => {},6370 .Comma => {},
6392 .RBrace => break,6371 .RBrace => break,
6393 else => {6372 else => {
6394 try m.fail(c, "unable to translate C expr: expected ',' or '}}'", .{});6373 try m.fail(c, "unable to translate C expr: expected ',' or '}}' instead got '{s}'", .{next_id.symbol()});
6395 return error.ParseError;6374 return error.ParseError;
6396 },6375 },
6397 }6376 }
...@@ -6438,10 +6417,7 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -6438,10 +6417,7 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6438 const operand = if (m.peek().? == .LParen) blk: {6417 const operand = if (m.peek().? == .LParen) blk: {
6439 _ = m.next();6418 _ = m.next();
6440 const inner = (try parseCTypeName(c, m, scope, false)).?;6419 const inner = (try parseCTypeName(c, m, scope, false)).?;
6441 if (m.next().? != .RParen) {6420 try m.skip(c, .RParen);
6442 try m.fail(c, "unable to translate C expr: expected ')'", .{});
6443 return error.ParseError;
6444 }
6445 break :blk inner;6421 break :blk inner;
6446 } else try parseCUnaryExpr(c, m, scope);6422 } else try parseCUnaryExpr(c, m, scope);
64476423
...@@ -6450,15 +6426,9 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {...@@ -6450,15 +6426,9 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6450 .Keyword_alignof => {6426 .Keyword_alignof => {
6451 // TODO this won't work if using <stdalign.h>'s6427 // TODO this won't work if using <stdalign.h>'s
6452 // #define alignof _Alignof6428 // #define alignof _Alignof
6453 if (m.next().? != .LParen) {6429 try m.skip(c, .LParen);
6454 try m.fail(c, "unable to translate C expr: expected '('", .{});
6455 return error.ParseError;
6456 }
6457 const operand = (try parseCTypeName(c, m, scope, false)).?;6430 const operand = (try parseCTypeName(c, m, scope, false)).?;
6458 if (m.next().? != .RParen) {6431 try m.skip(c, .RParen);
6459 try m.fail(c, "unable to translate C expr: expected ')'", .{});
6460 return error.ParseError;
6461 }
64626432
6463 return Tag.alignof.create(c.arena, operand);6433 return Tag.alignof.create(c.arena, operand);
6464 },6434 },
test/translate_c.zig+1-1
...@@ -2076,7 +2076,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2076,7 +2076,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2076 , &[_][]const u8{2076 , &[_][]const u8{
2077 \\pub export var @"anyerror": c_uint = 2;2077 \\pub export var @"anyerror": c_uint = 2;
2078 ,2078 ,
2079 \\pub const @"noreturn" = @compileError("unable to translate C expr: unexpected token .Keyword_noreturn");2079 \\pub const @"noreturn" = @compileError("unable to translate C expr: unexpected token '_Noreturn'");
2080 ,2080 ,
2081 \\pub const @"f32": c_int = 0;2081 \\pub const @"f32": c_int = 0;
2082 \\pub const @"u32": c_int = 1;2082 \\pub const @"u32": c_int = 1;