88
99import * as o from '../../../../output/output_ast' ;
1010import * as ir from '../../ir' ;
11- import { CompilationJob , ComponentCompilationJob } from '../compilation' ;
11+ import type { CompilationJob , CompilationUnit } from '../compilation' ;
1212
1313/**
1414 * Find all assignments and usages of temporary variables, which are linked to each other with cross
@@ -21,49 +21,69 @@ import {CompilationJob, ComponentCompilationJob} from '../compilation';
2121 */
2222export function phaseTemporaryVariables ( cpl : CompilationJob ) : void {
2323 for ( const unit of cpl . units ) {
24- let opCount = 0 ;
25- let generatedStatements : Array < ir . StatementOp < ir . UpdateOp > > = [ ] ;
26- for ( const op of unit . ops ( ) ) {
27- // Identify the final time each temp var is read.
28- const finalReads = new Map < ir . XrefId , ir . ReadTemporaryExpr > ( ) ;
29- ir . visitExpressionsInOp ( op , expr => {
30- if ( expr instanceof ir . ReadTemporaryExpr ) {
31- finalReads . set ( expr . xref , expr ) ;
32- }
33- } ) ;
24+ unit . create . prepend ( generateTemporaries ( unit . create ) as Array < ir . StatementOp < ir . CreateOp > > ) ;
25+ unit . update . prepend ( generateTemporaries ( unit . update ) as Array < ir . StatementOp < ir . UpdateOp > > ) ;
26+ }
27+ }
28+
29+ function generateTemporaries ( ops : ir . OpList < ir . CreateOp | ir . UpdateOp > ) :
30+ Array < ir . StatementOp < ir . CreateOp | ir . UpdateOp > > {
31+ let opCount = 0 ;
32+ let generatedStatements : Array < ir . StatementOp < ir . UpdateOp > > = [ ] ;
3433
35- // Name the temp vars, accounting for the fact that a name can be reused after it has been
36- // read for the final time.
37- let count = 0 ;
38- const assigned = new Set < ir . XrefId > ( ) ;
39- const released = new Set < ir . XrefId > ( ) ;
40- const defs = new Map < ir . XrefId , string > ( ) ;
41- ir . visitExpressionsInOp ( op , expr => {
42- if ( expr instanceof ir . AssignTemporaryExpr ) {
43- if ( ! assigned . has ( expr . xref ) ) {
44- assigned . add ( expr . xref ) ;
45- // TODO: Exactly replicate the naming scheme used by `TemplateDefinitionBuilder`.
46- // It seems to rely on an expression index instead of an op index.
47- defs . set ( expr . xref , `tmp_${ opCount } _${ count ++ } ` ) ;
48- }
49- assignName ( defs , expr ) ;
50- } else if ( expr instanceof ir . ReadTemporaryExpr ) {
51- if ( finalReads . get ( expr . xref ) === expr ) {
52- released . add ( expr . xref ) ;
53- count -- ;
54- }
55- assignName ( defs , expr ) ;
34+ // For each op, search for any variables that are assigned or read. For each variable, generate a
35+ // name and produce a `DeclareVarStmt` to the beginning of the block.
36+ for ( const op of ops ) {
37+ // Identify the final time each temp var is read.
38+ const finalReads = new Map < ir . XrefId , ir . ReadTemporaryExpr > ( ) ;
39+ ir . visitExpressionsInOp ( op , ( expr , flag ) => {
40+ if ( flag & ir . VisitorContextFlag . InChildOperation ) {
41+ return ;
42+ }
43+ if ( expr instanceof ir . ReadTemporaryExpr ) {
44+ finalReads . set ( expr . xref , expr ) ;
45+ }
46+ } ) ;
47+
48+ // Name the temp vars, accounting for the fact that a name can be reused after it has been
49+ // read for the final time.
50+ let count = 0 ;
51+ const assigned = new Set < ir . XrefId > ( ) ;
52+ const released = new Set < ir . XrefId > ( ) ;
53+ const defs = new Map < ir . XrefId , string > ( ) ;
54+ ir . visitExpressionsInOp ( op , ( expr , flag ) => {
55+ if ( flag & ir . VisitorContextFlag . InChildOperation ) {
56+ return ;
57+ }
58+ if ( expr instanceof ir . AssignTemporaryExpr ) {
59+ if ( ! assigned . has ( expr . xref ) ) {
60+ assigned . add ( expr . xref ) ;
61+ // TODO: Exactly replicate the naming scheme used by `TemplateDefinitionBuilder`.
62+ // It seems to rely on an expression index instead of an op index.
63+ defs . set ( expr . xref , `tmp_${ opCount } _${ count ++ } ` ) ;
64+ }
65+ assignName ( defs , expr ) ;
66+ } else if ( expr instanceof ir . ReadTemporaryExpr ) {
67+ if ( finalReads . get ( expr . xref ) === expr ) {
68+ released . add ( expr . xref ) ;
69+ count -- ;
5670 }
57- } ) ;
71+ assignName ( defs , expr ) ;
72+ }
73+ } ) ;
5874
59- // Add declarations for the temp vars.
60- generatedStatements . push (
61- ...Array . from ( new Set ( defs . values ( ) ) )
62- . map ( name => ir . createStatementOp < ir . UpdateOp > ( new o . DeclareVarStmt ( name ) ) ) ) ;
63- opCount ++ ;
75+ // Add declarations for the temp vars.
76+ generatedStatements . push (
77+ ...Array . from ( new Set ( defs . values ( ) ) )
78+ . map ( name => ir . createStatementOp < ir . UpdateOp > ( new o . DeclareVarStmt ( name ) ) ) ) ;
79+ opCount ++ ;
80+
81+ if ( op . kind === ir . OpKind . Listener ) {
82+ op . handlerOps . prepend ( generateTemporaries ( op . handlerOps ) as ir . UpdateOp [ ] ) ;
6483 }
65- unit . update . prepend ( generatedStatements ) ;
6684 }
85+
86+ return generatedStatements ;
6787}
6888
6989/**
0 commit comments