Skip to content

Commit

Permalink
Merge pull request #1556 from DanielXMoore/more-ref
Browse files Browse the repository at this point in the history
Avoid duplicate calls in relation chains and `@` bind shorthand via refs
  • Loading branch information
edemaine authored Nov 1, 2024
2 parents 056d5ae + 01b39ae commit 1cc4b46
Show file tree
Hide file tree
Showing 11 changed files with 309 additions and 249 deletions.
25 changes: 18 additions & 7 deletions source/parser.hera
Original file line number Diff line number Diff line change
Expand Up @@ -1272,7 +1272,11 @@ FieldDefinition
}

ThisLiteral
This
This -> {
type: "Identifier",
name: "this",
children: [ $1 ],
}
HashThis
# NOTE: Added @identifier shorthand, also works for private identifiers
# Converts 'IdentifierName' node to string so this won't interfere with refs
Expand Down Expand Up @@ -1344,7 +1348,11 @@ LengthShorthand
# NOTE: Added '@' as a 'this' shorthand from CoffeeScript
AtThis
At:at ->
return { ...at, token: "this" }
return {
type: "Identifier",
name: "this",
children: [{ ...at, token: "this" }]
}

# https://262.ecma-international.org/#prod-LeftHandSideExpression
LeftHandSideExpression
Expand Down Expand Up @@ -7033,14 +7041,17 @@ JSXAttribute
# NOTE: @foo and @@foo shorthands
# for foo={this.foo} and foo={this.foo.bind(this)}
AtThis:at Identifier?:id InlineJSXCallExpressionRest*:rest &JSXAttributeSpace ->
const access = id && {
type: "PropertyAccess",
children: [".", id],
name: id,
const children = [ at, ...rest.flat() ]
if (id) {
children.splice(1, 0, {
type: "PropertyAccess",
children: [".", id],
name: id,
})
}
const expr = processCallMemberExpression({
type: "CallExpression",
children: [ at, access, ...rest.flat() ],
children,
})
const last = lastAccessInCallExpression(expr)
if (!last) return $skip
Expand Down
5 changes: 1 addition & 4 deletions source/parser/function.civet
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,6 @@ import {
getHelperRef
} from ./helper.civet

import {
replaceNode
} from ./lib.civet

import {
findAncestor
findChildIndex
Expand Down Expand Up @@ -74,6 +70,7 @@ import {
isWhitespaceOrEmpty
makeLeftHandSideExpression
makeNode
replaceNode
startsWithPredicate
trimFirstSpace
updateParentPointers
Expand Down
71 changes: 10 additions & 61 deletions source/parser/lib.civet
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ import {
inplaceInsertTrimmingSpace
inplacePrepend
insertTrimmingSpace
isASTNodeObject
isComma
isEmptyBareBlock
isFunction
Expand All @@ -77,6 +76,8 @@ import {
maybeUnwrap
parenthesizeType
prepend
replaceNode
replaceNodes
stripTrailingImplicitComma
trimFirstSpace
wrapIIFE
Expand Down Expand Up @@ -633,19 +634,20 @@ function processCallMemberExpression(node: CallExpression | MemberExpression): A
children: [object, ...children[i+1..]]
})
else if glob?.type is "PropertyBind"
// TODO: add ref to ensure object base evaluated only once
prefix := children[0...i]
assert.notEqual i, 0, "@ bind must be preceded by an expression"
prefix := i is 1 ? children[0] : children[<i]
{ ref, refAssignment } := maybeRefAssignment prefix
return processCallMemberExpression({ // in case there are more
...node
children: [
prefix
makeLeftHandSideExpression refAssignment ?? prefix
{
...glob
type: "PropertyAccess"
children: [
...glob.children
".bind("
prefix
ref
...glob.args.length > 0 ? [", "] : []
...glob.args
")"
Expand All @@ -655,9 +657,9 @@ function processCallMemberExpression(node: CallExpression | MemberExpression): A
]
})
else if glob is like {type: "Index", mod: true}
assert.notEqual i, 0, "Index modifier must be preceded by an expression"
assert.notEqual i, 0, "Index access must be preceded by an expression"
prefix := i is 1 ? children[0] : children[<i]
{ ref, refAssignment } .= maybeRefAssignment prefix
{ ref, refAssignment } := maybeRefAssignment prefix
call := makeNode
type: "CallExpression"
children: [
Expand Down Expand Up @@ -721,36 +723,6 @@ function processCallMemberExpression(node: CallExpression | MemberExpression): A
}
return node

/**
* Replace this node with another, by modifying its parent's children.
*/
function replaceNode(node: ASTNodeObject, newNode: ASTNode, parent?: ASTNodeParent): void
parent ??= node.parent
unless parent?
throw new Error "replaceNode failed: node has no parent"

function recurse(children: ASTNode[]): boolean
for each child, i of children
if child is node
children[i] = newNode
return true
else if Array.isArray child
return true if recurse child
return false

unless recurse parent.children
throw new Error "replaceNode failed: didn't find child node in parent"

// Adjust 'expression' etc. alias pointers
for key, value in parent
if value is node
parent[key] = newNode

if isASTNodeObject newNode
newNode.parent = parent
// Don't destroy node's parent, as we often include it within newNode
//node.parent = undefined

// Wrap expression in parentheses to make into a statement when:
// * object literal expression
// * anonymous function expression
Expand Down Expand Up @@ -1688,29 +1660,6 @@ function reorderBindingRestProperty(props)

return { children, names }

/**
* Replace all nodes that match predicate with replacer(node)
*/
function replaceNodes(root, predicate, replacer)
return root unless root?

array := Array.isArray(root) ? root : root.children

unless array
if predicate root
return replacer root, root
else
return root

for each node, i of array
return unless node?
if predicate node
array[i] = replacer node, root
else
replaceNodes node, predicate, replacer

return root

function typeOfJSX(node, config) {
switch (node.type) {
case "JSXElement":
Expand Down Expand Up @@ -1844,8 +1793,8 @@ export {
processUnaryExpression
processUnaryNestedExpression
quoteString
replaceNode
reorderBindingRestProperty
replaceNode
replaceNodes
skipImplicitArguments
stripTrailingImplicitComma
Expand Down
Loading

0 comments on commit 1cc4b46

Please sign in to comment.