Skip to content

Commit

Permalink
Flatten CallAndWriteNode, CallOrWriteNode, and CallOperatorWriteNode
Browse files Browse the repository at this point in the history
  • Loading branch information
kddnewton committed Sep 5, 2023
1 parent fbcd307 commit 8f26ffa
Show file tree
Hide file tree
Showing 22 changed files with 770 additions and 776 deletions.
109 changes: 80 additions & 29 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,37 @@ nodes:
break foo
^^^^^^^^^
- name: CallAndWriteNode
fields:
- name: receiver
type: node?
- name: call_operator_loc
type: location?
- name: message_loc
type: location?
- name: opening_loc
type: location?
- name: arguments
type: node?
kind: ArgumentsNode
- name: closing_loc
type: location?
- name: flags
type: flags
kind: CallNodeFlags
- name: read_name
type: string
- name: write_name
type: string
- name: operator_loc
type: location
- name: value
type: node
comment: |
Represents the use of the `&&=` operator on a call.
foo.bar &&= value
^^^^^^^^^^^^^^^^^
- name: CallNode
fields:
- name: receiver
Expand Down Expand Up @@ -625,50 +656,70 @@ nodes:
foo&.bar
^^^^^^^^
- name: CallOperatorAndWriteNode
- name: CallOperatorWriteNode
fields:
- name: target
type: node
kind: CallNode
- name: receiver
type: node?
- name: call_operator_loc
type: location?
- name: message_loc
type: location?
- name: opening_loc
type: location?
- name: arguments
type: node?
kind: ArgumentsNode
- name: closing_loc
type: location?
- name: flags
type: flags
kind: CallNodeFlags
- name: read_name
type: string
- name: write_name
type: string
- name: operator
type: constant
- name: operator_loc
type: location
- name: value
type: node
comment: |
Represents the use of the `&&=` operator on a call.
Represents the use of an assignment operator on a call.
foo.bar &&= value
^^^^^^^^^^^^^^^^^
- name: CallOperatorOrWriteNode
foo.bar += baz
^^^^^^^^^^^^^^
- name: CallOrWriteNode
fields:
- name: target
type: node
kind: CallNode
- name: value
type: node
- name: receiver
type: node?
- name: call_operator_loc
type: location?
- name: message_loc
type: location?
- name: opening_loc
type: location?
- name: arguments
type: node?
kind: ArgumentsNode
- name: closing_loc
type: location?
- name: flags
type: flags
kind: CallNodeFlags
- name: read_name
type: string
- name: write_name
type: string
- name: operator_loc
type: location
- name: value
type: node
comment: |
Represents the use of the `||=` operator on a call.
foo.bar ||= value
^^^^^^^^^^^^^^^^^
- name: CallOperatorWriteNode
fields:
- name: target
type: node
kind: CallNode
- name: operator_loc
type: location
- name: value
type: node
- name: operator
type: constant
comment: |
Represents the use of an assignment operator on a call.
foo.bar += baz
^^^^^^^^^^^^^^
- name: CapturePatternNode
fields:
- name: value
Expand Down
8 changes: 4 additions & 4 deletions rust/yarp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,17 +370,17 @@ end
let call = asgn.as_local_variable_write_node().unwrap().value();
let call = call.as_call_node().unwrap();

let operator_loc = call.operator_loc();
assert!(operator_loc.is_none());
let call_operator_loc = call.call_operator_loc();
assert!(call_operator_loc.is_none());
let closing_loc = call.closing_loc();
assert!(closing_loc.is_some());

let asgn = &writes[1];
let call = asgn.as_local_variable_write_node().unwrap().value();
let call = call.as_call_node().unwrap();

let operator_loc = call.operator_loc();
assert!(operator_loc.is_some());
let call_operator_loc = call.call_operator_loc();
assert!(call_operator_loc.is_some());
let closing_loc = call.closing_loc();
assert!(closing_loc.is_none());
}
Expand Down
95 changes: 77 additions & 18 deletions src/yarp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1435,69 +1435,128 @@ yp_call_node_variable_call_p(yp_call_node_t *node) {
return node->base.flags & YP_CALL_NODE_FLAGS_VARIABLE_CALL;
}

// Allocate and initialize a new CallOperatorAndWriteNode node.
static yp_call_operator_and_write_node_t *
yp_call_operator_and_write_node_create(yp_parser_t *parser, yp_call_node_t *target, const yp_token_t *operator, yp_node_t *value) {
// Initialize the read name by reading the write name and chopping off the '='.
static void
yp_call_write_read_name_init(yp_string_t *read_name, yp_string_t *write_name) {
size_t length = write_name->length - 1;

void *memory = malloc(length);
memcpy(memory, write_name->source, length);

yp_string_owned_init(read_name, (uint8_t *) memory, length);
}

// Allocate and initialize a new CallAndWriteNode node.
static yp_call_and_write_node_t *
yp_call_and_write_node_create(yp_parser_t *parser, yp_call_node_t *target, const yp_token_t *operator, yp_node_t *value) {
assert(target->block == NULL);
assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
yp_call_operator_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_call_operator_and_write_node_t);
yp_call_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_call_and_write_node_t);

*node = (yp_call_operator_and_write_node_t) {
*node = (yp_call_and_write_node_t) {
{
.type = YP_NODE_CALL_OPERATOR_AND_WRITE_NODE,
.type = YP_NODE_CALL_AND_WRITE_NODE,
.flags = target->base.flags,
.location = {
.start = target->base.location.start,
.end = value->location.end
}
},
.target = target,
.receiver = target->receiver,
.call_operator_loc = target->call_operator_loc,
.message_loc = target->message_loc,
.opening_loc = target->opening_loc,
.arguments = target->arguments,
.closing_loc = target->closing_loc,
.read_name = YP_EMPTY_STRING,
.write_name = target->name,
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
.value = value
};

yp_call_write_read_name_init(&node->read_name, &node->write_name);

// Here we're going to free the target, since it is no longer necessary.
// However, we don't want to call `yp_node_destroy` because we want to keep
// around all of its children since we just reused them.
free(target);

return node;
}

// Allocate a new CallOperatorWriteNode node.
static yp_call_operator_write_node_t *
yp_call_operator_write_node_create(yp_parser_t *parser, yp_call_node_t *target, const yp_token_t *operator, yp_node_t *value) {
assert(target->block == NULL);
yp_call_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_call_operator_write_node_t);

*node = (yp_call_operator_write_node_t) {
{
.type = YP_NODE_CALL_OPERATOR_WRITE_NODE,
.flags = target->base.flags,
.location = {
.start = target->base.location.start,
.end = value->location.end
}
},
.target = target,
.receiver = target->receiver,
.call_operator_loc = target->call_operator_loc,
.message_loc = target->message_loc,
.opening_loc = target->opening_loc,
.arguments = target->arguments,
.closing_loc = target->closing_loc,
.read_name = YP_EMPTY_STRING,
.write_name = target->name,
.operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1),
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
.value = value,
.operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1)
.value = value
};

yp_call_write_read_name_init(&node->read_name, &node->write_name);

// Here we're going to free the target, since it is no longer necessary.
// However, we don't want to call `yp_node_destroy` because we want to keep
// around all of its children since we just reused them.
free(target);

return node;
}

// Allocate and initialize a new CallOperatorOrWriteNode node.
static yp_call_operator_or_write_node_t *
yp_call_operator_or_write_node_create(yp_parser_t *parser, yp_call_node_t *target, const yp_token_t *operator, yp_node_t *value) {
static yp_call_or_write_node_t *
yp_call_or_write_node_create(yp_parser_t *parser, yp_call_node_t *target, const yp_token_t *operator, yp_node_t *value) {
assert(target->block == NULL);
assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
yp_call_operator_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_call_operator_or_write_node_t);
yp_call_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_call_or_write_node_t);

*node = (yp_call_operator_or_write_node_t) {
*node = (yp_call_or_write_node_t) {
{
.type = YP_NODE_CALL_OPERATOR_OR_WRITE_NODE,
.type = YP_NODE_CALL_OR_WRITE_NODE,
.flags = target->base.flags,
.location = {
.start = target->base.location.start,
.end = value->location.end
}
},
.target = target,
.receiver = target->receiver,
.call_operator_loc = target->call_operator_loc,
.message_loc = target->message_loc,
.opening_loc = target->opening_loc,
.arguments = target->arguments,
.closing_loc = target->closing_loc,
.read_name = YP_EMPTY_STRING,
.write_name = target->name,
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
.value = value
};

yp_call_write_read_name_init(&node->read_name, &node->write_name);

// Here we're going to free the target, since it is no longer necessary.
// However, we don't want to call `yp_node_destroy` because we want to keep
// around all of its children since we just reused them.
free(target);

return node;
}

Expand Down Expand Up @@ -12978,7 +13037,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
node = parse_target(parser, node);

yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
return (yp_node_t *) yp_call_operator_and_write_node_create(parser, (yp_call_node_t *) node, &token, value);
return (yp_node_t *) yp_call_and_write_node_create(parser, (yp_call_node_t *) node, &token, value);
}
case YP_NODE_MULTI_WRITE_NODE: {
parser_lex(parser);
Expand Down Expand Up @@ -13079,7 +13138,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
node = parse_target(parser, node);

yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
return (yp_node_t *) yp_call_operator_or_write_node_create(parser, (yp_call_node_t *) node, &token, value);
return (yp_node_t *) yp_call_or_write_node_create(parser, (yp_call_node_t *) node, &token, value);
}
case YP_NODE_MULTI_WRITE_NODE: {
parser_lex(parser);
Expand Down
12 changes: 6 additions & 6 deletions test/yarp/location_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,19 +166,19 @@ def test_CallNode
assert_location(CallNode, "foo bar('baz')")
end

def test_CallOperatorAndWriteNode
assert_location(CallOperatorAndWriteNode, "foo.foo &&= bar")
assert_location(CallOperatorAndWriteNode, "foo[foo] &&= bar")
def test_CallAndWriteNode
assert_location(CallAndWriteNode, "foo.foo &&= bar")
assert_location(CallAndWriteNode, "foo[foo] &&= bar")
end

def test_CallOperatorWriteNode
assert_location(CallOperatorWriteNode, "foo.foo += bar")
assert_location(CallOperatorWriteNode, "foo[foo] += bar")
end

def test_CallOperatorOrWriteNode
assert_location(CallOperatorOrWriteNode, "foo.foo ||= bar")
assert_location(CallOperatorOrWriteNode, "foo[foo] ||= bar")
def test_CallOrWriteNode
assert_location(CallOrWriteNode, "foo.foo ||= bar")
assert_location(CallOrWriteNode, "foo[foo] ||= bar")
end

def test_CapturePatternNode
Expand Down
24 changes: 11 additions & 13 deletions test/yarp/snapshots/seattlerb/index_0_opasgn.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 8f26ffa

Please sign in to comment.