Skip to content

Commit

Permalink
feat: Named expression as property value
Browse files Browse the repository at this point in the history
closes #204
  • Loading branch information
giann committed Oct 16, 2023
1 parent 91e8d73 commit 88c114c
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 22 deletions.
53 changes: 31 additions & 22 deletions src/parser.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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.");
Expand Down Expand Up @@ -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),
);

Expand Down
48 changes: 48 additions & 0 deletions tests/069-named-expr.buzz
Original file line number Diff line number Diff line change
@@ -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"
);
}

0 comments on commit 88c114c

Please sign in to comment.