@@ -10,7 +10,7 @@ use num_bigint::BigInt;
1010use rustc_hash:: FxHashMap ;
1111
1212use oxc_allocator:: Address ;
13- use oxc_ast:: { AstKind , ast:: * } ;
13+ use oxc_ast:: { AstBuilder , AstKind , ast:: * } ;
1414use oxc_ast_visit:: Visit ;
1515#[ cfg( feature = "cfg" ) ]
1616use oxc_cfg:: {
@@ -29,18 +29,24 @@ use oxc_syntax::{
2929#[ cfg( feature = "linter" ) ]
3030use crate :: jsdoc:: JSDocBuilder ;
3131use crate :: {
32- const_enum:: { ConstEnumTable , ConstEnumMemberValue , ConstEnumMemberInfo , ConstEnumInfo } ,
3332 Semantic ,
3433 binder:: { Binder , ModuleInstanceState } ,
3534 checker,
3635 class:: ClassTableBuilder ,
36+ const_enum:: {
37+ ConstEnumInfo , ConstEnumMemberInfo , ConstEnumTable , ConstantEnumCtx ,
38+ NormalizedConstEnumInfo , NormalizedConstEnumMemberInfo ,
39+ } ,
3740 diagnostics:: redeclaration,
3841 label:: UnusedLabels ,
3942 node:: AstNodes ,
4043 scoping:: { Bindings , Scoping } ,
4144 stats:: Stats ,
4245 unresolved_stack:: UnresolvedReferencesStack ,
4346} ;
47+ use oxc_ecmascript:: constant_evaluation:: {
48+ ConstantEvaluation , ConstantEvaluationCtx , ConstantValue ,
49+ } ;
4450
4551#[ cfg( feature = "cfg" ) ]
4652macro_rules! control_flow {
@@ -112,7 +118,7 @@ pub struct SemanticBuilder<'a> {
112118 pub ( crate ) class_table_builder : ClassTableBuilder < ' a > ,
113119
114120 /// Table for storing const enum information
115- pub ( crate ) const_enum_table : ConstEnumTable < ' a > ,
121+ pub ( crate ) const_enum_table : ConstEnumTable ,
116122
117123 #[ cfg( feature = "cfg" ) ]
118124 ast_node_records : Vec < NodeId > ,
@@ -2154,11 +2160,6 @@ impl<'a> SemanticBuilder<'a> {
21542160 }
21552161 AstKind :: TSEnumDeclaration ( enum_declaration) => {
21562162 enum_declaration. bind ( self ) ;
2157-
2158- // Process const enums
2159- if enum_declaration. r#const {
2160- self . process_const_enum ( enum_declaration) ;
2161- }
21622163 }
21632164 AstKind :: TSEnumMember ( enum_member) => {
21642165 enum_member. bind ( self ) ;
@@ -2223,6 +2224,11 @@ impl<'a> SemanticBuilder<'a> {
22232224 // Clear the reference flags that may have been set when entering the node.
22242225 self . current_reference_flags = ReferenceFlags :: empty ( ) ;
22252226 }
2227+ AstKind :: TSEnumDeclaration ( enum_declaration) => {
2228+ if enum_declaration. r#const {
2229+ self . process_const_enum ( enum_declaration) ;
2230+ }
2231+ }
22262232 _ => { }
22272233 }
22282234 }
@@ -2248,9 +2254,11 @@ impl<'a> SemanticBuilder<'a> {
22482254 /// Process a const enum declaration and evaluate its members
22492255 fn process_const_enum ( & mut self , enum_declaration : & TSEnumDeclaration < ' a > ) {
22502256 // Get the symbol ID for this enum
2251- let symbol_id = enum_declaration. id . symbol_id . get ( ) . expect ( "enum should have symbol ID" ) ;
2252-
2253- let mut members = std:: collections:: HashMap :: new ( ) ;
2257+ let symbol_id = enum_declaration. id . symbol_id ( ) ;
2258+ let current_scope = enum_declaration. scope_id ( ) ;
2259+ let allocator = oxc_allocator:: Allocator :: default ( ) ;
2260+ let ast_builder = AstBuilder :: new ( & allocator) ;
2261+ let mut members = FxHashMap :: default ( ) ;
22542262 let mut current_value: f64 = -1.0 ; // Start at -1, first auto-increment will make it 0
22552263
22562264 for member in & enum_declaration. body . members {
@@ -2260,7 +2268,7 @@ impl<'a> SemanticBuilder<'a> {
22602268 TSEnumMemberName :: ComputedString ( string) => string. value . as_str ( ) ,
22612269 TSEnumMemberName :: ComputedTemplateString ( template) => {
22622270 // For computed template strings, we need to evaluate them
2263- if template. expressions . is_empty ( ) {
2271+ let v = if template. expressions . is_empty ( ) {
22642272 if let Some ( quasi) = template. quasis . first ( ) {
22652273 quasi. value . raw . as_str ( )
22662274 } else {
@@ -2269,184 +2277,41 @@ impl<'a> SemanticBuilder<'a> {
22692277 } else {
22702278 // Skip template literals with expressions for now
22712279 continue ;
2272- }
2280+ } ;
2281+ v
22732282 }
22742283 } ;
2275-
2284+ let Some ( member_symbol_id) = self . scoping . get_binding ( current_scope, member_name)
2285+ else {
2286+ continue ;
2287+ } ;
22762288 let value = if let Some ( initializer) = & member. initializer {
2277- // Evaluate the initializer expression
2278- let mut visited = std:: vec:: Vec :: new ( ) ;
2279- if let Some ( evaluated_value) = self . evaluate_const_enum_member ( initializer, Some ( symbol_id) , & mut visited) {
2280- // Update current_value based on the evaluated value
2281- match & evaluated_value {
2282- ConstEnumMemberValue :: Number ( n) => current_value = * n,
2283- _ => { } // Don't change current_value for non-numeric values
2284- }
2285- evaluated_value
2286- } else {
2287- // If evaluation fails, fall back to current_value + 1
2288- current_value += 1.0 ;
2289- ConstEnumMemberValue :: Number ( current_value)
2290- }
2289+ let ctx = ConstantEnumCtx :: new ( & members, & self . scoping , ast_builder) ;
2290+ initializer. evaluate_value ( & ctx) . unwrap_or ( ConstantValue :: Undefined )
22912291 } else {
22922292 // Auto-increment the value
22932293 current_value += 1.0 ;
2294- ConstEnumMemberValue :: Number ( current_value)
2294+ ConstantValue :: Number ( current_value)
22952295 } ;
2296+ dbg ! ( & value) ;
22962297
22972298 let member_info = ConstEnumMemberInfo {
22982299 name : member_name,
22992300 value,
23002301 span : member. span ,
23012302 has_initializer : member. initializer . is_some ( ) ,
2303+ symbol_id : member_symbol_id,
23022304 } ;
23032305
2304- members. insert ( member_name , member_info) ;
2306+ members. insert ( member_symbol_id , member_info) ;
23052307 }
23062308
2307- let enum_info = ConstEnumInfo {
2308- symbol_id ,
2309- members ,
2310- span : enum_declaration . span ,
2311- } ;
2309+ let members = members
2310+ . into_iter ( )
2311+ . map ( | ( symbol_id , member ) | ( symbol_id , member . into ( ) ) )
2312+ . collect :: < FxHashMap < SymbolId , NormalizedConstEnumMemberInfo > > ( ) ;
2313+ let enum_info = NormalizedConstEnumInfo { symbol_id , members , span : enum_declaration . span } ;
23122314
23132315 self . const_enum_table . add_enum ( symbol_id, enum_info) ;
23142316 }
2315-
2316- /// Evaluate a const enum member's value with improved JavaScript semantics
2317- fn evaluate_const_enum_member (
2318- & self ,
2319- expression : & Expression < ' a > ,
2320- current_enum : Option < SymbolId > ,
2321- _visited : & mut std:: vec:: Vec < & ' a str > ,
2322- ) -> Option < ConstEnumMemberValue < ' a > > {
2323- match expression {
2324- Expression :: StringLiteral ( string) => Some ( ConstEnumMemberValue :: String ( string. value . as_str ( ) ) ) ,
2325- Expression :: NumericLiteral ( number) => Some ( ConstEnumMemberValue :: Number ( number. value ) ) ,
2326- Expression :: BooleanLiteral ( boolean) => Some ( ConstEnumMemberValue :: Boolean ( boolean. value ) ) ,
2327- Expression :: BigIntLiteral ( bigint) => {
2328- bigint. value . parse :: < BigInt > ( ) . ok ( ) . map ( ConstEnumMemberValue :: BigInt )
2329- }
2330- Expression :: UnaryExpression ( unary) => {
2331- if let Some ( argument) = self . evaluate_const_enum_member ( & unary. argument , current_enum, _visited) {
2332- self . evaluate_unary_operation ( unary, argument)
2333- } else {
2334- None
2335- }
2336- }
2337- Expression :: BinaryExpression ( binary) => {
2338- if let ( Some ( left) , Some ( right) ) = (
2339- self . evaluate_const_enum_member ( & binary. left , current_enum, _visited) ,
2340- self . evaluate_const_enum_member ( & binary. right , current_enum, _visited) ,
2341- ) {
2342- self . evaluate_binary_operation ( binary, left, right)
2343- } else {
2344- None
2345- }
2346- }
2347- Expression :: Identifier ( ident) => {
2348- // Try to resolve this as a reference to another const enum member
2349- let name = ident. name . as_str ( ) ;
2350-
2351- if let Some ( current_enum_id) = current_enum {
2352- if let Some ( enum_info) = self . const_enum_table . get_enum ( current_enum_id) {
2353- if let Some ( member_info) = enum_info. members . get ( name) {
2354- return Some ( member_info. value . clone ( ) ) ;
2355- }
2356- }
2357- }
2358- None
2359- }
2360- _ => None ,
2361- }
2362- }
2363-
2364- /// Evaluate unary operations with proper JavaScript semantics
2365- fn evaluate_unary_operation (
2366- & self ,
2367- unary : & UnaryExpression < ' a > ,
2368- argument : ConstEnumMemberValue < ' a > ,
2369- ) -> Option < ConstEnumMemberValue < ' a > > {
2370- match unary. operator {
2371- UnaryOperator :: UnaryNegation => {
2372- match argument {
2373- ConstEnumMemberValue :: Number ( n) => Some ( ConstEnumMemberValue :: Number ( -n) ) ,
2374- _ => None ,
2375- }
2376- }
2377- UnaryOperator :: UnaryPlus => {
2378- match argument {
2379- ConstEnumMemberValue :: Number ( n) => Some ( ConstEnumMemberValue :: Number ( n) ) ,
2380- _ => None ,
2381- }
2382- }
2383- UnaryOperator :: LogicalNot => {
2384- match argument {
2385- ConstEnumMemberValue :: Boolean ( b) => Some ( ConstEnumMemberValue :: Boolean ( !b) ) ,
2386- _ => None ,
2387- }
2388- }
2389- _ => None ,
2390- }
2391- }
2392-
2393- /// Evaluate binary operations with proper JavaScript semantics
2394- fn evaluate_binary_operation (
2395- & self ,
2396- binary : & BinaryExpression < ' a > ,
2397- left : ConstEnumMemberValue < ' a > ,
2398- right : ConstEnumMemberValue < ' a > ,
2399- ) -> Option < ConstEnumMemberValue < ' a > > {
2400- match binary. operator {
2401- BinaryOperator :: Addition => {
2402- match ( & left, & right) {
2403- ( ConstEnumMemberValue :: Number ( l) , ConstEnumMemberValue :: Number ( r) ) => {
2404- Some ( ConstEnumMemberValue :: Number ( l + r) )
2405- }
2406- _ => None ,
2407- }
2408- }
2409- BinaryOperator :: Subtraction => {
2410- match ( & left, & right) {
2411- ( ConstEnumMemberValue :: Number ( l) , ConstEnumMemberValue :: Number ( r) ) => {
2412- Some ( ConstEnumMemberValue :: Number ( l - r) )
2413- }
2414- _ => None ,
2415- }
2416- }
2417- BinaryOperator :: Multiplication => {
2418- match ( & left, & right) {
2419- ( ConstEnumMemberValue :: Number ( l) , ConstEnumMemberValue :: Number ( r) ) => {
2420- Some ( ConstEnumMemberValue :: Number ( l * r) )
2421- }
2422- _ => None ,
2423- }
2424- }
2425- BinaryOperator :: Division => {
2426- match ( & left, & right) {
2427- ( ConstEnumMemberValue :: Number ( l) , ConstEnumMemberValue :: Number ( r) ) => {
2428- if * r == 0.0 { None } else { Some ( ConstEnumMemberValue :: Number ( l / r) ) }
2429- }
2430- _ => None ,
2431- }
2432- }
2433- BinaryOperator :: ShiftLeft => {
2434- match ( & left, & right) {
2435- ( ConstEnumMemberValue :: Number ( l) , ConstEnumMemberValue :: Number ( r) ) => {
2436- Some ( ConstEnumMemberValue :: Number ( ( ( * l as i64 ) << ( * r as i64 ) ) as f64 ) )
2437- }
2438- _ => None ,
2439- }
2440- }
2441- BinaryOperator :: BitwiseOR => {
2442- match ( & left, & right) {
2443- ( ConstEnumMemberValue :: Number ( l) , ConstEnumMemberValue :: Number ( r) ) => {
2444- Some ( ConstEnumMemberValue :: Number ( ( ( * l as i64 ) | ( * r as i64 ) ) as f64 ) )
2445- }
2446- _ => None ,
2447- }
2448- }
2449- _ => None ,
2450- }
2451- }
24522317}
0 commit comments