@ -1,7 +1,6 @@
/** @import { Expression, Identifier, Pattern } from 'estree' */
/** @import { Expression, Identifier, Pattern , Statement } from 'estree' */
/** @import { AST } from '#compiler' */
/** @import { AST } from '#compiler' */
/** @import { ComponentContext } from '../types' */
/** @import { ComponentContext } from '../types' */
/** @import { ExpressionMetadata } from '../../../nodes.js' */
import { dev } from '../../../../state.js' ;
import { dev } from '../../../../state.js' ;
import { extract _identifiers } from '../../../../utils/ast.js' ;
import { extract _identifiers } from '../../../../utils/ast.js' ;
import * as b from '#compiler/builders' ;
import * as b from '#compiler/builders' ;
@ -27,13 +26,7 @@ export function ConstTag(node, context) {
context . state . transform [ declaration . id . name ] = { read : get _value } ;
context . state . transform [ declaration . id . name ] = { read : get _value } ;
add _const _declaration (
add _const _declaration ( context . state , declaration . id , expression , node . metadata ) ;
context . state ,
declaration . id ,
expression ,
node . metadata . expression ,
context . state . scope . get _bindings ( declaration )
) ;
} else {
} else {
const identifiers = extract _identifiers ( declaration . id ) ;
const identifiers = extract _identifiers ( declaration . id ) ;
const tmp = b . id ( context . state . scope . generate ( 'computed_const' ) ) ;
const tmp = b . id ( context . state . scope . generate ( 'computed_const' ) ) ;
@ -70,13 +63,7 @@ export function ConstTag(node, context) {
expression = b . call ( '$.tag' , expression , b . literal ( '[@const]' ) ) ;
expression = b . call ( '$.tag' , expression , b . literal ( '[@const]' ) ) ;
}
}
add _const _declaration (
add _const _declaration ( context . state , tmp , expression , node . metadata ) ;
context . state ,
tmp ,
expression ,
node . metadata . expression ,
context . state . scope . get _bindings ( declaration )
) ;
for ( const node of identifiers ) {
for ( const node of identifiers ) {
context . state . transform [ node . name ] = {
context . state . transform [ node . name ] = {
@ -90,42 +77,40 @@ export function ConstTag(node, context) {
* @ param { ComponentContext [ 'state' ] } state
* @ param { ComponentContext [ 'state' ] } state
* @ param { Identifier } id
* @ param { Identifier } id
* @ param { Expression } expression
* @ param { Expression } expression
* @ param { ExpressionMetadata } metadata
* @ param { AST . ConstTag [ 'metadata' ] } metadata
* @ param { import ( '#compiler' ) . Binding [ ] } bindings
* /
* /
function add _const _declaration ( state , id , expression , metadata , bindings ) {
function add _const _declaration ( state , id , expression , metadata ) {
// we need to eagerly evaluate the expression in order to hit any
// we need to eagerly evaluate the expression in order to hit any
// 'Cannot access x before initialization' errors
// 'Cannot access x before initialization' errors
const after = dev ? [ b . stmt ( b . call ( '$.get' , id ) ) ] : [ ] ;
const after = dev ? [ b . stmt ( b . call ( '$.get' , id ) ) ] : [ ] ;
const has _await = metadata . has _await ;
const blockers = [ ... metadata . expression . dependencies ]
const blockers = [ ... metadata . dependencies ]
. map ( ( dep ) => dep . blocker )
. map ( ( dep ) => dep . blocker )
. filter ( ( b ) => b !== null && b . object !== state . async _consts ? . id ) ;
. filter ( ( b ) => b !== null && b . object !== state . async _consts ? . id ) ;
if ( has_await || state . async _consts || blockers . length > 0 ) {
if ( metadata. promises _id ) {
const run = ( state . async _consts ? ? = {
const run = ( state . async _consts ? ? = {
id : b. id ( state . scope . generate ( 'promises' ) ) ,
id : metadata. promises _id ,
thunks : [ ]
thunks : [ ]
} ) ;
} ) ;
state . consts . push ( b . let ( id ) ) ;
state . consts . push ( b . let ( id ) ) ;
const assignment = b . assignment ( '=' , id , expression ) ;
/** @type {Statement | undefined} */
const body = after . length === 0 ? assignment : b . block ( [ b . stmt ( assignment ) , ... after ] ) ;
let promise _stmt ;
if ( blockers . length === 1 ) {
if ( blockers . length === 1 ) {
run. thunks . push ( b . thunk ( b . member ( /** @type {Expression} */ ( blockers [ 0 ] ) , 'promise' ) ) ) ;
promise_stmt = b . stmt ( b . await ( b . member ( /** @type {Expression} */ ( blockers [ 0 ] ) , 'promise' ) ) ) ;
} else if ( blockers . length > 0 ) {
} else if ( blockers . length > 0 ) {
run. thunks . push ( b . thunk ( b . call ( '$.wait' , b . array ( blockers ) ) ) ) ;
promise_stmt = b . stmt ( b . await ( b . call ( '$.wait' , b . array ( blockers ) ) ) ) ;
}
}
run . thunks . push ( b . thunk ( body , has _await ) ) ;
// keep the number of thunks pushed in sync with ConstTag in analysis phase
const assignment = b . assignment ( '=' , id , expression ) ;
const blocker = b . member ( run . id , b . literal ( run . thunks . length - 1 ) , true ) ;
if ( promise _stmt ) {
run . thunks . push ( b . thunk ( b . block ( [ promise _stmt , b . stmt ( assignment ) ] ) , true ) ) ;
for ( const binding of bindings ) {
} else {
binding. blocker = blocker ;
run. thunks . push ( b . thunk ( assignment , metadata . expression . has _await ) ) ;
}
}
} else {
} else {
state . consts . push ( b . const ( id , expression ) ) ;
state . consts . push ( b . const ( id , expression ) ) ;