From 88c114c75561e103fa26f5358c5d79296d67194d Mon Sep 17 00:00:00 2001 From: Benoit Giannangeli Date: Sun, 15 Oct 2023 16:10:01 +0200 Subject: [PATCH] feat: Named expression as property value closes #204 --- src/parser.zig | 53 +++++++++++++++++++++++---------------- tests/069-named-expr.buzz | 48 +++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 22 deletions(-) create mode 100644 tests/069-named-expr.buzz diff --git a/src/parser.zig b/src/parser.zig index fea12f7d..1c280d5c 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -3459,11 +3459,20 @@ pub const Parser = struct { try PlaceholderDef.link(object.type_def.?, property_placeholder.?, .FieldAccess); } - try self.consume(.Equal, "Expected `=` after property name."); - - const expr = try self.expression(false); + // Named variable with the same name as property + if (self.check(.Comma) or self.check(.RightBrace)) { + try node.properties.put( + property_name, + try self.expression(true), + ); + } else { + try self.consume(.Equal, "Expected `=` after property name."); - try node.properties.put(property_name, expr); + try node.properties.put( + property_name, + try self.expression(false), + ); + } if (!self.check(.RightBrace) or self.check(.Comma)) { try self.consume(.Comma, "Expected `,` after field initialization."); @@ -4117,38 +4126,38 @@ pub const Parser = struct { return try self.@"if"(false, null); } - // FIXME: doesn't need its own function fn argumentList(self: *Self, trailing_comma: *bool) !std.AutoArrayHashMap(*ObjString, *ParseNode) { var arguments = std.AutoArrayHashMap(*ObjString, *ParseNode).init(self.gc.allocator); var arg_count: u8 = 0; while (!(try self.match(.RightParen)) and !(try self.match(.Eof))) { var hanging = false; - var arg_name: ?Token = null; - if (try self.match(.Identifier)) { - arg_name = self.parser.previous_token.?; - } - - if (arg_count != 0 and arg_name == null) { - self.reportError(.syntax, "Expected argument name."); - break; - } + const arg_name: ?Token = if (try self.match(.Identifier)) + self.parser.previous_token.? + else + null; if (arg_name != null) { - if (arg_count == 0) { - if (try self.match(.Colon)) { - hanging = false; - } else { - // The identifier we just parsed is not the argument name but the start of an expression - hanging = true; - } + if (arg_count == 0 or self.check(.Comma) or self.check(.RightParen)) { + // The identifier we just parsed might not be the argument name but the start of an expression or the expression itself + hanging = !(try self.match(.Colon)); } else { try self.consume(.Colon, "Expected `:` after argument name."); } + } else if (arg_count != 0 and arg_name == null) { + self.reportError(.syntax, "Expected argument name."); + break; } + const is_named_expr = arg_count != 0 and arg_name != null and hanging and (self.check(.Comma) or self.check(.RightParen)); + try arguments.put( - try self.gc.copyString(if (!hanging and arg_name != null) arg_name.?.lexeme else "$"), + try self.gc.copyString( + if ((!hanging and arg_name != null) or is_named_expr) + arg_name.?.lexeme + else + "$", + ), try self.expression(hanging), ); diff --git a/tests/069-named-expr.buzz b/tests/069-named-expr.buzz new file mode 100644 index 00000000..0a45386e --- /dev/null +++ b/tests/069-named-expr.buzz @@ -0,0 +1,48 @@ +import "std"; +import "debug"; + +object Person { + str name, + int age, + bool sex, +} + +test "Named expr object properties" { + var name = "joe"; + var age = 24; + + var person = Person{ + name, + age, + sex = true, + }; + + assert( + person.name == "joe" + and person.age == 24 + and person.sex, + message: "Could use named variable as object property value" + ); +} + +fun hello(str name, int age, bool sex) > Person { + return Person{ + name, + age, + sex, + }; +} + +test "Name expr function argument" { + var name = "joe"; + var age = 24; + + var person = hello(name, age, sex: true); + + assert( + person.name == "joe" + and person.age == 24 + and person.sex, + message: "Could use named variable as function arguments" + ); +} \ No newline at end of file