diff --git a/examples/hello.v b/examples/hello.v index 377d337..3d16d61 100644 --- a/examples/hello.v +++ b/examples/hello.v @@ -54,3 +54,16 @@ fn main(a int) int { } fn (v Typ) voidfunc() {} + +struct Foo { + a int +mut: + b int + c int +pub: + d int +pub mut: + e int +pub mut mut: + f int +} diff --git a/src/ast.zig b/src/ast.zig index 91a045d..baa49eb 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -227,8 +227,10 @@ pub const FieldList = std.ArrayList(StructField); pub const StructField = struct { name: Token, typ: Token, - mutable: bool = true, - public: bool = true, + + mutable: bool = false, + public: bool = false, + mutable_outside: bool = false, }; pub const Struct = struct { diff --git a/src/ast_printer.zig b/src/ast_printer.zig index 3a0ed4f..25f90b4 100644 --- a/src/ast_printer.zig +++ b/src/ast_printer.zig @@ -107,6 +107,10 @@ pub fn printNode(node: *Node, ident: usize) void { std.debug.warn("pub "); } + if (field.mutable_outside) { + std.debug.warn("MUT_OUT "); + } + std.debug.warn("{} {})\n", field.name.lexeme, field.typ.lexeme); } print(ident, "))\n"); diff --git a/src/parser.zig b/src/parser.zig index 02e9d22..9c0d436 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -18,6 +18,12 @@ const Stmt = ast.Stmt; const TokenList = std.ArrayList(Token); +const FieldState = struct { + public: bool = false, + mutable: bool = false, + mutable_outside: bool = false, +}; + pub const Parser = struct { allocator: *Allocator, scanner: *Scanner, @@ -405,8 +411,6 @@ pub const Parser = struct { while (self.peek().ttype != .RightParen) { const param_name = try self.consumeSingle(.Identifier); - - // TODO dedicated function to consume a type? const param_type = try self.consumeSingle(.Identifier); try param_list.append(ast.ParamDecl{ @@ -495,14 +499,25 @@ pub const Parser = struct { _ = try self.consumeSingle(.LeftBrace); + var field_state = FieldState{}; + while (!self.check(.RightBrace)) { - // TODO mut and pub + try self.parseFieldModifiers(&field_state); + const field_name = try self.consumeSingle(.Identifier); const field_type = try self.consumeSingle(.Identifier); + // we could create a FieldState on the heap and copy our current + // field state into a StructField.state, but copying via this makes + // things so much nicer. + try fields.append(ast.StructField{ .name = field_name, .typ = field_type, + + .mutable = field_state.mutable, + .public = field_state.public, + .mutable_outside = field_state.mutable_outside, }); } @@ -511,6 +526,51 @@ pub const Parser = struct { return Node.mkStructDecl(self.allocator, name, fields); } + fn parseFieldModifiers(self: *@This(), field_state: *FieldState) !void { + + // there are five access modifiers: + // - none (private immutable) + // - mut (private mutable) + // - pub (public immutable) + // - pub mut (public mutable only in module) + // - pub mut mut (public mutable everywhere) + + // this function takes care of that by changing the current FieldState + // to what the modifiers dictate. + switch (self.peek().ttype) { + .Mut => { + // There are no oher modifiers that start with mut, so we + // can just go the way of marking it as mutable + _ = try self.consumeSingle(.Mut); + _ = try self.consumeSingle(.Colon); + + field_state.mutable = true; + }, + + // 'pub', 'pub mut', and 'pub mut mut' are all handled here + .Pub => { + _ = try self.consumeSingle(.Pub); + field_state.public = true; + + if (self.check(.Mut)) { + _ = try self.consumeSingle(.Mut); + + field_state.mutable = true; + if (self.check(.Mut)) { + _ = try self.consumeSingle(.Mut); + field_state.mutable_outside = true; + } + } + + _ = try self.consumeSingle(.Colon); + }, + + // if it isn't mut or pub we're likely in an identifier, just + // ignore it. + else => return, + } + } + fn parseTopDecl(self: *@This()) !*Node { return switch (self.peek().ttype) { .Fn => try self.parseFnDecl(), diff --git a/src/scanner.zig b/src/scanner.zig index 2ee42d1..76a9c7e 100644 --- a/src/scanner.zig +++ b/src/scanner.zig @@ -51,6 +51,7 @@ const keywords = [_][]const u8{ "None", "println", "loop", + "pub", }; const keyword_ttypes = [_]TokenType{ @@ -80,6 +81,7 @@ const keyword_ttypes = [_]TokenType{ .None, .Println, .Loop, + .Pub, }; fn getKeyword(keyword: []const u8) ?TokenType { diff --git a/src/tokens.zig b/src/tokens.zig index 360c6b6..1a79a13 100644 --- a/src/tokens.zig +++ b/src/tokens.zig @@ -75,6 +75,7 @@ pub const TokenType = enum { None, Println, + Pub, EOF, };