]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor: process expression
author三咲智子 Kevin Deng <sxzz@sxzz.moe>
Fri, 1 Dec 2023 15:30:21 +0000 (23:30 +0800)
committer三咲智子 Kevin Deng <sxzz@sxzz.moe>
Fri, 1 Dec 2023 15:30:21 +0000 (23:30 +0800)
packages/compiler-vapor/__tests__/__snapshots__/compile.test.ts.snap
packages/compiler-vapor/src/generate.ts
packages/compiler-vapor/src/ir.ts
packages/compiler-vapor/src/transform.ts

index 4babbb9fd076bb1a08314af5deba66b8ed5dbfbc..1074169facc3e4591f2aeb22e248523321a95ae5 100644 (file)
@@ -1,7 +1,8 @@
 // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
 exports[`compile > bindings 1`] = `
-"export function render(_ctx) {
+"
+export function render(_ctx) {
   const t0 = _template(\\"<div>count is <!>.</div>\\")
   const n0 = t0()
   const { 0: [n3, { 1: [n2],}],} = _children(n0)
@@ -18,7 +19,8 @@ import { template as _template, children as _children, createTextNode as _create
 `;
 
 exports[`compile > directives > v-bind > simple expression 1`] = `
-"export function render(_ctx) {
+"
+export function render(_ctx) {
   const t0 = _template(\\"<div></div>\\")
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
@@ -33,22 +35,22 @@ import { template as _template, children as _children, effect as _effect, setAtt
 `;
 
 exports[`compile > directives > v-html > no expression 1`] = `
-"export function render(_ctx) {
+"
+export function render(_ctx) {
   const t0 = _template(\\"<div></div>\\")
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _effect(() => {
-    _setHtml(n1, undefined, \\"\\")
-  })
+  _setHtml(n1, undefined, \\"\\")
   return n0
 }
 
-import { template as _template, children as _children, effect as _effect, setHtml as _setHtml } from 'vue/vapor'
+import { template as _template, children as _children, setHtml as _setHtml } from 'vue/vapor'
 "
 `;
 
 exports[`compile > directives > v-html > simple expression 1`] = `
-"export function render(_ctx) {
+"
+export function render(_ctx) {
   const t0 = _template(\\"<div></div>\\")
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
@@ -63,7 +65,8 @@ import { template as _template, children as _children, effect as _effect, setHtm
 `;
 
 exports[`compile > directives > v-on > event modifier 1`] = `
-"export function render(_ctx) {
+"
+export function render(_ctx) {
   const t0 = _template(\\"<div></div>\\")
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
@@ -78,7 +81,8 @@ import { template as _template, children as _children, effect as _effect, withMo
 `;
 
 exports[`compile > directives > v-on > simple expression 1`] = `
-"export function render(_ctx) {
+"
+export function render(_ctx) {
   const t0 = _template(\\"<div></div>\\")
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
@@ -93,7 +97,8 @@ import { template as _template, children as _children, effect as _effect, on as
 `;
 
 exports[`compile > directives > v-once > as root node 1`] = `
-"export function render(_ctx) {
+"
+export function render(_ctx) {
   const t0 = _template(\\"<div></div>\\")
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
@@ -106,7 +111,8 @@ import { template as _template, children as _children, setAttr as _setAttr } fro
 `;
 
 exports[`compile > directives > v-once > basic 1`] = `
-"export function render(_ctx) {
+"
+export function render(_ctx) {
   const t0 = _template(\\"<div> <span></span></div>\\")
   const n0 = t0()
   const { 0: [n3, { 1: [n2],}],} = _children(n0)
@@ -122,7 +128,8 @@ import { template as _template, children as _children, createTextNode as _create
 `;
 
 exports[`compile > directives > v-pre > basic 1`] = `
-"export function render(_ctx) {
+"
+export function render(_ctx) {
   const t0 = _template(\\"<div :id=\\\\\\"foo\\\\\\"><Comp></Comp>{{ bar }}</div>\\")
   const n0 = t0()
   return n0
@@ -133,7 +140,8 @@ import { template as _template } from 'vue/vapor'
 `;
 
 exports[`compile > directives > v-pre > self-closing v-pre 1`] = `
-"export function render(_ctx) {
+"
+export function render(_ctx) {
   const t0 = _template(\\"<div></div><div><Comp></Comp></div>\\")
   const n0 = t0()
   const { 1: [n1],} = _children(n0)
@@ -153,7 +161,8 @@ import { template as _template, children as _children, createTextNode as _create
 `;
 
 exports[`compile > directives > v-pre > should not affect siblings after it 1`] = `
-"export function render(_ctx) {
+"
+export function render(_ctx) {
   const t0 = _template(\\"<div :id=\\\\\\"foo\\\\\\"><Comp></Comp>{{ bar }}</div><div><Comp></Comp></div>\\")
   const n0 = t0()
   const { 1: [n1],} = _children(n0)
@@ -173,22 +182,22 @@ import { template as _template, children as _children, createTextNode as _create
 `;
 
 exports[`compile > directives > v-text > no expression 1`] = `
-"export function render(_ctx) {
+"
+export function render(_ctx) {
   const t0 = _template(\\"<div></div>\\")
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _effect(() => {
-    _setText(n1, undefined, \\"\\")
-  })
+  _setText(n1, undefined, \\"\\")
   return n0
 }
 
-import { template as _template, children as _children, effect as _effect, setText as _setText } from 'vue/vapor'
+import { template as _template, children as _children, setText as _setText } from 'vue/vapor'
 "
 `;
 
 exports[`compile > directives > v-text > simple expression 1`] = `
-"export function render(_ctx) {
+"
+export function render(_ctx) {
   const t0 = _template(\\"<div></div>\\")
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
@@ -203,7 +212,8 @@ import { template as _template, children as _children, effect as _effect, setTex
 `;
 
 exports[`compile > dynamic root 1`] = `
-"export function render(_ctx) {
+"
+export function render(_ctx) {
   const t0 = _fragment()
 
   const n0 = t0()
@@ -224,7 +234,8 @@ import { fragment as _fragment, createTextNode as _createTextNode, append as _ap
 `;
 
 exports[`compile > dynamic root nodes and interpolation 1`] = `
-"export function render(_ctx) {
+"
+export function render(_ctx) {
   const t0 = _template(\\"<button>foo<!>foo</button>\\")
   const n0 = t0()
   const { 0: [n1, { 1: [n5],}],} = _children(n0)
@@ -239,8 +250,14 @@ exports[`compile > dynamic root nodes and interpolation 1`] = `
   })
   _effect(() => {
     _setAttr(n1, \\"id\\", undefined, count)
+  })
+  _effect(() => {
     _setText(n2, undefined, count)
+  })
+  _effect(() => {
     _setText(n3, undefined, count)
+  })
+  _effect(() => {
     _setText(n4, undefined, count)
   })
   return n0
@@ -251,7 +268,8 @@ import { template as _template, children as _children, createTextNode as _create
 `;
 
 exports[`compile > fragment 1`] = `
-"export function render(_ctx) {
+"
+export function render(_ctx) {
   const t0 = _template(\\"<p></p><span></span><div></div>\\")
   const n0 = t0()
   return n0
@@ -262,7 +280,8 @@ import { template as _template } from 'vue/vapor'
 `;
 
 exports[`compile > static + dynamic root 1`] = `
-"export function render(_ctx) {
+"
+export function render(_ctx) {
   const t0 = _template(\\"3<!>6<!>9\\")
   const n0 = t0()
   const { 1: [n9], 3: [n10],} = _children(n0)
@@ -310,7 +329,8 @@ import { template as _template, children as _children, createTextNode as _create
 `;
 
 exports[`compile > static template 1`] = `
-"export function render(_ctx) {
+"
+export function render(_ctx) {
   const t0 = _template(\\"<div><p>hello</p><input><span></span></div>\\")
   const n0 = t0()
   return n0
index 69bef1b0c53f42079a9125935e69d2fca3a0749a..3b8b45d04f8b4277035572fac5997589bf1a1ae7 100644 (file)
@@ -5,23 +5,26 @@ import {
   NewlineType,
   advancePositionWithMutation,
   locStub,
+  NodeTypes,
+  BindingTypes,
 } from '@vue/compiler-dom'
 import {
-  type DynamicChildren,
+  type IRDynamicChildren,
   type RootIRNode,
   IRNodeTypes,
   OperationNode,
   VaporHelper,
-  IRNode,
+  BaseIRNode,
+  IRExpression,
 } from './ir'
 import { SourceMapGenerator } from 'source-map-js'
+import { isString } from '@vue/shared'
 
 // remove when stable
 // @ts-expect-error
 function checkNever(x: never): never {}
 
-export interface CodegenContext
-  extends Omit<Required<CodegenOptions>, 'bindingMetadata' | 'inline'> {
+export interface CodegenContext extends Required<CodegenOptions> {
   source: string
   code: string
   line: number
@@ -30,8 +33,8 @@ export interface CodegenContext
   indentLevel: number
   map?: SourceMapGenerator
 
-  push(code: string, newlineIndex?: number, node?: IRNode): void
-  pushWithNewline(code: string, newlineIndex?: number, node?: IRNode): void
+  push(code: string, newlineIndex?: number, node?: BaseIRNode): void
+  pushWithNewline(code: string, newlineIndex?: number, node?: BaseIRNode): void
   indent(): void
   deindent(): void
   newline(): void
@@ -57,6 +60,8 @@ function createCodegenContext(
     ssr = false,
     isTS = false,
     inSSR = false,
+    inline = false,
+    bindingMetadata = {},
   }: CodegenOptions,
 ) {
   const { helpers, vaporHelpers } = ir
@@ -73,6 +78,8 @@ function createCodegenContext(
     ssr,
     isTS,
     inSSR,
+    bindingMetadata,
+    inline,
 
     source: ir.source,
     code: ``,
@@ -205,7 +212,7 @@ export function generate(
   if (isSetupInlined) {
     push(`(() => {`)
   } else {
-    push(`export function ${functionName}(_ctx) {`)
+    pushWithNewline(`export function ${functionName}(_ctx) {`)
   }
   indent()
 
@@ -239,7 +246,7 @@ export function generate(
     for (const operation of ir.operation) {
       genOperation(operation, ctx)
     }
-    for (const [_expr, operations] of Object.entries(ir.effect)) {
+    for (const { operations } of ir.effect) {
       pushWithNewline(`${vaporHelper('effect')}(() => {`)
       indent()
       for (const operation of operations) {
@@ -279,6 +286,8 @@ export function generate(
       NewlineType.End,
     )
 
+  console.log(ctx.code)
+
   return {
     code: ctx.code,
     ast: ir as any,
@@ -287,24 +296,25 @@ export function generate(
   }
 }
 
-function genOperation(
-  oper: OperationNode,
-  { vaporHelper, pushWithNewline }: CodegenContext,
-) {
+function genOperation(oper: OperationNode, context: CodegenContext) {
+  const { vaporHelper, pushWithNewline } = context
   // TODO: cache old value
   switch (oper.type) {
     case IRNodeTypes.SET_PROP: {
       pushWithNewline(
-        `${vaporHelper('setAttr')}(n${oper.element}, ${JSON.stringify(
+        `${vaporHelper('setAttr')}(n${oper.element}, ${processExpression(
           oper.name,
-        )}, undefined, ${oper.value})`,
+          context,
+        )}, undefined, ${processExpression(oper.value, context)})`,
       )
       return
     }
 
     case IRNodeTypes.SET_TEXT: {
       pushWithNewline(
-        `${vaporHelper('setText')}(n${oper.element}, undefined, ${oper.value})`,
+        `${vaporHelper('setText')}(n${
+          oper.element
+        }, undefined, ${processExpression(oper.value, context)})`,
       )
       return
     }
@@ -312,28 +322,34 @@ function genOperation(
     case IRNodeTypes.SET_EVENT: {
       let value = oper.value
       if (oper.modifiers.length) {
-        value = `${vaporHelper('withModifiers')}(${value}, ${genArrayExpression(
-          oper.modifiers,
-        )})`
+        value = `${vaporHelper('withModifiers')}(${processExpression(
+          value,
+          context,
+        )}, ${genArrayExpression(oper.modifiers)})`
       }
       pushWithNewline(
-        `${vaporHelper('on')}(n${oper.element}, ${JSON.stringify(
+        `${vaporHelper('on')}(n${oper.element}, ${processExpression(
           oper.name,
-        )}, ${value})`,
+          context,
+        )}, ${processExpression(value, context)})`,
       )
       return
     }
 
     case IRNodeTypes.SET_HTML: {
       pushWithNewline(
-        `${vaporHelper('setHtml')}(n${oper.element}, undefined, ${oper.value})`,
+        `${vaporHelper('setHtml')}(n${
+          oper.element
+        }, undefined, ${processExpression(oper.value, context)})`,
       )
       return
     }
 
     case IRNodeTypes.CREATE_TEXT_NODE: {
       pushWithNewline(
-        `const n${oper.id} = ${vaporHelper('createTextNode')}(${oper.value})`,
+        `const n${oper.id} = ${vaporHelper(
+          'createTextNode',
+        )}(${processExpression(oper.value, context)})`,
       )
       return
     }
@@ -370,7 +386,7 @@ function genOperation(
   }
 }
 
-function genChildren(children: DynamicChildren) {
+function genChildren(children: IRDynamicChildren) {
   let code = ''
   // TODO
   let offset = 0
@@ -400,3 +416,35 @@ function genChildren(children: DynamicChildren) {
 function genArrayExpression(elements: string[]) {
   return `[${elements.map((it) => `"${it}"`).join(', ')}]`
 }
+
+function processExpression(
+  exp: IRExpression,
+  { inline, prefixIdentifiers, bindingMetadata, vaporHelper }: CodegenContext,
+) {
+  if (isString(exp)) return exp
+
+  let content = ''
+  if (exp.type === NodeTypes.SIMPLE_EXPRESSION) {
+    content = exp.content
+    if (exp.isStatic) {
+      return JSON.stringify(content)
+    }
+  } else {
+    // TODO NodeTypes.COMPOUND_EXPRESSION
+  }
+
+  switch (bindingMetadata[content]) {
+    case BindingTypes.SETUP_REF:
+      content += '.value'
+      break
+    case BindingTypes.SETUP_MAYBE_REF:
+      content = `${vaporHelper('unref')}(${content})`
+      break
+  }
+
+  if (prefixIdentifiers && !inline) {
+    content = `_ctx.${content}`
+  }
+
+  return content
+}
index de518c10c31f5b9e8f73bdabfe8f8fe416d21237..5bf801a159476bfa741072dde27b3f76f0578f72 100644 (file)
@@ -1,4 +1,8 @@
-import type { SourceLocation } from '@vue/compiler-dom'
+import type {
+  ExpressionNode,
+  RootNode,
+  SourceLocation,
+} from '@vue/compiler-dom'
 
 export enum IRNodeTypes {
   ROOT,
@@ -16,7 +20,7 @@ export enum IRNodeTypes {
   CREATE_TEXT_NODE,
 }
 
-export interface IRNode {
+export interface BaseIRNode {
   type: IRNodeTypes
   loc: SourceLocation
 }
@@ -24,79 +28,84 @@ export interface IRNode {
 // TODO refactor
 export type VaporHelper = keyof typeof import('../../runtime-vapor/src')
 
-export interface RootIRNode extends IRNode {
+export interface RootIRNode extends BaseIRNode {
   type: IRNodeTypes.ROOT
   source: string
+  node: RootNode
   template: Array<TemplateFactoryIRNode | FragmentFactoryIRNode>
-  dynamic: DynamicInfo
-  // TODO multi-expression effect
-  effect: Record<string /* expr */, OperationNode[]>
+  dynamic: IRDynamicInfo
+  effect: IREffect[]
   operation: OperationNode[]
   helpers: Set<string>
   vaporHelpers: Set<VaporHelper>
 }
 
-export interface TemplateFactoryIRNode extends IRNode {
+export interface TemplateFactoryIRNode extends BaseIRNode {
   type: IRNodeTypes.TEMPLATE_FACTORY
   template: string
 }
 
-export interface FragmentFactoryIRNode extends IRNode {
+export interface FragmentFactoryIRNode extends BaseIRNode {
   type: IRNodeTypes.FRAGMENT_FACTORY
 }
 
-export interface SetPropIRNode extends IRNode {
+export interface SetPropIRNode extends BaseIRNode {
   type: IRNodeTypes.SET_PROP
   element: number
-  name: string
-  value: string
+  name: IRExpression
+  value: IRExpression
 }
 
-export interface SetTextIRNode extends IRNode {
+export interface SetTextIRNode extends BaseIRNode {
   type: IRNodeTypes.SET_TEXT
   element: number
-  value: string
+  value: IRExpression
 }
 
-export interface SetEventIRNode extends IRNode {
+export interface SetEventIRNode extends BaseIRNode {
   type: IRNodeTypes.SET_EVENT
   element: number
-  name: string
-  value: string
+  name: IRExpression
+  value: IRExpression
   modifiers: string[]
 }
 
-export interface SetHtmlIRNode extends IRNode {
+export interface SetHtmlIRNode extends BaseIRNode {
   type: IRNodeTypes.SET_HTML
   element: number
-  value: string
+  value: IRExpression
 }
 
-export interface CreateTextNodeIRNode extends IRNode {
+export interface CreateTextNodeIRNode extends BaseIRNode {
   type: IRNodeTypes.CREATE_TEXT_NODE
   id: number
-  value: string
+  value: IRExpression
 }
 
-export interface InsertNodeIRNode extends IRNode {
+export interface InsertNodeIRNode extends BaseIRNode {
   type: IRNodeTypes.INSERT_NODE
   element: number | number[]
   parent: number
   anchor: number
 }
 
-export interface PrependNodeIRNode extends IRNode {
+export interface PrependNodeIRNode extends BaseIRNode {
   type: IRNodeTypes.PREPEND_NODE
   elements: number[]
   parent: number
 }
 
-export interface AppendNodeIRNode extends IRNode {
+export interface AppendNodeIRNode extends BaseIRNode {
   type: IRNodeTypes.APPEND_NODE
   elements: number[]
   parent: number
 }
 
+export type IRNode =
+  | OperationNode
+  | RootIRNode
+  | TemplateFactoryIRNode
+  | FragmentFactoryIRNode
 export type OperationNode =
   | SetPropIRNode
   | SetTextIRNode
@@ -107,12 +116,19 @@ export type OperationNode =
   | PrependNodeIRNode
   | AppendNodeIRNode
 
-export interface DynamicInfo {
+export interface IRDynamicInfo {
   id: number | null
   referenced: boolean
   /** created by DOM API */
   ghost: boolean
   placeholder: number | null
-  children: DynamicChildren
+  children: IRDynamicChildren
+}
+export type IRDynamicChildren = Record<number, IRDynamicInfo>
+
+export type IRExpression = ExpressionNode | string
+export interface IREffect {
+  // TODO multi-expression effect
+  expressions: IRExpression[]
+  operations: OperationNode[]
 }
-export type DynamicChildren = Record<number, DynamicInfo>
index df7e73d6d9da48420101ba15e5a295fd7a6a638e..7b9c5e206cd4c2102f72a2426218a4ed82c030d4 100644 (file)
@@ -6,12 +6,10 @@ import {
   type InterpolationNode,
   type TransformOptions as BaseTransformOptions,
   type DirectiveNode,
-  type ExpressionNode,
   type ParentNode,
   type AllNode,
   type CompilerCompatOptions,
   NodeTypes,
-  BindingTypes,
   defaultOnError,
   defaultOnWarn,
   ErrorCodes,
@@ -21,8 +19,9 @@ import { EMPTY_OBJ, NOOP, isArray, isVoidTag } from '@vue/shared'
 import {
   type OperationNode,
   type RootIRNode,
+  type IRDynamicInfo,
+  type IRExpression,
   IRNodeTypes,
-  DynamicInfo,
 } from './ir'
 import type { HackOptions } from './hack'
 
@@ -43,14 +42,17 @@ export interface TransformContext<T extends AllNode = AllNode> {
   >
 
   template: string
-  dynamic: DynamicInfo
+  dynamic: IRDynamicInfo
 
   inVOnce: boolean
 
   reference(): number
   increaseId(): number
   registerTemplate(): number
-  registerEffect(expr: string, operation: OperationNode): void
+  registerEffect(
+    expressions: Array<IRExpression | null | undefined>,
+    operation: OperationNode[],
+  ): void
   registerOperation(...operations: OperationNode[]): void
   helper(name: string): string
 }
@@ -102,12 +104,18 @@ function createRootContext(
       this.dynamic.referenced = true
       return (this.dynamic.id = this.increaseId())
     },
-    registerEffect(expr, operation) {
-      if (this.inVOnce) {
-        return this.registerOperation(operation)
+    registerEffect(expressions, operations) {
+      if (
+        this.inVOnce ||
+        (expressions = expressions.filter(Boolean)).length === 0
+      ) {
+        return this.registerOperation(...operations)
       }
-      if (!effect[expr]) effect[expr] = []
-      effect[expr].push(operation)
+      // TODO combine effects
+      effect.push({
+        expressions: expressions as IRExpression[],
+        operations,
+      })
     },
 
     template: '',
@@ -175,6 +183,7 @@ export function transform(
 
   const ir: RootIRNode = {
     type: IRNodeTypes.ROOT,
+    node: root,
     source: root.source,
     loc: root.loc,
     template: [],
@@ -185,7 +194,7 @@ export function transform(
       placeholder: null,
       children: {},
     },
-    effect: Object.create(null),
+    effect: [],
     operation: [],
     helpers: new Set([]),
     vaporHelpers: new Set([]),
@@ -309,7 +318,7 @@ function transformChildren(ctx: TransformContext<RootNode | ElementNode>) {
   if (ctx.node.type === NodeTypes.ROOT) ctx.registerTemplate()
 
   function processDynamicChildren() {
-    let prevChildren: DynamicInfo[] = []
+    let prevChildren: IRDynamicInfo[] = []
     let hasStatic = false
     for (let index = 0; index < children.length; index++) {
       const child = ctx.dynamic.children[index]
@@ -378,22 +387,22 @@ function transformInterpolation(
 ) {
   const { node } = ctx
 
-  if (node.content.type === NodeTypes.COMPOUND_EXPRESSION) {
-    // TODO: CompoundExpressionNode: {{ count + 1 }}
-    return
-  }
-
-  const expr = processExpression(ctx, node.content)!
+  const expr = node.content
 
   if (isFirst && isLast) {
     const parent = ctx.parent!
     const parentId = parent.reference()
-    ctx.registerEffect(expr, {
-      type: IRNodeTypes.SET_TEXT,
-      loc: node.loc,
-      element: parentId,
-      value: expr,
-    })
+    ctx.registerEffect(
+      [expr],
+      [
+        {
+          type: IRNodeTypes.SET_TEXT,
+          loc: node.loc,
+          element: parentId,
+          value: expr,
+        },
+      ],
+    )
   } else {
     const id = ctx.reference()
     ctx.dynamic.ghost = true
@@ -403,12 +412,17 @@ function transformInterpolation(
       id,
       value: expr,
     })
-    ctx.registerEffect(expr, {
-      type: IRNodeTypes.SET_TEXT,
-      loc: node.loc,
-      element: id,
-      value: expr,
-    })
+    ctx.registerEffect(
+      [expr],
+      [
+        {
+          type: IRNodeTypes.SET_TEXT,
+          loc: node.loc,
+          element: id,
+          value: expr,
+        },
+      ],
+    )
   }
 }
 
@@ -427,9 +441,8 @@ function transformProp(
     return
   }
 
-  const { exp, loc, modifiers } = node
+  const { arg, exp, loc, modifiers } = node
 
-  const expr = processExpression(ctx, exp)
   switch (name) {
     case 'bind': {
       if (
@@ -442,25 +455,27 @@ function transformProp(
         return
       }
 
-      if (expr === null) {
+      if (exp === null) {
         // TODO: Vue 3.4 supported shorthand syntax
         // https://github.com/vuejs/core/pull/9451
         return
-      } else if (!node.arg) {
+      } else if (!arg) {
         // TODO support v-bind="{}"
         return
-      } else if (node.arg.type === NodeTypes.COMPOUND_EXPRESSION) {
-        // TODO support :[foo]="bar"
-        return
       }
 
-      ctx.registerEffect(expr, {
-        type: IRNodeTypes.SET_PROP,
-        loc: node.loc,
-        element: ctx.reference(),
-        name: node.arg.content,
-        value: expr,
-      })
+      ctx.registerEffect(
+        [exp],
+        [
+          {
+            type: IRNodeTypes.SET_PROP,
+            loc: node.loc,
+            element: ctx.reference(),
+            name: arg,
+            value: exp,
+          },
+        ],
+      )
       break
     }
     case 'on': {
@@ -471,46 +486,56 @@ function transformProp(
         return
       }
 
-      if (!node.arg) {
+      if (!arg) {
         // TODO support v-on="{}"
         return
-      } else if (node.arg.type === NodeTypes.COMPOUND_EXPRESSION) {
-        // TODO support @[foo]="bar"
-        return
-      } else if (expr === null) {
+      } else if (exp === undefined) {
         // TODO: support @foo
         // https://github.com/vuejs/core/pull/9451
         return
       }
 
-      ctx.registerEffect(expr, {
-        type: IRNodeTypes.SET_EVENT,
-        loc: node.loc,
-        element: ctx.reference(),
-        name: node.arg.content,
-        value: expr,
-        modifiers,
-      })
+      ctx.registerEffect(
+        [exp],
+        [
+          {
+            type: IRNodeTypes.SET_EVENT,
+            loc: node.loc,
+            element: ctx.reference(),
+            name: arg,
+            value: exp,
+            modifiers,
+          },
+        ],
+      )
       break
     }
     case 'html': {
-      const value = expr || '""'
-      ctx.registerEffect(value, {
-        type: IRNodeTypes.SET_HTML,
-        loc: node.loc,
-        element: ctx.reference(),
-        value,
-      })
+      ctx.registerEffect(
+        [exp],
+        [
+          {
+            type: IRNodeTypes.SET_HTML,
+            loc: node.loc,
+            element: ctx.reference(),
+            value: exp || '""',
+          },
+        ],
+      )
       break
     }
     case 'text': {
-      const value = expr || '""'
-      ctx.registerEffect(value, {
-        type: IRNodeTypes.SET_TEXT,
-        loc: node.loc,
-        element: ctx.reference(),
-        value,
-      })
+      ctx.registerEffect(
+        [exp],
+        [
+          {
+            type: IRNodeTypes.SET_TEXT,
+            loc: node.loc,
+            element: ctx.reference(),
+            value: exp || '""',
+          },
+        ],
+      )
       break
     }
     case 'cloak': {
@@ -519,24 +544,3 @@ function transformProp(
     }
   }
 }
-
-// TODO: reuse packages/compiler-core/src/transforms/transformExpression.ts
-function processExpression(
-  ctx: TransformContext,
-  expr: ExpressionNode | undefined,
-): string | null {
-  if (!expr) return null
-  if (expr.type === NodeTypes.COMPOUND_EXPRESSION) {
-    // TODO
-    return ''
-  }
-
-  let { content } = expr
-  if (ctx.options.bindingMetadata?.[content] === BindingTypes.SETUP_REF) {
-    content += '.value'
-  }
-  if (ctx.options.prefixIdentifiers && !ctx.options.inline) {
-    content = `_ctx.${content}`
-  }
-  return content
-}