From 5f3ec023cd697007ff868938e3b5fe387add6af5 Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 11 Apr 2018 12:53:01 +0200 Subject: [PATCH 01/12] std.zig.parser: Fixed parsing of field access rhs related: #909 --- std/zig/parser.zig | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/std/zig/parser.zig b/std/zig/parser.zig index f722703284..451bc9dd5b 100644 --- a/std/zig/parser.zig +++ b/std/zig/parser.zig @@ -1515,17 +1515,23 @@ pub const Parser = struct { continue; }, Token.Id.Period => { + const identifier = try self.createLiteral(arena, ast.NodeIdentifier, Token(undefined)); const node = try self.createToDestNode(arena, dest_ptr, ast.NodeInfixOp, ast.NodeInfixOp { .base = undefined, .lhs = dest_ptr.get(), .op_token = token, .op = ast.NodeInfixOp.InfixOp.Period, - .rhs = undefined, + .rhs = &identifier.base, } ); stack.append(State { .SuffixOpExpressionEnd = dest_ptr }) catch unreachable; - try stack.append(State { .SuffixOpExpressionBegin = DestPtr { .Field = &node.rhs }}); + try stack.append(State { + .ExpectTokenSave = ExpectTokenSave { + .id = Token.Id.Identifier, + .ptr = &identifier.token + } + }); continue; }, else => { @@ -5011,6 +5017,7 @@ test "zig fmt: inline asm" { test "zig fmt: coroutines" { try testCanonical( \\async fn simpleAsyncFn() void { + \\ const a = async a.b(); \\ x += 1; \\ suspend; \\ x += 1; From 6fb5ab1b523c58350321fdcbe7ba921300bef8af Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 11 Apr 2018 13:05:42 +0200 Subject: [PATCH 02/12] std.zig.parser: Redid parsing of error set delc related: #909 --- std/zig/parser.zig | 71 ++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 40 deletions(-) diff --git a/std/zig/parser.zig b/std/zig/parser.zig index 451bc9dd5b..3e69e0e163 100644 --- a/std/zig/parser.zig +++ b/std/zig/parser.zig @@ -177,6 +177,8 @@ pub const Parser = struct { FieldInitListItemOrEnd: ListSave(&ast.NodeFieldInitializer), FieldInitListCommaOrEnd: ListSave(&ast.NodeFieldInitializer), FieldListCommaOrEnd: &ast.NodeContainerDecl, + IdentifierListItemOrEnd: ListSave(&ast.NodeIdentifier), + IdentifierListCommaOrEnd: ListSave(&ast.NodeIdentifier), SwitchCaseOrEnd: ListSave(&ast.NodeSwitchCase), SuspendBody: &ast.NodeSuspend, AsyncEnd: AsyncEndCtx, @@ -1683,11 +1685,8 @@ pub const Parser = struct { }, Token.Id.Keyword_error => { - const next = self.getNextToken(); - - if (next.id != Token.Id.LBrace) { + if (self.eatToken(Token.Id.LBrace) == null) { dest_ptr.store(&(try self.createLiteral(arena, ast.NodeErrorType, token)).base); - self.putBackToken(next); continue; } @@ -1700,43 +1699,12 @@ pub const Parser = struct { } ); - while (true) { - const t = self.getNextToken(); - switch (t.id) { - Token.Id.RBrace => { - node.rbrace_token = t; - break; - }, - Token.Id.Identifier => { - try node.decls.append( - try self.createLiteral(arena, ast.NodeIdentifier, t) - ); - }, - else => { - try self.parseError(&stack, token, "expected {} or {}, found {}", - @tagName(Token.Id.RBrace), - @tagName(Token.Id.Identifier), - @tagName(token.id)); - continue; - } + stack.append(State { + .IdentifierListItemOrEnd = ListSave(&ast.NodeIdentifier) { + .list = &node.decls, + .ptr = &node.rbrace_token, } - - const t2 = self.getNextToken(); - switch (t2.id) { - Token.Id.RBrace => { - node.rbrace_token = t; - break; - }, - Token.Id.Comma => continue, - else => { - try self.parseError(&stack, token, "expected {} or {}, found {}", - @tagName(Token.Id.RBrace), - @tagName(Token.Id.Comma), - @tagName(token.id)); - continue; - } - } - } + }) catch unreachable; continue; }, Token.Id.Keyword_packed => { @@ -2082,6 +2050,24 @@ pub const Parser = struct { }); }, + State.IdentifierListItemOrEnd => |list_state| { + if (self.eatToken(Token.Id.RBrace)) |rbrace| { + *list_state.ptr = rbrace; + continue; + } + + const node = try self.createLiteral(arena, ast.NodeIdentifier, Token(undefined)); + try list_state.list.append(node); + + stack.append(State { .IdentifierListCommaOrEnd = list_state }) catch unreachable; + try stack.append(State { + .ExpectTokenSave = ExpectTokenSave { + .id = Token.Id.Identifier, + .ptr = &node.token, + } + }); + }, + State.SwitchCaseOrEnd => |list_state| { if (self.eatToken(Token.Id.RBrace)) |rbrace| { *list_state.ptr = rbrace; @@ -2139,6 +2125,11 @@ pub const Parser = struct { continue; }, + State.IdentifierListCommaOrEnd => |list_state| { + try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .IdentifierListItemOrEnd = list_state }); + continue; + }, + State.SwitchCaseCommaOrEnd => |list_state| { try self.commaOrEnd(&stack, Token.Id.RBrace, list_state.ptr, State { .SwitchCaseOrEnd = list_state }); continue; From 4b0556ebd4bdc2f3c05e85f3c003b6fc89f7ac0f Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 11 Apr 2018 13:38:06 +0200 Subject: [PATCH 03/12] std.zig.parser can now parse `std/heap.zig`: related: #909 * Struct fields can now be pub * Parsing of double deref now works * Block expressions now have the right precedence --- std/zig/ast.zig | 2 + std/zig/parser.zig | 288 ++++++++++++++++++++++++++++----------------- 2 files changed, 180 insertions(+), 110 deletions(-) diff --git a/std/zig/ast.zig b/std/zig/ast.zig index 9fb10aa0b1..b671feb4f2 100644 --- a/std/zig/ast.zig +++ b/std/zig/ast.zig @@ -360,6 +360,7 @@ pub const NodeContainerDecl = struct { pub const NodeStructField = struct { base: Node, + visib_token: ?Token, name_token: Token, type_expr: &Node, @@ -373,6 +374,7 @@ pub const NodeStructField = struct { } pub fn firstToken(self: &NodeStructField) Token { + if (self.visib_token) |visib_token| return visib_token; return self.name_token; } diff --git a/std/zig/parser.zig b/std/zig/parser.zig index 3e69e0e163..669bf70633 100644 --- a/std/zig/parser.zig +++ b/std/zig/parser.zig @@ -669,6 +669,7 @@ pub const Parser = struct { const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeStructField, ast.NodeStructField { .base = undefined, + .visib_token = null, .name_token = token, .type_expr = undefined, } @@ -721,7 +722,42 @@ pub const Parser = struct { }, } }, - Token.Id.Keyword_pub, Token.Id.Keyword_export => { + Token.Id.Keyword_pub => { + if (self.eatToken(Token.Id.Identifier)) |identifier| { + switch (container_decl.kind) { + ast.NodeContainerDecl.Kind.Struct => { + const node = try self.createAttachNode(arena, &container_decl.fields_and_decls, ast.NodeStructField, + ast.NodeStructField { + .base = undefined, + .visib_token = token, + .name_token = identifier, + .type_expr = undefined, + } + ); + + stack.append(State { .FieldListCommaOrEnd = container_decl }) catch unreachable; + try stack.append(State { .Expression = DestPtr { .Field = &node.type_expr } }); + try stack.append(State { .ExpectToken = Token.Id.Colon }); + continue; + }, + else => { + self.putBackToken(identifier); + } + } + } + + stack.append(State{ .ContainerDecl = container_decl }) catch unreachable; + try stack.append(State { + .TopLevelExtern = TopLevelDeclCtx { + .decls = &container_decl.fields_and_decls, + .visib_token = token, + .extern_token = null, + .lib_name = null, + } + }); + continue; + }, + Token.Id.Keyword_export => { stack.append(State{ .ContainerDecl = container_decl }) catch unreachable; try stack.append(State { .TopLevelExtern = TopLevelDeclCtx { @@ -864,111 +900,11 @@ pub const Parser = struct { stack.append(State { .Expression = DestPtr { .Field = &node.rhs } }) catch unreachable; continue; }, - Token.Id.Keyword_suspend => { - const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSuspend, - ast.NodeSuspend { - .base = undefined, - .suspend_token = token, - .payload = null, - .body = null, - } - ); - - stack.append(State { .SuspendBody = node }) catch unreachable; - try stack.append(State { .Payload = &node.payload }); - continue; - }, - Token.Id.Keyword_if => { - const node = try self.createToDestNode(arena, dest_ptr, ast.NodeIf, - ast.NodeIf { - .base = undefined, - .if_token = token, - .condition = undefined, - .payload = null, - .body = undefined, - .@"else" = null, - } - ); - - stack.append(State { .Else = &node.@"else" }) catch unreachable; - try stack.append(State { .Expression = DestPtr { .Field = &node.body } }); - try stack.append(State { .PointerPayload = &node.payload }); - try stack.append(State { .ExpectToken = Token.Id.RParen }); - try stack.append(State { .Expression = DestPtr { .Field = &node.condition } }); - try stack.append(State { .ExpectToken = Token.Id.LParen }); - continue; - }, - Token.Id.Keyword_while => { - stack.append(State { - .While = LoopCtx { - .label = null, - .inline_token = null, - .loop_token = token, - .dest_ptr = dest_ptr, - } - }) catch unreachable; - continue; - }, - Token.Id.Keyword_for => { - stack.append(State { - .For = LoopCtx { - .label = null, - .inline_token = null, - .loop_token = token, - .dest_ptr = dest_ptr, - } - }) catch unreachable; - continue; - }, - Token.Id.Keyword_switch => { - const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSwitch, - ast.NodeSwitch { - .base = undefined, - .switch_token = token, - .expr = undefined, - .cases = ArrayList(&ast.NodeSwitchCase).init(arena), - .rbrace = undefined, - } - ); - - stack.append(State { - .SwitchCaseOrEnd = ListSave(&ast.NodeSwitchCase) { - .list = &node.cases, - .ptr = &node.rbrace, - }, - }) catch unreachable; - try stack.append(State { .ExpectToken = Token.Id.LBrace }); - try stack.append(State { .ExpectToken = Token.Id.RParen }); - try stack.append(State { .Expression = DestPtr { .Field = &node.expr } }); - try stack.append(State { .ExpectToken = Token.Id.LParen }); - }, - Token.Id.Keyword_comptime => { - const node = try self.createToDestNode(arena, dest_ptr, ast.NodeComptime, - ast.NodeComptime { - .base = undefined, - .comptime_token = token, - .expr = undefined, - } - ); - try stack.append(State { .Expression = DestPtr { .Field = &node.expr } }); - continue; - }, - Token.Id.LBrace => { - const block = try self.createToDestNode(arena, dest_ptr, ast.NodeBlock, - ast.NodeBlock { - .base = undefined, - .label = null, - .lbrace = token, - .statements = ArrayList(&ast.Node).init(arena), - .rbrace = undefined, - } - ); - stack.append(State { .Block = block }) catch unreachable; - continue; - }, else => { - self.putBackToken(token); - stack.append(State { .UnwrapExpressionBegin = dest_ptr }) catch unreachable; + if (!try self.parseBlockExpr(&stack, arena, dest_ptr, token)) { + self.putBackToken(token); + stack.append(State { .UnwrapExpressionBegin = dest_ptr }) catch unreachable; + } continue; } } @@ -1407,7 +1343,7 @@ pub const Parser = struct { State.PrefixOpExpression => |dest_ptr| { const token = self.getNextToken(); if (tokenIdToPrefixOp(token.id)) |prefix_id| { - const node = try self.createToDestNode(arena, dest_ptr, ast.NodePrefixOp, + var node = try self.createToDestNode(arena, dest_ptr, ast.NodePrefixOp, ast.NodePrefixOp { .base = undefined, .op_token = token, @@ -1415,6 +1351,20 @@ pub const Parser = struct { .rhs = undefined, } ); + + if (token.id == Token.Id.AsteriskAsterisk) { + const child = try self.createNode(arena, ast.NodePrefixOp, + ast.NodePrefixOp { + .base = undefined, + .op_token = token, + .op = prefix_id, + .rhs = undefined, + } + ); + node.rhs = &child.base; + node = child; + } + stack.append(State { .TypeExprBegin = DestPtr { .Field = &node.rhs } }) catch unreachable; if (node.op == ast.NodePrefixOp.PrefixOp.AddrOf) { try stack.append(State { .AddrOfModifiers = &node.op.AddrOf }); @@ -1871,7 +1821,9 @@ pub const Parser = struct { continue; }, else => { - try self.parseError(&stack, token, "expected primary expression, found {}", @tagName(token.id)); + if (!try self.parseBlockExpr(&stack, arena, dest_ptr, token)) { + try self.parseError(&stack, token, "expected primary expression, found {}", @tagName(token.id)); + } continue; } } @@ -2790,6 +2742,117 @@ pub const Parser = struct { } } + fn parseBlockExpr(self: &Parser, stack: &ArrayList(State), arena: &mem.Allocator, dest_ptr: &const DestPtr, token: &const Token) !bool { + switch (token.id) { + Token.Id.Keyword_suspend => { + const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSuspend, + ast.NodeSuspend { + .base = undefined, + .suspend_token = *token, + .payload = null, + .body = null, + } + ); + + stack.append(State { .SuspendBody = node }) catch unreachable; + try stack.append(State { .Payload = &node.payload }); + return true; + }, + Token.Id.Keyword_if => { + const node = try self.createToDestNode(arena, dest_ptr, ast.NodeIf, + ast.NodeIf { + .base = undefined, + .if_token = *token, + .condition = undefined, + .payload = null, + .body = undefined, + .@"else" = null, + } + ); + + stack.append(State { .Else = &node.@"else" }) catch unreachable; + try stack.append(State { .Expression = DestPtr { .Field = &node.body } }); + try stack.append(State { .PointerPayload = &node.payload }); + try stack.append(State { .ExpectToken = Token.Id.RParen }); + try stack.append(State { .Expression = DestPtr { .Field = &node.condition } }); + try stack.append(State { .ExpectToken = Token.Id.LParen }); + return true; + }, + Token.Id.Keyword_while => { + stack.append(State { + .While = LoopCtx { + .label = null, + .inline_token = null, + .loop_token = *token, + .dest_ptr = *dest_ptr, + } + }) catch unreachable; + return true; + }, + Token.Id.Keyword_for => { + stack.append(State { + .For = LoopCtx { + .label = null, + .inline_token = null, + .loop_token = *token, + .dest_ptr = *dest_ptr, + } + }) catch unreachable; + return true; + }, + Token.Id.Keyword_switch => { + const node = try self.createToDestNode(arena, dest_ptr, ast.NodeSwitch, + ast.NodeSwitch { + .base = undefined, + .switch_token = *token, + .expr = undefined, + .cases = ArrayList(&ast.NodeSwitchCase).init(arena), + .rbrace = undefined, + } + ); + + stack.append(State { + .SwitchCaseOrEnd = ListSave(&ast.NodeSwitchCase) { + .list = &node.cases, + .ptr = &node.rbrace, + }, + }) catch unreachable; + try stack.append(State { .ExpectToken = Token.Id.LBrace }); + try stack.append(State { .ExpectToken = Token.Id.RParen }); + try stack.append(State { .Expression = DestPtr { .Field = &node.expr } }); + try stack.append(State { .ExpectToken = Token.Id.LParen }); + return true; + }, + Token.Id.Keyword_comptime => { + const node = try self.createToDestNode(arena, dest_ptr, ast.NodeComptime, + ast.NodeComptime { + .base = undefined, + .comptime_token = *token, + .expr = undefined, + } + ); + try stack.append(State { .Expression = DestPtr { .Field = &node.expr } }); + return true; + }, + Token.Id.LBrace => { + const block = try self.createToDestNode(arena, dest_ptr, ast.NodeBlock, + ast.NodeBlock { + .base = undefined, + .label = null, + .lbrace = *token, + .statements = ArrayList(&ast.Node).init(arena), + .rbrace = undefined, + } + ); + stack.append(State { .Block = block }) catch unreachable; + return true; + }, + else => { + return false; + } + } + } + fn commaOrEnd(self: &Parser, stack: &ArrayList(State), end: &const Token.Id, maybe_ptr: ?&Token, state_after_comma: &const State) !void { var token = self.getNextToken(); switch (token.id) { @@ -2881,7 +2944,7 @@ pub const Parser = struct { Token.Id.Tilde => ast.NodePrefixOp.PrefixOp { .BitNot = void{} }, Token.Id.Minus => ast.NodePrefixOp.PrefixOp { .Negation = void{} }, Token.Id.MinusPercent => ast.NodePrefixOp.PrefixOp { .NegationWrap = void{} }, - Token.Id.Asterisk => ast.NodePrefixOp.PrefixOp { .Deref = void{} }, + Token.Id.Asterisk, Token.Id.AsteriskAsterisk => ast.NodePrefixOp.PrefixOp { .Deref = void{} }, Token.Id.Ampersand => ast.NodePrefixOp.PrefixOp { .AddrOf = ast.NodePrefixOp.AddrOfInfo { .align_expr = null, @@ -3126,6 +3189,9 @@ pub const Parser = struct { }, ast.Node.Id.StructField => { const field = @fieldParentPtr(ast.NodeStructField, "base", decl); + if (field.visib_token) |visib_token| { + try stream.print("{} ", self.tokenizer.getTokenSlice(visib_token)); + } try stream.print("{}: ", self.tokenizer.getTokenSlice(field.name_token)); try stack.append(RenderState { .Expression = field.type_expr}); }, @@ -4573,6 +4639,7 @@ test "zig fmt: struct declaration" { \\const S = struct { \\ const Self = this; \\ f1: u8, + \\ pub f3: u8, \\ \\ fn method(self: &Self) Self { \\ return *self; @@ -4583,14 +4650,14 @@ test "zig fmt: struct declaration" { \\ \\const Ps = packed struct { \\ a: u8, - \\ b: u8, + \\ pub b: u8, \\ \\ c: u8 \\}; \\ \\const Es = extern struct { \\ a: u8, - \\ b: u8, + \\ pub b: u8, \\ \\ c: u8 \\}; @@ -4895,6 +4962,7 @@ test "zig fmt: if" { \\ } \\ \\ const is_world_broken = if (10 < 0) true else false; + \\ const some_number = 1 + if (10 < 0) 2 else 3; \\ \\ const a: ?u8 = 10; \\ const b: ?u8 = null; From 841ac0f4e1b5ca6ae8f2250248363521d9f56c36 Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 11 Apr 2018 13:46:35 +0200 Subject: [PATCH 04/12] std.zig.parser now allows assignment expr in switch cases. This makes `std/os/index.zig` parse related: #909 --- std/zig/parser.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/std/zig/parser.zig b/std/zig/parser.zig index 669bf70633..16afe57bed 100644 --- a/std/zig/parser.zig +++ b/std/zig/parser.zig @@ -2036,7 +2036,7 @@ pub const Parser = struct { ); try list_state.list.append(node); stack.append(State { .SwitchCaseCommaOrEnd = list_state }) catch unreachable; - try stack.append(State { .Expression = DestPtr{ .Field = &node.expr } }); + try stack.append(State { .AssignmentExpressionBegin = DestPtr{ .Field = &node.expr } }); try stack.append(State { .PointerPayload = &node.payload }); const maybe_else = self.getNextToken(); @@ -4817,6 +4817,7 @@ test "zig fmt: switch" { \\ const res = switch (0) { \\ 0 => 0, \\ 1 => 2, + \\ 1 => a = 4, \\ else => 4 \\ }; \\ From 28ea364e5e60464f68501fdfa69ba41b9cf9c47e Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 11 Apr 2018 13:56:39 +0200 Subject: [PATCH 05/12] std.zig.parser now handle `try`'s precedence correctly This allows parsing of `std/zig/parser.zig`. Related: #909 --- std/zig/parser.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/std/zig/parser.zig b/std/zig/parser.zig index 16afe57bed..104e7e4cff 100644 --- a/std/zig/parser.zig +++ b/std/zig/parser.zig @@ -2957,6 +2957,7 @@ pub const Parser = struct { Token.Id.QuestionMark => ast.NodePrefixOp.PrefixOp { .MaybeType = void{} }, Token.Id.QuestionMarkQuestionMark => ast.NodePrefixOp.PrefixOp { .UnwrapMaybe = void{} }, Token.Id.Keyword_await => ast.NodePrefixOp.PrefixOp { .Await = void{} }, + Token.Id.Keyword_try => ast.NodePrefixOp.PrefixOp { .Try = void{ } }, else => null, }; } From fe7146277d5a7f7c74a8c2f36719c946e6061c50 Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 11 Apr 2018 14:43:53 +0200 Subject: [PATCH 06/12] std.zig.parser now accept both string and multiline string for strings Related #909 Allows it to parse `std/special/compiler_rt/aullrem.zig`, `std/special/compiler_rt/aulldiv.zig` and `std/math/x86_64/sqrt.zig` --- std/zig/ast.zig | 14 +++--- std/zig/parser.zig | 121 +++++++++++++++++++++++++++------------------ 2 files changed, 81 insertions(+), 54 deletions(-) diff --git a/std/zig/ast.zig b/std/zig/ast.zig index b671feb4f2..a5006f192c 100644 --- a/std/zig/ast.zig +++ b/std/zig/ast.zig @@ -1608,7 +1608,7 @@ pub const NodeThisLiteral = struct { pub const NodeAsmOutput = struct { base: Node, symbolic_name: &NodeIdentifier, - constraint: &NodeStringLiteral, + constraint: &Node, kind: Kind, const Kind = union(enum) { @@ -1622,7 +1622,7 @@ pub const NodeAsmOutput = struct { if (i < 1) return &self.symbolic_name.base; i -= 1; - if (i < 1) return &self.constraint.base; + if (i < 1) return self.constraint; i -= 1; switch (self.kind) { @@ -1654,7 +1654,7 @@ pub const NodeAsmOutput = struct { pub const NodeAsmInput = struct { base: Node, symbolic_name: &NodeIdentifier, - constraint: &NodeStringLiteral, + constraint: &Node, expr: &Node, pub fn iterate(self: &NodeAsmInput, index: usize) ?&Node { @@ -1663,7 +1663,7 @@ pub const NodeAsmInput = struct { if (i < 1) return &self.symbolic_name.base; i -= 1; - if (i < 1) return &self.constraint.base; + if (i < 1) return self.constraint; i -= 1; if (i < 1) return self.expr; @@ -1685,11 +1685,11 @@ pub const NodeAsm = struct { base: Node, asm_token: Token, is_volatile: bool, - template: Token, + template: &Node, //tokens: ArrayList(AsmToken), outputs: ArrayList(&NodeAsmOutput), inputs: ArrayList(&NodeAsmInput), - cloppers: ArrayList(&NodeStringLiteral), + cloppers: ArrayList(&Node), rparen: Token, pub fn iterate(self: &NodeAsm, index: usize) ?&Node { @@ -1701,7 +1701,7 @@ pub const NodeAsm = struct { if (i < self.inputs.len) return &self.inputs.at(index).base; i -= self.inputs.len; - if (i < self.cloppers.len) return &self.cloppers.at(index).base; + if (i < self.cloppers.len) return self.cloppers.at(index); i -= self.cloppers.len; return null; diff --git a/std/zig/parser.zig b/std/zig/parser.zig index 104e7e4cff..7704698a0c 100644 --- a/std/zig/parser.zig +++ b/std/zig/parser.zig @@ -171,7 +171,7 @@ pub const Parser = struct { Semicolon: &const &const ast.Node, AsmOutputItems: &ArrayList(&ast.NodeAsmOutput), AsmInputItems: &ArrayList(&ast.NodeAsmInput), - AsmClopperItems: &ArrayList(&ast.NodeStringLiteral), + AsmClopperItems: &ArrayList(&ast.Node), ExprListItemOrEnd: ExprListCtx, ExprListCommaOrEnd: ExprListCtx, FieldInitListItemOrEnd: ListSave(&ast.NodeFieldInitializer), @@ -301,7 +301,11 @@ pub const Parser = struct { Token.Id.Keyword_test => { stack.append(State.TopLevel) catch unreachable; - const name_token = (try self.expectToken(&stack, Token.Id.StringLiteral)) ?? continue; + const name_token = self.getNextToken(); + const name = (try self.parseStringLiteral(arena, name_token)) ?? { + try self.parseError(&stack, name_token, "expected string literal, found {}", @tagName(name_token.id)); + continue; + }; const lbrace = (try self.expectToken(&stack, Token.Id.LBrace)) ?? continue; const block = try self.createNode(arena, ast.NodeBlock, @@ -317,7 +321,7 @@ pub const Parser = struct { ast.NodeTestDecl { .base = undefined, .test_token = token, - .name = &(try self.createLiteral(arena, ast.NodeStringLiteral, name_token)).base, + .name = name, .body_node = &block.base, } ); @@ -389,15 +393,12 @@ pub const Parser = struct { continue; }, Token.Id.Keyword_extern => { - const lib_name_token = self.getNextToken(); const lib_name = blk: { - if (lib_name_token.id == Token.Id.StringLiteral) { - const res = try self.createLiteral(arena, ast.NodeStringLiteral, lib_name_token); - break :blk &res.base; - } else { + const lib_name_token = self.getNextToken(); + break :blk (try self.parseStringLiteral(arena, lib_name_token)) ?? { self.putBackToken(lib_name_token); break :blk null; - } + }; }; stack.append(State { @@ -1504,10 +1505,6 @@ pub const Parser = struct { dest_ptr.store(&(try self.createLiteral(arena, ast.NodeFloatLiteral, token)).base); continue; }, - Token.Id.StringLiteral => { - dest_ptr.store(&(try self.createLiteral(arena, ast.NodeStringLiteral, token)).base); - continue; - }, Token.Id.CharLiteral => { dest_ptr.store(&(try self.createLiteral(arena, ast.NodeCharLiteral, token)).base); continue; @@ -1536,24 +1533,8 @@ pub const Parser = struct { dest_ptr.store(&(try self.createLiteral(arena, ast.NodeUnreachable, token)).base); continue; }, - Token.Id.MultilineStringLiteralLine => { - const node = try self.createToDestNode(arena, dest_ptr, ast.NodeMultilineStringLiteral, - ast.NodeMultilineStringLiteral { - .base = undefined, - .tokens = ArrayList(Token).init(arena), - } - ); - try node.tokens.append(token); - while (true) { - const multiline_str = self.getNextToken(); - if (multiline_str.id != Token.Id.MultilineStringLiteralLine) { - self.putBackToken(multiline_str); - break; - } - - try node.tokens.append(multiline_str); - } - continue; + Token.Id.StringLiteral, Token.Id.MultilineStringLiteralLine => { + dest_ptr.store((try self.parseStringLiteral(arena, token)) ?? unreachable); }, Token.Id.LParen => { const node = try self.createToDestNode(arena, dest_ptr, ast.NodeGroupedExpression, @@ -1781,7 +1762,12 @@ pub const Parser = struct { break :blk true; }; _ = (try self.expectToken(&stack, Token.Id.LParen)) ?? continue; - const template = (try self.expectToken(&stack, Token.Id.StringLiteral)) ?? continue; + + const template_token = self.getNextToken(); + const template = (try self.parseStringLiteral(arena, template_token)) ?? { + try self.parseError(&stack, template_token, "expected string literal, found {}", @tagName(template_token.id)); + continue; + }; // TODO parse template const node = try self.createToDestNode(arena, dest_ptr, ast.NodeAsm, @@ -1793,7 +1779,7 @@ pub const Parser = struct { //.tokens = ArrayList(ast.NodeAsm.AsmToken).init(arena), .outputs = ArrayList(&ast.NodeAsmOutput).init(arena), .inputs = ArrayList(&ast.NodeAsmInput).init(arena), - .cloppers = ArrayList(&ast.NodeStringLiteral).init(arena), + .cloppers = ArrayList(&ast.Node).init(arena), .rparen = undefined, } ); @@ -1881,7 +1867,12 @@ pub const Parser = struct { const symbolic_name = (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue; _ = (try self.expectToken(&stack, Token.Id.RBracket)) ?? continue; - const constraint = (try self.expectToken(&stack, Token.Id.StringLiteral)) ?? continue; + + const constraint_token = self.getNextToken(); + const constraint = (try self.parseStringLiteral(arena, constraint_token)) ?? { + try self.parseError(&stack, constraint_token, "expected string literal, found {}", @tagName(constraint_token.id)); + continue; + }; _ = (try self.expectToken(&stack, Token.Id.LParen)) ?? continue; try stack.append(State { .ExpectToken = Token.Id.RParen }); @@ -1890,7 +1881,7 @@ pub const Parser = struct { ast.NodeAsmOutput { .base = undefined, .symbolic_name = try self.createLiteral(arena, ast.NodeIdentifier, symbolic_name), - .constraint = try self.createLiteral(arena, ast.NodeStringLiteral, constraint), + .constraint = constraint, .kind = undefined, } ); @@ -1926,7 +1917,12 @@ pub const Parser = struct { const symbolic_name = (try self.expectToken(&stack, Token.Id.Identifier)) ?? continue; _ = (try self.expectToken(&stack, Token.Id.RBracket)) ?? continue; - const constraint = (try self.expectToken(&stack, Token.Id.StringLiteral)) ?? continue; + + const constraint_token = self.getNextToken(); + const constraint = (try self.parseStringLiteral(arena, constraint_token)) ?? { + try self.parseError(&stack, constraint_token, "expected string literal, found {}", @tagName(constraint_token.id)); + continue; + }; _ = (try self.expectToken(&stack, Token.Id.LParen)) ?? continue; try stack.append(State { .ExpectToken = Token.Id.RParen }); @@ -1935,7 +1931,7 @@ pub const Parser = struct { ast.NodeAsmInput { .base = undefined, .symbolic_name = try self.createLiteral(arena, ast.NodeIdentifier, symbolic_name), - .constraint = try self.createLiteral(arena, ast.NodeStringLiteral, constraint), + .constraint = constraint, .expr = undefined, } ); @@ -1944,13 +1940,13 @@ pub const Parser = struct { }, State.AsmClopperItems => |items| { - const string = self.getNextToken(); - if (string.id != Token.Id.StringLiteral) { - self.putBackToken(string); + const string_token = self.getNextToken(); + const string = (try self.parseStringLiteral(arena, string_token)) ?? { + self.putBackToken(string_token); continue; - } + }; + try items.append(string); - try items.append(try self.createLiteral(arena, ast.NodeStringLiteral, string)); stack.append(State { .AsmClopperItems = items }) catch unreachable; try stack.append(State { .IfToken = Token.Id.Comma }); }, @@ -2742,6 +2738,37 @@ pub const Parser = struct { } } + fn parseStringLiteral(self: &Parser, arena: &mem.Allocator, token: &const Token) !?&ast.Node { + switch (token.id) { + Token.Id.StringLiteral => { + return &(try self.createLiteral(arena, ast.NodeStringLiteral, token)).base; + }, + Token.Id.MultilineStringLiteralLine => { + const node = try self.createNode(arena, ast.NodeMultilineStringLiteral, + ast.NodeMultilineStringLiteral { + .base = undefined, + .tokens = ArrayList(Token).init(arena), + } + ); + try node.tokens.append(token); + while (true) { + const multiline_str = self.getNextToken(); + if (multiline_str.id != Token.Id.MultilineStringLiteralLine) { + self.putBackToken(multiline_str); + break; + } + + try node.tokens.append(multiline_str); + } + + return &node.base; + }, + // TODO: We shouldn't need a cast, but: + // zig: /home/jc/Documents/zig/src/ir.cpp:7962: TypeTableEntry* ir_resolve_peer_types(IrAnalyze*, AstNode*, IrInstruction**, size_t): Assertion `err_set_type != nullptr' failed. + else => return (?&ast.Node)(null), + } + } + fn parseBlockExpr(self: &Parser, stack: &ArrayList(State), arena: &mem.Allocator, dest_ptr: &const DestPtr, token: &const Token) !bool { switch (token.id) { Token.Id.Keyword_suspend => { @@ -4085,8 +4112,6 @@ pub const Parser = struct { try stream.write("volatile "); } - try stream.print("({}", self.tokenizer.getTokenSlice(asm_node.template)); - try stack.append(RenderState { .Indent = indent }); try stack.append(RenderState { .Text = ")" }); { @@ -4094,7 +4119,7 @@ pub const Parser = struct { var i = cloppers.len; while (i != 0) { i -= 1; - try stack.append(RenderState { .Expression = &cloppers[i].base }); + try stack.append(RenderState { .Expression = cloppers[i] }); if (i != 0) { try stack.append(RenderState { .Text = ", " }); @@ -4163,6 +4188,8 @@ pub const Parser = struct { try stack.append(RenderState.PrintIndent); try stack.append(RenderState { .Indent = indent + indent_delta}); try stack.append(RenderState { .Text = "\n" }); + try stack.append(RenderState { .Expression = asm_node.template }); + try stack.append(RenderState { .Text = "(" }); }, ast.Node.Id.AsmInput => { const asm_input = @fieldParentPtr(ast.NodeAsmInput, "base", base); @@ -4170,7 +4197,7 @@ pub const Parser = struct { try stack.append(RenderState { .Text = ")"}); try stack.append(RenderState { .Expression = asm_input.expr}); try stack.append(RenderState { .Text = " ("}); - try stack.append(RenderState { .Expression = &asm_input.constraint.base}); + try stack.append(RenderState { .Expression = asm_input.constraint }); try stack.append(RenderState { .Text = "] "}); try stack.append(RenderState { .Expression = &asm_input.symbolic_name.base}); try stack.append(RenderState { .Text = "["}); @@ -4189,7 +4216,7 @@ pub const Parser = struct { }, } try stack.append(RenderState { .Text = " ("}); - try stack.append(RenderState { .Expression = &asm_output.constraint.base}); + try stack.append(RenderState { .Expression = asm_output.constraint }); try stack.append(RenderState { .Text = "] "}); try stack.append(RenderState { .Expression = &asm_output.symbolic_name.base}); try stack.append(RenderState { .Text = "["}); From df4c575525a8ab3d190b46af724a718c77e607e3 Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 11 Apr 2018 15:17:51 +0200 Subject: [PATCH 07/12] std.zig.parser now parses inline fn proto Related #909 Allows parsing of `std/os/zen.zig`. --- std/zig/ast.zig | 10 ++-- std/zig/parser.zig | 142 +++++++++++++++++++++++++++------------------ 2 files changed, 91 insertions(+), 61 deletions(-) diff --git a/std/zig/ast.zig b/std/zig/ast.zig index a5006f192c..230fe26568 100644 --- a/std/zig/ast.zig +++ b/std/zig/ast.zig @@ -214,7 +214,7 @@ pub const NodeVarDecl = struct { eq_token: Token, mut_token: Token, comptime_token: ?Token, - extern_token: ?Token, + extern_export_token: ?Token, lib_name: ?&Node, type_node: ?&Node, align_node: ?&Node, @@ -245,7 +245,7 @@ pub const NodeVarDecl = struct { pub fn firstToken(self: &NodeVarDecl) Token { if (self.visib_token) |visib_token| return visib_token; if (self.comptime_token) |comptime_token| return comptime_token; - if (self.extern_token) |extern_token| return extern_token; + if (self.extern_export_token) |extern_export_token| return extern_export_token; assert(self.lib_name == null); return self.mut_token; } @@ -496,8 +496,7 @@ pub const NodeFnProto = struct { params: ArrayList(&Node), return_type: ReturnType, var_args_token: ?Token, - extern_token: ?Token, - inline_token: ?Token, + extern_export_inline_token: ?Token, cc_token: ?Token, async_attr: ?&NodeAsyncAttribute, body_node: ?&Node, @@ -547,9 +546,8 @@ pub const NodeFnProto = struct { pub fn firstToken(self: &NodeFnProto) Token { if (self.visib_token) |visib_token| return visib_token; - if (self.extern_token) |extern_token| return extern_token; + if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token; assert(self.lib_name == null); - if (self.inline_token) |inline_token| return inline_token; if (self.cc_token) |cc_token| return cc_token; return self.fn_token; } diff --git a/std/zig/parser.zig b/std/zig/parser.zig index 7704698a0c..50165164cd 100644 --- a/std/zig/parser.zig +++ b/std/zig/parser.zig @@ -55,7 +55,7 @@ pub const Parser = struct { const TopLevelDeclCtx = struct { decls: &ArrayList(&ast.Node), visib_token: ?Token, - extern_token: ?Token, + extern_export_inline_token: ?Token, lib_name: ?&ast.Node, }; @@ -142,6 +142,7 @@ pub const Parser = struct { const State = union(enum) { TopLevel, TopLevelExtern: TopLevelDeclCtx, + TopLevelLibname: TopLevelDeclCtx, TopLevelDecl: TopLevelDeclCtx, ContainerExtern: ContainerExternCtx, ContainerDecl: &ast.NodeContainerDecl, @@ -332,13 +333,13 @@ pub const Parser = struct { root_node.eof_token = token; return Tree {.root_node = root_node, .arena_allocator = arena_allocator}; }, - Token.Id.Keyword_pub, Token.Id.Keyword_export => { + Token.Id.Keyword_pub => { stack.append(State.TopLevel) catch unreachable; try stack.append(State { .TopLevelExtern = TopLevelDeclCtx { .decls = &root_node.decls, .visib_token = token, - .extern_token = null, + .extern_export_inline_token = null, .lib_name = null, } }); @@ -363,7 +364,7 @@ pub const Parser = struct { .TopLevelExtern = TopLevelDeclCtx { .decls = &root_node.decls, .visib_token = null, - .extern_token = null, + .extern_export_inline_token = null, .lib_name = null, } }); @@ -372,9 +373,66 @@ pub const Parser = struct { } }, State.TopLevelExtern => |ctx| { + const token = self.getNextToken(); + switch (token.id) { + Token.Id.Keyword_export, Token.Id.Keyword_inline => { + stack.append(State { + .TopLevelDecl = TopLevelDeclCtx { + .decls = ctx.decls, + .visib_token = ctx.visib_token, + .extern_export_inline_token = token, + .lib_name = null, + }, + }) catch unreachable; + continue; + }, + Token.Id.Keyword_extern => { + stack.append(State { + .TopLevelLibname = TopLevelDeclCtx { + .decls = ctx.decls, + .visib_token = ctx.visib_token, + .extern_export_inline_token = token, + .lib_name = null, + }, + }) catch unreachable; + continue; + }, + else => { + self.putBackToken(token); + stack.append(State { .TopLevelDecl = ctx }) catch unreachable; + continue; + } + } + }, + + State.TopLevelLibname => |ctx| { + const lib_name = blk: { + const lib_name_token = self.getNextToken(); + break :blk (try self.parseStringLiteral(arena, lib_name_token)) ?? { + self.putBackToken(lib_name_token); + break :blk null; + }; + }; + + stack.append(State { + .TopLevelDecl = TopLevelDeclCtx { + .decls = ctx.decls, + .visib_token = ctx.visib_token, + .extern_export_inline_token = ctx.extern_export_inline_token, + .lib_name = lib_name, + }, + }) catch unreachable; + }, + + State.TopLevelDecl => |ctx| { const token = self.getNextToken(); switch (token.id) { Token.Id.Keyword_use => { + if (ctx.extern_export_inline_token != null) { + try self.parseError(&stack, token, "Invalid token {}", @tagName((??ctx.extern_export_inline_token).id)); + continue; + } + const node = try self.createAttachNode(arena, ctx.decls, ast.NodeUse, ast.NodeUse { .base = undefined, @@ -392,43 +450,21 @@ pub const Parser = struct { try stack.append(State { .Expression = DestPtr { .Field = &node.expr } }); continue; }, - Token.Id.Keyword_extern => { - const lib_name = blk: { - const lib_name_token = self.getNextToken(); - break :blk (try self.parseStringLiteral(arena, lib_name_token)) ?? { - self.putBackToken(lib_name_token); - break :blk null; - }; - }; - - stack.append(State { - .TopLevelDecl = TopLevelDeclCtx { - .decls = ctx.decls, - .visib_token = ctx.visib_token, - .extern_token = token, - .lib_name = lib_name, - }, - }) catch unreachable; - continue; - }, - else => { - self.putBackToken(token); - stack.append(State { .TopLevelDecl = ctx }) catch unreachable; - continue; - } - } - }, - State.TopLevelDecl => |ctx| { - const token = self.getNextToken(); - switch (token.id) { Token.Id.Keyword_var, Token.Id.Keyword_const => { + if (ctx.extern_export_inline_token) |extern_export_inline_token| { + if (extern_export_inline_token.id == Token.Id.Keyword_inline) { + try self.parseError(&stack, token, "Invalid token {}", @tagName(extern_export_inline_token.id)); + continue; + } + } + const var_decl_node = try self.createAttachNode(arena, ctx.decls, ast.NodeVarDecl, ast.NodeVarDecl { .base = undefined, .visib_token = ctx.visib_token, .mut_token = token, .comptime_token = null, - .extern_token = ctx.extern_token, + .extern_export_token = ctx.extern_export_inline_token, .type_node = null, .align_node = null, .init_node = null, @@ -452,8 +488,7 @@ pub const Parser = struct { .params = ArrayList(&ast.Node).init(arena), .return_type = undefined, .var_args_token = null, - .extern_token = ctx.extern_token, - .inline_token = null, + .extern_export_inline_token = ctx.extern_export_inline_token, .cc_token = null, .async_attr = null, .body_node = null, @@ -475,8 +510,7 @@ pub const Parser = struct { .params = ArrayList(&ast.Node).init(arena), .return_type = undefined, .var_args_token = null, - .extern_token = ctx.extern_token, - .inline_token = null, + .extern_export_inline_token = ctx.extern_export_inline_token, .cc_token = token, .async_attr = null, .body_node = null, @@ -513,8 +547,7 @@ pub const Parser = struct { .params = ArrayList(&ast.Node).init(arena), .return_type = undefined, .var_args_token = null, - .extern_token = ctx.extern_token, - .inline_token = null, + .extern_export_inline_token = ctx.extern_export_inline_token, .cc_token = null, .async_attr = async_node, .body_node = null, @@ -752,7 +785,7 @@ pub const Parser = struct { .TopLevelExtern = TopLevelDeclCtx { .decls = &container_decl.fields_and_decls, .visib_token = token, - .extern_token = null, + .extern_export_inline_token = null, .lib_name = null, } }); @@ -764,7 +797,7 @@ pub const Parser = struct { .TopLevelExtern = TopLevelDeclCtx { .decls = &container_decl.fields_and_decls, .visib_token = token, - .extern_token = null, + .extern_export_inline_token = null, .lib_name = null, } }); @@ -781,7 +814,7 @@ pub const Parser = struct { .TopLevelExtern = TopLevelDeclCtx { .decls = &container_decl.fields_and_decls, .visib_token = null, - .extern_token = null, + .extern_export_inline_token = null, .lib_name = null, } }); @@ -1659,8 +1692,7 @@ pub const Parser = struct { .params = ArrayList(&ast.Node).init(arena), .return_type = undefined, .var_args_token = null, - .extern_token = token, - .inline_token = null, + .extern_export_inline_token = token, .cc_token = null, .async_attr = null, .body_node = null, @@ -1717,8 +1749,7 @@ pub const Parser = struct { .params = ArrayList(&ast.Node).init(arena), .return_type = undefined, .var_args_token = null, - .extern_token = null, - .inline_token = null, + .extern_export_inline_token = null, .cc_token = null, .async_attr = null, .body_node = null, @@ -1740,8 +1771,7 @@ pub const Parser = struct { .params = ArrayList(&ast.Node).init(arena), .return_type = undefined, .var_args_token = null, - .extern_token = null, - .inline_token = null, + .extern_export_inline_token = null, .cc_token = token, .async_attr = null, .body_node = null, @@ -2573,7 +2603,7 @@ pub const Parser = struct { .visib_token = null, .mut_token = mut_token, .comptime_token = next, - .extern_token = null, + .extern_export_token = null, .type_node = null, .align_node = null, .init_node = null, @@ -2601,7 +2631,7 @@ pub const Parser = struct { .visib_token = null, .mut_token = next, .comptime_token = null, - .extern_token = null, + .extern_export_token = null, .type_node = null, .align_node = null, .init_node = null, @@ -3281,13 +3311,13 @@ pub const Parser = struct { try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(comptime_token) }); } - if (var_decl.extern_token) |extern_token| { + if (var_decl.extern_export_token) |extern_export_token| { if (var_decl.lib_name != null) { try stack.append(RenderState { .Text = " " }); try stack.append(RenderState { .Expression = ??var_decl.lib_name }); } try stack.append(RenderState { .Text = " " }); - try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_token) }); + try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_export_token) }); } if (var_decl.visib_token) |visib_token| { @@ -3865,9 +3895,9 @@ pub const Parser = struct { try stack.append(RenderState { .Text = " " }); try stack.append(RenderState { .Expression = lib_name }); } - if (fn_proto.extern_token) |extern_token| { + if (fn_proto.extern_export_inline_token) |extern_export_inline_token| { try stack.append(RenderState { .Text = " " }); - try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_token) }); + try stack.append(RenderState { .Text = self.tokenizer.getTokenSlice(extern_export_inline_token) }); } if (fn_proto.visib_token) |visib_token| { @@ -4608,6 +4638,8 @@ test "zig fmt: extern function" { try testCanonical( \\extern fn puts(s: &const u8) c_int; \\extern "c" fn puts(s: &const u8) c_int; + \\export fn puts(s: &const u8) c_int; + \\inline fn puts(s: &const u8) c_int; \\ ); } From a7f77d7c6a4326de4c4cd356cd88e48854817e6f Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 11 Apr 2018 15:26:00 +0200 Subject: [PATCH 08/12] std.zig.parser: requireSemiColon now matches the C++ behavior Related #909 Allowes parsing of `std/os/child_process.zig` --- std/zig/parser.zig | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/std/zig/parser.zig b/std/zig/parser.zig index 50165164cd..f1f6b0e371 100644 --- a/std/zig/parser.zig +++ b/std/zig/parser.zig @@ -2722,7 +2722,7 @@ pub const Parser = struct { continue; } - n = while_node.body; + return while_node.body.id != ast.Node.Id.Block; }, ast.Node.Id.For => { const for_node = @fieldParentPtr(ast.NodeFor, "base", n); @@ -2731,7 +2731,7 @@ pub const Parser = struct { continue; } - n = for_node.body; + return for_node.body.id != ast.Node.Id.Block; }, ast.Node.Id.If => { const if_node = @fieldParentPtr(ast.NodeIf, "base", n); @@ -2740,25 +2740,25 @@ pub const Parser = struct { continue; } - n = if_node.body; + return if_node.body.id != ast.Node.Id.Block; }, ast.Node.Id.Else => { const else_node = @fieldParentPtr(ast.NodeElse, "base", n); n = else_node.body; + continue; }, ast.Node.Id.Defer => { const defer_node = @fieldParentPtr(ast.NodeDefer, "base", n); - n = defer_node.expr; + return defer_node.expr.id != ast.Node.Id.Block; }, ast.Node.Id.Comptime => { const comptime_node = @fieldParentPtr(ast.NodeComptime, "base", n); - n = comptime_node.expr; + return comptime_node.expr.id != ast.Node.Id.Block; }, ast.Node.Id.Suspend => { const suspend_node = @fieldParentPtr(ast.NodeSuspend, "base", n); if (suspend_node.body) |body| { - n = body; - continue; + return body.id != ast.Node.Id.Block; } return true; From e48e707c32121a73f1fd2862197c8f47dbceea5e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 11 Apr 2018 14:44:32 -0400 Subject: [PATCH 09/12] allow integer and float literals to be passed to var params closes #623 --- src/ir.cpp | 9 ++++++++- test/cases/fn.zig | 10 ++++++++++ test/compile_errors.zig | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 0b072cc696..7d8088d5ed 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -11804,7 +11804,8 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod } } - bool comptime_arg = param_decl_node->data.param_decl.is_inline; + bool comptime_arg = param_decl_node->data.param_decl.is_inline || + casted_arg->value.type->id == TypeTableEntryIdNumLitInt || casted_arg->value.type->id == TypeTableEntryIdNumLitFloat; ConstExprValue *arg_val; @@ -11829,6 +11830,12 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod var->shadowable = !comptime_arg; *next_proto_i += 1; + } else if (casted_arg->value.type->id == TypeTableEntryIdNumLitInt || + casted_arg->value.type->id == TypeTableEntryIdNumLitFloat) + { + ir_add_error(ira, casted_arg, + buf_sprintf("compiler bug: integer and float literals in var args function must be casted. https://github.com/zig-lang/zig/issues/557")); + return false; } if (!comptime_arg) { diff --git a/test/cases/fn.zig b/test/cases/fn.zig index e492f6036c..c125d98d8c 100644 --- a/test/cases/fn.zig +++ b/test/cases/fn.zig @@ -94,3 +94,13 @@ test "inline function call" { } fn add(a: i32, b: i32) i32 { return a + b; } + + +test "number literal as an argument" { + numberLiteralArg(3); + comptime numberLiteralArg(3); +} + +fn numberLiteralArg(a: var) void { + assert(a == 3); +} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index bed5aa1b63..21e384e389 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1723,7 +1723,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { \\} \\ \\export fn entry() usize { return @sizeOf(@typeOf(bar)); } - , ".tmp_source.zig:10:16: error: parameter of type '(integer literal)' requires comptime"); + , ".tmp_source.zig:10:16: error: compiler bug: integer and float literals in var args function must be casted"); cases.add("assign too big number to u16", \\export fn foo() void { From 5b584e06e37296c602357cbaf27d39e068ac98c9 Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Wed, 11 Apr 2018 20:56:05 +0200 Subject: [PATCH 10/12] std.zig.parser special cased error in return. Related #909 This allows parsing of `std/special/build_runner.zig` --- std/zig/parser.zig | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/std/zig/parser.zig b/std/zig/parser.zig index f1f6b0e371..88e6ece35b 100644 --- a/std/zig/parser.zig +++ b/std/zig/parser.zig @@ -2354,6 +2354,16 @@ pub const Parser = struct { continue; }, else => { + // TODO: this is a special case. Remove this when #760 is fixed + if (token.id == Token.Id.Keyword_error) { + if (self.isPeekToken(Token.Id.LBrace)) { + fn_proto.return_type = ast.NodeFnProto.ReturnType { + .Explicit = &(try self.createLiteral(arena, ast.NodeErrorType, token)).base + }; + continue; + } + } + self.putBackToken(token); fn_proto.return_type = ast.NodeFnProto.ReturnType { .Explicit = undefined }; stack.append(State { @@ -5185,3 +5195,13 @@ test "zig fmt: string identifier" { \\ ); } + +test "zig fmt: error return" { + try testCanonical( + \\fn err() error { + \\ call(); + \\ return error.InvalidArgs; + \\} + \\ + ); +} From 2b86ffe34a7a03b20544b13f541f61bbc50ae015 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 11 Apr 2018 18:02:27 -0400 Subject: [PATCH 11/12] LLD patch: Do not keep shared symbols to garbage... -collected eliminated DSOs. This applies https://reviews.llvm.org/D45536 to the embedded LLD. Closes #883 --- deps/lld/ELF/MarkLive.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/deps/lld/ELF/MarkLive.cpp b/deps/lld/ELF/MarkLive.cpp index 88f558c7a3..9fca927437 100644 --- a/deps/lld/ELF/MarkLive.cpp +++ b/deps/lld/ELF/MarkLive.cpp @@ -301,6 +301,15 @@ template void elf::markLive() { // Follow the graph to mark all live sections. doGcSections(); + // If all references to a DSO happen to be weak, the DSO is removed from + // DT_NEEDED, which creates dangling shared symbols to non-existent DSO. + // We'll replace such symbols with undefined ones to fix it. + for (Symbol *Sym : Symtab->getSymbols()) + if (auto *S = dyn_cast(Sym)) + if (S->isWeak() && !S->getFile().IsNeeded) + replaceSymbol(S, nullptr, S->getName(), STB_WEAK, S->StOther, + S->Type); + // Report garbage-collected sections. if (Config->PrintGcSections) for (InputSectionBase *Sec : InputSections) From 0d8646d262ebc3db6631421db8fc79228b6622f8 Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Thu, 12 Apr 2018 08:46:26 +0200 Subject: [PATCH 12/12] std.zig.parser now parses alignment of functions Related #909 This allows it to parse `std/special/compiler_rt/index.zig` --- std/zig/parser.zig | 51 +++++++++++++++++----------------------------- 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/std/zig/parser.zig b/std/zig/parser.zig index 88e6ece35b..8948990f45 100644 --- a/std/zig/parser.zig +++ b/std/zig/parser.zig @@ -2330,12 +2330,14 @@ pub const Parser = struct { }, State.FnProtoAlign => |fn_proto| { + stack.append(State { .FnProtoReturnType = fn_proto }) catch unreachable; + if (self.eatToken(Token.Id.Keyword_align)) |align_token| { - @panic("TODO fn proto align"); + try stack.append(State { .ExpectToken = Token.Id.RParen }); + try stack.append(State { .Expression = DestPtr { .NullableField = &fn_proto.align_expr } }); + try stack.append(State { .ExpectToken = Token.Id.LParen }); } - stack.append(State { - .FnProtoReturnType = fn_proto, - }) catch unreachable; + continue; }, @@ -2349,10 +2351,6 @@ pub const Parser = struct { }) catch unreachable; continue; }, - Token.Id.Keyword_align => { - @panic("TODO fn proto align"); - continue; - }, else => { // TODO: this is a special case. Remove this when #760 is fixed if (token.id == Token.Id.Keyword_error) { @@ -3179,7 +3177,6 @@ pub const Parser = struct { const RenderState = union(enum) { TopLevelDecl: &ast.Node, - FnProtoRParen: &ast.NodeFnProto, ParamDecl: &ast.Node, Text: []const u8, Expression: &ast.Node, @@ -3868,8 +3865,10 @@ pub const Parser = struct { }, } - if (fn_proto.align_expr != null) { - @panic("TODO"); + if (fn_proto.align_expr) |align_expr| { + try stack.append(RenderState { .Text = ") " }); + try stack.append(RenderState { .Expression = align_expr}); + try stack.append(RenderState { .Text = "align(" }); } try stack.append(RenderState { .Text = ") " }); @@ -4271,26 +4270,6 @@ pub const Parser = struct { ast.Node.Id.TestDecl, ast.Node.Id.ParamDecl => unreachable, }, - RenderState.FnProtoRParen => |fn_proto| { - try stream.print(")"); - if (fn_proto.align_expr != null) { - @panic("TODO"); - } - try stream.print(" "); - if (fn_proto.body_node) |body_node| { - try stack.append(RenderState { .Expression = body_node}); - try stack.append(RenderState { .Text = " "}); - } - switch (fn_proto.return_type) { - ast.NodeFnProto.ReturnType.Explicit => |node| { - try stack.append(RenderState { .Expression = node}); - }, - ast.NodeFnProto.ReturnType.InferErrorSet => |node| { - try stream.print("!"); - try stack.append(RenderState { .Expression = node}); - }, - } - }, RenderState.Statement => |base| { if (base.comment) |comment| { for (comment.lines.toSliceConst()) |line_token| { @@ -4644,12 +4623,20 @@ test "zig fmt: var type" { ); } -test "zig fmt: extern function" { +test "zig fmt: functions" { try testCanonical( \\extern fn puts(s: &const u8) c_int; \\extern "c" fn puts(s: &const u8) c_int; \\export fn puts(s: &const u8) c_int; \\inline fn puts(s: &const u8) c_int; + \\pub extern fn puts(s: &const u8) c_int; + \\pub extern "c" fn puts(s: &const u8) c_int; + \\pub export fn puts(s: &const u8) c_int; + \\pub inline fn puts(s: &const u8) c_int; + \\pub extern fn puts(s: &const u8) align(2 + 2) c_int; + \\pub extern "c" fn puts(s: &const u8) align(2 + 2) c_int; + \\pub export fn puts(s: &const u8) align(2 + 2) c_int; + \\pub inline fn puts(s: &const u8) align(2 + 2) c_int; \\ ); }