diff --git a/index.ts b/index.ts new file mode 100644 index 000000000..579018f4c --- /dev/null +++ b/index.ts @@ -0,0 +1,20 @@ +enum CompassDirection { + North, + East, + South, + West +} + +globalThis.__enumCheck = { + northValue: CompassDirection.North === 0, + eastValue: CompassDirection.East === 1, + southValue: CompassDirection.South === 2, + westValue: CompassDirection.West === 3, + + zeroName: CompassDirection[0] === "North", + oneName: CompassDirection[1] === "East", + twoName: CompassDirection[2] === "South", + threeName: CompassDirection[3] === "West", + + keys: Object.keys(CompassDirection) +}; diff --git a/nova_vm/src/ecmascript/syntax_directed_operations/scope_analysis.rs b/nova_vm/src/ecmascript/syntax_directed_operations/scope_analysis.rs index bd21a8100..639ebfb81 100644 --- a/nova_vm/src/ecmascript/syntax_directed_operations/scope_analysis.rs +++ b/nova_vm/src/ecmascript/syntax_directed_operations/scope_analysis.rs @@ -1107,15 +1107,18 @@ impl<'a> TopLevelLexicallyDeclaredNames<'a> for Statement<'a> { Statement::ImportDeclaration(decl) => decl.bound_names(f), Statement::ExportNamedDeclaration(decl) => decl.bound_names(f), #[cfg(feature = "typescript")] - Statement::TSTypeAliasDeclaration(_) | Statement::TSInterfaceDeclaration(_) => {} + Statement::TSTypeAliasDeclaration(_) + | Statement::TSInterfaceDeclaration(_) + | Statement::TSEnumDeclaration(_) => {} #[cfg(not(feature = "typescript"))] - Statement::TSTypeAliasDeclaration(_) | Statement::TSInterfaceDeclaration(_) => { + Statement::TSTypeAliasDeclaration(_) + | Statement::TSInterfaceDeclaration(_) + | Statement::TSEnumDeclaration(_) => { unreachable!() } // Note: No bounds names for export all and export default declarations. Statement::ExportAllDeclaration(_) | Statement::ExportDefaultDeclaration(_) => {} - Statement::TSEnumDeclaration(_) - | Statement::TSModuleDeclaration(_) + Statement::TSModuleDeclaration(_) | Statement::TSImportEqualsDeclaration(_) | Statement::TSExportAssignment(_) | Statement::TSNamespaceExportDeclaration(_) => unreachable!(), @@ -1189,13 +1192,16 @@ impl<'a> TopLevelLexicallyScopedDeclarations<'a> for Statement<'a> { } Statement::ClassDeclaration(decl) => f(LexicallyScopedDeclaration::Class(decl)), #[cfg(feature = "typescript")] - Statement::TSTypeAliasDeclaration(_) | Statement::TSInterfaceDeclaration(_) => {} + Statement::TSTypeAliasDeclaration(_) + | Statement::TSInterfaceDeclaration(_) + | Statement::TSEnumDeclaration(_) => {} #[cfg(not(feature = "typescript"))] - Statement::TSTypeAliasDeclaration(_) | Statement::TSInterfaceDeclaration(_) => { + Statement::TSTypeAliasDeclaration(_) + | Statement::TSInterfaceDeclaration(_) + | Statement::TSEnumDeclaration(_) => { unreachable!() } - Statement::TSEnumDeclaration(_) - | Statement::TSExportAssignment(_) + Statement::TSExportAssignment(_) | Statement::TSImportEqualsDeclaration(_) | Statement::TSModuleDeclaration(_) | Statement::TSNamespaceExportDeclaration(_) => unreachable!(), @@ -1275,13 +1281,16 @@ impl<'a> TopLevelVarDeclaredNames<'a> for Statement<'a> { | Statement::WhileStatement(_) | Statement::WithStatement(_) => self.var_declared_names(f), #[cfg(feature = "typescript")] - Statement::TSTypeAliasDeclaration(_) | Statement::TSInterfaceDeclaration(_) => {} + Statement::TSTypeAliasDeclaration(_) + | Statement::TSInterfaceDeclaration(_) + | Statement::TSEnumDeclaration(_) => {} #[cfg(not(feature = "typescript"))] - Statement::TSTypeAliasDeclaration(_) | Statement::TSInterfaceDeclaration(_) => { + Statement::TSTypeAliasDeclaration(_) + | Statement::TSInterfaceDeclaration(_) + | Statement::TSEnumDeclaration(_) => { unreachable!() } - Statement::TSEnumDeclaration(_) - | Statement::TSExportAssignment(_) + Statement::TSExportAssignment(_) | Statement::TSImportEqualsDeclaration(_) | Statement::TSModuleDeclaration(_) | Statement::TSNamespaceExportDeclaration(_) => unreachable!(), @@ -1404,13 +1413,17 @@ impl<'a> TopLevelVarScopedDeclarations<'a> for Statement<'a> { // 2. Return a new empty List. } #[cfg(feature = "typescript")] - Statement::TSTypeAliasDeclaration(_) | Statement::TSInterfaceDeclaration(_) => {} + Statement::TSTypeAliasDeclaration(_) + | Statement::TSInterfaceDeclaration(_) + | Statement::TSEnumDeclaration(_) => {} #[cfg(not(feature = "typescript"))] - Statement::TSTypeAliasDeclaration(_) | Statement::TSInterfaceDeclaration(_) => { + Statement::TSTypeAliasDeclaration(_) + | Statement::TSInterfaceDeclaration(_) + | Statement::TSEnumDeclaration(_) => { unreachable!() } - Statement::TSEnumDeclaration(_) - | Statement::TSExportAssignment(_) + + Statement::TSExportAssignment(_) | Statement::TSImportEqualsDeclaration(_) | Statement::TSModuleDeclaration(_) | Statement::TSNamespaceExportDeclaration(_) => unreachable!(), diff --git a/nova_vm/src/engine/bytecode/bytecode_compiler.rs b/nova_vm/src/engine/bytecode/bytecode_compiler.rs index 4dd87db2d..b99117e06 100644 --- a/nova_vm/src/engine/bytecode/bytecode_compiler.rs +++ b/nova_vm/src/engine/bytecode/bytecode_compiler.rs @@ -76,6 +76,7 @@ pub(crate) struct CompileContext<'agent, 'gc, 'scope> { /// In a `(a?.b)?.()` chain the evaluation of `(a?.b)` must be considered a /// reference. is_call_optional_chain_this: bool, + current_value: Option>, } impl<'a, 'gc, 'scope> CompileContext<'a, 'gc, 'scope> { @@ -98,6 +99,7 @@ impl<'a, 'gc, 'scope> CompileContext<'a, 'gc, 'scope> { current_break: None, optional_chains: None, is_call_optional_chain_this: false, + current_value: None, } } @@ -358,6 +360,7 @@ impl<'a, 'gc, 'scope> CompileContext<'a, 'gc, 'scope> { ) { debug_assert_eq!(instruction.argument_count(), 1); debug_assert!(instruction.has_identifier_index()); + self._push_instruction(instruction); let identifier = self.add_identifier(identifier); self.add_index(identifier); @@ -507,6 +510,7 @@ impl CompileEvaluation for ast::NumericLiteral<'_> { fn compile(&self, ctx: &mut CompileContext) { let constant = ctx.agent.heap.create(self.value); ctx.add_instruction_with_constant(Instruction::StoreConstant, constant); + ctx.current_value = Some(constant.into_value()); } } @@ -2935,6 +2939,62 @@ impl CompileEvaluation for ast::ContinueStatement<'_> { } } +#[cfg(feature = "typescript")] +impl CompileEvaluation for ast::TSEnumDeclaration<'_> { + fn compile<'gc>(&self, ctx: &mut CompileContext<'_, 'gc, '_>) { + let is_const = self.r#const; + if is_const { + return; + } + let enum_name = self.id.name; + println!("{:?}", enum_name); + + // TODO: implement var Foo + + ctx.add_instruction(Instruction::ObjectCreate); + ctx.add_instruction(Instruction::Store); + ctx.add_instruction(Instruction::LoadCopy); + ctx.add_instruction(Instruction::Load); + let mut next_value = 0.0; + for prop in self.members.iter() { + let key_str = match &prop.id { + ast::TSEnumMemberName::Identifier(ident) => ident.name.as_str(), + ast::TSEnumMemberName::String(string) => string.value.as_str(), + }; + let key = String::from_str(ctx.agent, key_str, ctx.gc); + let value: Value<'gc>; + if let Some(expr) = &prop.initializer { + expr.compile(ctx); + if is_reference(expr) { + ctx.add_instruction(Instruction::GetValue); + } + value = ctx + .current_value + .take() + .unwrap_or(Value::from_f64(ctx.agent, next_value, ctx.gc)); + + if value.is_number() { + next_value += 1.0; + } else { + next_value += 1.0; + } + } else { + value = Value::from_f64(ctx.agent, next_value, ctx.gc); + next_value += 1.0; + } + ctx.add_instruction_with_constant(Instruction::LoadConstant, key.into_value()); + ctx.add_instruction_with_constant(Instruction::StoreConstant, value); + ctx.add_instruction(Instruction::ObjectDefineProperty); + if value.is_number() { + ctx.add_instruction_with_constant(Instruction::LoadConstant, value); + ctx.add_instruction_with_constant(Instruction::StoreConstant, key.into_value()); + ctx.add_instruction(Instruction::ObjectDefineProperty); + } + } + ctx.add_instruction(Instruction::Store); + } +} + impl CompileEvaluation for ast::Statement<'_> { fn compile(&self, ctx: &mut CompileContext) { match self { @@ -2972,8 +3032,9 @@ impl CompileEvaluation for ast::Statement<'_> { Statement::TSTypeAliasDeclaration(_) | Statement::TSInterfaceDeclaration(_) => { unreachable!() } - Statement::TSEnumDeclaration(_) - | Statement::TSExportAssignment(_) + #[cfg(feature = "typescript")] + Statement::TSEnumDeclaration(x) => x.compile(ctx), + Statement::TSExportAssignment(_) | Statement::TSImportEqualsDeclaration(_) | Statement::TSModuleDeclaration(_) | Statement::TSNamespaceExportDeclaration(_) => unreachable!(),