From c95ba7b56928cc6143472a498d3f21a15d41ac81 Mon Sep 17 00:00:00 2001 From: Pure Krome Date: Thu, 18 Jan 2018 11:10:50 +1000 Subject: [PATCH 1/3] :rocket: Updated to NetStandard 2.0 / NET 4.5. --- .gitattributes | 1 + .gitignore | 22 +- .nuget/NuGet.Config | 6 - .nuget/NuGet.exe | Bin 558080 -> 0 bytes .nuget/NuGet.targets | 52 - CODE_OF_CONDUCT.md | 5 + CONTRIBUTING.md | 5 + Code/EcmaScript.NET/..svnbridge/.svnbridge | 6 - Code/EcmaScript.NET/AssemblyInfo.cs | 25 - Code/EcmaScript.NET/EcmaScript.NET.csproj | 403 - EcmaScript.NET.sln | 61 +- EcmaScript.NET.sln.DotSettings | 299 +- NuGet Packages/EcmaScript.Net.1.0.0.0.nupkg | Bin 200741 -> 0 bytes NuGet Packages/EcmaScript.Net.1.0.1.0.nupkg | Bin 200706 -> 0 bytes README.md | 27 + appveyor.yml | 61 + {Code => src}/EcmaScript.NET/Arguments.cs | 656 +- .../Attributes/EcmaScriptClassAttribute.cs | 80 +- .../Attributes/EcmaScriptFunctionAttribute.cs | 100 +- .../Attributes/EcmaScriptPropertyAccess.cs | 52 +- .../Attributes/EcmaScriptPropertyAttribute.cs | 118 +- {Code => src}/EcmaScript.NET/BaseFunction.cs | 1204 +-- .../EcmaScript.NET/Collections/ObjArray.cs | 1000 +- .../EcmaScript.NET/Collections/ObjToIntMap.cs | 950 +- .../EcmaScript.NET/Collections/UintMap.cs | 854 +- .../EcmaScript.NET/CompilerEnvirons.cs | 330 +- {Code => src}/EcmaScript.NET/Context.cs | 4026 +++---- {Code => src}/EcmaScript.NET/ContextEvents.cs | 210 +- .../EcmaScript.NET/ContextFactory.cs | 298 +- {Code => src}/EcmaScript.NET/Continuation.cs | 260 +- .../EcmaScript.NET/Debugging/DebugFrame.cs | 134 +- .../Debugging/DebuggableObject.cs | 78 +- .../Debugging/DebuggableScript.cs | 214 +- .../EcmaScript.NET/Debugging/Debugger.cs | 84 +- {Code => src}/EcmaScript.NET/Decompiler.cs | 2062 ++-- .../EcmaScript.NET/DefaultErrorReporter.cs | 146 +- {Code => src}/EcmaScript.NET/Delegator.cs | 484 +- src/EcmaScript.NET/EcmaScript.NET.csproj | 21 + .../EcmaScript.NET/EcmaScriptError.cs | 196 +- .../EcmaScript.NET/EcmaScriptException.cs | 439 +- .../EcmaScriptRuntimeException.cs | 166 +- .../EcmaScript.NET/EcmaScriptThrow.cs | 124 +- {Code => src}/EcmaScript.NET/ErrorReporter.cs | 180 +- {Code => src}/EcmaScript.NET/FunctionNode.cs | 168 +- .../EcmaScript.NET/Helpers/CliHelper.cs | 572 +- .../Helpers/StackOverflowVerifier.cs | 78 +- .../Helpers/StackOverflowVerifierException.cs | 20 +- {Code => src}/EcmaScript.NET/ICallable.cs | 76 +- {Code => src}/EcmaScript.NET/IFunction.cs | 86 +- {Code => src}/EcmaScript.NET/IIdEnumerable.cs | 54 +- .../EcmaScript.NET/IIdFunctionCall.cs | 66 +- {Code => src}/EcmaScript.NET/IRef.cs | 66 +- {Code => src}/EcmaScript.NET/IRefCallable.cs | 76 +- {Code => src}/EcmaScript.NET/IScript.cs | 92 +- {Code => src}/EcmaScript.NET/IScriptable.cs | 610 +- {Code => src}/EcmaScript.NET/IdEnumeration.cs | 288 +- .../EcmaScript.NET/IdFunctionObject.cs | 390 +- .../EcmaScript.NET/IdScriptableObject.cs | 1386 +-- .../EcmaScript.NET/InterpretedFunction.cs | 370 +- {Code => src}/EcmaScript.NET/Interpreter.cs | 9508 ++++++++--------- .../EcmaScript.NET/InterpreterData.cs | 370 +- {Code => src}/EcmaScript.NET/Node.cs | 1836 ++-- {Code => src}/EcmaScript.NET/NodeFactory.cs | 2856 ++--- .../EcmaScript.NET/NodeTransformer.cs | 688 +- {Code => src}/EcmaScript.NET/Parser.cs | 4926 ++++----- {Code => src}/EcmaScript.NET/RegExpProxy.cs | 90 +- .../EcmaScript.NET/Resources/ChangeLog | 68 +- .../EcmaScript.NET/Resources/LICENSE | 66 +- .../EcmaScript.NET/Resources/Messages.resx | 1348 +-- {Code => src}/EcmaScript.NET/Resources/TODO | 72 +- {Code => src}/EcmaScript.NET/ScriptConvert.cs | 1320 +-- .../EcmaScript.NET/ScriptOrFnNode.cs | 554 +- {Code => src}/EcmaScript.NET/ScriptRuntime.cs | 5218 ++++----- .../EcmaScript.NET/ScriptableObject.cs | 2818 ++--- .../EcmaScript.NET/SecurityController.cs | 272 +- {Code => src}/EcmaScript.NET/SpecialRef.cs | 288 +- {Code => src}/EcmaScript.NET/Token.cs | 1336 +-- {Code => src}/EcmaScript.NET/TokenStream.cs | 3818 +++---- .../EcmaScript.NET/Types/BuiltinArray.cs | 2796 ++--- .../EcmaScript.NET/Types/BuiltinBoolean.cs | 332 +- .../EcmaScript.NET/Types/BuiltinCall.cs | 276 +- .../EcmaScript.NET/Types/BuiltinDate.cs | 4038 +++---- .../EcmaScript.NET/Types/BuiltinError.cs | 434 +- .../EcmaScript.NET/Types/BuiltinFunction.cs | 216 +- .../EcmaScript.NET/Types/BuiltinGlobal.cs | 1596 +-- .../Types/BuiltinGlobalObject.cs | 298 +- .../EcmaScript.NET/Types/BuiltinMath.cs | 1202 +-- .../EcmaScript.NET/Types/BuiltinNumber.cs | 642 +- .../EcmaScript.NET/Types/BuiltinObject.cs | 730 +- .../EcmaScript.NET/Types/BuiltinScript.cs | 474 +- .../EcmaScript.NET/Types/BuiltinString.cs | 2308 ++-- .../EcmaScript.NET/Types/BuiltinWith.cs | 386 +- .../EcmaScript.NET/Types/Cli/CliArray.cs | 268 +- .../EcmaScript.NET/Types/Cli/CliEnum.cs | 48 +- .../EcmaScript.NET/Types/Cli/CliEventInfo.cs | 264 +- .../EcmaScript.NET/Types/Cli/CliMethodInfo.cs | 974 +- .../EcmaScript.NET/Types/Cli/CliObject.cs | 1816 ++-- .../EcmaScript.NET/Types/Cli/CliPackage.cs | 236 +- .../EcmaScript.NET/Types/Cli/CliType.cs | 536 +- .../EcmaScript.NET/Types/E4X/Namespace.cs | 882 +- .../EcmaScript.NET/Types/E4X/QName.cs | 872 +- {Code => src}/EcmaScript.NET/Types/E4X/XML.cs | 3774 +++---- .../EcmaScript.NET/Types/E4X/XMLCtor.cs | 598 +- .../EcmaScript.NET/Types/E4X/XMLLibImpl.cs | 732 +- .../EcmaScript.NET/Types/E4X/XMLList.cs | 2074 ++-- .../EcmaScript.NET/Types/E4X/XMLName.cs | 404 +- .../EcmaScript.NET/Types/E4X/XMLObjectImpl.cs | 332 +- .../Types/RegExp/BuiltinRegExp.cs | 5792 +++++----- .../Types/RegExp/BuiltinRegExpCtor.cs | 598 +- .../EcmaScript.NET/Types/RegExp/RegExpImpl.cs | 1034 +- .../EcmaScript.NET/Types/RegExp/SubString.cs | 104 +- {Code => src}/EcmaScript.NET/Undefined.cs | 66 +- {Code => src}/EcmaScript.NET/UniqueTag.cs | 126 +- {Code => src}/EcmaScript.NET/Wrapper.cs | 68 +- 114 files changed, 47055 insertions(+), 47560 deletions(-) create mode 100644 .gitattributes delete mode 100644 .nuget/NuGet.Config delete mode 100644 .nuget/NuGet.exe delete mode 100644 .nuget/NuGet.targets create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md delete mode 100644 Code/EcmaScript.NET/..svnbridge/.svnbridge delete mode 100644 Code/EcmaScript.NET/AssemblyInfo.cs delete mode 100644 Code/EcmaScript.NET/EcmaScript.NET.csproj delete mode 100644 NuGet Packages/EcmaScript.Net.1.0.0.0.nupkg delete mode 100644 NuGet Packages/EcmaScript.Net.1.0.1.0.nupkg create mode 100644 README.md create mode 100644 appveyor.yml rename {Code => src}/EcmaScript.NET/Arguments.cs (96%) rename {Code => src}/EcmaScript.NET/Attributes/EcmaScriptClassAttribute.cs (96%) rename {Code => src}/EcmaScript.NET/Attributes/EcmaScriptFunctionAttribute.cs (96%) rename {Code => src}/EcmaScript.NET/Attributes/EcmaScriptPropertyAccess.cs (96%) rename {Code => src}/EcmaScript.NET/Attributes/EcmaScriptPropertyAttribute.cs (96%) rename {Code => src}/EcmaScript.NET/BaseFunction.cs (96%) rename {Code => src}/EcmaScript.NET/Collections/ObjArray.cs (94%) rename {Code => src}/EcmaScript.NET/Collections/ObjToIntMap.cs (97%) rename {Code => src}/EcmaScript.NET/Collections/UintMap.cs (97%) rename {Code => src}/EcmaScript.NET/CompilerEnvirons.cs (96%) rename {Code => src}/EcmaScript.NET/Context.cs (96%) rename {Code => src}/EcmaScript.NET/ContextEvents.cs (95%) rename {Code => src}/EcmaScript.NET/ContextFactory.cs (95%) rename {Code => src}/EcmaScript.NET/Continuation.cs (96%) rename {Code => src}/EcmaScript.NET/Debugging/DebugFrame.cs (97%) rename {Code => src}/EcmaScript.NET/Debugging/DebuggableObject.cs (97%) rename {Code => src}/EcmaScript.NET/Debugging/DebuggableScript.cs (96%) rename {Code => src}/EcmaScript.NET/Debugging/Debugger.cs (97%) rename {Code => src}/EcmaScript.NET/Decompiler.cs (96%) rename {Code => src}/EcmaScript.NET/DefaultErrorReporter.cs (97%) rename {Code => src}/EcmaScript.NET/Delegator.cs (96%) create mode 100644 src/EcmaScript.NET/EcmaScript.NET.csproj rename {Code => src}/EcmaScript.NET/EcmaScriptError.cs (97%) rename {Code => src}/EcmaScript.NET/EcmaScriptException.cs (94%) rename {Code => src}/EcmaScript.NET/EcmaScriptRuntimeException.cs (97%) rename {Code => src}/EcmaScript.NET/EcmaScriptThrow.cs (96%) rename {Code => src}/EcmaScript.NET/ErrorReporter.cs (97%) rename {Code => src}/EcmaScript.NET/FunctionNode.cs (96%) rename {Code => src}/EcmaScript.NET/Helpers/CliHelper.cs (96%) rename {Code => src}/EcmaScript.NET/Helpers/StackOverflowVerifier.cs (95%) rename {Code => src}/EcmaScript.NET/Helpers/StackOverflowVerifierException.cs (64%) rename {Code => src}/EcmaScript.NET/ICallable.cs (97%) rename {Code => src}/EcmaScript.NET/IFunction.cs (97%) rename {Code => src}/EcmaScript.NET/IIdEnumerable.cs (96%) rename {Code => src}/EcmaScript.NET/IIdFunctionCall.cs (97%) rename {Code => src}/EcmaScript.NET/IRef.cs (96%) rename {Code => src}/EcmaScript.NET/IRefCallable.cs (97%) rename {Code => src}/EcmaScript.NET/IScript.cs (97%) rename {Code => src}/EcmaScript.NET/IScriptable.cs (97%) rename {Code => src}/EcmaScript.NET/IdEnumeration.cs (96%) rename {Code => src}/EcmaScript.NET/IdFunctionObject.cs (94%) rename {Code => src}/EcmaScript.NET/IdScriptableObject.cs (94%) rename {Code => src}/EcmaScript.NET/InterpretedFunction.cs (96%) rename {Code => src}/EcmaScript.NET/Interpreter.cs (97%) rename {Code => src}/EcmaScript.NET/InterpreterData.cs (96%) rename {Code => src}/EcmaScript.NET/Node.cs (96%) rename {Code => src}/EcmaScript.NET/NodeFactory.cs (97%) rename {Code => src}/EcmaScript.NET/NodeTransformer.cs (97%) rename {Code => src}/EcmaScript.NET/Parser.cs (97%) rename {Code => src}/EcmaScript.NET/RegExpProxy.cs (96%) rename {Code => src}/EcmaScript.NET/Resources/ChangeLog (97%) rename {Code => src}/EcmaScript.NET/Resources/LICENSE (97%) rename {Code => src}/EcmaScript.NET/Resources/Messages.resx (97%) rename {Code => src}/EcmaScript.NET/Resources/TODO (96%) rename {Code => src}/EcmaScript.NET/ScriptConvert.cs (97%) rename {Code => src}/EcmaScript.NET/ScriptOrFnNode.cs (95%) rename {Code => src}/EcmaScript.NET/ScriptRuntime.cs (96%) rename {Code => src}/EcmaScript.NET/ScriptableObject.cs (97%) rename {Code => src}/EcmaScript.NET/SecurityController.cs (97%) rename {Code => src}/EcmaScript.NET/SpecialRef.cs (96%) rename {Code => src}/EcmaScript.NET/Token.cs (96%) rename {Code => src}/EcmaScript.NET/TokenStream.cs (97%) rename {Code => src}/EcmaScript.NET/Types/BuiltinArray.cs (97%) rename {Code => src}/EcmaScript.NET/Types/BuiltinBoolean.cs (96%) rename {Code => src}/EcmaScript.NET/Types/BuiltinCall.cs (96%) rename {Code => src}/EcmaScript.NET/Types/BuiltinDate.cs (97%) rename {Code => src}/EcmaScript.NET/Types/BuiltinError.cs (97%) rename {Code => src}/EcmaScript.NET/Types/BuiltinFunction.cs (97%) rename {Code => src}/EcmaScript.NET/Types/BuiltinGlobal.cs (97%) rename {Code => src}/EcmaScript.NET/Types/BuiltinGlobalObject.cs (97%) rename {Code => src}/EcmaScript.NET/Types/BuiltinMath.cs (96%) rename {Code => src}/EcmaScript.NET/Types/BuiltinNumber.cs (97%) rename {Code => src}/EcmaScript.NET/Types/BuiltinObject.cs (97%) rename {Code => src}/EcmaScript.NET/Types/BuiltinScript.cs (96%) rename {Code => src}/EcmaScript.NET/Types/BuiltinString.cs (97%) rename {Code => src}/EcmaScript.NET/Types/BuiltinWith.cs (96%) rename {Code => src}/EcmaScript.NET/Types/Cli/CliArray.cs (95%) rename {Code => src}/EcmaScript.NET/Types/Cli/CliEnum.cs (94%) rename {Code => src}/EcmaScript.NET/Types/Cli/CliEventInfo.cs (94%) rename {Code => src}/EcmaScript.NET/Types/Cli/CliMethodInfo.cs (97%) rename {Code => src}/EcmaScript.NET/Types/Cli/CliObject.cs (97%) rename {Code => src}/EcmaScript.NET/Types/Cli/CliPackage.cs (96%) rename {Code => src}/EcmaScript.NET/Types/Cli/CliType.cs (96%) rename {Code => src}/EcmaScript.NET/Types/E4X/Namespace.cs (96%) rename {Code => src}/EcmaScript.NET/Types/E4X/QName.cs (96%) rename {Code => src}/EcmaScript.NET/Types/E4X/XML.cs (97%) rename {Code => src}/EcmaScript.NET/Types/E4X/XMLCtor.cs (97%) rename {Code => src}/EcmaScript.NET/Types/E4X/XMLLibImpl.cs (96%) rename {Code => src}/EcmaScript.NET/Types/E4X/XMLList.cs (97%) rename {Code => src}/EcmaScript.NET/Types/E4X/XMLName.cs (96%) rename {Code => src}/EcmaScript.NET/Types/E4X/XMLObjectImpl.cs (97%) rename {Code => src}/EcmaScript.NET/Types/RegExp/BuiltinRegExp.cs (97%) rename {Code => src}/EcmaScript.NET/Types/RegExp/BuiltinRegExpCtor.cs (96%) rename {Code => src}/EcmaScript.NET/Types/RegExp/RegExpImpl.cs (97%) rename {Code => src}/EcmaScript.NET/Types/RegExp/SubString.cs (96%) rename {Code => src}/EcmaScript.NET/Undefined.cs (96%) rename {Code => src}/EcmaScript.NET/UniqueTag.cs (97%) rename {Code => src}/EcmaScript.NET/Wrapper.cs (96%) diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..5378fe0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* -text \ No newline at end of file diff --git a/.gitignore b/.gitignore index e6008d0..2345128 100644 --- a/.gitignore +++ b/.gitignore @@ -18,19 +18,25 @@ *.lib *.sbr *.scc -[Bb]in/ -[Dd]ebug/ +[Bb]in +[Dd]ebug*/ obj/ -[Rr]elease/ +[Rr]elease*/ _ReSharper*/ -[Tt]humbs.db -[Tt]est[Rr]esult* -[Bb]uild[Ll]og.* *.[Pp]ublish.xml *.resharper* AppData/ +App_Data/ *.log.* [Ll]ogs/ -[Dd]ata/ [Pp]ackages/ -[Dd]atabase/ \ No newline at end of file +[Tt]humbs.db +[Tt]est[Rr]esult* +[Bb]uild[Ll]og.* +*.sln.DotSettings.* +*.ncrunchproject +*.ncrunchsolution +*.nupkg +.vs +.vscode +*.orig \ No newline at end of file diff --git a/.nuget/NuGet.Config b/.nuget/NuGet.Config deleted file mode 100644 index 67f8ea0..0000000 --- a/.nuget/NuGet.Config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.nuget/NuGet.exe b/.nuget/NuGet.exe deleted file mode 100644 index 34ad49b494dd855dabf1b1cee5d3a8d51525d3b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 558080 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%0A|w=%&@u7j7;}<-)k0>bYB`T-B(A&wRHbW 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

Ekj^+5jehgt4{Op!7wB|J;~=-=l2?c3i{CT#0( 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 z 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 G=zjnx2wiCa diff --git a/.nuget/NuGet.targets b/.nuget/NuGet.targets deleted file mode 100644 index 25380fe..0000000 --- a/.nuget/NuGet.targets +++ /dev/null @@ -1,52 +0,0 @@ - - - - $(MSBuildProjectDirectory)\..\ - $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) - $(NuGetToolsPath)\nuget.exe - $([System.IO.Path]::Combine($(ProjectDir), "packages.config")) - $([System.IO.Path]::Combine($(SolutionDir), "packages")) - $(TargetDir.Trim('\\')) - - - "" - - - false - - - false - - - "$(NuGetExePath)" install "$(PackagesConfig)" -source $(PackageSources) -o "$(PackagesDir)" - "$(NuGetExePath)" pack "$(ProjectPath)" -p Configuration=$(Configuration) -o "$(PackageOutputDir)" -symbols - - - - RestorePackages; - $(BuildDependsOn); - - - - - $(BuildDependsOn); - BuildPackage; - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..889e5c1 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,5 @@ +# Contributor Covenant Code of Conduct + +Please refer to the [code of conduct](https://github.com/OpenRealEstate/OpenRealEstate/blob/master/CODE_OF_CONDUCT.md) document that applies to all repositories in the OpenRealEstate organisation. + +--- \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..566383e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,5 @@ +# Contributing + +Please refer to the [contributing](https://github.com/OpenRealEstate/OpenRealEstate/blob/master/CONTRIBUTING.md) document that applies to all repositories in the OpenRealEstate organisation. + +--- \ No newline at end of file diff --git a/Code/EcmaScript.NET/..svnbridge/.svnbridge b/Code/EcmaScript.NET/..svnbridge/.svnbridge deleted file mode 100644 index a580b9e..0000000 --- a/Code/EcmaScript.NET/..svnbridge/.svnbridge +++ /dev/null @@ -1,6 +0,0 @@ -svn:ignorebin -obj -svn:ignorebin -obj -*.user - \ No newline at end of file diff --git a/Code/EcmaScript.NET/AssemblyInfo.cs b/Code/EcmaScript.NET/AssemblyInfo.cs deleted file mode 100644 index 546c972..0000000 --- a/Code/EcmaScript.NET/AssemblyInfo.cs +++ /dev/null @@ -1,25 +0,0 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ -using System; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Security; - -[assembly: AssemblyTitle("EcmaScript.NET")] -[assembly: AssemblyVersion("1.0.1.0")] - -[assembly: AssemblyDescriptionAttribute("Modified version of the EcmaScript.NET assembly.")] - -[assembly: CLSCompliant(true)] -[assembly: AllowPartiallyTrustedCallers] -[assembly: AssemblyFileVersionAttribute("1.0.1.0")] diff --git a/Code/EcmaScript.NET/EcmaScript.NET.csproj b/Code/EcmaScript.NET/EcmaScript.NET.csproj deleted file mode 100644 index 4a8e1b8..0000000 --- a/Code/EcmaScript.NET/EcmaScript.NET.csproj +++ /dev/null @@ -1,403 +0,0 @@ - - - - Local - 9.0.30729 - 2.0 - {ED3DF8AE-9541-4C95-93C5-8C417D4CBA50} - Debug - AnyCPU - - - - - EcmaScript.NET - - - JScript - Grid - IE50 - false - Library - EcmaScript.NET - OnBuildSuccess - - - - - - - - - - - - - - - true - 3.5 - false - v2.0 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - true - - ..\..\..\YUICompressor\ - true - - - bin\Debug\ - false - 285212672 - false - - - - - - - true - 4096 - false - 0162;0164;0675 - true - false - false - false - 4 - full - prompt - AllRules.ruleset - - - bin\Release\ - false - 4194304 - false - - - TRACE - - - false - 512 - false - - - true - false - false - false - 4 - none - prompt - AllRules.ruleset - - - - mscorlib - - - System - - - - - - - Code - - - - - - - Code - - - - - - - Code - - - Code - - - - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - - - - - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - - - - - Code - - - Code - - - Code - - - Designer - - - - - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 2.0 %28x86%29 - true - - - False - .NET Framework 3.0 %28x86%29 - false - - - False - .NET Framework 3.5 - false - - - False - .NET Framework 3.5 SP1 - false - - - - - - - - - - - \ No newline at end of file diff --git a/EcmaScript.NET.sln b/EcmaScript.NET.sln index f6e8362..470a86d 100644 --- a/EcmaScript.NET.sln +++ b/EcmaScript.NET.sln @@ -1,36 +1,25 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EcmaScript.NET", "Code\EcmaScript.NET\EcmaScript.NET.csproj", "{ED3DF8AE-9541-4C95-93C5-8C417D4CBA50}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{A2C19DA0-637F-462F-B950-53F7FE2F725C}" - ProjectSection(SolutionItems) = preProject - .nuget\NuGet.exe = .nuget\NuGet.exe - .nuget\NuGet.targets = .nuget\NuGet.targets - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|Mixed Platforms = Debug|Mixed Platforms - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|Mixed Platforms = Release|Mixed Platforms - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {ED3DF8AE-9541-4C95-93C5-8C417D4CBA50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ED3DF8AE-9541-4C95-93C5-8C417D4CBA50}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ED3DF8AE-9541-4C95-93C5-8C417D4CBA50}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {ED3DF8AE-9541-4C95-93C5-8C417D4CBA50}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {ED3DF8AE-9541-4C95-93C5-8C417D4CBA50}.Debug|x86.ActiveCfg = Debug|Any CPU - {ED3DF8AE-9541-4C95-93C5-8C417D4CBA50}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ED3DF8AE-9541-4C95-93C5-8C417D4CBA50}.Release|Any CPU.Build.0 = Release|Any CPU - {ED3DF8AE-9541-4C95-93C5-8C417D4CBA50}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {ED3DF8AE-9541-4C95-93C5-8C417D4CBA50}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {ED3DF8AE-9541-4C95-93C5-8C417D4CBA50}.Release|x86.ActiveCfg = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2024 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EcmaScript.NET", "src\EcmaScript.NET\EcmaScript.NET.csproj", "{93F6B750-891E-4E71-925A-5B40619BB3E2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {93F6B750-891E-4E71-925A-5B40619BB3E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {93F6B750-891E-4E71-925A-5B40619BB3E2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {93F6B750-891E-4E71-925A-5B40619BB3E2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {93F6B750-891E-4E71-925A-5B40619BB3E2}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {80F0CE8A-6E72-4246-A0F0-1D9C91E91DFD} + EndGlobalSection +EndGlobal diff --git a/EcmaScript.NET.sln.DotSettings b/EcmaScript.NET.sln.DotSettings index 9ce3616..1e2b3e6 100644 --- a/EcmaScript.NET.sln.DotSettings +++ b/EcmaScript.NET.sln.DotSettings @@ -1,226 +1,99 @@  + True + True + ERROR + ERROR + ERROR + ERROR + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + ERROR + ERROR + ERROR + <?xml version="1.0" encoding="utf-16"?><Profile name="PK Code Cleanup"><AspOptimizeRegisterDirectives>True</AspOptimizeRegisterDirectives><HtmlReformatCode>True</HtmlReformatCode><CSArrangeThisQualifier>True</CSArrangeThisQualifier><CSRemoveCodeRedundancies>True</CSRemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><CSReorderTypeMembers>True</CSReorderTypeMembers><VBOptimizeImports>True</VBOptimizeImports><VBShortenReferences>True</VBShortenReferences><VBReformatCode>True</VBReformatCode><JsReformatCode>True</JsReformatCode><JsInsertSemicolon>True</JsInsertSemicolon><CssAlphabetizeProperties>True</CssAlphabetizeProperties><CssReformatCode>True</CssReformatCode><XMLReformatCode>True</XMLReformatCode><StyleCop.Documentation><SA1600ElementsMustBeDocumented>False</SA1600ElementsMustBeDocumented><SA1604ElementDocumentationMustHaveSummary>False</SA1604ElementDocumentationMustHaveSummary><SA1609PropertyDocumentationMustHaveValueDocumented>False</SA1609PropertyDocumentationMustHaveValueDocumented><SA1611ElementParametersMustBeDocumented>False</SA1611ElementParametersMustBeDocumented><SA1615ElementReturnValueMustBeDocumented>False</SA1615ElementReturnValueMustBeDocumented><SA1617VoidReturnValueMustNotBeDocumented>False</SA1617VoidReturnValueMustNotBeDocumented><SA1618GenericTypeParametersMustBeDocumented>False</SA1618GenericTypeParametersMustBeDocumented><SA1626SingleLineCommentsMustNotUseDocumentationStyleSlashes>True</SA1626SingleLineCommentsMustNotUseDocumentationStyleSlashes><SA1628DocumentationTextMustBeginWithACapitalLetter>True</SA1628DocumentationTextMustBeginWithACapitalLetter><SA1629DocumentationTextMustEndWithAPeriod>True</SA1629DocumentationTextMustEndWithAPeriod><SA1633SA1641UpdateFileHeader>Ignore</SA1633SA1641UpdateFileHeader><SA1639FileHeaderMustHaveSummary>False</SA1639FileHeaderMustHaveSummary><SA1642ConstructorSummaryDocumentationMustBeginWithStandardText>False</SA1642ConstructorSummaryDocumentationMustBeginWithStandardText><SA1643DestructorSummaryDocumentationMustBeginWithStandardText>False</SA1643DestructorSummaryDocumentationMustBeginWithStandardText><SA1644DocumentationHeadersMustNotContainBlankLines>False</SA1644DocumentationHeadersMustNotContainBlankLines></StyleCop.Documentation></Profile> + PK Code Cleanup + public protected internal private new abstract virtual sealed override static readonly extern unsafe volatile async + True + True + True + True + True + True + True + True NEXT_LINE + 0 NEXT_LINE + MULTILINE + True + ALWAYS_ADD NEXT_LINE - <?xml version="1.0" encoding="utf-8" ?> - -<!-- -I. Overall - -I.1 Each pattern can have <Match>....</Match> element. For the given type declaration, the pattern with the match, evaluated to 'true' with the largest weight, will be used -I.2 Each pattern consists of the sequence of <Entry>...</Entry> elements. Type member declarations are distributed between entries -I.3 If pattern has RemoveAllRegions="true" attribute, then all regions will be cleared prior to reordering. Otherwise, only auto-generated regions will be cleared -I.4 The contents of each entry is sorted by given keys (First key is primary, next key is secondary, etc). Then the declarations are grouped and en-regioned by given property - -II. Available match operands - -Each operand may have Weight="..." attribute. This weight will be added to the match weight if the operand is evaluated to 'true'. -The default weight is 1 - -II.1 Boolean functions: -II.1.1 <And>....</And> -II.1.2 <Or>....</Or> -II.1.3 <Not>....</Not> - -II.2 Operands -II.2.1 <Kind Is="..."/>. Kinds are: class, struct, interface, enum, delegate, type, constructor, destructor, property, indexer, method, operator, field, constant, event, member -II.2.2 <Name Is="..." [IgnoreCase="true/false"] />. The 'Is' attribute contains regular expression -II.2.3 <HasAttribute CLRName="..." [Inherit="true/false"] />. The 'CLRName' attribute contains regular expression -II.2.4 <Access Is="..."/>. The 'Is' values are: public, protected, internal, protected internal, private -II.2.5 <Static/> -II.2.6 <Abstract/> -II.2.7 <Virtual/> -II.2.8 <Override/> -II.2.9 <Sealed/> -II.2.10 <Readonly/> -II.2.11 <ImplementsInterface CLRName="..."/>. The 'CLRName' attribute contains regular expression -II.2.12 <HandlesEvent /> ---> - -<Patterns xmlns="urn:shemas-jetbrains-com:member-reordering-patterns"> - - <!--Do not reorder COM interfaces and structs marked by StructLayout attribute--> - <Pattern> - <Match> - <Or Weight="100"> - <And> - <Kind Is="interface"/> - <Or> - <HasAttribute CLRName="System.Runtime.InteropServices.InterfaceTypeAttribute"/> - <HasAttribute CLRName="System.Runtime.InteropServices.ComImport"/> - </Or> - </And> - <HasAttribute CLRName="System.Runtime.InteropServices.StructLayoutAttribute"/> - </Or> - </Match> - </Pattern> - - <!--Special formatting of NUnit test fixture--> - <Pattern RemoveAllRegions="true"> - <Match> - <And Weight="100"> - <Kind Is="class"/> - <HasAttribute CLRName="NUnit.Framework.TestFixtureAttribute" Inherit="true"/> - </And> - </Match> - - <!--Setup/Teardow--> - <Entry> - <Match> - <And> - <Kind Is="method"/> - <Or> - <HasAttribute CLRName="NUnit.Framework.SetUpAttribute" Inherit="true"/> - <HasAttribute CLRName="NUnit.Framework.TearDownAttribute" Inherit="true"/> - <HasAttribute CLRName="NUnit.Framework.FixtureSetUpAttribute" Inherit="true"/> - <HasAttribute CLRName="NUnit.Framework.FixtureTearDownAttribute" Inherit="true"/> - </Or> - </And> - </Match> - <Group Region="Setup/Teardown"/> - </Entry> - - <!--All other members--> - <Entry/> - - <!--Test methods--> - <Entry> - <Match> - <And Weight="100"> - <Kind Is="method"/> - <HasAttribute CLRName="NUnit.Framework.TestAttribute" Inherit="false"/> - </And> - </Match> - <Sort> - <Name/> - </Sort> - </Entry> - </Pattern> - - <!--Default pattern--> - <Pattern> - - <!--public delegate--> - <Entry> - <Match> - <And Weight="100"> - <Access Is="public"/> - <Kind Is="delegate"/> - </And> - </Match> - <Sort> - <Name/> - </Sort> - <Group Region="Delegates"/> - </Entry> - - <!--public enum--> - <Entry> - <Match> - <And Weight="100"> - <Access Is="public"/> - <Kind Is="enum"/> - </And> - </Match> - <Sort> - <Name/> - </Sort> - <Group> - <Name Region="${Name} enum"/> - </Group> - </Entry> - - <!--static fields and constants--> - <Entry> - <Match> - <Or> - <Kind Is="constant"/> - <And> - <Kind Is="field"/> - <Static/> - </And> - </Or> - </Match> - <Sort> - <Kind Order="constant field"/> - </Sort> - </Entry> - - <!--instance fields--> - <Entry> - <Match> - <And> - <Kind Is="field"/> - <Not> - <Static/> - </Not> - </And> - </Match> - <Sort> - <Readonly/> - <Name/> - </Sort> - </Entry> - - <!--Constructors. Place static one first--> - <Entry> - <Match> - <Kind Is="constructor"/> - </Match> - <Sort> - <Static/> - </Sort> - </Entry> - - <!--properties, indexers--> - <Entry> - <Match> - <Or> - <Kind Is="property"/> - <Kind Is="indexer"/> - </Or> - </Match> - </Entry> - - <!--interface implementations--> - <Entry> - <Match> - <And Weight="100"> - <Kind Is="member"/> - <ImplementsInterface/> - </And> - </Match> - <Sort> - <ImplementsInterface Immediate="true"/> - </Sort> - <Group> - <ImplementsInterface Immediate="true" Region="${ImplementsInterface} Members"/> - </Group> - </Entry> - - <!--all other members--> - <Entry/> - - <!--nested types--> - <Entry> - <Match> - <Kind Is="type"/> - </Match> - <Sort> - <Name/> - </Sort> - </Entry> - </Pattern> - -</Patterns> - + NEXT_LINE + True + NEXT_LINE + NEVER + NEVER + DO_NOT_USE + LINE_BREAK + False + NEXT_LINE + False + CHOP_IF_LONG + CHOP_ALWAYS + True + CHOP_IF_LONG + CHOP_ALWAYS + 160 + True + CHOP_ALWAYS + CHOP_ALWAYS + CHOP_ALWAYS + CHOP_ALWAYS + PBKDF + <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> + TEMP_FOLDER + TEMP_FOLDER + + + + + + + True + + + + + + + True + 3 + True + True + True + True + True + True + True + True + True + + + + + True + True True True + False False True 4 False None - False \ No newline at end of file + False + <data /> + <data><IncludeFilters /><ExcludeFilters /></data> diff --git a/NuGet Packages/EcmaScript.Net.1.0.0.0.nupkg b/NuGet Packages/EcmaScript.Net.1.0.0.0.nupkg deleted file mode 100644 index db25f29665473d29ddda4c46ba79a739548211c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 200741 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 z z-mBE6*U*Ul!M1Co625WN4XwvhU!yG0gVa

%F&7*rI@6yZF^ckUw&EnLNVs$18g2W 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 diff --git a/NuGet Packages/EcmaScript.Net.1.0.1.0.nupkg b/NuGet Packages/EcmaScript.Net.1.0.1.0.nupkg deleted file mode 100644 index 26011398076c6e96534a816aad71c386fe5c1bd5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 200706 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

xAE_S2&sCB8GDWvJ@hZkxo~f+w|P0n$jA!Zq#I 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 **\packages.config \ No newline at end of file diff --git a/Code/EcmaScript.NET/Arguments.cs b/src/EcmaScript.NET/Arguments.cs similarity index 96% rename from Code/EcmaScript.NET/Arguments.cs rename to src/EcmaScript.NET/Arguments.cs index 2205814..3c577ba 100644 --- a/Code/EcmaScript.NET/Arguments.cs +++ b/src/EcmaScript.NET/Arguments.cs @@ -1,328 +1,328 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -using EcmaScript.NET.Types; - -namespace EcmaScript.NET -{ - - - ///

This class implements the "arguments" object. - /// - /// See ECMA 10.1.8 - /// - /// - sealed class Arguments : IdScriptableObject - { - override public string ClassName - { - get - { - return "Arguments"; - } - - } - override protected internal int MaxInstanceId - { - get - { - return MAX_INSTANCE_ID; - } - - } - - - public Arguments (BuiltinCall activation) - { - this.activation = activation; - - IScriptable parent = activation.ParentScope; - ParentScope = parent; - SetPrototype (ScriptableObject.GetObjectPrototype (parent)); - - args = activation.originalArgs; - lengthObj = (int)args.Length; - - BuiltinFunction f = activation.function; - calleeObj = f; - - Context.Versions version = f.LanguageVersion; - if (version <= Context.Versions.JS1_3 && version != Context.Versions.Default) { - callerObj = null; - } - else { - callerObj = UniqueTag.NotFound; - } - } - - public override bool Has (int index, IScriptable start) - { - if (0 <= index && index < args.Length) { - if (args [index] != UniqueTag.NotFound) { - return true; - } - } - return base.Has (index, start); - } - - public override object Get (int index, IScriptable start) - { - if (0 <= index && index < args.Length) { - object value = args [index]; - if (value != UniqueTag.NotFound) { - if (sharedWithActivation (index)) { - BuiltinFunction f = activation.function; - string argName = f.getParamOrVarName (index); - value = activation.Get (argName, activation); - if (value == UniqueTag.NotFound) - Context.CodeBug (); - } - return value; - } - } - return base.Get (index, start); - } - - private bool sharedWithActivation (int index) - { - BuiltinFunction f = activation.function; - int definedCount = f.ParamCount; - if (index < definedCount) { - // Check if argument is not hidden by later argument with the same - // name as hidden arguments are not shared with activation - if (index < definedCount - 1) { - string argName = f.getParamOrVarName (index); - for (int i = index + 1; i < definedCount; i++) { - if (argName.Equals (f.getParamOrVarName (i))) { - return false; - } - } - } - return true; - } - return false; - } - - public override object Put (int index, IScriptable start, object value) - { - if (0 <= index && index < args.Length) { - if (args [index] != UniqueTag.NotFound) { - if (sharedWithActivation (index)) { - string argName; - argName = activation.function.getParamOrVarName (index); - return activation.Put (argName, activation, value); - } - lock (this) { - if (args [index] != UniqueTag.NotFound) { - if (args == activation.originalArgs) { - args = new object [args.Length]; - args.CopyTo (args, 0); - } - args [index] = value; - return value; - } - } - } - } - return base.Put (index, start, value); - } - - public override void Delete (int index) - { - if (0 <= index && index < args.Length) { - lock (this) { - if (args [index] != UniqueTag.NotFound) { - if (args == activation.originalArgs) { - args = new object [args.Length]; - args.CopyTo (args, 0); - } - args [index] = UniqueTag.NotFound; - return; - } - } - } - base.Delete (index); - } - - #region InstanceIds - private const int Id_callee = 1; - private const int Id_length = 2; - private const int Id_caller = 3; - private const int MAX_INSTANCE_ID = 3; - #endregion - - protected internal override int FindInstanceIdInfo (string s) - { - int id; - #region Generated InstanceId Switch - L0: { - id = 0; - string X = null; - int c; - if (s.Length == 6) { - c = s [5]; - if (c == 'e') { X = "callee"; id = Id_callee; } - else if (c == 'h') { X = "length"; id = Id_length; } - else if (c == 'r') { X = "caller"; id = Id_caller; } - } - if (X != null && X != s && !X.Equals (s)) - id = 0; - } - EL0: - #endregion - - if (id == 0) - return base.FindInstanceIdInfo (s); - - int attr; - switch (id) { - - case Id_callee: - case Id_caller: - case Id_length: - attr = DONTENUM; - break; - - default: - throw new ApplicationException (); - - } - return InstanceIdInfo (attr, id); - } - - // #/string_id_map# - - protected internal override string GetInstanceIdName (int id) - { - switch (id) { - - case Id_callee: - return "callee"; - - case Id_length: - return "length"; - - case Id_caller: - return "caller"; - } - return null; - } - - protected internal override object GetInstanceIdValue (int id) - { - switch (id) { - - case Id_callee: - return calleeObj; - - case Id_length: - return lengthObj; - - case Id_caller: { - object value = callerObj; - if (value == UniqueTag.NullValue) { - value = null; - } - else if (value == null) { - BuiltinCall caller = activation.parentActivationCall; - if (caller != null) { - value = caller.Get ("arguments", caller); - } - else { - value = null; - } - } - return value; - } - } - return base.GetInstanceIdValue (id); - } - - protected internal override void SetInstanceIdValue (int id, object value) - { - switch (id) { - - case Id_callee: - calleeObj = value; - return; - - case Id_length: - lengthObj = value; - return; - - case Id_caller: - callerObj = (value != null) ? value : UniqueTag.NullValue; - return; - } - base.SetInstanceIdValue (id, value); - } - - internal override object [] GetIds (bool getAll) - { - object [] ids = base.GetIds (getAll); - if (getAll && args.Length != 0) { - bool [] present = null; - int extraCount = args.Length; - for (int i = 0; i != ids.Length; ++i) { - object id = ids [i]; - if (id is int) { - int index = ((int)id); - if (0 <= index && index < args.Length) { - if (present == null) { - present = new bool [args.Length]; - } - if (!present [index]) { - present [index] = true; - extraCount--; - } - } - } - } - if (extraCount != 0) { - object [] tmp = new object [extraCount + ids.Length]; - Array.Copy (ids, 0, tmp, extraCount, ids.Length); - ids = tmp; - int offset = 0; - for (int i = 0; i != args.Length; ++i) { - if (present == null || !present [i]) { - ids [offset] = (int)i; - ++offset; - } - } - if (offset != extraCount) - Context.CodeBug (); - } - } - return ids; - } - - // Fields to hold caller, callee and length properties, - // where NOT_FOUND value tags deleted properties. - // In addition if callerObj == NullValue, it tags null for scripts, as - // initial callerObj == null means access to caller arguments available - // only in JS <= 1.3 scripts - private object callerObj; - private object calleeObj; - private object lengthObj; - - private BuiltinCall activation; - - // Initially args holds activation.getOriginalArgs(), but any modification - // of its elements triggers creation of a copy. If its element holds NOT_FOUND, - // it indicates deleted index, in which case super class is queried. - private object [] args; - - } -} +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +using EcmaScript.NET.Types; + +namespace EcmaScript.NET +{ + + + /// This class implements the "arguments" object. + /// + /// See ECMA 10.1.8 + /// + /// + sealed class Arguments : IdScriptableObject + { + override public string ClassName + { + get + { + return "Arguments"; + } + + } + override protected internal int MaxInstanceId + { + get + { + return MAX_INSTANCE_ID; + } + + } + + + public Arguments (BuiltinCall activation) + { + this.activation = activation; + + IScriptable parent = activation.ParentScope; + ParentScope = parent; + SetPrototype (ScriptableObject.GetObjectPrototype (parent)); + + args = activation.originalArgs; + lengthObj = (int)args.Length; + + BuiltinFunction f = activation.function; + calleeObj = f; + + Context.Versions version = f.LanguageVersion; + if (version <= Context.Versions.JS1_3 && version != Context.Versions.Default) { + callerObj = null; + } + else { + callerObj = UniqueTag.NotFound; + } + } + + public override bool Has (int index, IScriptable start) + { + if (0 <= index && index < args.Length) { + if (args [index] != UniqueTag.NotFound) { + return true; + } + } + return base.Has (index, start); + } + + public override object Get (int index, IScriptable start) + { + if (0 <= index && index < args.Length) { + object value = args [index]; + if (value != UniqueTag.NotFound) { + if (sharedWithActivation (index)) { + BuiltinFunction f = activation.function; + string argName = f.getParamOrVarName (index); + value = activation.Get (argName, activation); + if (value == UniqueTag.NotFound) + Context.CodeBug (); + } + return value; + } + } + return base.Get (index, start); + } + + private bool sharedWithActivation (int index) + { + BuiltinFunction f = activation.function; + int definedCount = f.ParamCount; + if (index < definedCount) { + // Check if argument is not hidden by later argument with the same + // name as hidden arguments are not shared with activation + if (index < definedCount - 1) { + string argName = f.getParamOrVarName (index); + for (int i = index + 1; i < definedCount; i++) { + if (argName.Equals (f.getParamOrVarName (i))) { + return false; + } + } + } + return true; + } + return false; + } + + public override object Put (int index, IScriptable start, object value) + { + if (0 <= index && index < args.Length) { + if (args [index] != UniqueTag.NotFound) { + if (sharedWithActivation (index)) { + string argName; + argName = activation.function.getParamOrVarName (index); + return activation.Put (argName, activation, value); + } + lock (this) { + if (args [index] != UniqueTag.NotFound) { + if (args == activation.originalArgs) { + args = new object [args.Length]; + args.CopyTo (args, 0); + } + args [index] = value; + return value; + } + } + } + } + return base.Put (index, start, value); + } + + public override void Delete (int index) + { + if (0 <= index && index < args.Length) { + lock (this) { + if (args [index] != UniqueTag.NotFound) { + if (args == activation.originalArgs) { + args = new object [args.Length]; + args.CopyTo (args, 0); + } + args [index] = UniqueTag.NotFound; + return; + } + } + } + base.Delete (index); + } + + #region InstanceIds + private const int Id_callee = 1; + private const int Id_length = 2; + private const int Id_caller = 3; + private const int MAX_INSTANCE_ID = 3; + #endregion + + protected internal override int FindInstanceIdInfo (string s) + { + int id; + #region Generated InstanceId Switch + L0: { + id = 0; + string X = null; + int c; + if (s.Length == 6) { + c = s [5]; + if (c == 'e') { X = "callee"; id = Id_callee; } + else if (c == 'h') { X = "length"; id = Id_length; } + else if (c == 'r') { X = "caller"; id = Id_caller; } + } + if (X != null && X != s && !X.Equals (s)) + id = 0; + } + EL0: + #endregion + + if (id == 0) + return base.FindInstanceIdInfo (s); + + int attr; + switch (id) { + + case Id_callee: + case Id_caller: + case Id_length: + attr = DONTENUM; + break; + + default: + throw new Exception (); + + } + return InstanceIdInfo (attr, id); + } + + // #/string_id_map# + + protected internal override string GetInstanceIdName (int id) + { + switch (id) { + + case Id_callee: + return "callee"; + + case Id_length: + return "length"; + + case Id_caller: + return "caller"; + } + return null; + } + + protected internal override object GetInstanceIdValue (int id) + { + switch (id) { + + case Id_callee: + return calleeObj; + + case Id_length: + return lengthObj; + + case Id_caller: { + object value = callerObj; + if (value == UniqueTag.NullValue) { + value = null; + } + else if (value == null) { + BuiltinCall caller = activation.parentActivationCall; + if (caller != null) { + value = caller.Get ("arguments", caller); + } + else { + value = null; + } + } + return value; + } + } + return base.GetInstanceIdValue (id); + } + + protected internal override void SetInstanceIdValue (int id, object value) + { + switch (id) { + + case Id_callee: + calleeObj = value; + return; + + case Id_length: + lengthObj = value; + return; + + case Id_caller: + callerObj = (value != null) ? value : UniqueTag.NullValue; + return; + } + base.SetInstanceIdValue (id, value); + } + + internal override object [] GetIds (bool getAll) + { + object [] ids = base.GetIds (getAll); + if (getAll && args.Length != 0) { + bool [] present = null; + int extraCount = args.Length; + for (int i = 0; i != ids.Length; ++i) { + object id = ids [i]; + if (id is int) { + int index = ((int)id); + if (0 <= index && index < args.Length) { + if (present == null) { + present = new bool [args.Length]; + } + if (!present [index]) { + present [index] = true; + extraCount--; + } + } + } + } + if (extraCount != 0) { + object [] tmp = new object [extraCount + ids.Length]; + Array.Copy (ids, 0, tmp, extraCount, ids.Length); + ids = tmp; + int offset = 0; + for (int i = 0; i != args.Length; ++i) { + if (present == null || !present [i]) { + ids [offset] = (int)i; + ++offset; + } + } + if (offset != extraCount) + Context.CodeBug (); + } + } + return ids; + } + + // Fields to hold caller, callee and length properties, + // where NOT_FOUND value tags deleted properties. + // In addition if callerObj == NullValue, it tags null for scripts, as + // initial callerObj == null means access to caller arguments available + // only in JS <= 1.3 scripts + private object callerObj; + private object calleeObj; + private object lengthObj; + + private BuiltinCall activation; + + // Initially args holds activation.getOriginalArgs(), but any modification + // of its elements triggers creation of a copy. If its element holds NOT_FOUND, + // it indicates deleted index, in which case super class is queried. + private object [] args; + + } +} diff --git a/Code/EcmaScript.NET/Attributes/EcmaScriptClassAttribute.cs b/src/EcmaScript.NET/Attributes/EcmaScriptClassAttribute.cs similarity index 96% rename from Code/EcmaScript.NET/Attributes/EcmaScriptClassAttribute.cs rename to src/EcmaScript.NET/Attributes/EcmaScriptClassAttribute.cs index 8007f71..b4e0f40 100644 --- a/Code/EcmaScript.NET/Attributes/EcmaScriptClassAttribute.cs +++ b/src/EcmaScript.NET/Attributes/EcmaScriptClassAttribute.cs @@ -1,40 +1,40 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; -using System.Text; - -namespace EcmaScript.NET.Attributes -{ - - [AttributeUsage (AttributeTargets.Class)] - public class EcmaScriptClassAttribute : Attribute - { - - private string m_Name = string.Empty; - - /// - /// Name of this class - /// - public string Name - { - get { return m_Name; } - } - - public EcmaScriptClassAttribute (string name) - { - m_Name = name; - } - - } -} +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; +using System.Text; + +namespace EcmaScript.NET.Attributes +{ + + [AttributeUsage (AttributeTargets.Class)] + public class EcmaScriptClassAttribute : Attribute + { + + private string m_Name = string.Empty; + + /// + /// Name of this class + /// + public string Name + { + get { return m_Name; } + } + + public EcmaScriptClassAttribute (string name) + { + m_Name = name; + } + + } +} diff --git a/Code/EcmaScript.NET/Attributes/EcmaScriptFunctionAttribute.cs b/src/EcmaScript.NET/Attributes/EcmaScriptFunctionAttribute.cs similarity index 96% rename from Code/EcmaScript.NET/Attributes/EcmaScriptFunctionAttribute.cs rename to src/EcmaScript.NET/Attributes/EcmaScriptFunctionAttribute.cs index 46bfb40..da7d5be 100644 --- a/Code/EcmaScript.NET/Attributes/EcmaScriptFunctionAttribute.cs +++ b/src/EcmaScript.NET/Attributes/EcmaScriptFunctionAttribute.cs @@ -1,50 +1,50 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; -using System.Reflection; -using System.Text; - -namespace EcmaScript.NET.Attributes -{ - - [AttributeUsage (AttributeTargets.Method - | AttributeTargets.Constructor)] - public class EcmaScriptFunctionAttribute : Attribute - { - - private string m_Name = string.Empty; - - /// - /// Name of this function - /// - public string Name - { - get { return m_Name; } - } - - public EcmaScriptFunctionAttribute () - : this (string.Empty) - { - ; - } - - public EcmaScriptFunctionAttribute (string name) - { - m_Name = name; - } - - internal MethodInfo MethodInfo; - - } -} +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; +using System.Text; + +namespace EcmaScript.NET.Attributes +{ + + [AttributeUsage (AttributeTargets.Method + | AttributeTargets.Constructor)] + public class EcmaScriptFunctionAttribute : Attribute + { + + private string m_Name = string.Empty; + + /// + /// Name of this function + /// + public string Name + { + get { return m_Name; } + } + + public EcmaScriptFunctionAttribute () + : this (string.Empty) + { + ; + } + + public EcmaScriptFunctionAttribute (string name) + { + m_Name = name; + } + + internal MethodInfo MethodInfo; + + } +} diff --git a/Code/EcmaScript.NET/Attributes/EcmaScriptPropertyAccess.cs b/src/EcmaScript.NET/Attributes/EcmaScriptPropertyAccess.cs similarity index 96% rename from Code/EcmaScript.NET/Attributes/EcmaScriptPropertyAccess.cs rename to src/EcmaScript.NET/Attributes/EcmaScriptPropertyAccess.cs index ea32e0c..09fd6a1 100644 --- a/Code/EcmaScript.NET/Attributes/EcmaScriptPropertyAccess.cs +++ b/src/EcmaScript.NET/Attributes/EcmaScriptPropertyAccess.cs @@ -1,26 +1,26 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -namespace EcmaScript.NET.Attributes -{ - - public enum EcmaScriptPropertyAccess - { - AsDeclared = 0, - Get = 1, - Set = 2 - } - -} +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +namespace EcmaScript.NET.Attributes +{ + + public enum EcmaScriptPropertyAccess + { + AsDeclared = 0, + Get = 1, + Set = 2 + } + +} diff --git a/Code/EcmaScript.NET/Attributes/EcmaScriptPropertyAttribute.cs b/src/EcmaScript.NET/Attributes/EcmaScriptPropertyAttribute.cs similarity index 96% rename from Code/EcmaScript.NET/Attributes/EcmaScriptPropertyAttribute.cs rename to src/EcmaScript.NET/Attributes/EcmaScriptPropertyAttribute.cs index 9944015..24704d4 100644 --- a/Code/EcmaScript.NET/Attributes/EcmaScriptPropertyAttribute.cs +++ b/src/EcmaScript.NET/Attributes/EcmaScriptPropertyAttribute.cs @@ -1,59 +1,59 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - - -using System; -using System.Text; - -namespace EcmaScript.NET.Attributes -{ - - [AttributeUsage (AttributeTargets.Property - | AttributeTargets.Field)] - public class EcmaScriptPropertyAttribute : Attribute - { - - private string m_Name = string.Empty; - - /// - /// Name of this property - /// - public string Name - { - get { return m_Name; } - } - - private EcmaScriptPropertyAccess m_Access = EcmaScriptPropertyAccess.AsDeclared; - - /// - /// Access - /// - public EcmaScriptPropertyAccess Access - { - get { return m_Access; } - } - - public EcmaScriptPropertyAttribute (string name) - { - m_Name = name; - } - - public EcmaScriptPropertyAttribute (string name, EcmaScriptPropertyAccess access) - { - m_Name = name; - m_Access = access; - } - - } - -} +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + + +using System; +using System.Text; + +namespace EcmaScript.NET.Attributes +{ + + [AttributeUsage (AttributeTargets.Property + | AttributeTargets.Field)] + public class EcmaScriptPropertyAttribute : Attribute + { + + private string m_Name = string.Empty; + + /// + /// Name of this property + /// + public string Name + { + get { return m_Name; } + } + + private EcmaScriptPropertyAccess m_Access = EcmaScriptPropertyAccess.AsDeclared; + + /// + /// Access + /// + public EcmaScriptPropertyAccess Access + { + get { return m_Access; } + } + + public EcmaScriptPropertyAttribute (string name) + { + m_Name = name; + } + + public EcmaScriptPropertyAttribute (string name, EcmaScriptPropertyAccess access) + { + m_Name = name; + m_Access = access; + } + + } + +} diff --git a/Code/EcmaScript.NET/BaseFunction.cs b/src/EcmaScript.NET/BaseFunction.cs similarity index 96% rename from Code/EcmaScript.NET/BaseFunction.cs rename to src/EcmaScript.NET/BaseFunction.cs index ad364c9..4a37579 100644 --- a/Code/EcmaScript.NET/BaseFunction.cs +++ b/src/EcmaScript.NET/BaseFunction.cs @@ -1,602 +1,602 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -using EcmaScript.NET.Types; - -namespace EcmaScript.NET -{ - - /// The base class for Function objects - /// See ECMA 15.3. - /// - public class BaseFunction : IdScriptableObject, IFunction - { - override public string ClassName - { - get - { - return "Function"; - } - - } - override protected internal int MaxInstanceId - { - get - { - return MAX_INSTANCE_ID; - } - - } - /// Make value as DontEnum, DontDelete, ReadOnly - /// prototype property of this Function object - /// - virtual public object ImmunePrototypeProperty - { - set - { - if (isPrototypePropertyImmune) { - throw new ApplicationException (); - } - prototypeProperty = (value != null) ? value : UniqueTag.NullValue; - isPrototypePropertyImmune = true; - } - - } - virtual public int Arity - { - get - { - return 0; - } - - } - virtual public int Length - { - get - { - return 0; - } - - } - virtual public string FunctionName - { - get - { - return ""; - } - - } - virtual internal object PrototypeProperty - { - get - { - object result = prototypeProperty; - if (result == null) { - lock (this) { - result = prototypeProperty; - if (result == null) { - SetupDefaultPrototype (); - result = prototypeProperty; - } - } - } - else if (result == UniqueTag.NullValue) { - result = null; - } - return result; - } - - } - private object Arguments - { - get - { - // .arguments is deprecated, so we use a slow - // way of getting it that doesn't add to the invocation cost. - // TODO: add warning, error based on version - object value = DefaultGet ("arguments"); - if (value != UniqueTag.NotFound) { - // Should after changing .arguments its - // activation still be available during Function call? - // This code assumes it should not: - // defaultGet("arguments") != NOT_FOUND - // means assigned arguments - return value; - } - Context cx = Context.CurrentContext; - BuiltinCall activation = ScriptRuntime.findFunctionActivation (cx, this); - return (activation == null) ? null : activation.Get ("arguments", activation); - } - - } - - private static readonly object FUNCTION_TAG = new object (); - - internal static void Init (IScriptable scope, bool zealed) - { - BaseFunction obj = new BaseFunction (); - obj.isPrototypePropertyImmune = true; - obj.ExportAsJSClass (MAX_PROTOTYPE_ID, scope, zealed); - } - - public BaseFunction () - { - } - - public BaseFunction (IScriptable scope, IScriptable prototype) - : base (scope, prototype) - { - } - - /// Implements the instanceof operator for JavaScript Function objects. - ///

- /// - /// foo = new Foo();
- /// foo instanceof Foo; // true
- ///
- /// - ///

- /// The value that appeared on the LHS of the instanceof - /// operator - /// - /// true if the "prototype" property of "this" appears in - /// value's prototype chain - /// - /// - public override bool HasInstance (IScriptable instance) - { - object protoProp = ScriptableObject.GetProperty (this, "prototype"); - if (protoProp is IScriptable) { - return ScriptRuntime.jsDelegatesTo (instance, (IScriptable)protoProp); - } - throw ScriptRuntime.TypeErrorById ("msg.instanceof.bad.prototype", FunctionName); - } - - - #region InstanceIds - private const int Id_length = 1; - private const int Id_arity = 2; - private const int Id_name = 3; - private const int Id_prototype = 4; - private const int Id_arguments = 5; - private const int MAX_INSTANCE_ID = 5; - #endregion - - protected internal override int FindInstanceIdInfo (string s) - { - int id; - #region Generated InstanceId Switch - L0: { - id = 0; - string X = null; - int c; - L: - switch (s.Length) { - case 4: - X = "name"; - id = Id_name; - break; - case 5: - X = "arity"; - id = Id_arity; - break; - case 6: - X = "length"; - id = Id_length; - break; - case 9: - c = s [0]; - if (c == 'a') { X = "arguments"; id = Id_arguments; } - else if (c == 'p') { X = "prototype"; id = Id_prototype; } - break; - } - if (X != null && X != s && !X.Equals (s)) - id = 0; - } - EL0: - - #endregion - - if (id == 0) - return base.FindInstanceIdInfo (s); - - int attr; - switch (id) { - - case Id_length: - case Id_arity: - case Id_name: - attr = DONTENUM | READONLY | PERMANENT; - break; - - case Id_prototype: - // As of ECMA 15.3.2.1 prototype will be PERMANENT if it's not with "Function" - attr = (isPrototypePropertyImmune) ? DONTENUM | READONLY | PERMANENT : PERMANENT; - break; - - case Id_arguments: - attr = DONTENUM | PERMANENT; - break; - - default: - throw new ApplicationException (); - - } - return InstanceIdInfo (attr, id); - } - - protected internal override string GetInstanceIdName (int id) - { - switch (id) { - - case Id_length: - return "length"; - case Id_arity: - return "arity"; - case Id_name: - return "name"; - case Id_prototype: - return "prototype"; - case Id_arguments: - return "arguments"; - } - return base.GetInstanceIdName (id); - } - - - protected internal override object GetInstanceIdValue (int id) - { - switch (id) { - case Id_length: - return Length; - case Id_arity: - return Arity; - case Id_name: - return FunctionName; - case Id_prototype: - return PrototypeProperty; - case Id_arguments: - return Arguments; - } - return base.GetInstanceIdValue (id); - } - - protected internal override void SetInstanceIdValue (int id, object value) - { - if (id == Id_prototype) { - if (!isPrototypePropertyImmune) { - prototypeProperty = (value != null) ? value : UniqueTag.NullValue; - } - return; - } - else if (id == Id_arguments) { - if (value == UniqueTag.NotFound) { - // This should not be called since "arguments" is PERMANENT - Context.CodeBug (); - } - DefaultPut ("arguments", value); - } - base.SetInstanceIdValue (id, value); - } - - protected internal override void FillConstructorProperties (IdFunctionObject ctor) - { - // Fix up bootstrapping problem: getPrototype of the IdFunctionObject - // can not return Function.prototype because Function object is not - // yet defined. - ctor.SetPrototype (this); - base.FillConstructorProperties (ctor); - } - - protected internal override void InitPrototypeId (int id) - { - string s; - int arity; - switch (id) { - - case Id_constructor: - arity = 1; - s = "constructor"; - break; - - case Id_toString: - arity = 1; - s = "toString"; - break; - - case Id_toSource: - arity = 1; - s = "toSource"; - break; - - case Id_apply: - arity = 2; - s = "apply"; - break; - - case Id_call: - arity = 1; - s = "call"; - break; - - default: - throw new ArgumentException (Convert.ToString (id)); - - } - InitPrototypeMethod (FUNCTION_TAG, id, s, arity); - } - - public override object ExecIdCall (IdFunctionObject f, Context cx, IScriptable scope, IScriptable thisObj, object [] args) - { - if (!f.HasTag (FUNCTION_TAG)) { - return base.ExecIdCall (f, cx, scope, thisObj, args); - } - int id = f.MethodId; - switch (id) { - - case Id_constructor: - return JsConstructor (cx, scope, args); - - - case Id_toString: { - BaseFunction realf = RealFunction (thisObj, f); - int indent = ScriptConvert.ToInt32 (args, 0); - return realf.Decompile (indent, Decompiler.TO_STRING_FLAG); - } - - - case Id_toSource: { - BaseFunction realf = RealFunction (thisObj, f); - int indent = 0; - int flags = Decompiler.TO_SOURCE_FLAG; - if (args.Length != 0) { - indent = ScriptConvert.ToInt32 (args [0]); - if (indent >= 0) { - flags = 0; - } - else { - indent = 0; - } - } - return realf.Decompile (indent, flags); - } - - - case Id_apply: - case Id_call: - return ScriptRuntime.applyOrCall (id == Id_apply, cx, scope, thisObj, args); - } - throw new ArgumentException (Convert.ToString (id)); - } - - private BaseFunction RealFunction (IScriptable thisObj, IdFunctionObject f) - { - object x = thisObj.GetDefaultValue (typeof (IFunction)); - if (x is BaseFunction) { - return (BaseFunction)x; - } - throw ScriptRuntime.TypeErrorById ("msg.incompat.call", f.FunctionName); - } - - protected internal virtual IScriptable GetClassPrototype() - { - object protoVal = PrototypeProperty; - if (protoVal is IScriptable) { - return (IScriptable)protoVal; - } - return getClassPrototype (this, "Object"); - } - - /// Should be overridden. - public virtual object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args) - { - return Undefined.Value; - } - - public virtual IScriptable Construct (Context cx, IScriptable scope, object [] args) - { - IScriptable result = CreateObject (cx, scope); - if (result != null) { - object val = Call (cx, scope, result, args); - if (val is IScriptable) { - result = (IScriptable)val; - } - } - else { - object val = Call (cx, scope, null, args); - if (!(val is IScriptable)) { - // It is program error not to return Scriptable from - // the call method if createObject returns null. - throw new ApplicationException ("Bad implementaion of call as constructor, name=" + FunctionName + " in " + GetType ().FullName); - } - result = (IScriptable)val; - if (result.GetPrototype () == null) { - result.SetPrototype (GetClassPrototype ()); - } - if (result.ParentScope == null) { - IScriptable parent = ParentScope; - if (result != parent) { - result.ParentScope = parent; - } - } - } - return result; - } - - /// Creates new script object. - /// The default implementation of {@link #construct} uses the method to - /// to get the value for thisObj argument when invoking - /// {@link #call}. - /// The methos is allowed to return null to indicate that - /// {@link #call} will create a new object itself. In this case - /// {@link #construct} will set scope and prototype on the result - /// {@link #call} unless they are already set. - /// - public virtual IScriptable CreateObject (Context cx, IScriptable scope) - { - IScriptable newInstance = new BuiltinObject (); - newInstance.SetPrototype (GetClassPrototype ()); - newInstance.ParentScope = ParentScope; - return newInstance; - } - - /// Decompile the source information associated with this js - /// function/script back into a string. - /// - /// - /// How much to indent the decompiled result. - /// - /// - /// Flags specifying format of decompilation output. - /// - internal virtual string Decompile (int indent, int flags) - { - System.Text.StringBuilder sb = new System.Text.StringBuilder (); - bool justbody = (0 != (flags & Decompiler.ONLY_BODY_FLAG)); - if (!justbody) { - sb.Append ("function "); - sb.Append (FunctionName); - sb.Append ("() {\n\t"); - } - sb.Append ("[native code, arity="); - sb.Append (Arity); - sb.Append ("]\n"); - if (!justbody) { - sb.Append ("}\n"); - } - return sb.ToString (); - } - - private void SetupDefaultPrototype () - { - BuiltinObject obj = new BuiltinObject (); - obj.DefineProperty ("constructor", this, ScriptableObject.DONTENUM); - // put the prototype property into the object now, then in the - // wacky case of a user defining a function Object(), we don't - // get an infinite loop trying to find the prototype. - prototypeProperty = obj; - IScriptable proto = GetObjectPrototype (this); - if (proto != obj) { - // not the one we just made, it must remain grounded - obj.SetPrototype (proto); - } - } - - private static object JsConstructor (Context cx, IScriptable scope, object [] args) - { - int arglen = args.Length; - System.Text.StringBuilder sourceBuf = new System.Text.StringBuilder (); - - sourceBuf.Append ("function "); - /* version != 1.2 Function constructor behavior - - * print 'anonymous' as the function name if the - * version (under which the function was compiled) is - * less than 1.2... or if it's greater than 1.2, because - * we need to be closer to ECMA. - */ - if (cx.Version != Context.Versions.JS1_2) { - sourceBuf.Append ("anonymous"); - } - sourceBuf.Append ('('); - - // Append arguments as coma separated strings - for (int i = 0; i < arglen - 1; i++) { - if (i > 0) { - sourceBuf.Append (','); - } - sourceBuf.Append (ScriptConvert.ToString (args [i])); - } - sourceBuf.Append (") {"); - if (arglen != 0) { - // append function body - string funBody = ScriptConvert.ToString (args [arglen - 1]); - sourceBuf.Append (funBody); - } - sourceBuf.Append ('}'); - string source = sourceBuf.ToString (); - - int [] linep = new int [1]; - string filename = Context.GetSourcePositionFromStack (linep); - if (filename == null) { - filename = ""; - linep [0] = 1; - } - - string sourceURI = ScriptRuntime.makeUrlForGeneratedScript (false, filename, linep [0]); - - IScriptable global = ScriptableObject.GetTopLevelScope (scope); - - ErrorReporter reporter; - reporter = DefaultErrorReporter.ForEval (cx.ErrorReporter); - - // Compile with explicit interpreter instance to force interpreter - // mode. - return cx.CompileFunction (global, source, new Interpreter (), reporter, sourceURI, 1, (object)null); - } - - #region PrototypeIds - private const int Id_constructor = 1; - private const int Id_toString = 2; - private const int Id_toSource = 3; - private const int Id_apply = 4; - private const int Id_call = 5; - private const int MAX_PROTOTYPE_ID = 5; - #endregion - - protected internal override int FindPrototypeId (string s) - { - int id; - #region Generated PrototypeId Switch - L0: { - id = 0; - string X = null; - int c; - L: - switch (s.Length) { - case 4: - X = "call"; - id = Id_call; - break; - case 5: - X = "apply"; - id = Id_apply; - break; - case 8: - c = s [3]; - if (c == 'o') { X = "toSource"; id = Id_toSource; } - else if (c == 't') { X = "toString"; id = Id_toString; } - break; - case 11: - X = "constructor"; - id = Id_constructor; - break; - } - if (X != null && X != s && !X.Equals (s)) - id = 0; - } - EL0: - - #endregion - return id; - } - - - private object prototypeProperty; - private bool isPrototypePropertyImmune; - - - } -} - +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +using EcmaScript.NET.Types; + +namespace EcmaScript.NET +{ + + /// The base class for Function objects + /// See ECMA 15.3. + /// + public class BaseFunction : IdScriptableObject, IFunction + { + override public string ClassName + { + get + { + return "Function"; + } + + } + override protected internal int MaxInstanceId + { + get + { + return MAX_INSTANCE_ID; + } + + } + /// Make value as DontEnum, DontDelete, ReadOnly + /// prototype property of this Function object + /// + virtual public object ImmunePrototypeProperty + { + set + { + if (isPrototypePropertyImmune) { + throw new Exception (); + } + prototypeProperty = (value != null) ? value : UniqueTag.NullValue; + isPrototypePropertyImmune = true; + } + + } + virtual public int Arity + { + get + { + return 0; + } + + } + virtual public int Length + { + get + { + return 0; + } + + } + virtual public string FunctionName + { + get + { + return ""; + } + + } + virtual internal object PrototypeProperty + { + get + { + object result = prototypeProperty; + if (result == null) { + lock (this) { + result = prototypeProperty; + if (result == null) { + SetupDefaultPrototype (); + result = prototypeProperty; + } + } + } + else if (result == UniqueTag.NullValue) { + result = null; + } + return result; + } + + } + private object Arguments + { + get + { + // .arguments is deprecated, so we use a slow + // way of getting it that doesn't add to the invocation cost. + // TODO: add warning, error based on version + object value = DefaultGet ("arguments"); + if (value != UniqueTag.NotFound) { + // Should after changing .arguments its + // activation still be available during Function call? + // This code assumes it should not: + // defaultGet("arguments") != NOT_FOUND + // means assigned arguments + return value; + } + Context cx = Context.CurrentContext; + BuiltinCall activation = ScriptRuntime.findFunctionActivation (cx, this); + return (activation == null) ? null : activation.Get ("arguments", activation); + } + + } + + private static readonly object FUNCTION_TAG = new object (); + + internal static void Init (IScriptable scope, bool zealed) + { + BaseFunction obj = new BaseFunction (); + obj.isPrototypePropertyImmune = true; + obj.ExportAsJSClass (MAX_PROTOTYPE_ID, scope, zealed); + } + + public BaseFunction () + { + } + + public BaseFunction (IScriptable scope, IScriptable prototype) + : base (scope, prototype) + { + } + + /// Implements the instanceof operator for JavaScript Function objects. + ///

+ /// + /// foo = new Foo();
+ /// foo instanceof Foo; // true
+ ///
+ /// + ///

+ /// The value that appeared on the LHS of the instanceof + /// operator + /// + /// true if the "prototype" property of "this" appears in + /// value's prototype chain + /// + /// + public override bool HasInstance (IScriptable instance) + { + object protoProp = ScriptableObject.GetProperty (this, "prototype"); + if (protoProp is IScriptable) { + return ScriptRuntime.jsDelegatesTo (instance, (IScriptable)protoProp); + } + throw ScriptRuntime.TypeErrorById ("msg.instanceof.bad.prototype", FunctionName); + } + + + #region InstanceIds + private const int Id_length = 1; + private const int Id_arity = 2; + private const int Id_name = 3; + private const int Id_prototype = 4; + private const int Id_arguments = 5; + private const int MAX_INSTANCE_ID = 5; + #endregion + + protected internal override int FindInstanceIdInfo (string s) + { + int id; + #region Generated InstanceId Switch + L0: { + id = 0; + string X = null; + int c; + L: + switch (s.Length) { + case 4: + X = "name"; + id = Id_name; + break; + case 5: + X = "arity"; + id = Id_arity; + break; + case 6: + X = "length"; + id = Id_length; + break; + case 9: + c = s [0]; + if (c == 'a') { X = "arguments"; id = Id_arguments; } + else if (c == 'p') { X = "prototype"; id = Id_prototype; } + break; + } + if (X != null && X != s && !X.Equals (s)) + id = 0; + } + EL0: + + #endregion + + if (id == 0) + return base.FindInstanceIdInfo (s); + + int attr; + switch (id) { + + case Id_length: + case Id_arity: + case Id_name: + attr = DONTENUM | READONLY | PERMANENT; + break; + + case Id_prototype: + // As of ECMA 15.3.2.1 prototype will be PERMANENT if it's not with "Function" + attr = (isPrototypePropertyImmune) ? DONTENUM | READONLY | PERMANENT : PERMANENT; + break; + + case Id_arguments: + attr = DONTENUM | PERMANENT; + break; + + default: + throw new Exception (); + + } + return InstanceIdInfo (attr, id); + } + + protected internal override string GetInstanceIdName (int id) + { + switch (id) { + + case Id_length: + return "length"; + case Id_arity: + return "arity"; + case Id_name: + return "name"; + case Id_prototype: + return "prototype"; + case Id_arguments: + return "arguments"; + } + return base.GetInstanceIdName (id); + } + + + protected internal override object GetInstanceIdValue (int id) + { + switch (id) { + case Id_length: + return Length; + case Id_arity: + return Arity; + case Id_name: + return FunctionName; + case Id_prototype: + return PrototypeProperty; + case Id_arguments: + return Arguments; + } + return base.GetInstanceIdValue (id); + } + + protected internal override void SetInstanceIdValue (int id, object value) + { + if (id == Id_prototype) { + if (!isPrototypePropertyImmune) { + prototypeProperty = (value != null) ? value : UniqueTag.NullValue; + } + return; + } + else if (id == Id_arguments) { + if (value == UniqueTag.NotFound) { + // This should not be called since "arguments" is PERMANENT + Context.CodeBug (); + } + DefaultPut ("arguments", value); + } + base.SetInstanceIdValue (id, value); + } + + protected internal override void FillConstructorProperties (IdFunctionObject ctor) + { + // Fix up bootstrapping problem: getPrototype of the IdFunctionObject + // can not return Function.prototype because Function object is not + // yet defined. + ctor.SetPrototype (this); + base.FillConstructorProperties (ctor); + } + + protected internal override void InitPrototypeId (int id) + { + string s; + int arity; + switch (id) { + + case Id_constructor: + arity = 1; + s = "constructor"; + break; + + case Id_toString: + arity = 1; + s = "toString"; + break; + + case Id_toSource: + arity = 1; + s = "toSource"; + break; + + case Id_apply: + arity = 2; + s = "apply"; + break; + + case Id_call: + arity = 1; + s = "call"; + break; + + default: + throw new ArgumentException (Convert.ToString (id)); + + } + InitPrototypeMethod (FUNCTION_TAG, id, s, arity); + } + + public override object ExecIdCall (IdFunctionObject f, Context cx, IScriptable scope, IScriptable thisObj, object [] args) + { + if (!f.HasTag (FUNCTION_TAG)) { + return base.ExecIdCall (f, cx, scope, thisObj, args); + } + int id = f.MethodId; + switch (id) { + + case Id_constructor: + return JsConstructor (cx, scope, args); + + + case Id_toString: { + BaseFunction realf = RealFunction (thisObj, f); + int indent = ScriptConvert.ToInt32 (args, 0); + return realf.Decompile (indent, Decompiler.TO_STRING_FLAG); + } + + + case Id_toSource: { + BaseFunction realf = RealFunction (thisObj, f); + int indent = 0; + int flags = Decompiler.TO_SOURCE_FLAG; + if (args.Length != 0) { + indent = ScriptConvert.ToInt32 (args [0]); + if (indent >= 0) { + flags = 0; + } + else { + indent = 0; + } + } + return realf.Decompile (indent, flags); + } + + + case Id_apply: + case Id_call: + return ScriptRuntime.applyOrCall (id == Id_apply, cx, scope, thisObj, args); + } + throw new ArgumentException (Convert.ToString (id)); + } + + private BaseFunction RealFunction (IScriptable thisObj, IdFunctionObject f) + { + object x = thisObj.GetDefaultValue (typeof (IFunction)); + if (x is BaseFunction) { + return (BaseFunction)x; + } + throw ScriptRuntime.TypeErrorById ("msg.incompat.call", f.FunctionName); + } + + protected internal virtual IScriptable GetClassPrototype() + { + object protoVal = PrototypeProperty; + if (protoVal is IScriptable) { + return (IScriptable)protoVal; + } + return getClassPrototype (this, "Object"); + } + + /// Should be overridden. + public virtual object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args) + { + return Undefined.Value; + } + + public virtual IScriptable Construct (Context cx, IScriptable scope, object [] args) + { + IScriptable result = CreateObject (cx, scope); + if (result != null) { + object val = Call (cx, scope, result, args); + if (val is IScriptable) { + result = (IScriptable)val; + } + } + else { + object val = Call (cx, scope, null, args); + if (!(val is IScriptable)) { + // It is program error not to return Scriptable from + // the call method if createObject returns null. + throw new Exception ("Bad implementaion of call as constructor, name=" + FunctionName + " in " + GetType ().FullName); + } + result = (IScriptable)val; + if (result.GetPrototype () == null) { + result.SetPrototype (GetClassPrototype ()); + } + if (result.ParentScope == null) { + IScriptable parent = ParentScope; + if (result != parent) { + result.ParentScope = parent; + } + } + } + return result; + } + + /// Creates new script object. + /// The default implementation of {@link #construct} uses the method to + /// to get the value for thisObj argument when invoking + /// {@link #call}. + /// The methos is allowed to return null to indicate that + /// {@link #call} will create a new object itself. In this case + /// {@link #construct} will set scope and prototype on the result + /// {@link #call} unless they are already set. + /// + public virtual IScriptable CreateObject (Context cx, IScriptable scope) + { + IScriptable newInstance = new BuiltinObject (); + newInstance.SetPrototype (GetClassPrototype ()); + newInstance.ParentScope = ParentScope; + return newInstance; + } + + /// Decompile the source information associated with this js + /// function/script back into a string. + /// + /// + /// How much to indent the decompiled result. + /// + /// + /// Flags specifying format of decompilation output. + /// + internal virtual string Decompile (int indent, int flags) + { + System.Text.StringBuilder sb = new System.Text.StringBuilder (); + bool justbody = (0 != (flags & Decompiler.ONLY_BODY_FLAG)); + if (!justbody) { + sb.Append ("function "); + sb.Append (FunctionName); + sb.Append ("() {\n\t"); + } + sb.Append ("[native code, arity="); + sb.Append (Arity); + sb.Append ("]\n"); + if (!justbody) { + sb.Append ("}\n"); + } + return sb.ToString (); + } + + private void SetupDefaultPrototype () + { + BuiltinObject obj = new BuiltinObject (); + obj.DefineProperty ("constructor", this, ScriptableObject.DONTENUM); + // put the prototype property into the object now, then in the + // wacky case of a user defining a function Object(), we don't + // get an infinite loop trying to find the prototype. + prototypeProperty = obj; + IScriptable proto = GetObjectPrototype (this); + if (proto != obj) { + // not the one we just made, it must remain grounded + obj.SetPrototype (proto); + } + } + + private static object JsConstructor (Context cx, IScriptable scope, object [] args) + { + int arglen = args.Length; + System.Text.StringBuilder sourceBuf = new System.Text.StringBuilder (); + + sourceBuf.Append ("function "); + /* version != 1.2 Function constructor behavior - + * print 'anonymous' as the function name if the + * version (under which the function was compiled) is + * less than 1.2... or if it's greater than 1.2, because + * we need to be closer to ECMA. + */ + if (cx.Version != Context.Versions.JS1_2) { + sourceBuf.Append ("anonymous"); + } + sourceBuf.Append ('('); + + // Append arguments as coma separated strings + for (int i = 0; i < arglen - 1; i++) { + if (i > 0) { + sourceBuf.Append (','); + } + sourceBuf.Append (ScriptConvert.ToString (args [i])); + } + sourceBuf.Append (") {"); + if (arglen != 0) { + // append function body + string funBody = ScriptConvert.ToString (args [arglen - 1]); + sourceBuf.Append (funBody); + } + sourceBuf.Append ('}'); + string source = sourceBuf.ToString (); + + int [] linep = new int [1]; + string filename = Context.GetSourcePositionFromStack (linep); + if (filename == null) { + filename = ""; + linep [0] = 1; + } + + string sourceURI = ScriptRuntime.makeUrlForGeneratedScript (false, filename, linep [0]); + + IScriptable global = ScriptableObject.GetTopLevelScope (scope); + + ErrorReporter reporter; + reporter = DefaultErrorReporter.ForEval (cx.ErrorReporter); + + // Compile with explicit interpreter instance to force interpreter + // mode. + return cx.CompileFunction (global, source, new Interpreter (), reporter, sourceURI, 1, (object)null); + } + + #region PrototypeIds + private const int Id_constructor = 1; + private const int Id_toString = 2; + private const int Id_toSource = 3; + private const int Id_apply = 4; + private const int Id_call = 5; + private const int MAX_PROTOTYPE_ID = 5; + #endregion + + protected internal override int FindPrototypeId (string s) + { + int id; + #region Generated PrototypeId Switch + L0: { + id = 0; + string X = null; + int c; + L: + switch (s.Length) { + case 4: + X = "call"; + id = Id_call; + break; + case 5: + X = "apply"; + id = Id_apply; + break; + case 8: + c = s [3]; + if (c == 'o') { X = "toSource"; id = Id_toSource; } + else if (c == 't') { X = "toString"; id = Id_toString; } + break; + case 11: + X = "constructor"; + id = Id_constructor; + break; + } + if (X != null && X != s && !X.Equals (s)) + id = 0; + } + EL0: + + #endregion + return id; + } + + + private object prototypeProperty; + private bool isPrototypePropertyImmune; + + + } +} + diff --git a/Code/EcmaScript.NET/Collections/ObjArray.cs b/src/EcmaScript.NET/Collections/ObjArray.cs similarity index 94% rename from Code/EcmaScript.NET/Collections/ObjArray.cs rename to src/EcmaScript.NET/Collections/ObjArray.cs index 6b94dea..b8d0057 100644 --- a/Code/EcmaScript.NET/Collections/ObjArray.cs +++ b/src/EcmaScript.NET/Collections/ObjArray.cs @@ -1,501 +1,501 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; -using System.Runtime.InteropServices; - -namespace EcmaScript.NET.Collections -{ - - /// Implementation of resizable array with focus on minimizing memory usage by storing few initial array elements in object fields. Can also be used as a stack. - - - public class ObjArray - { - virtual public bool Sealed - { - get - { - return zealed; - } - - } - virtual public bool Empty - { - get - { - return m_Size == 0; - } - - } - virtual public int Size - { - set - { - if (value < 0) - throw new ArgumentException (); - if (zealed) - throw onSeledMutation (); - int N = m_Size; - if (value < N) { - for (int i = value; i != N; ++i) { - SetImpl (i, (object)null); - } - } - else if (value > N) { - if (value > FIELDS_STORE_SIZE) { - ensureCapacity (value); - } - } - m_Size = value; - } - - } - - public ObjArray () - { - } - - public void seal () - { - zealed = true; - } - - public int size () - { - return m_Size; - } - - public object Get (int index) - { - if (!(0 <= index && index < m_Size)) - throw onInvalidIndex (index, m_Size); - return GetImpl (index); - } - - public void Set (int index, object value) - { - if (!(0 <= index && index < m_Size)) - throw onInvalidIndex (index, m_Size); - if (zealed) - throw onSeledMutation (); - SetImpl (index, value); - } - - private object GetImpl (int index) - { - switch (index) { - - case 0: - return f0; - - case 1: - return f1; - - case 2: - return f2; - - case 3: - return f3; - - case 4: - return f4; - } - return data [index - FIELDS_STORE_SIZE]; - } - - private void SetImpl (int index, object value) - { - switch (index) { - - case 0: - f0 = value; - break; - - case 1: - f1 = value; - break; - - case 2: - f2 = value; - break; - - case 3: - f3 = value; - break; - - case 4: - f4 = value; - break; - - default: - data [index - FIELDS_STORE_SIZE] = value; - break; - - } - } - - public virtual int indexOf (object obj) - { - int N = m_Size; - for (int i = 0; i != N; ++i) { - object current = GetImpl (i); - if (current == obj || (current != null && current.Equals (obj))) { - return i; - } - } - return -1; - } - - public virtual int lastIndexOf (object obj) - { - for (int i = m_Size; i != 0; ) { - --i; - object current = GetImpl (i); - if (current == obj || (current != null && current.Equals (obj))) { - return i; - } - } - return -1; - } - - public object peek () - { - int N = m_Size; - if (N == 0) - throw onEmptyStackTopRead (); - return GetImpl (N - 1); - } - - public object pop () - { - if (zealed) - throw onSeledMutation (); - int N = m_Size; - --N; - object top; - switch (N) { - - case -1: - throw onEmptyStackTopRead (); - - case 0: - top = f0; - f0 = null; - break; - - case 1: - top = f1; - f1 = null; - break; - - case 2: - top = f2; - f2 = null; - break; - - case 3: - top = f3; - f3 = null; - break; - - case 4: - top = f4; - f4 = null; - break; - - default: - top = data [N - FIELDS_STORE_SIZE]; - data [N - FIELDS_STORE_SIZE] = null; - break; - - } - m_Size = N; - return top; - } - - public void push (object value) - { - add (value); - } - - public void add (object value) - { - if (zealed) - throw onSeledMutation (); - int N = m_Size; - if (N >= FIELDS_STORE_SIZE) { - ensureCapacity (N + 1); - } - m_Size = N + 1; - SetImpl (N, value); - } - - public void add (int index, object value) - { - int N = m_Size; - if (!(0 <= index && index <= N)) - throw onInvalidIndex (index, N + 1); - if (zealed) - throw onSeledMutation (); - object tmp; - switch (index) { - - case 0: - if (N == 0) { - f0 = value; - break; - } - tmp = f0; - f0 = value; - value = tmp; - goto case 1; - - case 1: - if (N == 1) { - f1 = value; - break; - } - tmp = f1; - f1 = value; - value = tmp; - goto case 2; - - case 2: - if (N == 2) { - f2 = value; - break; - } - tmp = f2; - f2 = value; - value = tmp; - goto case 3; - - case 3: - if (N == 3) { - f3 = value; - break; - } - tmp = f3; - f3 = value; - value = tmp; - goto case 4; - - case 4: - if (N == 4) { - f4 = value; - break; - } - tmp = f4; - f4 = value; - value = tmp; - - index = FIELDS_STORE_SIZE; - goto default; - - default: - ensureCapacity (N + 1); - if (index != N) { - Array.Copy (data, index - FIELDS_STORE_SIZE, data, index - FIELDS_STORE_SIZE + 1, N - index); - } - data [index - FIELDS_STORE_SIZE] = value; - break; - - } - m_Size = N + 1; - } - - public void remove (int index) - { - int N = m_Size; - if (!(0 <= index && index < N)) - throw onInvalidIndex (index, N); - if (zealed) - throw onSeledMutation (); - --N; - switch (index) { - - case 0: - if (N == 0) { - f0 = null; - break; - } - f0 = f1; - goto case 1; - - case 1: - if (N == 1) { - f1 = null; - break; - } - f1 = f2; - goto case 2; - - case 2: - if (N == 2) { - f2 = null; - break; - } - f2 = f3; - goto case 3; - - case 3: - if (N == 3) { - f3 = null; - break; - } - f3 = f4; - goto case 4; - - case 4: - if (N == 4) { - f4 = null; - break; - } - f4 = data [0]; - - index = FIELDS_STORE_SIZE; - goto default; - - default: - if (index != N) { - Array.Copy (data, index - FIELDS_STORE_SIZE + 1, data, index - FIELDS_STORE_SIZE, N - index); - } - data [N - FIELDS_STORE_SIZE] = null; - break; - - } - m_Size = N; - } - - public void clear () - { - if (zealed) - throw onSeledMutation (); - int N = m_Size; - for (int i = 0; i != N; ++i) { - SetImpl (i, (object)null); - } - m_Size = 0; - } - - public object [] ToArray () - { - object [] array = new object [m_Size]; - ToArray (array, 0); - return array; - } - - public void ToArray (object [] array) - { - ToArray (array, 0); - } - - public void ToArray (object [] array, int offset) - { - int N = m_Size; - switch (N) { - - default: - Array.Copy (data, 0, array, offset + FIELDS_STORE_SIZE, N - FIELDS_STORE_SIZE); - goto case 5; - - - case 5: - array [offset + 4] = f4; - goto case 4; - - case 4: - array [offset + 3] = f3; - goto case 3; - - case 3: - array [offset + 2] = f2; - goto case 2; - - case 2: - array [offset + 1] = f1; - goto case 1; - - case 1: - array [offset + 0] = f0; - goto case 0; - - case 0: - break; - } - } - - private void ensureCapacity (int minimalCapacity) - { - int required = minimalCapacity - FIELDS_STORE_SIZE; - if (required <= 0) - throw new ArgumentException (); - if (data == null) { - int alloc = FIELDS_STORE_SIZE * 2; - if (alloc < required) { - alloc = required; - } - data = new object [alloc]; - } - else { - int alloc = data.Length; - if (alloc < required) { - if (alloc <= FIELDS_STORE_SIZE) { - alloc = FIELDS_STORE_SIZE * 2; - } - else { - alloc *= 2; - } - if (alloc < required) { - alloc = required; - } - object [] tmp = new object [alloc]; - if (m_Size > FIELDS_STORE_SIZE) { - Array.Copy (data, 0, tmp, 0, m_Size - FIELDS_STORE_SIZE); - } - data = tmp; - } - } - } - - private static ApplicationException onInvalidIndex (int index, int upperBound) - { - // \u2209 is "NOT ELEMENT OF" - string msg = index + " \u2209 [0, " + upperBound + ')'; - throw new System.IndexOutOfRangeException (msg); - } - - private static ApplicationException onEmptyStackTopRead () - { - throw new ApplicationException ("Empty stack"); - } - - private static ApplicationException onSeledMutation () - { - throw new ApplicationException ("Attempt to modify sealed array"); - } - - - // Number of data elements - private int m_Size; - - private bool zealed; - - private const int FIELDS_STORE_SIZE = 5; - - private object f0, f1, f2, f3, f4; - - private object [] data; - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; +using System.Runtime.InteropServices; + +namespace EcmaScript.NET.Collections +{ + + /// Implementation of resizable array with focus on minimizing memory usage by storing few initial array elements in object fields. Can also be used as a stack. + + + public class ObjArray + { + virtual public bool Sealed + { + get + { + return zealed; + } + + } + virtual public bool Empty + { + get + { + return m_Size == 0; + } + + } + virtual public int Size + { + set + { + if (value < 0) + throw new ArgumentException (); + if (zealed) + throw onSeledMutation (); + int N = m_Size; + if (value < N) { + for (int i = value; i != N; ++i) { + SetImpl (i, (object)null); + } + } + else if (value > N) { + if (value > FIELDS_STORE_SIZE) { + ensureCapacity (value); + } + } + m_Size = value; + } + + } + + public ObjArray () + { + } + + public void seal () + { + zealed = true; + } + + public int size () + { + return m_Size; + } + + public object Get (int index) + { + if (!(0 <= index && index < m_Size)) + throw onInvalidIndex (index, m_Size); + return GetImpl (index); + } + + public void Set (int index, object value) + { + if (!(0 <= index && index < m_Size)) + throw onInvalidIndex (index, m_Size); + if (zealed) + throw onSeledMutation (); + SetImpl (index, value); + } + + private object GetImpl (int index) + { + switch (index) { + + case 0: + return f0; + + case 1: + return f1; + + case 2: + return f2; + + case 3: + return f3; + + case 4: + return f4; + } + return data [index - FIELDS_STORE_SIZE]; + } + + private void SetImpl (int index, object value) + { + switch (index) { + + case 0: + f0 = value; + break; + + case 1: + f1 = value; + break; + + case 2: + f2 = value; + break; + + case 3: + f3 = value; + break; + + case 4: + f4 = value; + break; + + default: + data [index - FIELDS_STORE_SIZE] = value; + break; + + } + } + + public virtual int indexOf (object obj) + { + int N = m_Size; + for (int i = 0; i != N; ++i) { + object current = GetImpl (i); + if (current == obj || (current != null && current.Equals (obj))) { + return i; + } + } + return -1; + } + + public virtual int lastIndexOf (object obj) + { + for (int i = m_Size; i != 0; ) { + --i; + object current = GetImpl (i); + if (current == obj || (current != null && current.Equals (obj))) { + return i; + } + } + return -1; + } + + public object peek () + { + int N = m_Size; + if (N == 0) + throw onEmptyStackTopRead (); + return GetImpl (N - 1); + } + + public object pop () + { + if (zealed) + throw onSeledMutation (); + int N = m_Size; + --N; + object top; + switch (N) { + + case -1: + throw onEmptyStackTopRead (); + + case 0: + top = f0; + f0 = null; + break; + + case 1: + top = f1; + f1 = null; + break; + + case 2: + top = f2; + f2 = null; + break; + + case 3: + top = f3; + f3 = null; + break; + + case 4: + top = f4; + f4 = null; + break; + + default: + top = data [N - FIELDS_STORE_SIZE]; + data [N - FIELDS_STORE_SIZE] = null; + break; + + } + m_Size = N; + return top; + } + + public void push (object value) + { + add (value); + } + + public void add (object value) + { + if (zealed) + throw onSeledMutation (); + int N = m_Size; + if (N >= FIELDS_STORE_SIZE) { + ensureCapacity (N + 1); + } + m_Size = N + 1; + SetImpl (N, value); + } + + public void add (int index, object value) + { + int N = m_Size; + if (!(0 <= index && index <= N)) + throw onInvalidIndex (index, N + 1); + if (zealed) + throw onSeledMutation (); + object tmp; + switch (index) { + + case 0: + if (N == 0) { + f0 = value; + break; + } + tmp = f0; + f0 = value; + value = tmp; + goto case 1; + + case 1: + if (N == 1) { + f1 = value; + break; + } + tmp = f1; + f1 = value; + value = tmp; + goto case 2; + + case 2: + if (N == 2) { + f2 = value; + break; + } + tmp = f2; + f2 = value; + value = tmp; + goto case 3; + + case 3: + if (N == 3) { + f3 = value; + break; + } + tmp = f3; + f3 = value; + value = tmp; + goto case 4; + + case 4: + if (N == 4) { + f4 = value; + break; + } + tmp = f4; + f4 = value; + value = tmp; + + index = FIELDS_STORE_SIZE; + goto default; + + default: + ensureCapacity (N + 1); + if (index != N) { + Array.Copy (data, index - FIELDS_STORE_SIZE, data, index - FIELDS_STORE_SIZE + 1, N - index); + } + data [index - FIELDS_STORE_SIZE] = value; + break; + + } + m_Size = N + 1; + } + + public void remove (int index) + { + int N = m_Size; + if (!(0 <= index && index < N)) + throw onInvalidIndex (index, N); + if (zealed) + throw onSeledMutation (); + --N; + switch (index) { + + case 0: + if (N == 0) { + f0 = null; + break; + } + f0 = f1; + goto case 1; + + case 1: + if (N == 1) { + f1 = null; + break; + } + f1 = f2; + goto case 2; + + case 2: + if (N == 2) { + f2 = null; + break; + } + f2 = f3; + goto case 3; + + case 3: + if (N == 3) { + f3 = null; + break; + } + f3 = f4; + goto case 4; + + case 4: + if (N == 4) { + f4 = null; + break; + } + f4 = data [0]; + + index = FIELDS_STORE_SIZE; + goto default; + + default: + if (index != N) { + Array.Copy (data, index - FIELDS_STORE_SIZE + 1, data, index - FIELDS_STORE_SIZE, N - index); + } + data [N - FIELDS_STORE_SIZE] = null; + break; + + } + m_Size = N; + } + + public void clear () + { + if (zealed) + throw onSeledMutation (); + int N = m_Size; + for (int i = 0; i != N; ++i) { + SetImpl (i, (object)null); + } + m_Size = 0; + } + + public object [] ToArray () + { + object [] array = new object [m_Size]; + ToArray (array, 0); + return array; + } + + public void ToArray (object [] array) + { + ToArray (array, 0); + } + + public void ToArray (object [] array, int offset) + { + int N = m_Size; + switch (N) { + + default: + Array.Copy (data, 0, array, offset + FIELDS_STORE_SIZE, N - FIELDS_STORE_SIZE); + goto case 5; + + + case 5: + array [offset + 4] = f4; + goto case 4; + + case 4: + array [offset + 3] = f3; + goto case 3; + + case 3: + array [offset + 2] = f2; + goto case 2; + + case 2: + array [offset + 1] = f1; + goto case 1; + + case 1: + array [offset + 0] = f0; + goto case 0; + + case 0: + break; + } + } + + private void ensureCapacity (int minimalCapacity) + { + int required = minimalCapacity - FIELDS_STORE_SIZE; + if (required <= 0) + throw new ArgumentException (); + if (data == null) { + int alloc = FIELDS_STORE_SIZE * 2; + if (alloc < required) { + alloc = required; + } + data = new object [alloc]; + } + else { + int alloc = data.Length; + if (alloc < required) { + if (alloc <= FIELDS_STORE_SIZE) { + alloc = FIELDS_STORE_SIZE * 2; + } + else { + alloc *= 2; + } + if (alloc < required) { + alloc = required; + } + object [] tmp = new object [alloc]; + if (m_Size > FIELDS_STORE_SIZE) { + Array.Copy (data, 0, tmp, 0, m_Size - FIELDS_STORE_SIZE); + } + data = tmp; + } + } + } + + private static Exception onInvalidIndex (int index, int upperBound) + { + // \u2209 is "NOT ELEMENT OF" + string msg = index + " \u2209 [0, " + upperBound + ')'; + throw new System.IndexOutOfRangeException (msg); + } + + private static Exception onEmptyStackTopRead () + { + throw new Exception ("Empty stack"); + } + + private static Exception onSeledMutation () + { + throw new Exception ("Attempt to modify sealed array"); + } + + + // Number of data elements + private int m_Size; + + private bool zealed; + + private const int FIELDS_STORE_SIZE = 5; + + private object f0, f1, f2, f3, f4; + + private object [] data; + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/Collections/ObjToIntMap.cs b/src/EcmaScript.NET/Collections/ObjToIntMap.cs similarity index 97% rename from Code/EcmaScript.NET/Collections/ObjToIntMap.cs rename to src/EcmaScript.NET/Collections/ObjToIntMap.cs index 7e3f60e..e42937f 100644 --- a/Code/EcmaScript.NET/Collections/ObjToIntMap.cs +++ b/src/EcmaScript.NET/Collections/ObjToIntMap.cs @@ -1,476 +1,476 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; -using System.Runtime.InteropServices; - - -namespace EcmaScript.NET.Collections -{ - - /// Map to associate objects to integers. - /// The map does not synchronize any of its operation, so either use - /// it from a single thread or do own synchronization or perform all mutation - /// operations on one thread before passing the map to others - /// - /// - public class ObjToIntMap - { - virtual public bool Empty - { - get - { - return keyCount == 0; - } - - } - - // Map implementation via hashtable, - // follows "The Art of Computer Programming" by Donald E. Knuth - - // ObjToIntMap is a copy cat of ObjToIntMap with API adjusted to object keys - - public class Iterator - { - virtual public object Key - { - get - { - object key = keys [cursor]; - if (key == UniqueTag.NullValue) { - key = null; - } - return key; - } - - } - virtual public int Value - { - get - { - return values [cursor]; - } - - set - { - values [cursor] = value; - } - - } - - internal Iterator (ObjToIntMap master) - { - this.master = master; - } - - internal void Init (object [] keys, int [] values, int keyCount) - { - this.keys = keys; - this.values = values; - this.cursor = -1; - this.remaining = keyCount; - } - - public virtual void start () - { - master.initIterator (this); - next (); - } - - public virtual bool done () - { - return remaining < 0; - } - - public virtual void next () - { - if (remaining == -1) - Context.CodeBug (); - if (remaining == 0) { - remaining = -1; - cursor = -1; - } - else { - for (++cursor; ; ++cursor) { - object key = keys [cursor]; - if (key != null && key != ObjToIntMap.DELETED) { - --remaining; - break; - } - } - } - } - - internal ObjToIntMap master; - private int cursor; - private int remaining; - private object [] keys; - private int [] values; - } - - public ObjToIntMap () - : this (4) - { - } - - public ObjToIntMap (int keyCountHint) - { - if (keyCountHint < 0) - Context.CodeBug (); - // Table grow when number of stored keys >= 3/4 of max capacity - int minimalCapacity = keyCountHint * 4 / 3; - int i; - for (i = 2; (1 << i) < minimalCapacity; ++i) { - } - power = i; - if (check && power < 2) - Context.CodeBug (); - } - - public virtual int size () - { - return keyCount; - } - - public virtual bool has (object key) - { - if (key == null) { - key = UniqueTag.NullValue; - } - return 0 <= findIndex (key); - } - - /// Get integer value assigned with key. - /// key integer value or defaultValue if key is absent - /// - public virtual int Get (object key, int defaultValue) - { - if (key == null) { - key = UniqueTag.NullValue; - } - int index = findIndex (key); - if (0 <= index) { - return values [index]; - } - return defaultValue; - } - - /// Get integer value assigned with key. - /// key integer value - /// - /// RuntimeException if key does not exist - public virtual int getExisting (object key) - { - if (key == null) { - key = UniqueTag.NullValue; - } - int index = findIndex (key); - if (0 <= index) { - return values [index]; - } - // Key must exist - Context.CodeBug (); - return 0; - } - - public virtual void put (object key, int value) - { - if (key == null) { - key = UniqueTag.NullValue; - } - int index = ensureIndex (key); - values [index] = value; - } - - /// If table already contains a key that equals to keyArg, return that key - /// while setting its value to zero, otherwise add keyArg with 0 value to - /// the table and return it. - /// - public virtual object intern (object keyArg) - { - bool nullKey = false; - if (keyArg == null) { - nullKey = true; - keyArg = UniqueTag.NullValue; - } - int index = ensureIndex (keyArg); - values [index] = 0; - return (nullKey) ? null : keys [index]; - } - - public virtual void remove (object key) - { - if (key == null) { - key = UniqueTag.NullValue; - } - int index = findIndex (key); - if (0 <= index) { - keys [index] = DELETED; - --keyCount; - } - } - - public virtual void clear () - { - int i = keys.Length; - while (i != 0) { - keys [--i] = null; - } - keyCount = 0; - occupiedCount = 0; - } - - public virtual Iterator newIterator () - { - return new Iterator (this); - } - - // The sole purpose of the method is to avoid accessing private fields - // from the Iterator inner class to workaround JDK 1.1 compiler bug which - // generates code triggering VerifierError on recent JVMs - internal void initIterator (Iterator i) - { - i.Init (keys, values, keyCount); - } - - /// Return array of present keys - public virtual object [] getKeys () - { - object [] array = new object [keyCount]; - getKeys (array, 0); - return array; - } - - public virtual void getKeys (object [] array, int offset) - { - int count = keyCount; - for (int i = 0; count != 0; ++i) { - object key = keys [i]; - if (key != null && key != DELETED) { - if (key == UniqueTag.NullValue) { - key = null; - } - array [offset] = key; - ++offset; - --count; - } - } - } - - private static int tableLookupStep (int fraction, int mask, int power) - { - int shift = 32 - 2 * power; - if (shift >= 0) { - return ((int)(((uint)fraction >> shift)) & mask) | 1; - } - else { - return (fraction & (int)((uint)mask >> -shift)) | 1; - } - } - - private int findIndex (object key) - { - if (keys != null) { - int hash = key.GetHashCode (); - int fraction = hash * A; - int index = (int)((uint)fraction >> (32 - power)); - object test = keys [index]; - if (test != null) { - int N = 1 << power; - if (test == key || (values [N + index] == hash && test.Equals (key))) { - return index; - } - // Search in table after first failed attempt - int mask = N - 1; - int step = tableLookupStep (fraction, mask, power); - int n = 0; - for (; ; ) { - if (check) { - if (n >= occupiedCount) - Context.CodeBug (); - ++n; - } - index = (index + step) & mask; - test = keys [index]; - if (test == null) { - break; - } - if (test == key || (values [N + index] == hash && test.Equals (key))) { - return index; - } - } - } - } - return -1; - } - - // Insert key that is not present to table without deleted entries - // and enough free space - private int insertNewKey (object key, int hash) - { - if (check && occupiedCount != keyCount) - Context.CodeBug (); - if (check && keyCount == 1 << power) - Context.CodeBug (); - int fraction = hash * A; - int index = (int)((uint)fraction >> (32 - power)); - int N = 1 << power; - if (keys [index] != null) { - int mask = N - 1; - int step = tableLookupStep (fraction, mask, power); - int firstIndex = index; - do { - if (check && keys [index] == DELETED) - Context.CodeBug (); - index = (index + step) & mask; - if (check && firstIndex == index) - Context.CodeBug (); - } - while (keys [index] != null); - } - keys [index] = key; - values [N + index] = hash; - ++occupiedCount; - ++keyCount; - - return index; - } - - private void rehashTable () - { - if (keys == null) { - if (check && keyCount != 0) - Context.CodeBug (); - if (check && occupiedCount != 0) - Context.CodeBug (); - int N = 1 << power; - keys = new object [N]; - values = new int [2 * N]; - } - else { - // Check if removing deleted entries would free enough space - if (keyCount * 2 >= occupiedCount) { - // Need to grow: less then half of deleted entries - ++power; - } - int N = 1 << power; - object [] oldKeys = keys; - int [] oldValues = values; - int oldN = oldKeys.Length; - keys = new object [N]; - values = new int [2 * N]; - - int remaining = keyCount; - occupiedCount = keyCount = 0; - for (int i = 0; remaining != 0; ++i) { - object key = oldKeys [i]; - if (key != null && key != DELETED) { - int keyHash = oldValues [oldN + i]; - int index = insertNewKey (key, keyHash); - values [index] = oldValues [i]; - --remaining; - } - } - } - } - - // Ensure key index creating one if necessary - private int ensureIndex (object key) - { - int hash = key.GetHashCode (); - int index = -1; - int firstDeleted = -1; - if (keys != null) { - int fraction = hash * A; - index = (int)((uint)fraction >> (32 - power)); - object test = keys [index]; - if (test != null) { - int N = 1 << power; - if (test == key || (values [N + index] == hash && test.Equals (key))) { - return index; - } - if (test == DELETED) { - firstDeleted = index; - } - - // Search in table after first failed attempt - int mask = N - 1; - int step = tableLookupStep (fraction, mask, power); - int n = 0; - for (; ; ) { - if (check) { - if (n >= occupiedCount) - Context.CodeBug (); - ++n; - } - index = (index + step) & mask; - test = keys [index]; - if (test == null) { - break; - } - if (test == key || (values [N + index] == hash && test.Equals (key))) { - return index; - } - if (test == DELETED && firstDeleted < 0) { - firstDeleted = index; - } - } - } - } - // Inserting of new key - if (check && keys != null && keys [index] != null) - Context.CodeBug (); - if (firstDeleted >= 0) { - index = firstDeleted; - } - else { - // Need to consume empty entry: check occupation level - if (keys == null || occupiedCount * 4 >= (1 << power) * 3) { - // Too litle unused entries: rehash - rehashTable (); - return insertNewKey (key, hash); - } - ++occupiedCount; - } - keys [index] = key; - values [(1 << power) + index] = hash; - ++keyCount; - return index; - } - - // A == golden_ratio * (1 << 32) = ((sqrt(5) - 1) / 2) * (1 << 32) - // See Knuth etc. - private const int A = unchecked ((int)0x9e3779b9); - - private static readonly object DELETED = new object (); - - // Structure of kyes and values arrays (N == 1 << power): - // keys[0 <= i < N]: key value or null or DELETED mark - // values[0 <= i < N]: value of key at keys[i] - // values[N <= i < 2*N]: hash code of key at keys[i-N] - - - private object [] keys; - - private int [] values; - - private int power; - private int keyCount; - - private int occupiedCount; // == keyCount + deleted_count - - // If true, enables consitency checks - private static readonly bool check = false; // TODO: make me a preprocessor directive - - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; +using System.Runtime.InteropServices; + + +namespace EcmaScript.NET.Collections +{ + + /// Map to associate objects to integers. + /// The map does not synchronize any of its operation, so either use + /// it from a single thread or do own synchronization or perform all mutation + /// operations on one thread before passing the map to others + /// + /// + public class ObjToIntMap + { + virtual public bool Empty + { + get + { + return keyCount == 0; + } + + } + + // Map implementation via hashtable, + // follows "The Art of Computer Programming" by Donald E. Knuth + + // ObjToIntMap is a copy cat of ObjToIntMap with API adjusted to object keys + + public class Iterator + { + virtual public object Key + { + get + { + object key = keys [cursor]; + if (key == UniqueTag.NullValue) { + key = null; + } + return key; + } + + } + virtual public int Value + { + get + { + return values [cursor]; + } + + set + { + values [cursor] = value; + } + + } + + internal Iterator (ObjToIntMap master) + { + this.master = master; + } + + internal void Init (object [] keys, int [] values, int keyCount) + { + this.keys = keys; + this.values = values; + this.cursor = -1; + this.remaining = keyCount; + } + + public virtual void start () + { + master.initIterator (this); + next (); + } + + public virtual bool done () + { + return remaining < 0; + } + + public virtual void next () + { + if (remaining == -1) + Context.CodeBug (); + if (remaining == 0) { + remaining = -1; + cursor = -1; + } + else { + for (++cursor; ; ++cursor) { + object key = keys [cursor]; + if (key != null && key != ObjToIntMap.DELETED) { + --remaining; + break; + } + } + } + } + + internal ObjToIntMap master; + private int cursor; + private int remaining; + private object [] keys; + private int [] values; + } + + public ObjToIntMap () + : this (4) + { + } + + public ObjToIntMap (int keyCountHint) + { + if (keyCountHint < 0) + Context.CodeBug (); + // Table grow when number of stored keys >= 3/4 of max capacity + int minimalCapacity = keyCountHint * 4 / 3; + int i; + for (i = 2; (1 << i) < minimalCapacity; ++i) { + } + power = i; + if (check && power < 2) + Context.CodeBug (); + } + + public virtual int size () + { + return keyCount; + } + + public virtual bool has (object key) + { + if (key == null) { + key = UniqueTag.NullValue; + } + return 0 <= findIndex (key); + } + + /// Get integer value assigned with key. + /// key integer value or defaultValue if key is absent + /// + public virtual int Get (object key, int defaultValue) + { + if (key == null) { + key = UniqueTag.NullValue; + } + int index = findIndex (key); + if (0 <= index) { + return values [index]; + } + return defaultValue; + } + + /// Get integer value assigned with key. + /// key integer value + /// + /// RuntimeException if key does not exist + public virtual int getExisting (object key) + { + if (key == null) { + key = UniqueTag.NullValue; + } + int index = findIndex (key); + if (0 <= index) { + return values [index]; + } + // Key must exist + Context.CodeBug (); + return 0; + } + + public virtual void put (object key, int value) + { + if (key == null) { + key = UniqueTag.NullValue; + } + int index = ensureIndex (key); + values [index] = value; + } + + /// If table already contains a key that equals to keyArg, return that key + /// while setting its value to zero, otherwise add keyArg with 0 value to + /// the table and return it. + /// + public virtual object intern (object keyArg) + { + bool nullKey = false; + if (keyArg == null) { + nullKey = true; + keyArg = UniqueTag.NullValue; + } + int index = ensureIndex (keyArg); + values [index] = 0; + return (nullKey) ? null : keys [index]; + } + + public virtual void remove (object key) + { + if (key == null) { + key = UniqueTag.NullValue; + } + int index = findIndex (key); + if (0 <= index) { + keys [index] = DELETED; + --keyCount; + } + } + + public virtual void clear () + { + int i = keys.Length; + while (i != 0) { + keys [--i] = null; + } + keyCount = 0; + occupiedCount = 0; + } + + public virtual Iterator newIterator () + { + return new Iterator (this); + } + + // The sole purpose of the method is to avoid accessing private fields + // from the Iterator inner class to workaround JDK 1.1 compiler bug which + // generates code triggering VerifierError on recent JVMs + internal void initIterator (Iterator i) + { + i.Init (keys, values, keyCount); + } + + /// Return array of present keys + public virtual object [] getKeys () + { + object [] array = new object [keyCount]; + getKeys (array, 0); + return array; + } + + public virtual void getKeys (object [] array, int offset) + { + int count = keyCount; + for (int i = 0; count != 0; ++i) { + object key = keys [i]; + if (key != null && key != DELETED) { + if (key == UniqueTag.NullValue) { + key = null; + } + array [offset] = key; + ++offset; + --count; + } + } + } + + private static int tableLookupStep (int fraction, int mask, int power) + { + int shift = 32 - 2 * power; + if (shift >= 0) { + return ((int)(((uint)fraction >> shift)) & mask) | 1; + } + else { + return (fraction & (int)((uint)mask >> -shift)) | 1; + } + } + + private int findIndex (object key) + { + if (keys != null) { + int hash = key.GetHashCode (); + int fraction = hash * A; + int index = (int)((uint)fraction >> (32 - power)); + object test = keys [index]; + if (test != null) { + int N = 1 << power; + if (test == key || (values [N + index] == hash && test.Equals (key))) { + return index; + } + // Search in table after first failed attempt + int mask = N - 1; + int step = tableLookupStep (fraction, mask, power); + int n = 0; + for (; ; ) { + if (check) { + if (n >= occupiedCount) + Context.CodeBug (); + ++n; + } + index = (index + step) & mask; + test = keys [index]; + if (test == null) { + break; + } + if (test == key || (values [N + index] == hash && test.Equals (key))) { + return index; + } + } + } + } + return -1; + } + + // Insert key that is not present to table without deleted entries + // and enough free space + private int insertNewKey (object key, int hash) + { + if (check && occupiedCount != keyCount) + Context.CodeBug (); + if (check && keyCount == 1 << power) + Context.CodeBug (); + int fraction = hash * A; + int index = (int)((uint)fraction >> (32 - power)); + int N = 1 << power; + if (keys [index] != null) { + int mask = N - 1; + int step = tableLookupStep (fraction, mask, power); + int firstIndex = index; + do { + if (check && keys [index] == DELETED) + Context.CodeBug (); + index = (index + step) & mask; + if (check && firstIndex == index) + Context.CodeBug (); + } + while (keys [index] != null); + } + keys [index] = key; + values [N + index] = hash; + ++occupiedCount; + ++keyCount; + + return index; + } + + private void rehashTable () + { + if (keys == null) { + if (check && keyCount != 0) + Context.CodeBug (); + if (check && occupiedCount != 0) + Context.CodeBug (); + int N = 1 << power; + keys = new object [N]; + values = new int [2 * N]; + } + else { + // Check if removing deleted entries would free enough space + if (keyCount * 2 >= occupiedCount) { + // Need to grow: less then half of deleted entries + ++power; + } + int N = 1 << power; + object [] oldKeys = keys; + int [] oldValues = values; + int oldN = oldKeys.Length; + keys = new object [N]; + values = new int [2 * N]; + + int remaining = keyCount; + occupiedCount = keyCount = 0; + for (int i = 0; remaining != 0; ++i) { + object key = oldKeys [i]; + if (key != null && key != DELETED) { + int keyHash = oldValues [oldN + i]; + int index = insertNewKey (key, keyHash); + values [index] = oldValues [i]; + --remaining; + } + } + } + } + + // Ensure key index creating one if necessary + private int ensureIndex (object key) + { + int hash = key.GetHashCode (); + int index = -1; + int firstDeleted = -1; + if (keys != null) { + int fraction = hash * A; + index = (int)((uint)fraction >> (32 - power)); + object test = keys [index]; + if (test != null) { + int N = 1 << power; + if (test == key || (values [N + index] == hash && test.Equals (key))) { + return index; + } + if (test == DELETED) { + firstDeleted = index; + } + + // Search in table after first failed attempt + int mask = N - 1; + int step = tableLookupStep (fraction, mask, power); + int n = 0; + for (; ; ) { + if (check) { + if (n >= occupiedCount) + Context.CodeBug (); + ++n; + } + index = (index + step) & mask; + test = keys [index]; + if (test == null) { + break; + } + if (test == key || (values [N + index] == hash && test.Equals (key))) { + return index; + } + if (test == DELETED && firstDeleted < 0) { + firstDeleted = index; + } + } + } + } + // Inserting of new key + if (check && keys != null && keys [index] != null) + Context.CodeBug (); + if (firstDeleted >= 0) { + index = firstDeleted; + } + else { + // Need to consume empty entry: check occupation level + if (keys == null || occupiedCount * 4 >= (1 << power) * 3) { + // Too litle unused entries: rehash + rehashTable (); + return insertNewKey (key, hash); + } + ++occupiedCount; + } + keys [index] = key; + values [(1 << power) + index] = hash; + ++keyCount; + return index; + } + + // A == golden_ratio * (1 << 32) = ((sqrt(5) - 1) / 2) * (1 << 32) + // See Knuth etc. + private const int A = unchecked ((int)0x9e3779b9); + + private static readonly object DELETED = new object (); + + // Structure of kyes and values arrays (N == 1 << power): + // keys[0 <= i < N]: key value or null or DELETED mark + // values[0 <= i < N]: value of key at keys[i] + // values[N <= i < 2*N]: hash code of key at keys[i-N] + + + private object [] keys; + + private int [] values; + + private int power; + private int keyCount; + + private int occupiedCount; // == keyCount + deleted_count + + // If true, enables consitency checks + private static readonly bool check = false; // TODO: make me a preprocessor directive + + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/Collections/UintMap.cs b/src/EcmaScript.NET/Collections/UintMap.cs similarity index 97% rename from Code/EcmaScript.NET/Collections/UintMap.cs rename to src/EcmaScript.NET/Collections/UintMap.cs index 3f77b66..4f3360e 100644 --- a/Code/EcmaScript.NET/Collections/UintMap.cs +++ b/src/EcmaScript.NET/Collections/UintMap.cs @@ -1,428 +1,428 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; -using System.Runtime.InteropServices; - -namespace EcmaScript.NET.Collections -{ - - /// Map to associate non-negative integers to objects or integers. - /// The map does not synchronize any of its operation, so either use - /// it from a single thread or do own synchronization or perform all mutation - /// operations on one thread before passing the map to others. - /// - /// - - public class UintMap - { - virtual public bool Empty - { - get - { - return keyCount == 0; - } - - } - /// Return array of present keys - virtual public int [] Keys - { - get - { - int [] keys = this.keys; - int n = keyCount; - int [] result = new int [n]; - for (int i = 0; n != 0; ++i) { - int entry = keys [i]; - if (entry != EMPTY && entry != DELETED) { - result [--n] = entry; - } - } - return result; - } - - } - - // Map implementation via hashtable, - // follows "The Art of Computer Programming" by Donald E. Knuth - - public UintMap () - : this (4) - { - } - - public UintMap (int initialCapacity) - { - if (initialCapacity < 0) - Context.CodeBug (); - // Table grow when number of stored keys >= 3/4 of max capacity - int minimalCapacity = initialCapacity * 4 / 3; - int i; - for (i = 2; (1 << i) < minimalCapacity; ++i) { - } - power = i; - if (check && power < 2) - Context.CodeBug (); - } - - public virtual int size () - { - return keyCount; - } - - public virtual bool has (int key) - { - if (key < 0) - Context.CodeBug (); - return 0 <= findIndex (key); - } - - /// Get object value assigned with key. - /// key object value or null if key is absent - /// - public virtual object getObject (int key) - { - if (key < 0) - Context.CodeBug (); - if (values != null) { - int index = findIndex (key); - if (0 <= index) { - return values [index]; - } - } - return null; - } - - /// Get integer value assigned with key. - /// key integer value or defaultValue if key is absent - /// - public virtual int getInt (int key, int defaultValue) - { - if (key < 0) - Context.CodeBug (); - int index = findIndex (key); - if (0 <= index) { - if (ivaluesShift != 0) { - return keys [ivaluesShift + index]; - } - return 0; - } - return defaultValue; - } - - /// Get integer value assigned with key. - /// key integer value or defaultValue if key does not exist or does - /// not have int value - /// - /// RuntimeException if key does not exist - public virtual int getExistingInt (int key) - { - if (key < 0) - Context.CodeBug (); - int index = findIndex (key); - if (0 <= index) { - if (ivaluesShift != 0) { - return keys [ivaluesShift + index]; - } - return 0; - } - // Key must exist - Context.CodeBug (); - return 0; - } - - /// Set object value of the key. - /// If key does not exist, also set its int value to 0. - /// - public virtual void put (int key, object value) - { - if (key < 0) - Context.CodeBug (); - int index = ensureIndex (key, false); - if (values == null) { - values = new object [1 << power]; - } - values [index] = value; - } - - /// Set int value of the key. - /// If key does not exist, also set its object value to null. - /// - public virtual void put (int key, int value) - { - if (key < 0) - Context.CodeBug (); - int index = ensureIndex (key, true); - if (ivaluesShift == 0) { - int N = 1 << power; - // keys.length can be N * 2 after clear which set ivaluesShift to 0 - if (keys.Length != N * 2) { - int [] tmp = new int [N * 2]; - Array.Copy (keys, 0, tmp, 0, N); - keys = tmp; - } - ivaluesShift = N; - } - keys [ivaluesShift + index] = value; - } - - public virtual void remove (int key) - { - if (key < 0) - Context.CodeBug (); - int index = findIndex (key); - if (0 <= index) { - keys [index] = DELETED; - --keyCount; - // Allow to GC value and make sure that new key with the deleted - // slot shall get proper default values - if (values != null) { - values [index] = null; - } - if (ivaluesShift != 0) { - keys [ivaluesShift + index] = 0; - } - } - } - - public virtual void clear () - { - int N = 1 << power; - if (keys != null) { - for (int i = 0; i != N; ++i) { - keys [i] = EMPTY; - } - if (values != null) { - for (int i = 0; i != N; ++i) { - values [i] = null; - } - } - } - ivaluesShift = 0; - keyCount = 0; - occupiedCount = 0; - } - - private static int tableLookupStep (int fraction, int mask, int power) - { - int shift = 32 - 2 * power; - if (shift >= 0) { - return (((int)((uint)fraction >> shift)) & mask) | 1; - } - else { - return (fraction & (int)((uint)mask >> -shift)) | 1; - } - } - - private int findIndex (int key) - { - int [] keys = this.keys; - if (keys != null) { - int fraction = key * A; - int index = (int)((uint)fraction >> (32 - power)); - int entry = keys [index]; - if (entry == key) { - return index; - } - if (entry != EMPTY) { - // Search in table after first failed attempt - int mask = (1 << power) - 1; - int step = tableLookupStep (fraction, mask, power); - int n = 0; - do { - if (check) { - if (n >= occupiedCount) - Context.CodeBug (); - ++n; - } - index = (index + step) & mask; - entry = keys [index]; - if (entry == key) { - return index; - } - } - while (entry != EMPTY); - } - } - return -1; - } - - // Insert key that is not present to table without deleted entries - // and enough free space - private int insertNewKey (int key) - { - if (check && occupiedCount != keyCount) - Context.CodeBug (); - if (check && keyCount == 1 << power) - Context.CodeBug (); - int [] keys = this.keys; - int fraction = key * A; - int index = (int)((uint)fraction >> (32 - power)); - if (keys [index] != EMPTY) { - int mask = (1 << power) - 1; - int step = tableLookupStep (fraction, mask, power); - int firstIndex = index; - do { - if (check && keys [index] == DELETED) - Context.CodeBug (); - index = (index + step) & mask; - if (check && firstIndex == index) - Context.CodeBug (); - } - while (keys [index] != EMPTY); - } - keys [index] = key; - ++occupiedCount; - ++keyCount; - return index; - } - - private void rehashTable (bool ensureIntSpace) - { - if (keys != null) { - // Check if removing deleted entries would free enough space - if (keyCount * 2 >= occupiedCount) { - // Need to grow: less then half of deleted entries - ++power; - } - } - int N = 1 << power; - int [] old = keys; - int oldShift = ivaluesShift; - if (oldShift == 0 && !ensureIntSpace) { - keys = new int [N]; - } - else { - ivaluesShift = N; - keys = new int [N * 2]; - } - for (int i = 0; i != N; ++i) { - keys [i] = EMPTY; - } - - object [] oldValues = values; - if (oldValues != null) { - values = new object [N]; - } - - int oldCount = keyCount; - occupiedCount = 0; - if (oldCount != 0) { - keyCount = 0; - for (int i = 0, remaining = oldCount; remaining != 0; ++i) { - int key = old [i]; - if (key != EMPTY && key != DELETED) { - int index = insertNewKey (key); - if (oldValues != null) { - values [index] = oldValues [i]; - } - if (oldShift != 0) { - keys [ivaluesShift + index] = old [oldShift + i]; - } - --remaining; - } - } - } - } - - // Ensure key index creating one if necessary - private int ensureIndex (int key, bool intType) - { - int index = -1; - int firstDeleted = -1; - int [] keys = this.keys; - if (keys != null) { - int fraction = key * A; - index = (int)((uint)fraction >> (32 - power)); - int entry = keys [index]; - if (entry == key) { - return index; - } - if (entry != EMPTY) { - if (entry == DELETED) { - firstDeleted = index; - } - // Search in table after first failed attempt - int mask = (1 << power) - 1; - int step = tableLookupStep (fraction, mask, power); - int n = 0; - do { - if (check) { - if (n >= occupiedCount) - Context.CodeBug (); - ++n; - } - index = (index + step) & mask; - entry = keys [index]; - if (entry == key) { - return index; - } - if (entry == DELETED && firstDeleted < 0) { - firstDeleted = index; - } - } - while (entry != EMPTY); - } - } - // Inserting of new key - if (check && keys != null && keys [index] != EMPTY) - Context.CodeBug (); - if (firstDeleted >= 0) { - index = firstDeleted; - } - else { - // Need to consume empty entry: check occupation level - if (keys == null || occupiedCount * 4 >= (1 << power) * 3) { - // Too litle unused entries: rehash - rehashTable (intType); - keys = this.keys; - return insertNewKey (key); - } - ++occupiedCount; - } - keys [index] = key; - ++keyCount; - return index; - } - // A == golden_ratio * (1 << 32) = ((sqrt(5) - 1) / 2) * (1 << 32) - // See Knuth etc. - private const int A = unchecked ((int)0x9e3779b9); - - private const int EMPTY = -1; - private const int DELETED = -2; - - // Structure of kyes and values arrays (N == 1 << power): - // keys[0 <= i < N]: key value or EMPTY or DELETED mark - // values[0 <= i < N]: value of key at keys[i] - // keys[N <= i < 2N]: int values of keys at keys[i - N] - - - private int [] keys; - - private object [] values; - - private int power; - private int keyCount; - - private int occupiedCount; // == keyCount + deleted_count - - // If ivaluesShift != 0, keys[ivaluesShift + index] contains integer - // values associated with keys - - private int ivaluesShift; - - // If true, enables consitency checks - private static readonly bool check = false; // TODO: make me a preprocessor directive - - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; +using System.Runtime.InteropServices; + +namespace EcmaScript.NET.Collections +{ + + /// Map to associate non-negative integers to objects or integers. + /// The map does not synchronize any of its operation, so either use + /// it from a single thread or do own synchronization or perform all mutation + /// operations on one thread before passing the map to others. + /// + /// + + public class UintMap + { + virtual public bool Empty + { + get + { + return keyCount == 0; + } + + } + /// Return array of present keys + virtual public int [] Keys + { + get + { + int [] keys = this.keys; + int n = keyCount; + int [] result = new int [n]; + for (int i = 0; n != 0; ++i) { + int entry = keys [i]; + if (entry != EMPTY && entry != DELETED) { + result [--n] = entry; + } + } + return result; + } + + } + + // Map implementation via hashtable, + // follows "The Art of Computer Programming" by Donald E. Knuth + + public UintMap () + : this (4) + { + } + + public UintMap (int initialCapacity) + { + if (initialCapacity < 0) + Context.CodeBug (); + // Table grow when number of stored keys >= 3/4 of max capacity + int minimalCapacity = initialCapacity * 4 / 3; + int i; + for (i = 2; (1 << i) < minimalCapacity; ++i) { + } + power = i; + if (check && power < 2) + Context.CodeBug (); + } + + public virtual int size () + { + return keyCount; + } + + public virtual bool has (int key) + { + if (key < 0) + Context.CodeBug (); + return 0 <= findIndex (key); + } + + /// Get object value assigned with key. + /// key object value or null if key is absent + /// + public virtual object getObject (int key) + { + if (key < 0) + Context.CodeBug (); + if (values != null) { + int index = findIndex (key); + if (0 <= index) { + return values [index]; + } + } + return null; + } + + /// Get integer value assigned with key. + /// key integer value or defaultValue if key is absent + /// + public virtual int getInt (int key, int defaultValue) + { + if (key < 0) + Context.CodeBug (); + int index = findIndex (key); + if (0 <= index) { + if (ivaluesShift != 0) { + return keys [ivaluesShift + index]; + } + return 0; + } + return defaultValue; + } + + /// Get integer value assigned with key. + /// key integer value or defaultValue if key does not exist or does + /// not have int value + /// + /// RuntimeException if key does not exist + public virtual int getExistingInt (int key) + { + if (key < 0) + Context.CodeBug (); + int index = findIndex (key); + if (0 <= index) { + if (ivaluesShift != 0) { + return keys [ivaluesShift + index]; + } + return 0; + } + // Key must exist + Context.CodeBug (); + return 0; + } + + /// Set object value of the key. + /// If key does not exist, also set its int value to 0. + /// + public virtual void put (int key, object value) + { + if (key < 0) + Context.CodeBug (); + int index = ensureIndex (key, false); + if (values == null) { + values = new object [1 << power]; + } + values [index] = value; + } + + /// Set int value of the key. + /// If key does not exist, also set its object value to null. + /// + public virtual void put (int key, int value) + { + if (key < 0) + Context.CodeBug (); + int index = ensureIndex (key, true); + if (ivaluesShift == 0) { + int N = 1 << power; + // keys.length can be N * 2 after clear which set ivaluesShift to 0 + if (keys.Length != N * 2) { + int [] tmp = new int [N * 2]; + Array.Copy (keys, 0, tmp, 0, N); + keys = tmp; + } + ivaluesShift = N; + } + keys [ivaluesShift + index] = value; + } + + public virtual void remove (int key) + { + if (key < 0) + Context.CodeBug (); + int index = findIndex (key); + if (0 <= index) { + keys [index] = DELETED; + --keyCount; + // Allow to GC value and make sure that new key with the deleted + // slot shall get proper default values + if (values != null) { + values [index] = null; + } + if (ivaluesShift != 0) { + keys [ivaluesShift + index] = 0; + } + } + } + + public virtual void clear () + { + int N = 1 << power; + if (keys != null) { + for (int i = 0; i != N; ++i) { + keys [i] = EMPTY; + } + if (values != null) { + for (int i = 0; i != N; ++i) { + values [i] = null; + } + } + } + ivaluesShift = 0; + keyCount = 0; + occupiedCount = 0; + } + + private static int tableLookupStep (int fraction, int mask, int power) + { + int shift = 32 - 2 * power; + if (shift >= 0) { + return (((int)((uint)fraction >> shift)) & mask) | 1; + } + else { + return (fraction & (int)((uint)mask >> -shift)) | 1; + } + } + + private int findIndex (int key) + { + int [] keys = this.keys; + if (keys != null) { + int fraction = key * A; + int index = (int)((uint)fraction >> (32 - power)); + int entry = keys [index]; + if (entry == key) { + return index; + } + if (entry != EMPTY) { + // Search in table after first failed attempt + int mask = (1 << power) - 1; + int step = tableLookupStep (fraction, mask, power); + int n = 0; + do { + if (check) { + if (n >= occupiedCount) + Context.CodeBug (); + ++n; + } + index = (index + step) & mask; + entry = keys [index]; + if (entry == key) { + return index; + } + } + while (entry != EMPTY); + } + } + return -1; + } + + // Insert key that is not present to table without deleted entries + // and enough free space + private int insertNewKey (int key) + { + if (check && occupiedCount != keyCount) + Context.CodeBug (); + if (check && keyCount == 1 << power) + Context.CodeBug (); + int [] keys = this.keys; + int fraction = key * A; + int index = (int)((uint)fraction >> (32 - power)); + if (keys [index] != EMPTY) { + int mask = (1 << power) - 1; + int step = tableLookupStep (fraction, mask, power); + int firstIndex = index; + do { + if (check && keys [index] == DELETED) + Context.CodeBug (); + index = (index + step) & mask; + if (check && firstIndex == index) + Context.CodeBug (); + } + while (keys [index] != EMPTY); + } + keys [index] = key; + ++occupiedCount; + ++keyCount; + return index; + } + + private void rehashTable (bool ensureIntSpace) + { + if (keys != null) { + // Check if removing deleted entries would free enough space + if (keyCount * 2 >= occupiedCount) { + // Need to grow: less then half of deleted entries + ++power; + } + } + int N = 1 << power; + int [] old = keys; + int oldShift = ivaluesShift; + if (oldShift == 0 && !ensureIntSpace) { + keys = new int [N]; + } + else { + ivaluesShift = N; + keys = new int [N * 2]; + } + for (int i = 0; i != N; ++i) { + keys [i] = EMPTY; + } + + object [] oldValues = values; + if (oldValues != null) { + values = new object [N]; + } + + int oldCount = keyCount; + occupiedCount = 0; + if (oldCount != 0) { + keyCount = 0; + for (int i = 0, remaining = oldCount; remaining != 0; ++i) { + int key = old [i]; + if (key != EMPTY && key != DELETED) { + int index = insertNewKey (key); + if (oldValues != null) { + values [index] = oldValues [i]; + } + if (oldShift != 0) { + keys [ivaluesShift + index] = old [oldShift + i]; + } + --remaining; + } + } + } + } + + // Ensure key index creating one if necessary + private int ensureIndex (int key, bool intType) + { + int index = -1; + int firstDeleted = -1; + int [] keys = this.keys; + if (keys != null) { + int fraction = key * A; + index = (int)((uint)fraction >> (32 - power)); + int entry = keys [index]; + if (entry == key) { + return index; + } + if (entry != EMPTY) { + if (entry == DELETED) { + firstDeleted = index; + } + // Search in table after first failed attempt + int mask = (1 << power) - 1; + int step = tableLookupStep (fraction, mask, power); + int n = 0; + do { + if (check) { + if (n >= occupiedCount) + Context.CodeBug (); + ++n; + } + index = (index + step) & mask; + entry = keys [index]; + if (entry == key) { + return index; + } + if (entry == DELETED && firstDeleted < 0) { + firstDeleted = index; + } + } + while (entry != EMPTY); + } + } + // Inserting of new key + if (check && keys != null && keys [index] != EMPTY) + Context.CodeBug (); + if (firstDeleted >= 0) { + index = firstDeleted; + } + else { + // Need to consume empty entry: check occupation level + if (keys == null || occupiedCount * 4 >= (1 << power) * 3) { + // Too litle unused entries: rehash + rehashTable (intType); + keys = this.keys; + return insertNewKey (key); + } + ++occupiedCount; + } + keys [index] = key; + ++keyCount; + return index; + } + // A == golden_ratio * (1 << 32) = ((sqrt(5) - 1) / 2) * (1 << 32) + // See Knuth etc. + private const int A = unchecked ((int)0x9e3779b9); + + private const int EMPTY = -1; + private const int DELETED = -2; + + // Structure of kyes and values arrays (N == 1 << power): + // keys[0 <= i < N]: key value or EMPTY or DELETED mark + // values[0 <= i < N]: value of key at keys[i] + // keys[N <= i < 2N]: int values of keys at keys[i - N] + + + private int [] keys; + + private object [] values; + + private int power; + private int keyCount; + + private int occupiedCount; // == keyCount + deleted_count + + // If ivaluesShift != 0, keys[ivaluesShift + index] contains integer + // values associated with keys + + private int ivaluesShift; + + // If true, enables consitency checks + private static readonly bool check = false; // TODO: make me a preprocessor directive + + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/CompilerEnvirons.cs b/src/EcmaScript.NET/CompilerEnvirons.cs similarity index 96% rename from Code/EcmaScript.NET/CompilerEnvirons.cs rename to src/EcmaScript.NET/CompilerEnvirons.cs index 4894638..9e376ff 100644 --- a/Code/EcmaScript.NET/CompilerEnvirons.cs +++ b/src/EcmaScript.NET/CompilerEnvirons.cs @@ -1,166 +1,166 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; -using System.Collections; - -namespace EcmaScript.NET -{ - - public class CompilerEnvirons - { - virtual public bool UseDynamicScope - { - get - { - return useDynamicScope; - } - - } - public CompilerEnvirons () - { - errorReporter = DefaultErrorReporter.instance; - languageVersion = Context.Versions.Default; - generateDebugInfo = true; - useDynamicScope = false; - reservedKeywordAsIdentifier = false; - allowMemberExprAsFunctionName = false; - xmlAvailable = true; - optimizationLevel = 0; - generatingSource = true; - } - - public virtual void initFromContext (Context cx) - { - setErrorReporter (cx.ErrorReporter); - this.languageVersion = cx.Version; - useDynamicScope = cx.compileFunctionsWithDynamicScopeFlag; - generateDebugInfo = (!cx.GeneratingDebugChanged || cx.GeneratingDebug); - reservedKeywordAsIdentifier = cx.HasFeature (Context.Features.ReservedKeywordAsIdentifier); - allowMemberExprAsFunctionName = cx.HasFeature (Context.Features.MemberExprAsFunctionName); - xmlAvailable = cx.HasFeature (Context.Features.E4x); - getterAndSetterSupport = cx.HasFeature (Context.Features.GetterAndSetter); - - optimizationLevel = cx.OptimizationLevel; - - generatingSource = cx.GeneratingSource; - activationNames = cx.activationNames; - } - - public ErrorReporter getErrorReporter () - { - return errorReporter; - } - - public virtual void setErrorReporter (ErrorReporter errorReporter) - { - if (errorReporter == null) - throw new ArgumentException (); - this.errorReporter = errorReporter; - } - - public Context.Versions LanguageVersion - { - get - { - return languageVersion; - } - set - { - languageVersion = value; - } - } - - public bool isGenerateDebugInfo () - { - return generateDebugInfo; - } - - public virtual void setGenerateDebugInfo (bool flag) - { - this.generateDebugInfo = flag; - } - - public bool isReservedKeywordAsIdentifier () - { - return reservedKeywordAsIdentifier; - } - - public virtual void setReservedKeywordAsIdentifier (bool flag) - { - reservedKeywordAsIdentifier = flag; - } - - public bool isAllowMemberExprAsFunctionName () - { - return allowMemberExprAsFunctionName; - } - - public virtual void setAllowMemberExprAsFunctionName (bool flag) - { - allowMemberExprAsFunctionName = flag; - } - - public bool isXmlAvailable () - { - return xmlAvailable; - } - - public virtual void setXmlAvailable (bool flag) - { - xmlAvailable = flag; - } - - public int getOptimizationLevel () - { - return optimizationLevel; - } - - public virtual void setOptimizationLevel (int level) - { - Context.CheckOptimizationLevel (level); - this.optimizationLevel = level; - } - - public bool isGeneratingSource () - { - return generatingSource; - } - - /// Specify whether or not source information should be generated. - ///

- /// Without source information, evaluating the "toString" method - /// on JavaScript functions produces only "[native code]" for - /// the body of the function. - /// Note that code generated without source is not fully ECMA - /// conformant. - ///

- public virtual void setGeneratingSource (bool generatingSource) - { - this.generatingSource = generatingSource; - } - - private ErrorReporter errorReporter; - - private Context.Versions languageVersion; - private bool generateDebugInfo; - private bool useDynamicScope; - private bool reservedKeywordAsIdentifier; - private bool allowMemberExprAsFunctionName; - private bool xmlAvailable; - private int optimizationLevel; - private bool generatingSource; - internal Hashtable activationNames; - internal bool getterAndSetterSupport; - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; +using System.Collections; + +namespace EcmaScript.NET +{ + + public class CompilerEnvirons + { + virtual public bool UseDynamicScope + { + get + { + return useDynamicScope; + } + + } + public CompilerEnvirons () + { + errorReporter = DefaultErrorReporter.instance; + languageVersion = Context.Versions.Default; + generateDebugInfo = true; + useDynamicScope = false; + reservedKeywordAsIdentifier = false; + allowMemberExprAsFunctionName = false; + xmlAvailable = true; + optimizationLevel = 0; + generatingSource = true; + } + + public virtual void initFromContext (Context cx) + { + setErrorReporter (cx.ErrorReporter); + this.languageVersion = cx.Version; + useDynamicScope = cx.compileFunctionsWithDynamicScopeFlag; + generateDebugInfo = (!cx.GeneratingDebugChanged || cx.GeneratingDebug); + reservedKeywordAsIdentifier = cx.HasFeature (Context.Features.ReservedKeywordAsIdentifier); + allowMemberExprAsFunctionName = cx.HasFeature (Context.Features.MemberExprAsFunctionName); + xmlAvailable = cx.HasFeature (Context.Features.E4x); + getterAndSetterSupport = cx.HasFeature (Context.Features.GetterAndSetter); + + optimizationLevel = cx.OptimizationLevel; + + generatingSource = cx.GeneratingSource; + activationNames = cx.activationNames; + } + + public ErrorReporter getErrorReporter () + { + return errorReporter; + } + + public virtual void setErrorReporter (ErrorReporter errorReporter) + { + if (errorReporter == null) + throw new ArgumentException (); + this.errorReporter = errorReporter; + } + + public Context.Versions LanguageVersion + { + get + { + return languageVersion; + } + set + { + languageVersion = value; + } + } + + public bool isGenerateDebugInfo () + { + return generateDebugInfo; + } + + public virtual void setGenerateDebugInfo (bool flag) + { + this.generateDebugInfo = flag; + } + + public bool isReservedKeywordAsIdentifier () + { + return reservedKeywordAsIdentifier; + } + + public virtual void setReservedKeywordAsIdentifier (bool flag) + { + reservedKeywordAsIdentifier = flag; + } + + public bool isAllowMemberExprAsFunctionName () + { + return allowMemberExprAsFunctionName; + } + + public virtual void setAllowMemberExprAsFunctionName (bool flag) + { + allowMemberExprAsFunctionName = flag; + } + + public bool isXmlAvailable () + { + return xmlAvailable; + } + + public virtual void setXmlAvailable (bool flag) + { + xmlAvailable = flag; + } + + public int getOptimizationLevel () + { + return optimizationLevel; + } + + public virtual void setOptimizationLevel (int level) + { + Context.CheckOptimizationLevel (level); + this.optimizationLevel = level; + } + + public bool isGeneratingSource () + { + return generatingSource; + } + + /// Specify whether or not source information should be generated. + ///

+ /// Without source information, evaluating the "toString" method + /// on JavaScript functions produces only "[native code]" for + /// the body of the function. + /// Note that code generated without source is not fully ECMA + /// conformant. + ///

+ public virtual void setGeneratingSource (bool generatingSource) + { + this.generatingSource = generatingSource; + } + + private ErrorReporter errorReporter; + + private Context.Versions languageVersion; + private bool generateDebugInfo; + private bool useDynamicScope; + private bool reservedKeywordAsIdentifier; + private bool allowMemberExprAsFunctionName; + private bool xmlAvailable; + private int optimizationLevel; + private bool generatingSource; + internal Hashtable activationNames; + internal bool getterAndSetterSupport; + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/Context.cs b/src/EcmaScript.NET/Context.cs similarity index 96% rename from Code/EcmaScript.NET/Context.cs rename to src/EcmaScript.NET/Context.cs index 4d8432a..cc85274 100644 --- a/Code/EcmaScript.NET/Context.cs +++ b/src/EcmaScript.NET/Context.cs @@ -1,2013 +1,2013 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; -using System.IO; -using System.Threading; -using System.Globalization; -using System.Reflection; -using System.Collections; - -using EcmaScript.NET.Debugging; -using EcmaScript.NET.Collections; -using EcmaScript.NET.Types; -using EcmaScript.NET.Types.Cli; -using EcmaScript.NET.Types.E4X; - -namespace EcmaScript.NET -{ - - /// - /// This class represents the runtime context of an executing script. - /// - /// Before executing a script, an instance of Context must be created - /// and associated with the thread that will be executing the script. - /// The Context will be used to store information about the executing - /// of the script such as the call stack. Contexts are associated with - /// the current thread using the {@link #call(ContextAction)} - /// or {@link #enter()} methods.

- /// - /// Different forms of script execution are supported. Scripts may be - /// evaluated from the source directly, or first compiled and then later - /// executed. Interactive execution is also supported.

- /// - /// Some aspects of script execution, such as type conversions and - /// object creation, may be accessed directly through methods of - /// Context. - /// - ///

- public class Context : IDisposable - { - - public enum Features - { - /// - /// No features at all - /// - None = 0, - - /// - /// Support for E4X - /// - E4x = 1 << 1, - - /// - /// Support for get and set - /// - GetterAndSetter = 1 << 2, - - /// - /// - /// - NonEcmaGetYear = 1 << 3, - - /// Control if dynamic scope should be used for name access. - /// If hasFeature(FEATURE_DYNAMIC_SCOPE) returns true, then the name lookup - /// during name resolution will use the top scope of the script or function - /// which is at the top of JS execution stack instead of the top scope of the - /// script or function from the current stack frame if the top scope of - /// the top stack frame contains the top scope of the current stack frame - /// on its prototype chain. - ///

- /// This is useful to define shared scope containing functions that can - /// be called from scripts and functions using private scopes. - ///

- /// By default {@link #hasFeature(int)} returns false. - ///

- DynamicScope = 1 << 4, - /// Control if member expression as function name extension is available. - /// If hasFeature(FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME) returns - /// true, allow function memberExpression(args) { body } to be - /// syntax sugar for memberExpression = function(args) { body }, - /// when memberExpression is not a simple identifier. - /// See ECMAScript-262, section 11.2 for definition of memberExpression. - /// By default {@link #hasFeature(int)} returns false. - /// - MemberExprAsFunctionName = 1 << 5, - - /// Control if reserved keywords are treated as identifiers. - /// If hasFeature(RESERVED_KEYWORD_AS_IDENTIFIER) returns true, - /// treat future reserved keyword (see Ecma-262, section 7.5.3) as ordinary - /// identifiers but warn about this usage. - /// - /// By default {@link #hasFeature(int)} returns false. - /// - ReservedKeywordAsIdentifier = 1 << 6, - - /// Control if toString() should returns the same result - /// as toSource() when applied to objects and arrays. - /// If hasFeature(FEATURE_TO_STRING_AS_SOURCE) returns true, - /// calling toString() on JS objects gives the same result as - /// calling toSource(). That is it returns JS source with code - /// to create an object with all enumeratable fields of the original object - /// instead of printing [object result of - /// {@link Scriptable#getClassName()}]. - ///

- /// By default {@link #hasFeature(int)} returns true only if - /// the current JS version is set to {@link #Versions.JS1_2}. - ///

- ToStringAsSource = 1 << 7, - - /// Control if properties __proto__ and __parent__ - /// are treated specially. - /// If hasFeature(FEATURE_PARENT_PROTO_PROPRTIES) returns true, - /// treat __parent__ and __proto__ as special properties. - ///

- /// The properties allow to query and set scope and prototype chains for the - /// objects. The special meaning of the properties is available - /// only when they are used as the right hand side of the dot operator. - /// For example, while x.__proto__ = y changes the prototype - /// chain of the object x to point to y, - /// x["__proto__"] = y simply assigns a new value to the property - /// __proto__ in x even when the feature is on. - /// - /// By default {@link #hasFeature(int)} returns true. - ///

- ParentProtoProperties = 1 << 8, - - /// Control if strict variable mode is enabled. - /// When the feature is on Rhino reports runtime errors if assignment - /// to a global variable that does not exist is executed. When the feature - /// is off such assignments creates new variable in the global scope as - /// required by ECMA 262. - ///

- /// By default {@link #hasFeature(int)} returns false. - ///

- StrictVars = 1 << 9, - - /// Control if strict eval mode is enabled. - /// When the feature is on Rhino reports runtime errors if non-string - /// argument is passed to the eval function. When the feature is off - /// eval simply return non-string argument as is without performing any - /// evaluation as required by ECMA 262. - ///

- /// By default {@link #hasFeature(int)} returns false. - ///

- StrictEval = 1 << 10, - - /// - /// Controls if the non-ecma function 'print' is available or not. - /// - NonEcmaPrintFunction = 1 << 11, - - /// - /// Controls if the non-ecma function 'version' is available or not - /// - NonEcmaVersionFunction = 1 << 12, - - /// - /// Controls if the non-ecma function 'options' is available or not - /// - NonEcmaOptionsFunction = 1 << 13, - - Strict = 1 << 14, - - /// - /// Controls if the non-ecma function 'options' is available or not - /// - NonEcmaGcFunction = 1 << 14, - - /// - /// The famous 'it' object (@see js.c:2315) - /// - NonEcmaItObject = 1 << 15, - - } - - public enum Versions - { - Unknown = -1, - Default = 0, - JS1_0 = 100, - JS1_1 = 110, - JS1_2 = 120, - JS1_3 = 130, - JS1_4 = 140, - JS1_5 = 150, - JS1_6 = 160 - } - - /// - /// - /// - public event ContextWrapHandler OnWrap; - - private int m_MaximumInterpreterStackDepth = 8092; - - /// - /// - /// - public int MaximumInterpreterStackDepth - { - get - { - return m_MaximumInterpreterStackDepth; - } - set - { - if (Sealed) - OnSealedMutation (); - m_MaximumInterpreterStackDepth = value; - } - } - - private AppDomain m_AppDomain = null; - - /// - /// Associated app domain - /// - public AppDomain AppDomain - { - get { return m_AppDomain; } - } - - private static LocalDataStoreSlot LocalSlot - { - get - { - LocalDataStoreSlot slot = Thread.GetNamedDataSlot ("Context"); - if (slot == null) { - slot = Thread.AllocateNamedDataSlot ("Context"); - } - return slot; - } - } - - /// Get the current Context. - /// - /// The current Context is per-thread; this method looks up - /// the Context associated with the current thread.

- /// - ///

- /// the Context associated with the current thread, or - /// null if no context is associated with the current - /// thread. - /// - public static Context CurrentContext - { - get - { - Context cx = (Context)Thread.GetData (LocalSlot); - return cx; - } - } - - /// Return {@link ContextFactory} instance used to create this Context - /// or the result of {@link ContextFactory#getGlobal()} if no factory - /// was used for Context creation. - /// - public ContextFactory Factory - { - get - { - ContextFactory result = factory; - if (result == null) { - result = ContextFactory.Global; - } - return result; - } - - } - /// Checks if this is a sealed Context. A sealed Context instance does not - /// allow to modify any of its properties and will throw an exception - /// on any such attempt. - /// - public bool Sealed - { - get - { - return m_Sealed; - } - - } - /// Get the implementation version. - /// - ///

- /// The implementation version is of the form - ///

-        /// "name langVer release relNum date"
-        /// 
- /// where name is the name of the product, langVer is - /// the language version, relNum is the release number, and - /// date is the release date for that specific - /// release in the form "yyyy mm dd". - /// - ///
- /// a string that encodes the product, language version, release - /// number, and date. - /// - public string ImplementationVersion - { - get - { - // TODO: Probably it would be better to embed this directly into source - // TODO: with special build preprocessing but that would require some ant - // TODO: tweaking and then replacing token in resource files was simpler - if (implementationVersion == null) { - implementationVersion = ScriptRuntime.GetMessage ("implementation.version"); - } - return implementationVersion; - } - - } - /// Get the singleton object that represents the JavaScript Undefined value. - public static object UndefinedValue - { - get - { - return Undefined.Value; - } - - } - /// Specify whether or not debug information should be generated. - ///

- /// Setting the generation of debug information on will set the - /// optimization level to zero. - ///

- public bool GeneratingDebug - { - get - { - return generatingDebug; - } - - set - { - if (m_Sealed) - OnSealedMutation (); - generatingDebugChanged = true; - if (value && OptimizationLevel > 0) - OptimizationLevel = 0; - this.generatingDebug = value; - } - - } - - /// Specify whether or not source information should be generated. - ///

- /// Without source information, evaluating the "toString" method - /// on JavaScript functions produces only "[native code]" for - /// the body of the function. - /// Note that code generated without source is not fully ECMA - /// conformant. - ///

- public bool GeneratingSource - { - get - { - return generatingSource; - } - set - { - if (m_Sealed) - OnSealedMutation (); - this.generatingSource = value; - } - - } - /// Set the current optimization level. - ///

- /// The optimization level is expected to be an integer between -1 and - /// 9. Any negative values will be interpreted as -1, and any values - /// greater than 9 will be interpreted as 9. - /// An optimization level of -1 indicates that interpretive mode will - /// always be used. Levels 0 through 9 indicate that class files may - /// be generated. Higher optimization levels trade off compile time - /// performance for runtime performance. - /// The optimizer level can't be set greater than -1 if the optimizer - /// package doesn't exist at run time. - ///

- /// an integer indicating the level of - /// optimization to perform - /// - public int OptimizationLevel - { - get - { - return m_OptimizationLevel; - } - - set - { - if (m_Sealed) - OnSealedMutation (); - if (value == -2) { - // To be compatible with Cocoon fork - value = -1; - } - CheckOptimizationLevel (value); - this.m_OptimizationLevel = value; - } - - } - - /// Return the debugger context data associated with current context. - /// the debugger data, or null if debugger is not attached - /// - public object DebuggerContextData - { - get - { - return debuggerData; - } - - } - - public object Wrap (IScriptable scope, object obj, Type staticType) - { - if (obj == null || obj is IScriptable) - return obj; - if (staticType == null) - staticType = obj.GetType (); - - if (staticType.IsArray) - return new CliArray (scope, obj as Array); - - if (staticType.IsPrimitive) - return obj; - - if (OnWrap != null) { - ContextWrapEventArgs e = new ContextWrapEventArgs (this, scope, obj, staticType); - OnWrap (this, e); - obj = e.Target; - } - - return new CliObject (obj); - } - - /// Get/Set threshold of executed instructions counter that triggers call to - /// observeInstructionCount(). - /// When the threshold is zero, instruction counting is disabled, - /// otherwise each time the run-time executes at least the threshold value - /// of script instructions, observeInstructionCount() will - /// be called. - /// - public int InstructionObserverThreshold - { - get - { - return instructionThreshold; - } - - set - { - if (m_Sealed) - OnSealedMutation (); - if (value < 0) - throw new ArgumentException (); - instructionThreshold = value; - } - - } - - internal RegExpProxy RegExpProxy - { - get - { - if (regExpProxy == null) { - regExpProxy = new Types.RegExp.RegExpImpl (); - } - return regExpProxy; - } - set { - regExpProxy = value; - } - } - internal bool VersionECMA1 - { - get - { - return m_Version == Versions.Default || m_Version >= Versions.JS1_3; - } - - } - public bool GeneratingDebugChanged - { - get - { - return generatingDebugChanged; - } - - } - /// Language versions. - /// - /// All integral values are reserved for future version numbers. - /// - - - - - - - - - - - - public const string languageVersionProperty = "language version"; - public const string errorReporterProperty = "error reporter"; - - /// Convinient value to use as zero-length array of objects. - public static readonly object [] EmptyArgs; - - /// Create a new Context. - /// - /// Note that the Context must be associated with a thread before - /// it can be used to execute a script. - /// - /// - public Context (AppDomain appDomain) - { - if (appDomain == null) - throw new ArgumentNullException ("appDomain"); - Version = Versions.Default; - m_AppDomain = appDomain; - } - - /// Get a context associated with the current thread, creating - /// one if need be. - /// - /// The Context stores the execution state of the JavaScript - /// engine, so it is required that the context be entered - /// before execution may begin. Once a thread has entered - /// a Context, then getCurrentContext() may be called to find - /// the context that is associated with the current thread. - ///

- /// Calling enter() will - /// return either the Context currently associated with the - /// thread, or will create a new context and associate it - /// with the current thread. Each call to enter() - /// must have a matching call to exit(). For example, - ///

-        /// Context cx = Context.enter();
-        /// try {
-        /// ...
-        /// cx.evaluateString(...);
-        /// } finally {
-        /// Context.exit();
-        /// }
-        /// 
- /// Instead of using enter(), exit() pair consider using - /// {@link #call(ContextAction)} which guarantees proper - /// association of Context instances with the current thread and is faster. - /// With this method the above example becomes: - ///
-        /// Context.call(new ContextAction() {
-        /// public Object run(Context cx) {
-        /// ...
-        /// cx.evaluateString(...);
-        /// return null;
-        /// }
-        /// });
-        /// 
- /// - ///
- /// a Context associated with the current thread - /// - public static Context Enter () - { - return Enter (null, AppDomain.CurrentDomain); - } - - public static Context Enter (AppDomain appDomain) - { - return Enter (null, appDomain); - } - - /// Get a Context associated with the current thread, using - /// the given Context if need be. - ///

- /// The same as enter() except that cx - /// is associated with the current thread and returned if - /// the current thread has no associated context and cx - /// is not associated with any other thread. - ///

- /// a Context to associate with the thread if possible - /// - /// a Context associated with the current thread - /// - /// - public static Context Enter (Context cx) - { - return Enter (cx, AppDomain.CurrentDomain); - } - - public static Context Enter (Context cx, AppDomain appDomain) - { - Context old = CurrentContext; - if (old != null) { - if (cx != null && cx != old && cx.enterCount != 0) { - // The suplied context must be the context for - // the current thread if it is already entered - throw new ArgumentException ("Cannot enter Context active on another thread"); - } - if (old.factory != null) { - // Context with associated factory will be released - // automatically and does not need to change enterCount - return old; - } - if (old.m_Sealed) - OnSealedMutation (); - cx = old; - } - else { - if (cx == null) { - cx = new Context (appDomain); - } - else { - if (cx.m_Sealed) - OnSealedMutation (); - } - if (cx.enterCount != 0 || cx.factory != null) { - throw new ApplicationException (); - } - - if (!cx.creationEventWasSent) { - cx.creationEventWasSent = true; - ContextFactory.Global.FireOnContextCreated (cx); - } - } - - if (old == null) { - Thread.SetData (LocalSlot, cx); - } - ++cx.enterCount; - - return cx; - } - - /// Exit a block of code requiring a Context. - /// - /// Calling exit() will remove the association between - /// the current thread and a Context if the prior call to - /// enter() on this thread newly associated a Context - /// with this thread. - /// Once the current thread no longer has an associated Context, - /// it cannot be used to execute JavaScript until it is again associated - /// with a Context. - /// - /// - public static void Exit () - { - Context cx = CurrentContext; - if (cx == null) { - throw new ApplicationException ("Calling Context.exit without previous Context.enter"); - } - if (cx.factory != null) { - // Context with associated factory will be released - // automatically and does not need to change enterCount - return; - } - if (cx.enterCount < 1) - Context.CodeBug (); - if (cx.m_Sealed) - OnSealedMutation (); - --cx.enterCount; - if (cx.enterCount == 0) { - Thread.SetData (LocalSlot, null); - ContextFactory.Global.FireOnContextReleased (cx); - } - } - - - /// Call {@link - /// Callable#call(Context cx, Scriptable scope, Scriptable thisObj, - /// Object[] args)} - /// using the Context instance associated with the current thread. - /// If no Context is associated with the thread, then - /// {@link ContextFactory#makeContext()} will be called to construct - /// new Context instance. The instance will be temporary associated - /// with the thread during call to {@link ContextAction#run(Context)}. - ///

- /// It is allowed to use null for factory argument - /// in which case the factory associated with the scope will be - /// used to create new context instances. - /// - ///

- public static object Call (ContextFactory factory, ICallable callable, IScriptable scope, IScriptable thisObj, object [] args) - { - if (factory == null) { - factory = ContextFactory.Global; - } - - Context cx = CurrentContext; - if (cx != null) { - object result; - if (cx.factory != null) { - result = callable.Call (cx, scope, thisObj, args); - } - else { - // Context was associated with the thread via Context.enter, - // set factory to make Context.enter/exit to be no-op - // during call - cx.factory = factory; - try { - result = callable.Call (cx, scope, thisObj, args); - } - finally { - cx.factory = null; - } - } - return result; - } - - cx = PrepareNewContext (AppDomain.CurrentDomain, factory); - try { - return callable.Call (cx, scope, thisObj, args); - } - finally { - ReleaseContext (cx); - } - } - - internal void InitDefaultFeatures () - { - m_Features = Features.None; - - SetFeature (Features.E4x, (Version == Context.Versions.Default || Version >= Context.Versions.JS1_6)); - SetFeature (Features.GetterAndSetter, (Version == Context.Versions.Default || Version >= Context.Versions.JS1_5)); - SetFeature (Features.NonEcmaGetYear, (Version == Context.Versions.JS1_0 || Version == Context.Versions.JS1_1 || Version == Context.Versions.JS1_2)); - SetFeature (Features.ToStringAsSource, Version == Context.Versions.JS1_2); - SetFeature (Features.ParentProtoProperties, true); - } - - - private static Context PrepareNewContext (AppDomain appDomain, ContextFactory factory) - { - Context cx = new Context (appDomain); - if (cx.factory != null || cx.enterCount != 0) { - throw new ApplicationException ("factory.makeContext() returned Context instance already associated with some thread"); - } - cx.factory = factory; - factory.FireOnContextCreated (cx); - if (factory.Sealed && !cx.Sealed) { - cx.Seal ((object)null); - } - Thread.SetData (LocalSlot, cx); - return cx; - } - - private static void ReleaseContext (Context cx) - { - Thread.SetData (LocalSlot, null); - try { - cx.factory.FireOnContextReleased (cx); - } - finally { - cx.factory = null; - } - } - - - - /// Seal this Context object so any attempt to modify any of its properties - /// including calling {@link #enter()} and {@link #exit()} methods will - /// throw an exception. - ///

- /// If sealKey is not null, calling - /// {@link #unseal(Object sealKey)} with the same key unseals - /// the object. If sealKey is null, unsealing is no longer possible. - /// - ///

- public void Seal (object sealKey) - { - if (m_Sealed) - OnSealedMutation (); - m_Sealed = true; - this.m_SealKey = sealKey; - } - - /// Unseal previously sealed Context object. - /// The sealKey argument should not be null and should match - /// sealKey suplied with the last call to - /// {@link #seal(Object)} or an exception will be thrown. - /// - /// - public void Unseal (object sealKey) - { - if (sealKey == null) - throw new ArgumentException (); - if (this.m_SealKey != sealKey) - throw new ArgumentException (); - if (!m_Sealed) - throw new ApplicationException (); - m_Sealed = false; - this.m_SealKey = null; - } - - internal static void OnSealedMutation () - { - throw new ApplicationException (); - } - - /// - /// Get the current language version. - /// - public Versions Version - { - get - { - return m_Version; - } - set - { - if (m_Sealed) - OnSealedMutation (); - this.m_Version = value; - - InitDefaultFeatures (); - } - } - - public static bool IsValidLanguageVersion (int version) - { - return ToValidLanguageVersion (version) != Versions.Unknown; - } - - public static Versions ToValidLanguageVersion (int version) - { - Versions ver = Versions.Unknown; - if (version > 0 || version < (int)Versions.JS1_6) - ver = (Versions)version; - return ver; - } - - public static void CheckLanguageVersion (int version) - { - if (IsValidLanguageVersion (version)) { - return; - } - throw new ArgumentException ("Bad language version: " + version); - } - - /// Get the current error reporter. - /// - /// - public ErrorReporter ErrorReporter - { - get - { - if (m_ErrorReporter == null) { - return DefaultErrorReporter.instance; - } - return m_ErrorReporter; - } - set - { - if (m_Sealed) - OnSealedMutation (); - if (value == null) - throw new ArgumentException (); - this.m_ErrorReporter = value; - } - } - - /// - /// Get the current locale. Returns the default locale if none has - /// been set. - /// - public CultureInfo CurrentCulture - { - get - { - if (culture == null) - culture = Thread.CurrentThread.CurrentCulture; - return culture; - } - set - { - if (m_Sealed) - OnSealedMutation (); - culture = value; - - // HACK: Needed for example on DateTime.ToString() - if (Thread.CurrentThread.CurrentCulture != culture) - Thread.CurrentThread.CurrentCulture = culture; - } - } - - /// Report a warning using the error reporter for the current thread. - /// - /// - /// the warning message to report - /// - /// a string describing the source, such as a filename - /// - /// the starting line number - /// - /// the text of the line (may be null) - /// - /// the offset into lineSource where problem was detected - /// - - public static void ReportWarning (string message, string sourceName, int lineno, string lineSource, int lineOffset) - { - Context cx = Context.CurrentContext; - cx.ErrorReporter.Warning (message, sourceName, lineno, lineSource, lineOffset); - } - - public static void ReportWarningById (string messageId, params string [] arguments) - { - int [] linep = new int [] { 0 }; - string filename = GetSourcePositionFromStack (linep); - Context.ReportWarning (ScriptRuntime.GetMessage (messageId, arguments), filename, linep [0], null, 0); - } - - /// Report a warning using the error reporter for the current thread. - /// - /// - /// the warning message to report - /// - public static void ReportWarning (string message) - { - int [] linep = new int [] { 0 }; - string filename = GetSourcePositionFromStack (linep); - Context.ReportWarning (message, filename, linep [0], null, 0); - } - - /// Report an error using the error reporter for the current thread. - /// - /// - /// the error message to report - /// - /// a string describing the source, such as a filename - /// - /// the starting line number - /// - /// the text of the line (may be null) - /// - /// the offset into lineSource where problem was detected - /// - public static void ReportError (string message, string sourceName, int lineno, string lineSource, int lineOffset) - { - Context cx = CurrentContext; - if (cx != null) { - cx.ErrorReporter.Error (message, sourceName, lineno, lineSource, lineOffset); - } - else { - throw new EcmaScriptRuntimeException (message, sourceName, lineno, lineSource, lineOffset); - } - } - - /// Report an error using the error reporter for the current thread. - /// - /// - /// the error message to report - /// - - public static void ReportError (string message) - { - int [] linep = new int [] { 0 }; - string filename = GetSourcePositionFromStack (linep); - Context.ReportError (message, filename, linep [0], null, 0); - } - - /// Report a runtime error using the error reporter for the current thread. - /// - /// - /// the error message to report - /// - /// a string describing the source, such as a filename - /// - /// the starting line number - /// - /// the text of the line (may be null) - /// - /// the offset into lineSource where problem was detected - /// - /// a runtime exception that will be thrown to terminate the - /// execution of the script - /// - public static EcmaScriptRuntimeException ReportRuntimeError (string message, string sourceName, int lineno, string lineSource, int lineOffset) - { - Context cx = CurrentContext; - if (cx != null) { - return cx.ErrorReporter.RuntimeError (message, sourceName, lineno, lineSource, lineOffset); - } - else { - throw new EcmaScriptRuntimeException (message, sourceName, lineno, lineSource, lineOffset); - } - } - - - internal static EcmaScriptRuntimeException ReportRuntimeErrorById (string messageId, params object [] args) - { - return ReportRuntimeError (ScriptRuntime.GetMessage (messageId, args)); - } - - /// Report a runtime error using the error reporter for the current thread. - /// - /// - /// the error message to report - /// - public static EcmaScriptRuntimeException ReportRuntimeError (string message) - { - int [] linep = new int [] { 0 }; - string filename = GetSourcePositionFromStack (linep); - return Context.ReportRuntimeError (message, filename, linep [0], null, 0); - } - - /// Initialize the standard objects. - /// - /// Creates instances of the standard objects and their constructors - /// (Object, String, Number, Date, etc.), setting up 'scope' to act - /// as a global object as in ECMA 15.1.

- /// - /// This method must be called to initialize a scope before scripts - /// can be evaluated in that scope.

- /// - /// This method does not affect the Context it is called upon. - /// - ///

- /// the initialized scope - /// - public ScriptableObject InitStandardObjects () - { - return InitStandardObjects (null, false); - } - - /// Initialize the standard objects. - /// - /// Creates instances of the standard objects and their constructors - /// (Object, String, Number, Date, etc.), setting up 'scope' to act - /// as a global object as in ECMA 15.1.

- /// - /// This method must be called to initialize a scope before scripts - /// can be evaluated in that scope.

- /// - /// This method does not affect the Context it is called upon. - /// - ///

- /// the scope to initialize, or null, in which case a new - /// object will be created to serve as the scope - /// - /// the initialized scope. The method returns the value of the scope - /// argument if it is not null or newly allocated scope object which - /// is an instance {@link ScriptableObject}. - /// - public IScriptable InitStandardObjects (ScriptableObject scope) - { - return InitStandardObjects (scope, false); - } - - /// Initialize the standard objects. - /// - /// Creates instances of the standard objects and their constructors - /// (Object, String, Number, Date, etc.), setting up 'scope' to act - /// as a global object as in ECMA 15.1.

- /// - /// This method must be called to initialize a scope before scripts - /// can be evaluated in that scope.

- /// - /// This method does not affect the Context it is called upon.

- /// - /// This form of the method also allows for creating "sealed" standard - /// objects. An object that is sealed cannot have properties added, changed, - /// or removed. This is useful to create a "superglobal" that can be shared - /// among several top-level objects. Note that sealing is not allowed in - /// the current ECMA/ISO language specification, but is likely for - /// the next version. - /// - ///

- /// the scope to initialize, or null, in which case a new - /// object will be created to serve as the scope - /// - /// whether or not to create sealed standard objects that - /// cannot be modified. - /// - /// the initialized scope. The method returns the value of the scope - /// argument if it is not null or newly allocated scope object. - /// - public ScriptableObject InitStandardObjects (ScriptableObject scope, bool zealed) - { - return ScriptRuntime.InitStandardObjects (this, scope, zealed); - } - - /// Evaluate a JavaScript source string. - /// - /// The provided source name and line number are used for error messages - /// and for producing debug information. - /// - /// - /// the scope to execute in - /// - /// the JavaScript source - /// - /// a string describing the source, such as a filename - /// - /// the starting line number - /// - /// an arbitrary object that specifies security - /// information about the origin or owner of the script. For - /// implementations that don't care about security, this value - /// may be null. - /// - /// the result of evaluating the string - /// - public object EvaluateString (IScriptable scope, string source, string sourceName, int lineno, object securityDomain) - { - IScript script = CompileString (source, sourceName, lineno, securityDomain); - if (script != null) { - return script.Exec (this, scope); - } - else { - return null; - } - } - - /// Evaluate a reader as JavaScript source. - /// - /// All characters of the reader are consumed. - /// - /// - /// the scope to execute in - /// - /// the Reader to get JavaScript source from - /// - /// a string describing the source, such as a filename - /// - /// the starting line number - /// - /// an arbitrary object that specifies security - /// information about the origin or owner of the script. For - /// implementations that don't care about security, this value - /// may be null. - /// - /// the result of evaluating the source - /// - /// - /// IOException if an IOException was generated by the Reader - /// - public object EvaluateReader (IScriptable scope, StreamReader sr, string sourceName, int lineno, object securityDomain) - { - IScript script = CompileReader (sr, sourceName, lineno, securityDomain); - - if (script != null) { - return script.Exec (this, scope); - } - return null; - } - - /// Check whether a string is ready to be compiled. - ///

- /// stringIsCompilableUnit is intended to support interactive compilation of - /// javascript. If compiling the string would result in an error - /// that might be fixed by appending more source, this method - /// returns false. In every other case, it returns true. - ///

- /// Interactive shells may accumulate source lines, using this - /// method after each new line is appended to check whether the - /// statement being entered is complete. - /// - ///

- /// the source buffer to check - /// - /// whether the source is ready for compilation - /// - public ScriptOrFnNode IsCompilableUnit (string source) - { - ScriptOrFnNode ret = null; - bool errorseen = false; - CompilerEnvirons compilerEnv = new CompilerEnvirons (); - compilerEnv.initFromContext (this); - // no source name or source text manager, because we're just - // going to throw away the result. - compilerEnv.setGeneratingSource (false); - Parser p = new Parser (compilerEnv, DefaultErrorReporter.instance); - try { - ret = p.Parse (source, null, 1); - } - catch (EcmaScriptRuntimeException) { - errorseen = true; - } - // Return false only if an error occurred as a result of reading past - // the end of the file, i.e. if the source could be fixed by - // appending more source. - if (!(errorseen && p.Eof)) - return ret; - return null; - } - - - /// Compiles the source in the given reader. - ///

- /// Returns a script that may later be executed. - /// Will consume all the source in the reader. - /// - ///

- /// the input reader - /// - /// a string describing the source, such as a filename - /// - /// the starting line number for reporting errors - /// - /// an arbitrary object that specifies security - /// information about the origin or owner of the script. For - /// implementations that don't care about security, this value - /// may be null. - /// - /// a script that may later be executed - /// - /// IOException if an IOException was generated by the Reader - /// - public IScript CompileReader (StreamReader sr, string sourceName, int lineno, object securityDomain) - { - if (lineno < 0) - throw new ArgumentException ("lineno may not be negative", "lineno"); - return (IScript)CompileImpl (null, sr, null, sourceName, lineno, securityDomain, false, null, null); - } - - /// Compiles the source in the given string. - ///

- /// Returns a script that may later be executed. - /// - ///

- /// the source string - /// - /// a string describing the source, such as a filename - /// - /// the starting line number for reporting errors - /// - /// an arbitrary object that specifies security - /// information about the origin or owner of the script. For - /// implementations that don't care about security, this value - /// may be null. - /// - /// a script that may later be executed - /// - public IScript CompileString (string source, string sourceName, int lineno, object securityDomain) - { - if (lineno < 0) { - // For compatibility IllegalArgumentException can not be thrown here - lineno = 0; - } - return CompileString (source, null, null, sourceName, lineno, securityDomain); - } - - internal IScript CompileString (string source, Interpreter compiler, ErrorReporter compilationErrorReporter, string sourceName, int lineno, object securityDomain) - { - return (IScript)CompileImpl (null, null, source, sourceName, lineno, securityDomain, false, compiler, compilationErrorReporter); - } - - /// Compile a JavaScript function. - ///

- /// The function source must be a function definition as defined by - /// ECMA (e.g., "function f(a) { return a; }"). - /// - ///

- /// the scope to compile relative to - /// - /// the function definition source - /// - /// a string describing the source, such as a filename - /// - /// the starting line number - /// - /// an arbitrary object that specifies security - /// information about the origin or owner of the script. For - /// implementations that don't care about security, this value - /// may be null. - /// - /// a Function that may later be called - /// - public IFunction CompileFunction (IScriptable scope, string source, string sourceName, int lineno, object securityDomain) - { - return CompileFunction (scope, source, null, null, sourceName, lineno, securityDomain); - } - - internal IFunction CompileFunction (IScriptable scope, string source, Interpreter compiler, ErrorReporter compilationErrorReporter, string sourceName, int lineno, object securityDomain) - { - return (IFunction)CompileImpl (scope, null, source, sourceName, lineno, securityDomain, true, compiler, compilationErrorReporter); - } - - /// Decompile the script. - ///

- /// The canonical source of the script is returned. - /// - ///

- /// the script to decompile - /// - /// the number of spaces to indent the result - /// - /// a string representing the script source - /// - public string DecompileScript (IScript script, int indent) - { - BuiltinFunction scriptImpl = (BuiltinFunction)script; - return scriptImpl.Decompile (indent, 0); - } - - /// Decompile a JavaScript Function. - ///

- /// Decompiles a previously compiled JavaScript function object to - /// canonical source. - ///

- /// Returns function body of '[native code]' if no decompilation - /// information is available. - /// - ///

- /// the JavaScript function to decompile - /// - /// the number of spaces to indent the result - /// - /// a string representing the function source - /// - public string DecompileFunction (IFunction fun, int indent) - { - if (fun is BaseFunction) - return ((BaseFunction)fun).Decompile (indent, 0); - else - return "function " + fun.ClassName + "() {\n\t[native code]\n}\n"; - } - - /// Decompile the body of a JavaScript Function. - ///

- /// Decompiles the body a previously compiled JavaScript Function - /// object to canonical source, omitting the function header and - /// trailing brace. - /// - /// Returns '[native code]' if no decompilation information is available. - /// - ///

- /// the JavaScript function to decompile - /// - /// the number of spaces to indent the result - /// - /// a string representing the function body source. - /// - public string DecompileFunctionBody (IFunction fun, int indent) - { - if (fun is BaseFunction) { - BaseFunction bf = (BaseFunction)fun; - return bf.Decompile (indent, Decompiler.ONLY_BODY_FLAG); - } - // ALERT: not sure what the right response here is. - return "[native code]\n"; - } - - /// Create a new JavaScript object. - /// - /// Equivalent to evaluating "new Object()". - /// - /// the scope to search for the constructor and to evaluate - /// against - /// - /// the new object - /// - public IScriptable NewObject (IScriptable scope) - { - return NewObject (scope, "Object", ScriptRuntime.EmptyArgs); - } - - /// Create a new JavaScript object by executing the named constructor. - /// - /// The call newObject(scope, "Foo") is equivalent to - /// evaluating "new Foo()". - /// - /// - /// the scope to search for the constructor and to evaluate against - /// - /// the name of the constructor to call - /// - /// the new object - /// - public IScriptable NewObject (IScriptable scope, string constructorName) - { - return NewObject (scope, constructorName, ScriptRuntime.EmptyArgs); - } - - /// Creates a new JavaScript object by executing the named constructor. - /// - /// Searches scope for the named constructor, calls it with - /// the given arguments, and returns the result.

- /// - /// The code - ///

-        /// Object[] args = { "a", "b" };
-        /// newObject(scope, "Foo", args)
- /// is equivalent to evaluating "new Foo('a', 'b')", assuming that the Foo - /// constructor has been defined in scope. - /// - ///
- /// The scope to search for the constructor and to evaluate - /// against - /// - /// the name of the constructor to call - /// - /// the array of arguments for the constructor - /// - /// the new object - /// - public IScriptable NewObject (IScriptable scope, string constructorName, object [] args) - { - scope = ScriptableObject.GetTopLevelScope (scope); - IFunction ctor = ScriptRuntime.getExistingCtor (this, scope, constructorName); - if (args == null) { - args = ScriptRuntime.EmptyArgs; - } - return ctor.Construct (this, scope, args); - } - - /// Create an array with a specified initial length. - ///

- ///

- /// the scope to create the object in - /// - /// the initial length (JavaScript arrays may have - /// additional properties added dynamically). - /// - /// the new array object - /// - public IScriptable NewArray (IScriptable scope, int length) - { - BuiltinArray result = new BuiltinArray (length); - ScriptRuntime.setObjectProtoAndParent (result, scope); - return result; - } - - /// Create an array with a set of initial elements. - /// - /// - /// the scope to create the object in. - /// - /// the initial elements. Each object in this array - /// must be an acceptable JavaScript type and type - /// of array should be exactly Object[], not - /// SomeObjectSubclass[]. - /// - /// the new array object. - /// - public IScriptable NewArray (IScriptable scope, object [] elements) - { - Type elementType = elements.GetType ().GetElementType (); - if (elementType != typeof (object)) - throw new ArgumentException (); - BuiltinArray result = new BuiltinArray (elements); - ScriptRuntime.setObjectProtoAndParent (result, scope); - return result; - } - - /// Get the elements of a JavaScript array. - ///

- /// If the object defines a length property convertible to double number, - /// then the number is converted Uint32 value as defined in Ecma 9.6 - /// and Java array of that size is allocated. - /// The array is initialized with the values obtained by - /// calling get() on object for each value of i in [0,length-1]. If - /// there is not a defined value for a property the Undefined value - /// is used to initialize the corresponding element in the array. The - /// Java array is then returned. - /// If the object doesn't define a length property or it is not a number, - /// empty array is returned. - ///

- /// the JavaScript array or array-like object - /// - /// a Java array of objects - /// - - public object [] GetElements (IScriptable obj) - { - return ScriptRuntime.getArrayElements (obj); - } - - - /// Convenient method to convert java value to its closest representation - /// in JavaScript. - ///

- /// If value is an instance of String, Number, Boolean, Function or - /// Scriptable, it is returned as it and will be treated as the corresponding - /// JavaScript type of string, number, boolean, function and object. - ///

- /// Note that for Number instances during any arithmetic operation in - /// JavaScript the engine will always use the result of - /// Number.doubleValue() resulting in a precision loss if - /// the number can not fit into double. - ///

- /// If value is an instance of Character, it will be converted to string of - /// length 1 and its JavaScript type will be string. - ///

- /// The rest of values will be wrapped as LiveConnect objects - /// by calling {@link WrapFactory#wrap(Context cx, Scriptable scope, - /// Object obj, Class staticType)} as in: - ///

-        /// Context cx = Context.getCurrentContext();
-        /// return cx.getWrapFactory().wrap(cx, scope, value, null);
-        /// 
- /// - ///
- /// any Java object - /// - /// top scope object - /// - /// value suitable to pass to any API that takes JavaScript values. - /// - public static object CliToJS (Context cx, object value, IScriptable scope) - { - if (value is string || CliHelper.IsNumber (value) || value is bool || value is IScriptable) { - return value; - } - else if (value is char) { - return Convert.ToString (((char)value)); - } - else { - Type type = (value as Type); - if (type != null) { - return cx.Wrap (scope, value, (Type)value); - } else { - return cx.Wrap (scope, value, null); - } - } - } - - /// Convert a JavaScript value into the desired type. - /// Uses the semantics defined with LiveConnect3 and throws an - /// Illegal argument exception if the conversion cannot be performed. - /// - /// the JavaScript value to convert - /// - /// the Java type to convert to. Primitive Java - /// types are represented using the TYPE fields in the corresponding - /// wrapper class in java.lang. - /// - /// the converted value - /// - /// EvaluatorException if the conversion cannot be performed - public static object JsToCli (object value, System.Type desiredType) - { - return CliObject.CoerceType (desiredType, value); - } - - - - /// Rethrow the exception wrapping it as the script runtime exception. - /// Unless the exception is instance of {@link EcmaError} or - /// {@link EvaluatorException} it will be wrapped as - /// {@link WrappedException}, a subclass of {@link EvaluatorException}. - /// The resulting exception object always contains - /// source name and line number of script that triggered exception. - ///

- /// This method always throws an exception, its return value is provided - /// only for convenience to allow a usage like: - ///

-        /// throw Context.throwAsScriptRuntimeEx(ex);
-        /// 
- /// to indicate that code after the method is unreachable. - ///
- /// EvaluatorException - /// EcmaError - public static ApplicationException ThrowAsScriptRuntimeEx (Exception e) - { - while ((e is TargetInvocationException)) { - e = ((TargetInvocationException)e).InnerException; - } - if (e is EcmaScriptException) { - throw e; - } - throw new EcmaScriptRuntimeException (e); - } - - public static bool IsValidOptimizationLevel (int optimizationLevel) - { - return -1 <= optimizationLevel && optimizationLevel <= 9; - } - - public static void CheckOptimizationLevel (int optimizationLevel) - { - if (IsValidOptimizationLevel (optimizationLevel)) { - return; - } - throw new ArgumentException ("Optimization level outside [-1..9]: " + optimizationLevel); - } - - /// Set the security controller for this context. - ///

SecurityController may only be set if it is currently null - /// and {@link SecurityController#hasGlobal()} is false. - /// Otherwise a SecurityException is thrown. - ///

- /// a SecurityController object - /// - /// SecurityException if there is already a SecurityController - /// object for this Context or globally installed. - /// - public SecurityController SecurityController - { - set - { - if (m_Sealed) - OnSealedMutation (); - if (value == null) - throw new ArgumentException (); - if (securityController != null) { - throw new System.Security.SecurityException ("Can not overwrite existing SecurityController object"); - } - if (SecurityController.HasGlobal ()) { - throw new System.Security.SecurityException ("Can not overwrite existing global SecurityController object"); - } - securityController = value; - } - get - { - SecurityController global = SecurityController.Global; - if (global != null) { - return global; - } - return securityController; - } - } - - /// Get a value corresponding to a key. - ///

- /// Since the Context is associated with a thread it can be - /// used to maintain values that can be later retrieved using - /// the current thread. - ///

- /// Note that the values are maintained with the Context, so - /// if the Context is disassociated from the thread the values - /// cannot be retreived. Also, if private data is to be maintained - /// in this manner the key should be a java.lang.Object - /// whose reference is not divulged to untrusted code. - ///

- /// the key used to lookup the value - /// - /// a value previously stored using putThreadLocal. - /// - public object GetThreadLocal (object key) - { - if (hashtable == null) - return null; - return hashtable [key]; - } - - /// Put a value that can later be retrieved using a given key. - ///

- ///

- /// the key used to index the value - /// - /// the value to save - /// - public void PutThreadLocal (object key, object value) - { - if (m_Sealed) - OnSealedMutation (); - if (hashtable == null) - hashtable = Hashtable.Synchronized (new Hashtable ()); - hashtable [key] = value; - } - - /// Remove values from thread-local storage. - /// the key for the entry to remove. - /// - public void RemoveThreadLocal (object key) - { - if (m_Sealed) - OnSealedMutation (); - if (hashtable == null) - return; - hashtable.Remove (key); - } - - - - /// Return the current debugger. - /// the debugger, or null if none is attached. - /// - public Debugger Debugger - { - get - { - return m_Debugger; - } - } - - /// Set the associated debugger. - /// the debugger to be used on callbacks from - /// the engine. - /// - /// arbitrary object that debugger can use to store - /// per Context data. - /// - public void SetDebugger (Debugger debugger, object contextData) - { - if (m_Sealed) - OnSealedMutation (); - this.m_Debugger = debugger; - debuggerData = contextData; - } - - /// Return DebuggableScript instance if any associated with the script. - /// If callable supports DebuggableScript implementation, the method - /// returns it. Otherwise null is returned. - /// - public static DebuggableScript getDebuggableView (IScript script) - { - if (script is BuiltinFunction) { - return ((BuiltinFunction)script).DebuggableView; - } - return null; - } - - - private Features m_Features = Features.None; - - /// - /// Controls certain aspects of script semantics. - /// Should be overwritten to alter default behavior. - /// - /// The default implementation calls - /// {@link ContextFactory#hasFeature(Context cx, int featureIndex)} - /// that allows to customize Context behavior without introducing - /// Context subclasses. {@link ContextFactory} documentation gives - /// an example of hasFeature implementation. - /// - /// - /// feature to check - /// - /// true if the feature feature is turned on - /// - public bool HasFeature (Features feature) - { - return (m_Features & feature) == feature; - } - - public void SetFeature (Features feature, bool isEnabled) - { - if (isEnabled) { - m_Features |= feature; - } - else { - if (HasFeature (feature)) - m_Features = m_Features ^ feature; - } - } - - - /// Allow application to monitor counter of executed script instructions - /// in Context subclasses. - /// Run-time calls this when instruction counting is enabled and the counter - /// reaches limit set by setInstructionObserverThreshold(). - /// The method is useful to observe long running scripts and if necessary - /// to terminate them. - ///

- /// The instruction counting support is available only for interpreted - /// scripts generated when the optimization level is set to -1. - ///

- /// The default implementation calls - /// {@link ContextFactory#observeInstructionCount(Context cx, - /// int instructionCount)} - /// that allows to customize Context behavior without introducing - /// Context subclasses. - /// - ///

- /// amount of script instruction executed since - /// last call to observeInstructionCount - /// - /// Error to terminate the script - protected internal void ObserveInstructionCount (int instructionCount) - { - Factory.ObserveInstructionCount (this, instructionCount); - } - - private object CompileImpl (IScriptable scope, StreamReader sourceReader, string sourceString, string sourceName, int lineno, object securityDomain, bool returnFunction, Interpreter compiler, ErrorReporter compilationErrorReporter) - { - if (securityDomain != null && securityController == null) { - throw new ArgumentException ("securityDomain should be null if setSecurityController() was never called"); - } - - // One of sourceReader or sourceString has to be null - if (!(sourceReader == null ^ sourceString == null)) - Context.CodeBug (); - // scope should be given if and only if compiling function - if (!(scope == null ^ returnFunction)) - Context.CodeBug (); - - CompilerEnvirons compilerEnv = new CompilerEnvirons (); - compilerEnv.initFromContext (this); - if (compilationErrorReporter == null) { - compilationErrorReporter = compilerEnv.getErrorReporter (); - } - - if (m_Debugger != null) { - if (sourceReader != null) { - sourceString = sourceReader.ReadToEnd (); - sourceReader = null; - } - } - - Parser p = new Parser (compilerEnv, compilationErrorReporter); - if (returnFunction) { - p.calledByCompileFunction = true; - } - ScriptOrFnNode tree; - if (sourceString != null) { - tree = p.Parse (sourceString, sourceName, lineno); - } - else { - tree = p.Parse (sourceReader, sourceName, lineno); - } - if (returnFunction) { - if (!(tree.FunctionCount == 1 && tree.FirstChild != null && tree.FirstChild.Type == Token.FUNCTION)) { - // TODO: the check just look for the first child - // TODO: and allows for more nodes after it for compatibility - // TODO: with sources like function() {};;; - throw new ArgumentException ("compileFunction only accepts source with single JS function: " + sourceString); - } - } - - - - if (compiler == null) { - compiler = new Interpreter (); - //compiler = new Compiler(); - } - - string encodedSource = p.EncodedSource; - - object bytecode = compiler.Compile (compilerEnv, tree, encodedSource, returnFunction); - - if (m_Debugger != null) { - if (sourceString == null) - Context.CodeBug (); - if (bytecode is DebuggableScript) { - DebuggableScript dscript = (DebuggableScript)bytecode; - NotifyDebugger (this, dscript, sourceString); - } - else { - throw new ApplicationException ("NOT SUPPORTED"); - } - } - - object result; - if (returnFunction) { - result = compiler.CreateFunctionObject (this, scope, bytecode, securityDomain); - } - else { - result = compiler.CreateScriptObject (bytecode, securityDomain); - } - - return result; - } - - private static void NotifyDebugger (Context cx, DebuggableScript dscript, string debugSource) - { - cx.m_Debugger.HandleCompilationDone (cx, dscript, debugSource); - for (int i = 0; i != dscript.FunctionCount; ++i) { - NotifyDebugger (cx, dscript.GetFunction (i), debugSource); - } - } - - internal static string GetSourcePositionFromStack (int [] linep) - { - Context cx = CurrentContext; - if (cx == null) - return null; - if (cx.lastInterpreterFrame != null) { - return Interpreter.GetSourcePositionFromStack (cx, linep); - } - - System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace (); - System.Diagnostics.StackFrame sf = st.GetFrame (0); - linep [0] = sf.GetFileLineNumber (); - return Path.GetFileName (sf.GetFileName ()); - } - - - /// Add a name to the list of names forcing the creation of real - /// activation objects for functions. - /// - /// - /// the name of the object to add to the list - /// - public void AddActivationName (string name) - { - if (m_Sealed) - OnSealedMutation (); - if (activationNames == null) - activationNames = Hashtable.Synchronized (new Hashtable (5)); - activationNames [name] = name; - } - - /// Check whether the name is in the list of names of objects - /// forcing the creation of activation objects. - /// - /// - /// the name of the object to test - /// - /// - /// true if an function activation object is needed. - /// - public bool IsActivationNeeded (string name) - { - return activationNames != null && activationNames.ContainsKey (name); - } - - /// Remove a name from the list of names forcing the creation of real - /// activation objects for functions. - /// - /// - /// the name of the object to remove from the list - /// - public void RemoveActivationName (string name) - { - if (m_Sealed) - OnSealedMutation (); - if (activationNames != null) - activationNames.Remove (name); - } - - private static string implementationVersion; - - private ContextFactory factory; - private bool m_Sealed; - private object m_SealKey; - - internal IScriptable topCallScope; - internal BuiltinCall currentActivationCall; - internal XMLLib cachedXMLLib; - - // for Objects, Arrays to tag themselves as being printed out, - // so they don't print themselves out recursively. - // Use ObjToIntMap instead of java.util.HashSet for JDK 1.1 compatibility - internal ObjToIntMap iterating; - - internal object interpreterSecurityDomain; - - internal Versions m_Version = Versions.Unknown; - - private SecurityController securityController; - - private ErrorReporter m_ErrorReporter; - internal RegExpProxy regExpProxy; - private System.Globalization.CultureInfo culture; - private bool generatingDebug; - private bool generatingDebugChanged; - private bool generatingSource = true; - internal bool compileFunctionsWithDynamicScopeFlag = false; - internal bool useDynamicScope; - private int m_OptimizationLevel; - - internal Debugger m_Debugger; - private object debuggerData; - private int enterCount; - private Hashtable hashtable; - - private bool creationEventWasSent; - - /// This is the list of names of objects forcing the creation of - /// function activation records. - /// - internal Hashtable activationNames; - - // For the interpreter to store the last frame for error reports etc. - internal object lastInterpreterFrame; - - // For the interpreter to store information about previous invocations - // interpreter invocations - internal ObjArray previousInterpreterInvocations; - - // For instruction counting (interpreter only) - internal int instructionCount; - internal int instructionThreshold; - - // It can be used to return the second index-like result from function - internal int scratchIndex; - - // It can be used to return the second uint32 result from function - internal long scratchUint32; - - // It can be used to return the second Scriptable result from function - internal IScriptable scratchScriptable; - static Context () - { - EmptyArgs = ScriptRuntime.EmptyArgs; - } - - public void Dispose () - { - Context.Exit (); - } - - /// - /// Throws RuntimeException to indicate failed assertion. - /// The function never returns and its return type is RuntimeException - /// only to be able to write throw EcmaScriptHelper.CodeBug() if plain - /// EcmaScriptHelper.CodeBug() triggers unreachable code error. - /// - public static ApplicationException CodeBug () - { - ApplicationException ex = new ApplicationException ("FAILED ASSERTION"); - Console.Error.WriteLine (ex.ToString ()); - throw ex; - } - - } -} +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; +using System.IO; +using System.Threading; +using System.Globalization; +using System.Reflection; +using System.Collections; + +using EcmaScript.NET.Debugging; +using EcmaScript.NET.Collections; +using EcmaScript.NET.Types; +using EcmaScript.NET.Types.Cli; +using EcmaScript.NET.Types.E4X; + +namespace EcmaScript.NET +{ + + /// + /// This class represents the runtime context of an executing script. + /// + /// Before executing a script, an instance of Context must be created + /// and associated with the thread that will be executing the script. + /// The Context will be used to store information about the executing + /// of the script such as the call stack. Contexts are associated with + /// the current thread using the {@link #call(ContextAction)} + /// or {@link #enter()} methods.

+ /// + /// Different forms of script execution are supported. Scripts may be + /// evaluated from the source directly, or first compiled and then later + /// executed. Interactive execution is also supported.

+ /// + /// Some aspects of script execution, such as type conversions and + /// object creation, may be accessed directly through methods of + /// Context. + /// + ///

+ public class Context : IDisposable + { + + public enum Features + { + /// + /// No features at all + /// + None = 0, + + /// + /// Support for E4X + /// + E4x = 1 << 1, + + /// + /// Support for get and set + /// + GetterAndSetter = 1 << 2, + + /// + /// + /// + NonEcmaGetYear = 1 << 3, + + /// Control if dynamic scope should be used for name access. + /// If hasFeature(FEATURE_DYNAMIC_SCOPE) returns true, then the name lookup + /// during name resolution will use the top scope of the script or function + /// which is at the top of JS execution stack instead of the top scope of the + /// script or function from the current stack frame if the top scope of + /// the top stack frame contains the top scope of the current stack frame + /// on its prototype chain. + ///

+ /// This is useful to define shared scope containing functions that can + /// be called from scripts and functions using private scopes. + ///

+ /// By default {@link #hasFeature(int)} returns false. + ///

+ DynamicScope = 1 << 4, + /// Control if member expression as function name extension is available. + /// If hasFeature(FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME) returns + /// true, allow function memberExpression(args) { body } to be + /// syntax sugar for memberExpression = function(args) { body }, + /// when memberExpression is not a simple identifier. + /// See ECMAScript-262, section 11.2 for definition of memberExpression. + /// By default {@link #hasFeature(int)} returns false. + /// + MemberExprAsFunctionName = 1 << 5, + + /// Control if reserved keywords are treated as identifiers. + /// If hasFeature(RESERVED_KEYWORD_AS_IDENTIFIER) returns true, + /// treat future reserved keyword (see Ecma-262, section 7.5.3) as ordinary + /// identifiers but warn about this usage. + /// + /// By default {@link #hasFeature(int)} returns false. + /// + ReservedKeywordAsIdentifier = 1 << 6, + + /// Control if toString() should returns the same result + /// as toSource() when applied to objects and arrays. + /// If hasFeature(FEATURE_TO_STRING_AS_SOURCE) returns true, + /// calling toString() on JS objects gives the same result as + /// calling toSource(). That is it returns JS source with code + /// to create an object with all enumeratable fields of the original object + /// instead of printing [object result of + /// {@link Scriptable#getClassName()}]. + ///

+ /// By default {@link #hasFeature(int)} returns true only if + /// the current JS version is set to {@link #Versions.JS1_2}. + ///

+ ToStringAsSource = 1 << 7, + + /// Control if properties __proto__ and __parent__ + /// are treated specially. + /// If hasFeature(FEATURE_PARENT_PROTO_PROPRTIES) returns true, + /// treat __parent__ and __proto__ as special properties. + ///

+ /// The properties allow to query and set scope and prototype chains for the + /// objects. The special meaning of the properties is available + /// only when they are used as the right hand side of the dot operator. + /// For example, while x.__proto__ = y changes the prototype + /// chain of the object x to point to y, + /// x["__proto__"] = y simply assigns a new value to the property + /// __proto__ in x even when the feature is on. + /// + /// By default {@link #hasFeature(int)} returns true. + ///

+ ParentProtoProperties = 1 << 8, + + /// Control if strict variable mode is enabled. + /// When the feature is on Rhino reports runtime errors if assignment + /// to a global variable that does not exist is executed. When the feature + /// is off such assignments creates new variable in the global scope as + /// required by ECMA 262. + ///

+ /// By default {@link #hasFeature(int)} returns false. + ///

+ StrictVars = 1 << 9, + + /// Control if strict eval mode is enabled. + /// When the feature is on Rhino reports runtime errors if non-string + /// argument is passed to the eval function. When the feature is off + /// eval simply return non-string argument as is without performing any + /// evaluation as required by ECMA 262. + ///

+ /// By default {@link #hasFeature(int)} returns false. + ///

+ StrictEval = 1 << 10, + + /// + /// Controls if the non-ecma function 'print' is available or not. + /// + NonEcmaPrintFunction = 1 << 11, + + /// + /// Controls if the non-ecma function 'version' is available or not + /// + NonEcmaVersionFunction = 1 << 12, + + /// + /// Controls if the non-ecma function 'options' is available or not + /// + NonEcmaOptionsFunction = 1 << 13, + + Strict = 1 << 14, + + /// + /// Controls if the non-ecma function 'options' is available or not + /// + NonEcmaGcFunction = 1 << 14, + + /// + /// The famous 'it' object (@see js.c:2315) + /// + NonEcmaItObject = 1 << 15, + + } + + public enum Versions + { + Unknown = -1, + Default = 0, + JS1_0 = 100, + JS1_1 = 110, + JS1_2 = 120, + JS1_3 = 130, + JS1_4 = 140, + JS1_5 = 150, + JS1_6 = 160 + } + + /// + /// + /// + public event ContextWrapHandler OnWrap; + + private int m_MaximumInterpreterStackDepth = 8092; + + /// + /// + /// + public int MaximumInterpreterStackDepth + { + get + { + return m_MaximumInterpreterStackDepth; + } + set + { + if (Sealed) + OnSealedMutation (); + m_MaximumInterpreterStackDepth = value; + } + } + + private AppDomain m_AppDomain = null; + + /// + /// Associated app domain + /// + public AppDomain AppDomain + { + get { return m_AppDomain; } + } + + private static LocalDataStoreSlot LocalSlot + { + get + { + LocalDataStoreSlot slot = Thread.GetNamedDataSlot ("Context"); + if (slot == null) { + slot = Thread.AllocateNamedDataSlot ("Context"); + } + return slot; + } + } + + /// Get the current Context. + /// + /// The current Context is per-thread; this method looks up + /// the Context associated with the current thread.

+ /// + ///

+ /// the Context associated with the current thread, or + /// null if no context is associated with the current + /// thread. + /// + public static Context CurrentContext + { + get + { + Context cx = (Context)Thread.GetData (LocalSlot); + return cx; + } + } + + /// Return {@link ContextFactory} instance used to create this Context + /// or the result of {@link ContextFactory#getGlobal()} if no factory + /// was used for Context creation. + /// + public ContextFactory Factory + { + get + { + ContextFactory result = factory; + if (result == null) { + result = ContextFactory.Global; + } + return result; + } + + } + /// Checks if this is a sealed Context. A sealed Context instance does not + /// allow to modify any of its properties and will throw an exception + /// on any such attempt. + /// + public bool Sealed + { + get + { + return m_Sealed; + } + + } + /// Get the implementation version. + /// + ///

+ /// The implementation version is of the form + ///

+        /// "name langVer release relNum date"
+        /// 
+ /// where name is the name of the product, langVer is + /// the language version, relNum is the release number, and + /// date is the release date for that specific + /// release in the form "yyyy mm dd". + /// + ///
+ /// a string that encodes the product, language version, release + /// number, and date. + /// + public string ImplementationVersion + { + get + { + // TODO: Probably it would be better to embed this directly into source + // TODO: with special build preprocessing but that would require some ant + // TODO: tweaking and then replacing token in resource files was simpler + if (implementationVersion == null) { + implementationVersion = ScriptRuntime.GetMessage ("implementation.version"); + } + return implementationVersion; + } + + } + /// Get the singleton object that represents the JavaScript Undefined value. + public static object UndefinedValue + { + get + { + return Undefined.Value; + } + + } + /// Specify whether or not debug information should be generated. + ///

+ /// Setting the generation of debug information on will set the + /// optimization level to zero. + ///

+ public bool GeneratingDebug + { + get + { + return generatingDebug; + } + + set + { + if (m_Sealed) + OnSealedMutation (); + generatingDebugChanged = true; + if (value && OptimizationLevel > 0) + OptimizationLevel = 0; + this.generatingDebug = value; + } + + } + + /// Specify whether or not source information should be generated. + ///

+ /// Without source information, evaluating the "toString" method + /// on JavaScript functions produces only "[native code]" for + /// the body of the function. + /// Note that code generated without source is not fully ECMA + /// conformant. + ///

+ public bool GeneratingSource + { + get + { + return generatingSource; + } + set + { + if (m_Sealed) + OnSealedMutation (); + this.generatingSource = value; + } + + } + /// Set the current optimization level. + ///

+ /// The optimization level is expected to be an integer between -1 and + /// 9. Any negative values will be interpreted as -1, and any values + /// greater than 9 will be interpreted as 9. + /// An optimization level of -1 indicates that interpretive mode will + /// always be used. Levels 0 through 9 indicate that class files may + /// be generated. Higher optimization levels trade off compile time + /// performance for runtime performance. + /// The optimizer level can't be set greater than -1 if the optimizer + /// package doesn't exist at run time. + ///

+ /// an integer indicating the level of + /// optimization to perform + /// + public int OptimizationLevel + { + get + { + return m_OptimizationLevel; + } + + set + { + if (m_Sealed) + OnSealedMutation (); + if (value == -2) { + // To be compatible with Cocoon fork + value = -1; + } + CheckOptimizationLevel (value); + this.m_OptimizationLevel = value; + } + + } + + /// Return the debugger context data associated with current context. + /// the debugger data, or null if debugger is not attached + /// + public object DebuggerContextData + { + get + { + return debuggerData; + } + + } + + public object Wrap (IScriptable scope, object obj, Type staticType) + { + if (obj == null || obj is IScriptable) + return obj; + if (staticType == null) + staticType = obj.GetType (); + + if (staticType.IsArray) + return new CliArray (scope, obj as Array); + + if (staticType.IsPrimitive) + return obj; + + if (OnWrap != null) { + ContextWrapEventArgs e = new ContextWrapEventArgs (this, scope, obj, staticType); + OnWrap (this, e); + obj = e.Target; + } + + return new CliObject (obj); + } + + /// Get/Set threshold of executed instructions counter that triggers call to + /// observeInstructionCount(). + /// When the threshold is zero, instruction counting is disabled, + /// otherwise each time the run-time executes at least the threshold value + /// of script instructions, observeInstructionCount() will + /// be called. + /// + public int InstructionObserverThreshold + { + get + { + return instructionThreshold; + } + + set + { + if (m_Sealed) + OnSealedMutation (); + if (value < 0) + throw new ArgumentException (); + instructionThreshold = value; + } + + } + + internal RegExpProxy RegExpProxy + { + get + { + if (regExpProxy == null) { + regExpProxy = new Types.RegExp.RegExpImpl (); + } + return regExpProxy; + } + set { + regExpProxy = value; + } + } + internal bool VersionECMA1 + { + get + { + return m_Version == Versions.Default || m_Version >= Versions.JS1_3; + } + + } + public bool GeneratingDebugChanged + { + get + { + return generatingDebugChanged; + } + + } + /// Language versions. + /// + /// All integral values are reserved for future version numbers. + /// + + + + + + + + + + + + public const string languageVersionProperty = "language version"; + public const string errorReporterProperty = "error reporter"; + + /// Convinient value to use as zero-length array of objects. + public static readonly object [] EmptyArgs; + + /// Create a new Context. + /// + /// Note that the Context must be associated with a thread before + /// it can be used to execute a script. + /// + /// + public Context (AppDomain appDomain) + { + if (appDomain == null) + throw new ArgumentNullException ("appDomain"); + Version = Versions.Default; + m_AppDomain = appDomain; + } + + /// Get a context associated with the current thread, creating + /// one if need be. + /// + /// The Context stores the execution state of the JavaScript + /// engine, so it is required that the context be entered + /// before execution may begin. Once a thread has entered + /// a Context, then getCurrentContext() may be called to find + /// the context that is associated with the current thread. + ///

+ /// Calling enter() will + /// return either the Context currently associated with the + /// thread, or will create a new context and associate it + /// with the current thread. Each call to enter() + /// must have a matching call to exit(). For example, + ///

+        /// Context cx = Context.enter();
+        /// try {
+        /// ...
+        /// cx.evaluateString(...);
+        /// } finally {
+        /// Context.exit();
+        /// }
+        /// 
+ /// Instead of using enter(), exit() pair consider using + /// {@link #call(ContextAction)} which guarantees proper + /// association of Context instances with the current thread and is faster. + /// With this method the above example becomes: + ///
+        /// Context.call(new ContextAction() {
+        /// public Object run(Context cx) {
+        /// ...
+        /// cx.evaluateString(...);
+        /// return null;
+        /// }
+        /// });
+        /// 
+ /// + ///
+ /// a Context associated with the current thread + /// + public static Context Enter () + { + return Enter (null, AppDomain.CurrentDomain); + } + + public static Context Enter (AppDomain appDomain) + { + return Enter (null, appDomain); + } + + /// Get a Context associated with the current thread, using + /// the given Context if need be. + ///

+ /// The same as enter() except that cx + /// is associated with the current thread and returned if + /// the current thread has no associated context and cx + /// is not associated with any other thread. + ///

+ /// a Context to associate with the thread if possible + /// + /// a Context associated with the current thread + /// + /// + public static Context Enter (Context cx) + { + return Enter (cx, AppDomain.CurrentDomain); + } + + public static Context Enter (Context cx, AppDomain appDomain) + { + Context old = CurrentContext; + if (old != null) { + if (cx != null && cx != old && cx.enterCount != 0) { + // The suplied context must be the context for + // the current thread if it is already entered + throw new ArgumentException ("Cannot enter Context active on another thread"); + } + if (old.factory != null) { + // Context with associated factory will be released + // automatically and does not need to change enterCount + return old; + } + if (old.m_Sealed) + OnSealedMutation (); + cx = old; + } + else { + if (cx == null) { + cx = new Context (appDomain); + } + else { + if (cx.m_Sealed) + OnSealedMutation (); + } + if (cx.enterCount != 0 || cx.factory != null) { + throw new Exception (); + } + + if (!cx.creationEventWasSent) { + cx.creationEventWasSent = true; + ContextFactory.Global.FireOnContextCreated (cx); + } + } + + if (old == null) { + Thread.SetData (LocalSlot, cx); + } + ++cx.enterCount; + + return cx; + } + + /// Exit a block of code requiring a Context. + /// + /// Calling exit() will remove the association between + /// the current thread and a Context if the prior call to + /// enter() on this thread newly associated a Context + /// with this thread. + /// Once the current thread no longer has an associated Context, + /// it cannot be used to execute JavaScript until it is again associated + /// with a Context. + /// + /// + public static void Exit () + { + Context cx = CurrentContext; + if (cx == null) { + throw new Exception ("Calling Context.exit without previous Context.enter"); + } + if (cx.factory != null) { + // Context with associated factory will be released + // automatically and does not need to change enterCount + return; + } + if (cx.enterCount < 1) + Context.CodeBug (); + if (cx.m_Sealed) + OnSealedMutation (); + --cx.enterCount; + if (cx.enterCount == 0) { + Thread.SetData (LocalSlot, null); + ContextFactory.Global.FireOnContextReleased (cx); + } + } + + + /// Call {@link + /// Callable#call(Context cx, Scriptable scope, Scriptable thisObj, + /// Object[] args)} + /// using the Context instance associated with the current thread. + /// If no Context is associated with the thread, then + /// {@link ContextFactory#makeContext()} will be called to construct + /// new Context instance. The instance will be temporary associated + /// with the thread during call to {@link ContextAction#run(Context)}. + ///

+ /// It is allowed to use null for factory argument + /// in which case the factory associated with the scope will be + /// used to create new context instances. + /// + ///

+ public static object Call (ContextFactory factory, ICallable callable, IScriptable scope, IScriptable thisObj, object [] args) + { + if (factory == null) { + factory = ContextFactory.Global; + } + + Context cx = CurrentContext; + if (cx != null) { + object result; + if (cx.factory != null) { + result = callable.Call (cx, scope, thisObj, args); + } + else { + // Context was associated with the thread via Context.enter, + // set factory to make Context.enter/exit to be no-op + // during call + cx.factory = factory; + try { + result = callable.Call (cx, scope, thisObj, args); + } + finally { + cx.factory = null; + } + } + return result; + } + + cx = PrepareNewContext (AppDomain.CurrentDomain, factory); + try { + return callable.Call (cx, scope, thisObj, args); + } + finally { + ReleaseContext (cx); + } + } + + internal void InitDefaultFeatures () + { + m_Features = Features.None; + + SetFeature (Features.E4x, (Version == Context.Versions.Default || Version >= Context.Versions.JS1_6)); + SetFeature (Features.GetterAndSetter, (Version == Context.Versions.Default || Version >= Context.Versions.JS1_5)); + SetFeature (Features.NonEcmaGetYear, (Version == Context.Versions.JS1_0 || Version == Context.Versions.JS1_1 || Version == Context.Versions.JS1_2)); + SetFeature (Features.ToStringAsSource, Version == Context.Versions.JS1_2); + SetFeature (Features.ParentProtoProperties, true); + } + + + private static Context PrepareNewContext (AppDomain appDomain, ContextFactory factory) + { + Context cx = new Context (appDomain); + if (cx.factory != null || cx.enterCount != 0) { + throw new Exception ("factory.makeContext() returned Context instance already associated with some thread"); + } + cx.factory = factory; + factory.FireOnContextCreated (cx); + if (factory.Sealed && !cx.Sealed) { + cx.Seal ((object)null); + } + Thread.SetData (LocalSlot, cx); + return cx; + } + + private static void ReleaseContext (Context cx) + { + Thread.SetData (LocalSlot, null); + try { + cx.factory.FireOnContextReleased (cx); + } + finally { + cx.factory = null; + } + } + + + + /// Seal this Context object so any attempt to modify any of its properties + /// including calling {@link #enter()} and {@link #exit()} methods will + /// throw an exception. + ///

+ /// If sealKey is not null, calling + /// {@link #unseal(Object sealKey)} with the same key unseals + /// the object. If sealKey is null, unsealing is no longer possible. + /// + ///

+ public void Seal (object sealKey) + { + if (m_Sealed) + OnSealedMutation (); + m_Sealed = true; + this.m_SealKey = sealKey; + } + + /// Unseal previously sealed Context object. + /// The sealKey argument should not be null and should match + /// sealKey suplied with the last call to + /// {@link #seal(Object)} or an exception will be thrown. + /// + /// + public void Unseal (object sealKey) + { + if (sealKey == null) + throw new ArgumentException (); + if (this.m_SealKey != sealKey) + throw new ArgumentException (); + if (!m_Sealed) + throw new Exception (); + m_Sealed = false; + this.m_SealKey = null; + } + + internal static void OnSealedMutation () + { + throw new Exception (); + } + + /// + /// Get the current language version. + /// + public Versions Version + { + get + { + return m_Version; + } + set + { + if (m_Sealed) + OnSealedMutation (); + this.m_Version = value; + + InitDefaultFeatures (); + } + } + + public static bool IsValidLanguageVersion (int version) + { + return ToValidLanguageVersion (version) != Versions.Unknown; + } + + public static Versions ToValidLanguageVersion (int version) + { + Versions ver = Versions.Unknown; + if (version > 0 || version < (int)Versions.JS1_6) + ver = (Versions)version; + return ver; + } + + public static void CheckLanguageVersion (int version) + { + if (IsValidLanguageVersion (version)) { + return; + } + throw new ArgumentException ("Bad language version: " + version); + } + + /// Get the current error reporter. + /// + /// + public ErrorReporter ErrorReporter + { + get + { + if (m_ErrorReporter == null) { + return DefaultErrorReporter.instance; + } + return m_ErrorReporter; + } + set + { + if (m_Sealed) + OnSealedMutation (); + if (value == null) + throw new ArgumentException (); + this.m_ErrorReporter = value; + } + } + + /// + /// Get the current locale. Returns the default locale if none has + /// been set. + /// + public CultureInfo CurrentCulture + { + get + { + if (culture == null) + culture = Thread.CurrentThread.CurrentCulture; + return culture; + } + set + { + if (m_Sealed) + OnSealedMutation (); + culture = value; + + // HACK: Needed for example on DateTime.ToString() + if (Thread.CurrentThread.CurrentCulture != culture) + Thread.CurrentThread.CurrentCulture = culture; + } + } + + /// Report a warning using the error reporter for the current thread. + /// + /// + /// the warning message to report + /// + /// a string describing the source, such as a filename + /// + /// the starting line number + /// + /// the text of the line (may be null) + /// + /// the offset into lineSource where problem was detected + /// + + public static void ReportWarning (string message, string sourceName, int lineno, string lineSource, int lineOffset) + { + Context cx = Context.CurrentContext; + cx.ErrorReporter.Warning (message, sourceName, lineno, lineSource, lineOffset); + } + + public static void ReportWarningById (string messageId, params string [] arguments) + { + int [] linep = new int [] { 0 }; + string filename = GetSourcePositionFromStack (linep); + Context.ReportWarning (ScriptRuntime.GetMessage (messageId, arguments), filename, linep [0], null, 0); + } + + /// Report a warning using the error reporter for the current thread. + /// + /// + /// the warning message to report + /// + public static void ReportWarning (string message) + { + int [] linep = new int [] { 0 }; + string filename = GetSourcePositionFromStack (linep); + Context.ReportWarning (message, filename, linep [0], null, 0); + } + + /// Report an error using the error reporter for the current thread. + /// + /// + /// the error message to report + /// + /// a string describing the source, such as a filename + /// + /// the starting line number + /// + /// the text of the line (may be null) + /// + /// the offset into lineSource where problem was detected + /// + public static void ReportError (string message, string sourceName, int lineno, string lineSource, int lineOffset) + { + Context cx = CurrentContext; + if (cx != null) { + cx.ErrorReporter.Error (message, sourceName, lineno, lineSource, lineOffset); + } + else { + throw new EcmaScriptRuntimeException (message, sourceName, lineno, lineSource, lineOffset); + } + } + + /// Report an error using the error reporter for the current thread. + /// + /// + /// the error message to report + /// + + public static void ReportError (string message) + { + int [] linep = new int [] { 0 }; + string filename = GetSourcePositionFromStack (linep); + Context.ReportError (message, filename, linep [0], null, 0); + } + + /// Report a runtime error using the error reporter for the current thread. + /// + /// + /// the error message to report + /// + /// a string describing the source, such as a filename + /// + /// the starting line number + /// + /// the text of the line (may be null) + /// + /// the offset into lineSource where problem was detected + /// + /// a runtime exception that will be thrown to terminate the + /// execution of the script + /// + public static EcmaScriptRuntimeException ReportRuntimeError (string message, string sourceName, int lineno, string lineSource, int lineOffset) + { + Context cx = CurrentContext; + if (cx != null) { + return cx.ErrorReporter.RuntimeError (message, sourceName, lineno, lineSource, lineOffset); + } + else { + throw new EcmaScriptRuntimeException (message, sourceName, lineno, lineSource, lineOffset); + } + } + + + internal static EcmaScriptRuntimeException ReportRuntimeErrorById (string messageId, params object [] args) + { + return ReportRuntimeError (ScriptRuntime.GetMessage (messageId, args)); + } + + /// Report a runtime error using the error reporter for the current thread. + /// + /// + /// the error message to report + /// + public static EcmaScriptRuntimeException ReportRuntimeError (string message) + { + int [] linep = new int [] { 0 }; + string filename = GetSourcePositionFromStack (linep); + return Context.ReportRuntimeError (message, filename, linep [0], null, 0); + } + + /// Initialize the standard objects. + /// + /// Creates instances of the standard objects and their constructors + /// (Object, String, Number, Date, etc.), setting up 'scope' to act + /// as a global object as in ECMA 15.1.

+ /// + /// This method must be called to initialize a scope before scripts + /// can be evaluated in that scope.

+ /// + /// This method does not affect the Context it is called upon. + /// + ///

+ /// the initialized scope + /// + public ScriptableObject InitStandardObjects () + { + return InitStandardObjects (null, false); + } + + /// Initialize the standard objects. + /// + /// Creates instances of the standard objects and their constructors + /// (Object, String, Number, Date, etc.), setting up 'scope' to act + /// as a global object as in ECMA 15.1.

+ /// + /// This method must be called to initialize a scope before scripts + /// can be evaluated in that scope.

+ /// + /// This method does not affect the Context it is called upon. + /// + ///

+ /// the scope to initialize, or null, in which case a new + /// object will be created to serve as the scope + /// + /// the initialized scope. The method returns the value of the scope + /// argument if it is not null or newly allocated scope object which + /// is an instance {@link ScriptableObject}. + /// + public IScriptable InitStandardObjects (ScriptableObject scope) + { + return InitStandardObjects (scope, false); + } + + /// Initialize the standard objects. + /// + /// Creates instances of the standard objects and their constructors + /// (Object, String, Number, Date, etc.), setting up 'scope' to act + /// as a global object as in ECMA 15.1.

+ /// + /// This method must be called to initialize a scope before scripts + /// can be evaluated in that scope.

+ /// + /// This method does not affect the Context it is called upon.

+ /// + /// This form of the method also allows for creating "sealed" standard + /// objects. An object that is sealed cannot have properties added, changed, + /// or removed. This is useful to create a "superglobal" that can be shared + /// among several top-level objects. Note that sealing is not allowed in + /// the current ECMA/ISO language specification, but is likely for + /// the next version. + /// + ///

+ /// the scope to initialize, or null, in which case a new + /// object will be created to serve as the scope + /// + /// whether or not to create sealed standard objects that + /// cannot be modified. + /// + /// the initialized scope. The method returns the value of the scope + /// argument if it is not null or newly allocated scope object. + /// + public ScriptableObject InitStandardObjects (ScriptableObject scope, bool zealed) + { + return ScriptRuntime.InitStandardObjects (this, scope, zealed); + } + + /// Evaluate a JavaScript source string. + /// + /// The provided source name and line number are used for error messages + /// and for producing debug information. + /// + /// + /// the scope to execute in + /// + /// the JavaScript source + /// + /// a string describing the source, such as a filename + /// + /// the starting line number + /// + /// an arbitrary object that specifies security + /// information about the origin or owner of the script. For + /// implementations that don't care about security, this value + /// may be null. + /// + /// the result of evaluating the string + /// + public object EvaluateString (IScriptable scope, string source, string sourceName, int lineno, object securityDomain) + { + IScript script = CompileString (source, sourceName, lineno, securityDomain); + if (script != null) { + return script.Exec (this, scope); + } + else { + return null; + } + } + + /// Evaluate a reader as JavaScript source. + /// + /// All characters of the reader are consumed. + /// + /// + /// the scope to execute in + /// + /// the Reader to get JavaScript source from + /// + /// a string describing the source, such as a filename + /// + /// the starting line number + /// + /// an arbitrary object that specifies security + /// information about the origin or owner of the script. For + /// implementations that don't care about security, this value + /// may be null. + /// + /// the result of evaluating the source + /// + /// + /// IOException if an IOException was generated by the Reader + /// + public object EvaluateReader (IScriptable scope, StreamReader sr, string sourceName, int lineno, object securityDomain) + { + IScript script = CompileReader (sr, sourceName, lineno, securityDomain); + + if (script != null) { + return script.Exec (this, scope); + } + return null; + } + + /// Check whether a string is ready to be compiled. + ///

+ /// stringIsCompilableUnit is intended to support interactive compilation of + /// javascript. If compiling the string would result in an error + /// that might be fixed by appending more source, this method + /// returns false. In every other case, it returns true. + ///

+ /// Interactive shells may accumulate source lines, using this + /// method after each new line is appended to check whether the + /// statement being entered is complete. + /// + ///

+ /// the source buffer to check + /// + /// whether the source is ready for compilation + /// + public ScriptOrFnNode IsCompilableUnit (string source) + { + ScriptOrFnNode ret = null; + bool errorseen = false; + CompilerEnvirons compilerEnv = new CompilerEnvirons (); + compilerEnv.initFromContext (this); + // no source name or source text manager, because we're just + // going to throw away the result. + compilerEnv.setGeneratingSource (false); + Parser p = new Parser (compilerEnv, DefaultErrorReporter.instance); + try { + ret = p.Parse (source, null, 1); + } + catch (EcmaScriptRuntimeException) { + errorseen = true; + } + // Return false only if an error occurred as a result of reading past + // the end of the file, i.e. if the source could be fixed by + // appending more source. + if (!(errorseen && p.Eof)) + return ret; + return null; + } + + + /// Compiles the source in the given reader. + ///

+ /// Returns a script that may later be executed. + /// Will consume all the source in the reader. + /// + ///

+ /// the input reader + /// + /// a string describing the source, such as a filename + /// + /// the starting line number for reporting errors + /// + /// an arbitrary object that specifies security + /// information about the origin or owner of the script. For + /// implementations that don't care about security, this value + /// may be null. + /// + /// a script that may later be executed + /// + /// IOException if an IOException was generated by the Reader + /// + public IScript CompileReader (StreamReader sr, string sourceName, int lineno, object securityDomain) + { + if (lineno < 0) + throw new ArgumentException ("lineno may not be negative", "lineno"); + return (IScript)CompileImpl (null, sr, null, sourceName, lineno, securityDomain, false, null, null); + } + + /// Compiles the source in the given string. + ///

+ /// Returns a script that may later be executed. + /// + ///

+ /// the source string + /// + /// a string describing the source, such as a filename + /// + /// the starting line number for reporting errors + /// + /// an arbitrary object that specifies security + /// information about the origin or owner of the script. For + /// implementations that don't care about security, this value + /// may be null. + /// + /// a script that may later be executed + /// + public IScript CompileString (string source, string sourceName, int lineno, object securityDomain) + { + if (lineno < 0) { + // For compatibility IllegalArgumentException can not be thrown here + lineno = 0; + } + return CompileString (source, null, null, sourceName, lineno, securityDomain); + } + + internal IScript CompileString (string source, Interpreter compiler, ErrorReporter compilationErrorReporter, string sourceName, int lineno, object securityDomain) + { + return (IScript)CompileImpl (null, null, source, sourceName, lineno, securityDomain, false, compiler, compilationErrorReporter); + } + + /// Compile a JavaScript function. + ///

+ /// The function source must be a function definition as defined by + /// ECMA (e.g., "function f(a) { return a; }"). + /// + ///

+ /// the scope to compile relative to + /// + /// the function definition source + /// + /// a string describing the source, such as a filename + /// + /// the starting line number + /// + /// an arbitrary object that specifies security + /// information about the origin or owner of the script. For + /// implementations that don't care about security, this value + /// may be null. + /// + /// a Function that may later be called + /// + public IFunction CompileFunction (IScriptable scope, string source, string sourceName, int lineno, object securityDomain) + { + return CompileFunction (scope, source, null, null, sourceName, lineno, securityDomain); + } + + internal IFunction CompileFunction (IScriptable scope, string source, Interpreter compiler, ErrorReporter compilationErrorReporter, string sourceName, int lineno, object securityDomain) + { + return (IFunction)CompileImpl (scope, null, source, sourceName, lineno, securityDomain, true, compiler, compilationErrorReporter); + } + + /// Decompile the script. + ///

+ /// The canonical source of the script is returned. + /// + ///

+ /// the script to decompile + /// + /// the number of spaces to indent the result + /// + /// a string representing the script source + /// + public string DecompileScript (IScript script, int indent) + { + BuiltinFunction scriptImpl = (BuiltinFunction)script; + return scriptImpl.Decompile (indent, 0); + } + + /// Decompile a JavaScript Function. + ///

+ /// Decompiles a previously compiled JavaScript function object to + /// canonical source. + ///

+ /// Returns function body of '[native code]' if no decompilation + /// information is available. + /// + ///

+ /// the JavaScript function to decompile + /// + /// the number of spaces to indent the result + /// + /// a string representing the function source + /// + public string DecompileFunction (IFunction fun, int indent) + { + if (fun is BaseFunction) + return ((BaseFunction)fun).Decompile (indent, 0); + else + return "function " + fun.ClassName + "() {\n\t[native code]\n}\n"; + } + + /// Decompile the body of a JavaScript Function. + ///

+ /// Decompiles the body a previously compiled JavaScript Function + /// object to canonical source, omitting the function header and + /// trailing brace. + /// + /// Returns '[native code]' if no decompilation information is available. + /// + ///

+ /// the JavaScript function to decompile + /// + /// the number of spaces to indent the result + /// + /// a string representing the function body source. + /// + public string DecompileFunctionBody (IFunction fun, int indent) + { + if (fun is BaseFunction) { + BaseFunction bf = (BaseFunction)fun; + return bf.Decompile (indent, Decompiler.ONLY_BODY_FLAG); + } + // ALERT: not sure what the right response here is. + return "[native code]\n"; + } + + /// Create a new JavaScript object. + /// + /// Equivalent to evaluating "new Object()". + /// + /// the scope to search for the constructor and to evaluate + /// against + /// + /// the new object + /// + public IScriptable NewObject (IScriptable scope) + { + return NewObject (scope, "Object", ScriptRuntime.EmptyArgs); + } + + /// Create a new JavaScript object by executing the named constructor. + /// + /// The call newObject(scope, "Foo") is equivalent to + /// evaluating "new Foo()". + /// + /// + /// the scope to search for the constructor and to evaluate against + /// + /// the name of the constructor to call + /// + /// the new object + /// + public IScriptable NewObject (IScriptable scope, string constructorName) + { + return NewObject (scope, constructorName, ScriptRuntime.EmptyArgs); + } + + /// Creates a new JavaScript object by executing the named constructor. + /// + /// Searches scope for the named constructor, calls it with + /// the given arguments, and returns the result.

+ /// + /// The code + ///

+        /// Object[] args = { "a", "b" };
+        /// newObject(scope, "Foo", args)
+ /// is equivalent to evaluating "new Foo('a', 'b')", assuming that the Foo + /// constructor has been defined in scope. + /// + ///
+ /// The scope to search for the constructor and to evaluate + /// against + /// + /// the name of the constructor to call + /// + /// the array of arguments for the constructor + /// + /// the new object + /// + public IScriptable NewObject (IScriptable scope, string constructorName, object [] args) + { + scope = ScriptableObject.GetTopLevelScope (scope); + IFunction ctor = ScriptRuntime.getExistingCtor (this, scope, constructorName); + if (args == null) { + args = ScriptRuntime.EmptyArgs; + } + return ctor.Construct (this, scope, args); + } + + /// Create an array with a specified initial length. + ///

+ ///

+ /// the scope to create the object in + /// + /// the initial length (JavaScript arrays may have + /// additional properties added dynamically). + /// + /// the new array object + /// + public IScriptable NewArray (IScriptable scope, int length) + { + BuiltinArray result = new BuiltinArray (length); + ScriptRuntime.setObjectProtoAndParent (result, scope); + return result; + } + + /// Create an array with a set of initial elements. + /// + /// + /// the scope to create the object in. + /// + /// the initial elements. Each object in this array + /// must be an acceptable JavaScript type and type + /// of array should be exactly Object[], not + /// SomeObjectSubclass[]. + /// + /// the new array object. + /// + public IScriptable NewArray (IScriptable scope, object [] elements) + { + Type elementType = elements.GetType ().GetElementType (); + if (elementType != typeof (object)) + throw new ArgumentException (); + BuiltinArray result = new BuiltinArray (elements); + ScriptRuntime.setObjectProtoAndParent (result, scope); + return result; + } + + /// Get the elements of a JavaScript array. + ///

+ /// If the object defines a length property convertible to double number, + /// then the number is converted Uint32 value as defined in Ecma 9.6 + /// and Java array of that size is allocated. + /// The array is initialized with the values obtained by + /// calling get() on object for each value of i in [0,length-1]. If + /// there is not a defined value for a property the Undefined value + /// is used to initialize the corresponding element in the array. The + /// Java array is then returned. + /// If the object doesn't define a length property or it is not a number, + /// empty array is returned. + ///

+ /// the JavaScript array or array-like object + /// + /// a Java array of objects + /// + + public object [] GetElements (IScriptable obj) + { + return ScriptRuntime.getArrayElements (obj); + } + + + /// Convenient method to convert java value to its closest representation + /// in JavaScript. + ///

+ /// If value is an instance of String, Number, Boolean, Function or + /// Scriptable, it is returned as it and will be treated as the corresponding + /// JavaScript type of string, number, boolean, function and object. + ///

+ /// Note that for Number instances during any arithmetic operation in + /// JavaScript the engine will always use the result of + /// Number.doubleValue() resulting in a precision loss if + /// the number can not fit into double. + ///

+ /// If value is an instance of Character, it will be converted to string of + /// length 1 and its JavaScript type will be string. + ///

+ /// The rest of values will be wrapped as LiveConnect objects + /// by calling {@link WrapFactory#wrap(Context cx, Scriptable scope, + /// Object obj, Class staticType)} as in: + ///

+        /// Context cx = Context.getCurrentContext();
+        /// return cx.getWrapFactory().wrap(cx, scope, value, null);
+        /// 
+ /// + ///
+ /// any Java object + /// + /// top scope object + /// + /// value suitable to pass to any API that takes JavaScript values. + /// + public static object CliToJS (Context cx, object value, IScriptable scope) + { + if (value is string || CliHelper.IsNumber (value) || value is bool || value is IScriptable) { + return value; + } + else if (value is char) { + return Convert.ToString (((char)value)); + } + else { + Type type = (value as Type); + if (type != null) { + return cx.Wrap (scope, value, (Type)value); + } else { + return cx.Wrap (scope, value, null); + } + } + } + + /// Convert a JavaScript value into the desired type. + /// Uses the semantics defined with LiveConnect3 and throws an + /// Illegal argument exception if the conversion cannot be performed. + /// + /// the JavaScript value to convert + /// + /// the Java type to convert to. Primitive Java + /// types are represented using the TYPE fields in the corresponding + /// wrapper class in java.lang. + /// + /// the converted value + /// + /// EvaluatorException if the conversion cannot be performed + public static object JsToCli (object value, System.Type desiredType) + { + return CliObject.CoerceType (desiredType, value); + } + + + + /// Rethrow the exception wrapping it as the script runtime exception. + /// Unless the exception is instance of {@link EcmaError} or + /// {@link EvaluatorException} it will be wrapped as + /// {@link WrappedException}, a subclass of {@link EvaluatorException}. + /// The resulting exception object always contains + /// source name and line number of script that triggered exception. + ///

+ /// This method always throws an exception, its return value is provided + /// only for convenience to allow a usage like: + ///

+        /// throw Context.throwAsScriptRuntimeEx(ex);
+        /// 
+ /// to indicate that code after the method is unreachable. + ///
+ /// EvaluatorException + /// EcmaError + public static Exception ThrowAsScriptRuntimeEx (Exception e) + { + while ((e is TargetInvocationException)) { + e = ((TargetInvocationException)e).InnerException; + } + if (e is EcmaScriptException) { + throw e; + } + throw new EcmaScriptRuntimeException (e); + } + + public static bool IsValidOptimizationLevel (int optimizationLevel) + { + return -1 <= optimizationLevel && optimizationLevel <= 9; + } + + public static void CheckOptimizationLevel (int optimizationLevel) + { + if (IsValidOptimizationLevel (optimizationLevel)) { + return; + } + throw new ArgumentException ("Optimization level outside [-1..9]: " + optimizationLevel); + } + + /// Set the security controller for this context. + ///

SecurityController may only be set if it is currently null + /// and {@link SecurityController#hasGlobal()} is false. + /// Otherwise a SecurityException is thrown. + ///

+ /// a SecurityController object + /// + /// SecurityException if there is already a SecurityController + /// object for this Context or globally installed. + /// + public SecurityController SecurityController + { + set + { + if (m_Sealed) + OnSealedMutation (); + if (value == null) + throw new ArgumentException (); + if (securityController != null) { + throw new System.Security.SecurityException ("Can not overwrite existing SecurityController object"); + } + if (SecurityController.HasGlobal ()) { + throw new System.Security.SecurityException ("Can not overwrite existing global SecurityController object"); + } + securityController = value; + } + get + { + SecurityController global = SecurityController.Global; + if (global != null) { + return global; + } + return securityController; + } + } + + /// Get a value corresponding to a key. + ///

+ /// Since the Context is associated with a thread it can be + /// used to maintain values that can be later retrieved using + /// the current thread. + ///

+ /// Note that the values are maintained with the Context, so + /// if the Context is disassociated from the thread the values + /// cannot be retreived. Also, if private data is to be maintained + /// in this manner the key should be a java.lang.Object + /// whose reference is not divulged to untrusted code. + ///

+ /// the key used to lookup the value + /// + /// a value previously stored using putThreadLocal. + /// + public object GetThreadLocal (object key) + { + if (hashtable == null) + return null; + return hashtable [key]; + } + + /// Put a value that can later be retrieved using a given key. + ///

+ ///

+ /// the key used to index the value + /// + /// the value to save + /// + public void PutThreadLocal (object key, object value) + { + if (m_Sealed) + OnSealedMutation (); + if (hashtable == null) + hashtable = Hashtable.Synchronized (new Hashtable ()); + hashtable [key] = value; + } + + /// Remove values from thread-local storage. + /// the key for the entry to remove. + /// + public void RemoveThreadLocal (object key) + { + if (m_Sealed) + OnSealedMutation (); + if (hashtable == null) + return; + hashtable.Remove (key); + } + + + + /// Return the current debugger. + /// the debugger, or null if none is attached. + /// + public Debugger Debugger + { + get + { + return m_Debugger; + } + } + + /// Set the associated debugger. + /// the debugger to be used on callbacks from + /// the engine. + /// + /// arbitrary object that debugger can use to store + /// per Context data. + /// + public void SetDebugger (Debugger debugger, object contextData) + { + if (m_Sealed) + OnSealedMutation (); + this.m_Debugger = debugger; + debuggerData = contextData; + } + + /// Return DebuggableScript instance if any associated with the script. + /// If callable supports DebuggableScript implementation, the method + /// returns it. Otherwise null is returned. + /// + public static DebuggableScript getDebuggableView (IScript script) + { + if (script is BuiltinFunction) { + return ((BuiltinFunction)script).DebuggableView; + } + return null; + } + + + private Features m_Features = Features.None; + + /// + /// Controls certain aspects of script semantics. + /// Should be overwritten to alter default behavior. + /// + /// The default implementation calls + /// {@link ContextFactory#hasFeature(Context cx, int featureIndex)} + /// that allows to customize Context behavior without introducing + /// Context subclasses. {@link ContextFactory} documentation gives + /// an example of hasFeature implementation. + /// + /// + /// feature to check + /// + /// true if the feature feature is turned on + /// + public bool HasFeature (Features feature) + { + return (m_Features & feature) == feature; + } + + public void SetFeature (Features feature, bool isEnabled) + { + if (isEnabled) { + m_Features |= feature; + } + else { + if (HasFeature (feature)) + m_Features = m_Features ^ feature; + } + } + + + /// Allow application to monitor counter of executed script instructions + /// in Context subclasses. + /// Run-time calls this when instruction counting is enabled and the counter + /// reaches limit set by setInstructionObserverThreshold(). + /// The method is useful to observe long running scripts and if necessary + /// to terminate them. + ///

+ /// The instruction counting support is available only for interpreted + /// scripts generated when the optimization level is set to -1. + ///

+ /// The default implementation calls + /// {@link ContextFactory#observeInstructionCount(Context cx, + /// int instructionCount)} + /// that allows to customize Context behavior without introducing + /// Context subclasses. + /// + ///

+ /// amount of script instruction executed since + /// last call to observeInstructionCount + /// + /// Error to terminate the script + protected internal void ObserveInstructionCount (int instructionCount) + { + Factory.ObserveInstructionCount (this, instructionCount); + } + + private object CompileImpl (IScriptable scope, StreamReader sourceReader, string sourceString, string sourceName, int lineno, object securityDomain, bool returnFunction, Interpreter compiler, ErrorReporter compilationErrorReporter) + { + if (securityDomain != null && securityController == null) { + throw new ArgumentException ("securityDomain should be null if setSecurityController() was never called"); + } + + // One of sourceReader or sourceString has to be null + if (!(sourceReader == null ^ sourceString == null)) + Context.CodeBug (); + // scope should be given if and only if compiling function + if (!(scope == null ^ returnFunction)) + Context.CodeBug (); + + CompilerEnvirons compilerEnv = new CompilerEnvirons (); + compilerEnv.initFromContext (this); + if (compilationErrorReporter == null) { + compilationErrorReporter = compilerEnv.getErrorReporter (); + } + + if (m_Debugger != null) { + if (sourceReader != null) { + sourceString = sourceReader.ReadToEnd (); + sourceReader = null; + } + } + + Parser p = new Parser (compilerEnv, compilationErrorReporter); + if (returnFunction) { + p.calledByCompileFunction = true; + } + ScriptOrFnNode tree; + if (sourceString != null) { + tree = p.Parse (sourceString, sourceName, lineno); + } + else { + tree = p.Parse (sourceReader, sourceName, lineno); + } + if (returnFunction) { + if (!(tree.FunctionCount == 1 && tree.FirstChild != null && tree.FirstChild.Type == Token.FUNCTION)) { + // TODO: the check just look for the first child + // TODO: and allows for more nodes after it for compatibility + // TODO: with sources like function() {};;; + throw new ArgumentException ("compileFunction only accepts source with single JS function: " + sourceString); + } + } + + + + if (compiler == null) { + compiler = new Interpreter (); + //compiler = new Compiler(); + } + + string encodedSource = p.EncodedSource; + + object bytecode = compiler.Compile (compilerEnv, tree, encodedSource, returnFunction); + + if (m_Debugger != null) { + if (sourceString == null) + Context.CodeBug (); + if (bytecode is DebuggableScript) { + DebuggableScript dscript = (DebuggableScript)bytecode; + NotifyDebugger (this, dscript, sourceString); + } + else { + throw new Exception ("NOT SUPPORTED"); + } + } + + object result; + if (returnFunction) { + result = compiler.CreateFunctionObject (this, scope, bytecode, securityDomain); + } + else { + result = compiler.CreateScriptObject (bytecode, securityDomain); + } + + return result; + } + + private static void NotifyDebugger (Context cx, DebuggableScript dscript, string debugSource) + { + cx.m_Debugger.HandleCompilationDone (cx, dscript, debugSource); + for (int i = 0; i != dscript.FunctionCount; ++i) { + NotifyDebugger (cx, dscript.GetFunction (i), debugSource); + } + } + + internal static string GetSourcePositionFromStack (int [] linep) + { + Context cx = CurrentContext; + if (cx == null) + return null; + if (cx.lastInterpreterFrame != null) { + return Interpreter.GetSourcePositionFromStack (cx, linep); + } + + System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace (); + System.Diagnostics.StackFrame sf = st.GetFrame (0); + linep [0] = sf.GetFileLineNumber (); + return Path.GetFileName (sf.GetFileName ()); + } + + + /// Add a name to the list of names forcing the creation of real + /// activation objects for functions. + /// + /// + /// the name of the object to add to the list + /// + public void AddActivationName (string name) + { + if (m_Sealed) + OnSealedMutation (); + if (activationNames == null) + activationNames = Hashtable.Synchronized (new Hashtable (5)); + activationNames [name] = name; + } + + /// Check whether the name is in the list of names of objects + /// forcing the creation of activation objects. + /// + /// + /// the name of the object to test + /// + /// + /// true if an function activation object is needed. + /// + public bool IsActivationNeeded (string name) + { + return activationNames != null && activationNames.ContainsKey (name); + } + + /// Remove a name from the list of names forcing the creation of real + /// activation objects for functions. + /// + /// + /// the name of the object to remove from the list + /// + public void RemoveActivationName (string name) + { + if (m_Sealed) + OnSealedMutation (); + if (activationNames != null) + activationNames.Remove (name); + } + + private static string implementationVersion; + + private ContextFactory factory; + private bool m_Sealed; + private object m_SealKey; + + internal IScriptable topCallScope; + internal BuiltinCall currentActivationCall; + internal XMLLib cachedXMLLib; + + // for Objects, Arrays to tag themselves as being printed out, + // so they don't print themselves out recursively. + // Use ObjToIntMap instead of java.util.HashSet for JDK 1.1 compatibility + internal ObjToIntMap iterating; + + internal object interpreterSecurityDomain; + + internal Versions m_Version = Versions.Unknown; + + private SecurityController securityController; + + private ErrorReporter m_ErrorReporter; + internal RegExpProxy regExpProxy; + private System.Globalization.CultureInfo culture; + private bool generatingDebug; + private bool generatingDebugChanged; + private bool generatingSource = true; + internal bool compileFunctionsWithDynamicScopeFlag = false; + internal bool useDynamicScope; + private int m_OptimizationLevel; + + internal Debugger m_Debugger; + private object debuggerData; + private int enterCount; + private Hashtable hashtable; + + private bool creationEventWasSent; + + /// This is the list of names of objects forcing the creation of + /// function activation records. + /// + internal Hashtable activationNames; + + // For the interpreter to store the last frame for error reports etc. + internal object lastInterpreterFrame; + + // For the interpreter to store information about previous invocations + // interpreter invocations + internal ObjArray previousInterpreterInvocations; + + // For instruction counting (interpreter only) + internal int instructionCount; + internal int instructionThreshold; + + // It can be used to return the second index-like result from function + internal int scratchIndex; + + // It can be used to return the second uint32 result from function + internal long scratchUint32; + + // It can be used to return the second Scriptable result from function + internal IScriptable scratchScriptable; + static Context () + { + EmptyArgs = ScriptRuntime.EmptyArgs; + } + + public void Dispose () + { + Context.Exit (); + } + + /// + /// Throws RuntimeException to indicate failed assertion. + /// The function never returns and its return type is RuntimeException + /// only to be able to write throw EcmaScriptHelper.CodeBug() if plain + /// EcmaScriptHelper.CodeBug() triggers unreachable code error. + /// + public static Exception CodeBug () + { + Exception ex = new Exception ("FAILED ASSERTION"); + Console.Error.WriteLine (ex.ToString ()); + throw ex; + } + + } +} diff --git a/Code/EcmaScript.NET/ContextEvents.cs b/src/EcmaScript.NET/ContextEvents.cs similarity index 95% rename from Code/EcmaScript.NET/ContextEvents.cs rename to src/EcmaScript.NET/ContextEvents.cs index d7ce984..20a6e39 100644 --- a/Code/EcmaScript.NET/ContextEvents.cs +++ b/src/EcmaScript.NET/ContextEvents.cs @@ -1,105 +1,105 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -namespace EcmaScript.NET -{ - - public class ContextEventArgs : EventArgs - { - - private Context m_Context = null; - - /// - /// The underlying context - /// - public Context Context - { - get { return m_Context; } - } - - /// - /// Creates a new ContextEventArgs object - /// - /// - public ContextEventArgs (Context cx) - { - m_Context = cx; - } - - } - - public class ContextScriptableEventArgs : ContextEventArgs - { - - - private IScriptable m_Scope = null; - - public ContextScriptableEventArgs (Context cx, IScriptable scope) - : base (cx) - { - m_Scope = scope; - } - - public IScriptable Scope - { - get { return m_Scope; } - } - - } - - - /// - /// - /// - public class ContextWrapEventArgs : ContextScriptableEventArgs - { - - private object m_Source = null; - - public object Source - { - get { return m_Source; } - } - - private object m_Target = null; - - public object Target - { - get { return m_Target; } - set { m_Target = null; } - } - - - private Type m_StaticType = null; - - public Type staticType - { - get { return m_StaticType; } - } - - public ContextWrapEventArgs (Context cx, IScriptable scope, object obj, Type staticType) - : base (cx, scope) - { - m_Source = obj; - m_StaticType = staticType; - } - - } - - public delegate void ContextEventHandler (object sender, ContextEventArgs e); - - public delegate void ContextWrapHandler (object sender, ContextWrapEventArgs e); - -} +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +namespace EcmaScript.NET +{ + + public class ContextEventArgs : EventArgs + { + + private Context m_Context = null; + + /// + /// The underlying context + /// + public Context Context + { + get { return m_Context; } + } + + /// + /// Creates a new ContextEventArgs object + /// + /// + public ContextEventArgs (Context cx) + { + m_Context = cx; + } + + } + + public class ContextScriptableEventArgs : ContextEventArgs + { + + + private IScriptable m_Scope = null; + + public ContextScriptableEventArgs (Context cx, IScriptable scope) + : base (cx) + { + m_Scope = scope; + } + + public IScriptable Scope + { + get { return m_Scope; } + } + + } + + + /// + /// + /// + public class ContextWrapEventArgs : ContextScriptableEventArgs + { + + private object m_Source = null; + + public object Source + { + get { return m_Source; } + } + + private object m_Target = null; + + public object Target + { + get { return m_Target; } + set { m_Target = null; } + } + + + private Type m_StaticType = null; + + public Type staticType + { + get { return m_StaticType; } + } + + public ContextWrapEventArgs (Context cx, IScriptable scope, object obj, Type staticType) + : base (cx, scope) + { + m_Source = obj; + m_StaticType = staticType; + } + + } + + public delegate void ContextEventHandler (object sender, ContextEventArgs e); + + public delegate void ContextWrapHandler (object sender, ContextWrapEventArgs e); + +} diff --git a/Code/EcmaScript.NET/ContextFactory.cs b/src/EcmaScript.NET/ContextFactory.cs similarity index 95% rename from Code/EcmaScript.NET/ContextFactory.cs rename to src/EcmaScript.NET/ContextFactory.cs index 65819fc..f80d038 100644 --- a/Code/EcmaScript.NET/ContextFactory.cs +++ b/src/EcmaScript.NET/ContextFactory.cs @@ -1,150 +1,150 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -namespace EcmaScript.NET -{ - - /// Factory class that Rhino runtime use to create new {@link Context} - /// instances or to notify about Context execution. - ///

- /// When Rhino runtime needs to create new {@link Context} instance during - /// execution of {@link Context#enter()} or {@link Context}, it will call - /// {@link #makeContext()} of the current global ContextFactory. - /// See {@link #getGlobal()} and {@link #initGlobal(ContextFactory)}. - ///

- /// It is also possible to use explicit ContextFactory instances for Context - /// creation. This is useful to have a set of independent Rhino runtime - /// instances under single JVM. See {@link #call(ContextAction)}. - ///

- ///

- - public class ContextFactory - { - /// Get global ContextFactory. - /// - /// - public static ContextFactory Global - { - get - { - return global; - } - - } - - /// Checks if this is a sealed ContextFactory. - virtual public bool Sealed - { - get - { - return zealed; - } - - } - private static volatile bool hasCustomGlobal; - private static ContextFactory global = new ContextFactory (); - - private volatile bool zealed; - - - /// Notify about newly created {@link Context} object. - public event ContextEventHandler OnContextCreated; - - /// Notify that the specified {@link Context} instance is no longer - /// associated with the current thread. - /// - public event ContextEventHandler OnContextReleased; - - /// Check if global factory was set. - /// Return true to indicate that {@link #initGlobal(ContextFactory)} was - /// already called and false to indicate that the global factory was not - /// explicitly set. - /// - /// - public static bool HasExplicitGlobal - { - get - { - return hasCustomGlobal; - } - } - - /// Set global ContextFactory. - /// The method can only be called once. - /// - /// - public static void InitGlobal (ContextFactory factory) - { - if (factory == null) { - throw new ArgumentException (); - } - if (hasCustomGlobal) { - throw new ApplicationException (); - } - hasCustomGlobal = true; - global = factory; - } - - - /// Execute top call to script or function. - /// When the runtime is about to execute a script or function that will - /// create the first stack frame with scriptable code, it calls this method - /// to perform the real call. In this way execution of any script - /// happens inside this function. - /// - protected internal virtual object DoTopCall (ICallable callable, Context cx, IScriptable scope, IScriptable thisObj, object [] args) - { - return callable.Call (cx, scope, thisObj, args); - } - - /// Implementation of - /// {@link Context#observeInstructionCount(int instructionCount)}. - /// This can be used to customize {@link Context} without introducing - /// additional subclasses. - /// - protected internal virtual void ObserveInstructionCount (Context cx, int instructionCount) - { - } - - protected internal virtual void FireOnContextCreated (Context cx) - { - if (OnContextCreated != null) - OnContextCreated (this, new ContextEventArgs (cx)); - } - - protected internal virtual void FireOnContextReleased (Context cx) - { - if (OnContextReleased != null) - OnContextReleased (this, new ContextEventArgs (cx)); - } - - - /// Seal this ContextFactory so any attempt to modify it like to add or - /// remove its listeners will throw an exception. - /// - public void Seal () - { - CheckNotSealed (); - zealed = true; - } - - protected internal void CheckNotSealed () - { - if (zealed) - throw new ApplicationException (); - } - - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +namespace EcmaScript.NET +{ + + /// Factory class that Rhino runtime use to create new {@link Context} + /// instances or to notify about Context execution. + ///

+ /// When Rhino runtime needs to create new {@link Context} instance during + /// execution of {@link Context#enter()} or {@link Context}, it will call + /// {@link #makeContext()} of the current global ContextFactory. + /// See {@link #getGlobal()} and {@link #initGlobal(ContextFactory)}. + ///

+ /// It is also possible to use explicit ContextFactory instances for Context + /// creation. This is useful to have a set of independent Rhino runtime + /// instances under single JVM. See {@link #call(ContextAction)}. + ///

+ ///

+ + public class ContextFactory + { + /// Get global ContextFactory. + /// + /// + public static ContextFactory Global + { + get + { + return global; + } + + } + + /// Checks if this is a sealed ContextFactory. + virtual public bool Sealed + { + get + { + return zealed; + } + + } + private static volatile bool hasCustomGlobal; + private static ContextFactory global = new ContextFactory (); + + private volatile bool zealed; + + + /// Notify about newly created {@link Context} object. + public event ContextEventHandler OnContextCreated; + + /// Notify that the specified {@link Context} instance is no longer + /// associated with the current thread. + /// + public event ContextEventHandler OnContextReleased; + + /// Check if global factory was set. + /// Return true to indicate that {@link #initGlobal(ContextFactory)} was + /// already called and false to indicate that the global factory was not + /// explicitly set. + /// + /// + public static bool HasExplicitGlobal + { + get + { + return hasCustomGlobal; + } + } + + /// Set global ContextFactory. + /// The method can only be called once. + /// + /// + public static void InitGlobal (ContextFactory factory) + { + if (factory == null) { + throw new ArgumentException (); + } + if (hasCustomGlobal) { + throw new Exception (); + } + hasCustomGlobal = true; + global = factory; + } + + + /// Execute top call to script or function. + /// When the runtime is about to execute a script or function that will + /// create the first stack frame with scriptable code, it calls this method + /// to perform the real call. In this way execution of any script + /// happens inside this function. + /// + protected internal virtual object DoTopCall (ICallable callable, Context cx, IScriptable scope, IScriptable thisObj, object [] args) + { + return callable.Call (cx, scope, thisObj, args); + } + + /// Implementation of + /// {@link Context#observeInstructionCount(int instructionCount)}. + /// This can be used to customize {@link Context} without introducing + /// additional subclasses. + /// + protected internal virtual void ObserveInstructionCount (Context cx, int instructionCount) + { + } + + protected internal virtual void FireOnContextCreated (Context cx) + { + if (OnContextCreated != null) + OnContextCreated (this, new ContextEventArgs (cx)); + } + + protected internal virtual void FireOnContextReleased (Context cx) + { + if (OnContextReleased != null) + OnContextReleased (this, new ContextEventArgs (cx)); + } + + + /// Seal this ContextFactory so any attempt to modify it like to add or + /// remove its listeners will throw an exception. + /// + public void Seal () + { + CheckNotSealed (); + zealed = true; + } + + protected internal void CheckNotSealed () + { + if (zealed) + throw new Exception (); + } + + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/Continuation.cs b/src/EcmaScript.NET/Continuation.cs similarity index 96% rename from Code/EcmaScript.NET/Continuation.cs rename to src/EcmaScript.NET/Continuation.cs index bd0d89e..7df3552 100644 --- a/Code/EcmaScript.NET/Continuation.cs +++ b/src/EcmaScript.NET/Continuation.cs @@ -1,130 +1,130 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; -using EcmaScript.NET; - -namespace EcmaScript.NET -{ - - - public sealed class Continuation : IdScriptableObject, IFunction - { - public object Implementation - { - get - { - return implementation; - } - - } - override public string ClassName - { - get - { - return "Continuation"; - } - - } - - - private static readonly object FTAG = new object (); - - private object implementation; - - public static void Init (IScriptable scope, bool zealed) - { - Continuation obj = new Continuation (); - obj.ExportAsJSClass (MAX_PROTOTYPE_ID, scope, zealed); - } - - public void initImplementation (object implementation) - { - this.implementation = implementation; - } - - public IScriptable Construct (Context cx, IScriptable scope, object [] args) - { - throw Context.ReportRuntimeError ("Direct call is not supported"); - } - - public object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args) - { - return Interpreter.restartContinuation (this, cx, scope, args); - } - - public static bool IsContinuationConstructor (IdFunctionObject f) - { - if (f.HasTag (FTAG) && f.MethodId == Id_constructor) { - return true; - } - return false; - } - - protected internal override void InitPrototypeId (int id) - { - string s; - int arity; - switch (id) { - - case Id_constructor: - arity = 0; - s = "constructor"; - break; - - default: - throw new ArgumentException (Convert.ToString (id)); - - } - InitPrototypeMethod (FTAG, id, s, arity); - } - - public override object ExecIdCall (IdFunctionObject f, Context cx, IScriptable scope, IScriptable thisObj, object [] args) - { - if (!f.HasTag (FTAG)) { - return base.ExecIdCall (f, cx, scope, thisObj, args); - } - int id = f.MethodId; - switch (id) { - - case Id_constructor: - throw Context.ReportRuntimeError ("Direct call is not supported"); - } - throw new ArgumentException (Convert.ToString (id)); - } - - // #string_id_map# - - protected internal override int FindPrototypeId (string s) - { - int id; - #region Generated PrototypeId Switch - L0: { - id = 0; - string X = null; - if (s.Length == 11) { X = "constructor"; id = Id_constructor; } - if (X != null && X != s && !X.Equals (s)) - id = 0; - } - EL0: - #endregion - return id; - } - - #region PrototypeIds - private const int Id_constructor = 1; - private const int MAX_PROTOTYPE_ID = 1; - #endregion - - } -} +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; +using EcmaScript.NET; + +namespace EcmaScript.NET +{ + + + public sealed class Continuation : IdScriptableObject, IFunction + { + public object Implementation + { + get + { + return implementation; + } + + } + override public string ClassName + { + get + { + return "Continuation"; + } + + } + + + private static readonly object FTAG = new object (); + + private object implementation; + + public static void Init (IScriptable scope, bool zealed) + { + Continuation obj = new Continuation (); + obj.ExportAsJSClass (MAX_PROTOTYPE_ID, scope, zealed); + } + + public void initImplementation (object implementation) + { + this.implementation = implementation; + } + + public IScriptable Construct (Context cx, IScriptable scope, object [] args) + { + throw Context.ReportRuntimeError ("Direct call is not supported"); + } + + public object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args) + { + return Interpreter.restartContinuation (this, cx, scope, args); + } + + public static bool IsContinuationConstructor (IdFunctionObject f) + { + if (f.HasTag (FTAG) && f.MethodId == Id_constructor) { + return true; + } + return false; + } + + protected internal override void InitPrototypeId (int id) + { + string s; + int arity; + switch (id) { + + case Id_constructor: + arity = 0; + s = "constructor"; + break; + + default: + throw new ArgumentException (Convert.ToString (id)); + + } + InitPrototypeMethod (FTAG, id, s, arity); + } + + public override object ExecIdCall (IdFunctionObject f, Context cx, IScriptable scope, IScriptable thisObj, object [] args) + { + if (!f.HasTag (FTAG)) { + return base.ExecIdCall (f, cx, scope, thisObj, args); + } + int id = f.MethodId; + switch (id) { + + case Id_constructor: + throw Context.ReportRuntimeError ("Direct call is not supported"); + } + throw new ArgumentException (Convert.ToString (id)); + } + + // #string_id_map# + + protected internal override int FindPrototypeId (string s) + { + int id; + #region Generated PrototypeId Switch + L0: { + id = 0; + string X = null; + if (s.Length == 11) { X = "constructor"; id = Id_constructor; } + if (X != null && X != s && !X.Equals (s)) + id = 0; + } + EL0: + #endregion + return id; + } + + #region PrototypeIds + private const int Id_constructor = 1; + private const int MAX_PROTOTYPE_ID = 1; + #endregion + + } +} diff --git a/Code/EcmaScript.NET/Debugging/DebugFrame.cs b/src/EcmaScript.NET/Debugging/DebugFrame.cs similarity index 97% rename from Code/EcmaScript.NET/Debugging/DebugFrame.cs rename to src/EcmaScript.NET/Debugging/DebugFrame.cs index d8f263e..a6b7208 100644 --- a/Code/EcmaScript.NET/Debugging/DebugFrame.cs +++ b/src/EcmaScript.NET/Debugging/DebugFrame.cs @@ -1,68 +1,68 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -// API class -using System; -using Context = EcmaScript.NET.Context; -using Scriptable = EcmaScript.NET.IScriptable; -namespace EcmaScript.NET.Debugging -{ - - /// Interface to implement if the application is interested in receiving debug - /// information during execution of a particular script or function. - /// - public interface DebugFrame - { - - /// Called when execution is ready to start bytecode interpretation for entered a particular function or script. - /// current Context for this thread - /// - /// the activation scope for the function or script. - /// - /// value of the JavaScript this object - /// - /// the array of arguments - /// - void OnEnter (Context cx, IScriptable activation, IScriptable thisObj, object [] args); - /// Called when executed code reaches new line in the source. - /// current Context for this thread - /// - /// current line number in the script source - /// - void OnLineChange (Context cx, int lineNumber); - - /// Called when thrown exception is handled by the function or script. - /// current Context for this thread - /// - /// exception object - /// - void OnExceptionThrown (Context cx, Exception ex); - - /// Called when the function or script for this frame is about to return. - /// current Context for this thread - /// - /// if true function will leave by throwing exception, otherwise it - /// will execute normal return - /// - /// function result in case of normal return or - /// exception object if about to throw exception - /// - void OnExit (Context cx, bool byThrow, object resultOrException); - - /// - /// Called when the function or script executes a 'debugger' statement. - /// - /// current Context for this thread - void OnDebuggerStatement(Context cx); - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +// API class +using System; +using Context = EcmaScript.NET.Context; +using Scriptable = EcmaScript.NET.IScriptable; +namespace EcmaScript.NET.Debugging +{ + + /// Interface to implement if the application is interested in receiving debug + /// information during execution of a particular script or function. + /// + public interface DebugFrame + { + + /// Called when execution is ready to start bytecode interpretation for entered a particular function or script. + /// current Context for this thread + /// + /// the activation scope for the function or script. + /// + /// value of the JavaScript this object + /// + /// the array of arguments + /// + void OnEnter (Context cx, IScriptable activation, IScriptable thisObj, object [] args); + /// Called when executed code reaches new line in the source. + /// current Context for this thread + /// + /// current line number in the script source + /// + void OnLineChange (Context cx, int lineNumber); + + /// Called when thrown exception is handled by the function or script. + /// current Context for this thread + /// + /// exception object + /// + void OnExceptionThrown (Context cx, Exception ex); + + /// Called when the function or script for this frame is about to return. + /// current Context for this thread + /// + /// if true function will leave by throwing exception, otherwise it + /// will execute normal return + /// + /// function result in case of normal return or + /// exception object if about to throw exception + /// + void OnExit (Context cx, bool byThrow, object resultOrException); + + /// + /// Called when the function or script executes a 'debugger' statement. + /// + /// current Context for this thread + void OnDebuggerStatement(Context cx); + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/Debugging/DebuggableObject.cs b/src/EcmaScript.NET/Debugging/DebuggableObject.cs similarity index 97% rename from Code/EcmaScript.NET/Debugging/DebuggableObject.cs rename to src/EcmaScript.NET/Debugging/DebuggableObject.cs index b960823..73bacc2 100644 --- a/Code/EcmaScript.NET/Debugging/DebuggableObject.cs +++ b/src/EcmaScript.NET/Debugging/DebuggableObject.cs @@ -1,40 +1,40 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -// API class -using System; -namespace EcmaScript.NET.Debugging -{ - - /// This interface exposes debugging information from objects. - public interface DebuggableObject - { - /// Returns an array of ids for the properties of the object. - /// - ///

All properties, even those with attribute {DontEnum}, are listed. - /// This allows the debugger to display all properties of the object.

- /// - ///

- /// an array of java.lang.Objects with an entry for every - /// listed property. Properties accessed via an integer index will - /// have a corresponding - /// Integer entry in the returned array. Properties accessed by - /// a String will have a String entry in the returned array. - /// - object [] AllIds - { - get; - - } - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +// API class +using System; +namespace EcmaScript.NET.Debugging +{ + + /// This interface exposes debugging information from objects. + public interface DebuggableObject + { + /// Returns an array of ids for the properties of the object. + /// + ///

All properties, even those with attribute {DontEnum}, are listed. + /// This allows the debugger to display all properties of the object.

+ /// + ///

+ /// an array of java.lang.Objects with an entry for every + /// listed property. Properties accessed via an integer index will + /// have a corresponding + /// Integer entry in the returned array. Properties accessed by + /// a String will have a String entry in the returned array. + /// + object [] AllIds + { + get; + + } + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/Debugging/DebuggableScript.cs b/src/EcmaScript.NET/Debugging/DebuggableScript.cs similarity index 96% rename from Code/EcmaScript.NET/Debugging/DebuggableScript.cs rename to src/EcmaScript.NET/Debugging/DebuggableScript.cs index c192aff..c997228 100644 --- a/Code/EcmaScript.NET/Debugging/DebuggableScript.cs +++ b/src/EcmaScript.NET/Debugging/DebuggableScript.cs @@ -1,108 +1,108 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -// API class -using System; -namespace EcmaScript.NET.Debugging -{ - - /// This interface exposes debugging information from executable - /// code (either functions or top-level scripts). - /// - public interface DebuggableScript - { - bool TopLevel - { - get; - - } - /// Get name of the function described by this script. - /// Return null or an empty string if this script is not function. - /// - string FunctionName - { - get; - - } - /// Get number of declared parameters in function. - /// Return 0 if this script is not function. - /// - /// - int ParamCount - { - get; - - } - /// Get number of declared parameters and local variables. - /// Return number of declared global variables if this script is not - /// function. - /// - /// - int ParamAndVarCount - { - get; - - } - /// Get the name of the source (usually filename or URL) - /// of the script. - /// - string SourceName - { - get; - - } - /// Returns true if this script or function were runtime-generated - /// from JavaScript using eval function or Function - /// or Script constructors. - /// - bool GeneratedScript - { - get; - - } - /// Get array containing the line numbers that - /// that can be passed to DebugFrame.onLineChange(). - /// Note that line order in the resulting array is arbitrary - /// - int [] LineNumbers - { - get; - - } - int FunctionCount - { - get; - - } - DebuggableScript Parent - { - get; - - } - - /// Returns true if this is a function, false if it is a script. - bool IsFunction (); - - /// Get name of a declared parameter or local variable. - /// index should be less then {@link #getParamAndVarCount()}. - /// If index < {@link #getParamCount()}, return - /// the name of the corresponding parameter, otherwise return the name - /// of variable. - /// If this script is not function, return the name of the declared - /// global variable. - /// - string GetParamOrVarName (int index); - - DebuggableScript GetFunction (int index); - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +// API class +using System; +namespace EcmaScript.NET.Debugging +{ + + /// This interface exposes debugging information from executable + /// code (either functions or top-level scripts). + /// + public interface DebuggableScript + { + bool TopLevel + { + get; + + } + /// Get name of the function described by this script. + /// Return null or an empty string if this script is not function. + /// + string FunctionName + { + get; + + } + /// Get number of declared parameters in function. + /// Return 0 if this script is not function. + /// + /// + int ParamCount + { + get; + + } + /// Get number of declared parameters and local variables. + /// Return number of declared global variables if this script is not + /// function. + /// + /// + int ParamAndVarCount + { + get; + + } + /// Get the name of the source (usually filename or URL) + /// of the script. + /// + string SourceName + { + get; + + } + /// Returns true if this script or function were runtime-generated + /// from JavaScript using eval function or Function + /// or Script constructors. + /// + bool GeneratedScript + { + get; + + } + /// Get array containing the line numbers that + /// that can be passed to DebugFrame.onLineChange(). + /// Note that line order in the resulting array is arbitrary + /// + int [] LineNumbers + { + get; + + } + int FunctionCount + { + get; + + } + DebuggableScript Parent + { + get; + + } + + /// Returns true if this is a function, false if it is a script. + bool IsFunction (); + + /// Get name of a declared parameter or local variable. + /// index should be less then {@link #getParamAndVarCount()}. + /// If index < {@link #getParamCount()}, return + /// the name of the corresponding parameter, otherwise return the name + /// of variable. + /// If this script is not function, return the name of the declared + /// global variable. + /// + string GetParamOrVarName (int index); + + DebuggableScript GetFunction (int index); + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/Debugging/Debugger.cs b/src/EcmaScript.NET/Debugging/Debugger.cs similarity index 97% rename from Code/EcmaScript.NET/Debugging/Debugger.cs rename to src/EcmaScript.NET/Debugging/Debugger.cs index 970f451..06b279a 100644 --- a/Code/EcmaScript.NET/Debugging/Debugger.cs +++ b/src/EcmaScript.NET/Debugging/Debugger.cs @@ -1,43 +1,43 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -// API class -using System; -using Context = EcmaScript.NET.Context; -namespace EcmaScript.NET.Debugging -{ - - /// Interface to implement if the application is interested in receiving debug - /// information. - /// - public interface Debugger - { - - /// Called when compilation of a particular function or script into internal - /// bytecode is done. - /// - /// current Context for this thread - /// - /// object describing the function or script - /// - /// the function or script source - /// - void HandleCompilationDone (Context cx, DebuggableScript fnOrScript, string source); - - /// Called when execution entered a particular function or script. - /// implementation of DebugFrame which receives debug information during - /// the function or script execution or null otherwise - /// - DebugFrame GetFrame (Context cx, DebuggableScript fnOrScript); - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +// API class +using System; +using Context = EcmaScript.NET.Context; +namespace EcmaScript.NET.Debugging +{ + + /// Interface to implement if the application is interested in receiving debug + /// information. + /// + public interface Debugger + { + + /// Called when compilation of a particular function or script into internal + /// bytecode is done. + /// + /// current Context for this thread + /// + /// object describing the function or script + /// + /// the function or script source + /// + void HandleCompilationDone (Context cx, DebuggableScript fnOrScript, string source); + + /// Called when execution entered a particular function or script. + /// implementation of DebugFrame which receives debug information during + /// the function or script execution or null otherwise + /// + DebugFrame GetFrame (Context cx, DebuggableScript fnOrScript); + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/Decompiler.cs b/src/EcmaScript.NET/Decompiler.cs similarity index 96% rename from Code/EcmaScript.NET/Decompiler.cs rename to src/EcmaScript.NET/Decompiler.cs index 5eed814..77f6496 100644 --- a/Code/EcmaScript.NET/Decompiler.cs +++ b/src/EcmaScript.NET/Decompiler.cs @@ -1,1032 +1,1032 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -using EcmaScript.NET.Collections; - -namespace EcmaScript.NET -{ - - /// The following class save decompilation information about the source. - /// Source information is returned from the parser as a String - /// associated with function nodes and with the toplevel script. When - /// saved in the constant pool of a class, this string will be UTF-8 - /// encoded, and token values will occupy a single byte. - /// Source is saved (mostly) as token numbers. The tokens saved pretty - /// much correspond to the token stream of a 'canonical' representation - /// of the input program, as directed by the parser. (There were a few - /// cases where tokens could have been left out where decompiler could - /// easily reconstruct them, but I left them in for clarity). (I also - /// looked adding source collection to TokenStream instead, where I - /// could have limited the changes to a few lines in getToken... but - /// this wouldn't have saved any space in the resulting source - /// representation, and would have meant that I'd have to duplicate - /// parser logic in the decompiler to disambiguate situations where - /// newlines are important.) The function decompile expands the - /// tokens back into their string representations, using simple - /// lookahead to correct spacing and indentation. - /// - /// Assignments are saved as two-token pairs (Token.ASSIGN, op). Number tokens - /// are stored inline, as a NUMBER token, a character representing the type, and - /// either 1 or 4 characters representing the bit-encoding of the number. String - /// types NAME, STRING and OBJECT are currently stored as a token type, - /// followed by a character giving the length of the string (assumed to - /// be less than 2^16), followed by the characters of the string - /// inlined into the source string. Changing this to some reference to - /// to the string in the compiled class' constant pool would probably - /// save a lot of space... but would require some method of deriving - /// the final constant pool entry from information available at parse - /// time. - /// - public class Decompiler - { - internal string EncodedSource - { - get - { - return SourceToString(0); - } - - } - internal int CurrentOffset - { - get - { - return sourceTop; - } - - } - /// Flag to indicate that the decompilation should omit the - /// function header and trailing brace. - /// - public const int ONLY_BODY_FLAG = 1 << 0; - - /// Flag to indicate that the decompilation generates toSource result. - public const int TO_SOURCE_FLAG = 1 << 1; - - public const int TO_STRING_FLAG = 1 << 2; - - /// Decompilation property to specify initial ident value. - public const int INITIAL_INDENT_PROP = 1; - - /// Decompilation property to specify default identation offset. - public const int INDENT_GAP_PROP = 2; - - /// Decompilation property to specify identation offset for case labels. - public const int CASE_GAP_PROP = 3; - - // Marker to denote the last RC of function so it can be distinguished from - // the last RC of object literals in case of function expressions - private const int FUNCTION_END = 147; - - internal int MarkFunctionStart(int functionType) - { - int savedOffset = CurrentOffset; - AddToken(Token.FUNCTION); - Append((char)functionType); - return savedOffset; - } - - internal int MarkFunctionEnd(int functionStart) - { - int offset = CurrentOffset; - Append((char)FUNCTION_END); - return offset; - } - - internal void AddToken(int token) - { - if (!(0 <= token && token <= Token.LAST_TOKEN)) - throw new ArgumentException(); - - Append((char)token); - } - - internal void AddEol(int token) - { - if (!(0 <= token && token <= Token.LAST_TOKEN)) - throw new ArgumentException(); - - Append((char)token); - Append((char)Token.EOL); - } - - internal void AddName(string str) - { - AddToken(Token.NAME); - AppendString(str); - } - - internal void AddString(string str) - { - AddToken(Token.STRING); - AppendString(str); - } - - internal void AddRegexp(string regexp, string flags) - { - AddToken(Token.REGEXP); - AppendString('/' + regexp + '/' + flags); - } - - internal void AddJScriptConditionalComment(String str) - { - AddToken(Token.CONDCOMMENT); - AppendString(str); - } - - internal void AddPreservedComment(String str) - { - AddToken(Token.KEEPCOMMENT); - AppendString(str); - } - - internal void AddNumber(double n) - { - AddToken(Token.NUMBER); - - /* encode the number in the source stream. - * Save as NUMBER type (char | char char char char) - * where type is - * 'D' - double, 'S' - short, 'J' - long. - - * We need to retain float vs. integer type info to keep the - * behavior of liveconnect type-guessing the same after - * decompilation. (Liveconnect tries to present 1.0 to Java - * as a float/double) - * OPT: This is no longer true. We could compress the format. - - * This may not be the most space-efficient encoding; - * the chars created below may take up to 3 bytes in - * constant pool UTF-8 encoding, so a Double could take - * up to 12 bytes. - */ - - long lbits = (long)n; - if (lbits != n) - { - // if it's floating point, save as a Double bit pattern. - // (12/15/97 our scanner only returns Double for f.p.) - lbits = BitConverter.DoubleToInt64Bits(n); - Append('D'); - Append((char)(lbits >> 48)); - Append((char)(lbits >> 32)); - Append((char)(lbits >> 16)); - Append((char)lbits); - } - else - { - // we can ignore negative values, bc they're already prefixed - // by NEG - if (lbits < 0) - Context.CodeBug(); - - // will it fit in a char? - // this gives a short encoding for integer values up to 2^16. - if (lbits <= char.MaxValue) - { - Append('S'); - Append((char)lbits); - } - else - { - // Integral, but won't fit in a char. Store as a long. - Append('J'); - Append((char)(lbits >> 48)); - Append((char)(lbits >> 32)); - Append((char)(lbits >> 16)); - Append((char)lbits); - } - } - } - - private void AppendString(string str) - { - int L = str.Length; - int lengthEncodingSize = 1; - if (L >= 0x8000) - { - lengthEncodingSize = 2; - } - int nextTop = sourceTop + lengthEncodingSize + L; - if (nextTop > sourceBuffer.Length) - { - IncreaseSourceCapacity(nextTop); - } - if (L >= 0x8000) - { - // Use 2 chars to encode strings exceeding 32K, were the highest - // bit in the first char indicates presence of the next byte - sourceBuffer[sourceTop] = (char)(0x8000 | (int)((uint)L >> 16)); - ++sourceTop; - } - sourceBuffer[sourceTop] = (char)L; - ++sourceTop; - str.ToCharArray(0, L).CopyTo(sourceBuffer, sourceTop); - sourceTop = nextTop; - } - - private void Append(char c) - { - if (sourceTop == sourceBuffer.Length) - { - IncreaseSourceCapacity(sourceTop + 1); - } - sourceBuffer[sourceTop] = c; - ++sourceTop; - } - - private void IncreaseSourceCapacity(int minimalCapacity) - { - // Call this only when capacity increase is must - if (minimalCapacity <= sourceBuffer.Length) - Context.CodeBug(); - int newCapacity = sourceBuffer.Length * 2; - if (newCapacity < minimalCapacity) - { - newCapacity = minimalCapacity; - } - char[] tmp = new char[newCapacity]; - Array.Copy(sourceBuffer, 0, tmp, 0, sourceTop); - sourceBuffer = tmp; - } - - private string SourceToString(int offset) - { - if (offset < 0 || sourceTop < offset) - Context.CodeBug(); - return new string(sourceBuffer, offset, sourceTop - offset); - } - - /// Decompile the source information associated with this js - /// function/script back into a string. For the most part, this - /// just means translating tokens back to their string - /// representations; there's a little bit of lookahead logic to - /// decide the proper spacing/indentation. Most of the work in - /// mapping the original source to the prettyprinted decompiled - /// version is done by the parser. - /// - /// - /// encoded source tree presentation - /// - /// - /// flags to select output format - /// - /// - /// indentation properties - /// - /// - public static string Decompile(string source, int flags, UintMap properties) - { - int length = source.Length; - if (length == 0) - { - return ""; - } - - int indent = properties.getInt(INITIAL_INDENT_PROP, 0); - if (indent < 0) - throw new ArgumentException(); - int indentGap = properties.getInt(INDENT_GAP_PROP, 4); - if (indentGap < 0) - throw new ArgumentException(); - int caseGap = properties.getInt(CASE_GAP_PROP, 2); - if (caseGap < 0) - throw new ArgumentException(); - - System.Text.StringBuilder result = new System.Text.StringBuilder(); - bool justFunctionBody = (0 != (flags & Decompiler.ONLY_BODY_FLAG)); - bool toSource = (0 != (flags & Decompiler.TO_SOURCE_FLAG)); - bool toString = (0 != (flags & Decompiler.TO_STRING_FLAG)); - - // Spew tokens in source, for debugging. - // as TYPE number char - if (printSource) - { - System.Console.Error.WriteLine("length:" + length); - for (int i = 0; i < length; ++i) - { - // Note that tokenToName will fail unless Context.printTrees - // is true. - string tokenname = null; - if (Token.printNames) - { - tokenname = Token.name(source[i]); - } - if (tokenname == null) - { - tokenname = "---"; - } - string pad = tokenname.Length > 7 ? "\t" : "\t\t"; - System.Console.Error.WriteLine(tokenname + pad + (int)source[i] + "\t'" + ScriptRuntime.escapeString(source.Substring(i, (i + 1) - (i))) + "'"); - } - System.Console.Error.WriteLine(); - } - - int braceNesting = 0; - bool afterFirstEOL = false; - int i2 = 0; - int topFunctionType; - if (source[i2] == Token.SCRIPT) - { - ++i2; - topFunctionType = -1; - } - else - { - topFunctionType = source[i2 + 1]; - } - - if (!toSource) - { - if (!toString) - { - // add an initial newline to exactly match js. - result.Append('\n'); - } - for (int j = 0; j < indent; j++) - result.Append(' '); - } - else - { - if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION) - { - result.Append('('); - } - } - - while (i2 < length) - { - switch (source[i2]) - { - - case (char)(Token.NAME): - case (char)(Token.REGEXP): // re-wrapped in '/'s in parser... - i2 = PrintSourceString(source, i2 + 1, false, result); - continue; - - - case (char)(Token.STRING): - i2 = PrintSourceString(source, i2 + 1, true, result); - continue; - - - case (char)(Token.NUMBER): - i2 = PrintSourceNumber(source, i2 + 1, result); - continue; - - - case (char)(Token.TRUE): - result.Append("true"); - break; - - - case (char)(Token.FALSE): - result.Append("false"); - break; - - - case (char)(Token.NULL): - result.Append("null"); - break; - - - case (char)(Token.THIS): - result.Append("this"); - break; - - - case (char)(Token.FUNCTION): - ++i2; // skip function type - result.Append("function "); - break; - - - case (char)(FUNCTION_END): - // Do nothing - break; - - - case (char)(Token.COMMA): - result.Append(", "); - break; - - - case (char)(Token.LC): - ++braceNesting; - if (Token.EOL == GetNext(source, length, i2)) - indent += indentGap; - result.Append('{'); - break; - - - case (char)(Token.RC): - { - --braceNesting; - /* don't print the closing RC if it closes the - * toplevel function and we're called from - * decompileFunctionBody. - */ - if (justFunctionBody && braceNesting == 0) - break; - - result.Append('}'); - switch (GetNext(source, length, i2)) - { - - case Token.EOL: - case FUNCTION_END: - indent -= indentGap; - break; - - case Token.WHILE: - case Token.ELSE: - indent -= indentGap; - result.Append(' '); - break; - } - break; - } - - case (char)(Token.LP): - result.Append('('); - break; - - - case (char)(Token.RP): - result.Append(')'); - if (Token.LC == GetNext(source, length, i2)) - result.Append(' '); - break; - - - case (char)(Token.LB): - result.Append('['); - break; - - - case (char)(Token.RB): - result.Append(']'); - break; - - - case (char)(Token.EOL): - { - if (toSource) - break; - bool newLine = true; - if (!afterFirstEOL) - { - afterFirstEOL = true; - if (justFunctionBody) - { - /* throw away just added 'function name(...) {' - * and restore the original indent - */ - result.Length = 0; - indent -= indentGap; - newLine = false; - } - } - if (newLine) - { - result.Append('\n'); - } - - /* add indent if any tokens remain, - * less setback if next token is - * a label, case or default. - */ - if (i2 + 1 < length) - { - int less = 0; - int nextToken = source[i2 + 1]; - if (nextToken == Token.CASE || nextToken == Token.DEFAULT) - { - less = indentGap - caseGap; - } - else if (nextToken == Token.RC) - { - less = indentGap; - } - /* elaborate check against label... skip past a - * following inlined NAME and look for a COLON. - */ - else if (nextToken == Token.NAME) - { - int afterName = GetSourceStringEnd(source, i2 + 2); - if (source[afterName] == Token.COLON) - less = indentGap; - } - - for (; less < indent; less++) - result.Append(' '); - } - break; - } - - case (char)(Token.DOT): - result.Append('.'); - break; - - - case (char)(Token.NEW): - result.Append("new "); - break; - - - case (char)(Token.DELPROP): - result.Append("delete "); - break; - - - case (char)(Token.IF): - result.Append("if "); - break; - - - case (char)(Token.ELSE): - result.Append("else "); - break; - - - case (char)(Token.FOR): - result.Append("for "); - break; - - - case (char)(Token.IN): - result.Append(" in "); - break; - - - case (char)(Token.WITH): - result.Append("with "); - break; - - - case (char)(Token.WHILE): - result.Append("while "); - break; - - - case (char)(Token.DO): - result.Append("do "); - break; - - - case (char)(Token.TRY): - result.Append("try "); - break; - - - case (char)(Token.CATCH): - result.Append("catch "); - break; - - - case (char)(Token.FINALLY): - result.Append("finally "); - break; - - - case (char)(Token.THROW): - result.Append("throw "); - break; - - - case (char)(Token.SWITCH): - result.Append("switch "); - break; - - - case (char)(Token.BREAK): - result.Append("break"); - if (Token.NAME == GetNext(source, length, i2)) - result.Append(' '); - break; - - - case (char)(Token.CONTINUE): - result.Append("continue"); - if (Token.NAME == GetNext(source, length, i2)) - result.Append(' '); - break; - - - case (char)(Token.CASE): - result.Append("case "); - break; - - - case (char)(Token.DEFAULT): - result.Append("default"); - break; - - - case (char)(Token.RETURN): - result.Append("return"); - if (Token.SEMI != GetNext(source, length, i2)) - result.Append(' '); - break; - - - case (char)(Token.VAR): - result.Append("var "); - break; - - - case (char)(Token.SEMI): - result.Append(';'); - if (Token.EOL != GetNext(source, length, i2)) - { - // separators in FOR - result.Append(' '); - } - break; - - - case (char)(Token.ASSIGN): - result.Append(" = "); - break; - - - case (char)(Token.ASSIGN_ADD): - result.Append(" += "); - break; - - - case (char)(Token.ASSIGN_SUB): - result.Append(" -= "); - break; - - - case (char)(Token.ASSIGN_MUL): - result.Append(" *= "); - break; - - - case (char)(Token.ASSIGN_DIV): - result.Append(" /= "); - break; - - - case (char)(Token.ASSIGN_MOD): - result.Append(" %= "); - break; - - - case (char)(Token.ASSIGN_BITOR): - result.Append(" |= "); - break; - - - case (char)(Token.ASSIGN_BITXOR): - result.Append(" ^= "); - break; - - - case (char)(Token.ASSIGN_BITAND): - result.Append(" &= "); - break; - - - case (char)(Token.ASSIGN_LSH): - result.Append(" <<= "); - break; - - - case (char)(Token.ASSIGN_RSH): - result.Append(" >>= "); - break; - - - case (char)(Token.ASSIGN_URSH): - result.Append(" >>>= "); - break; - - - case (char)(Token.HOOK): - result.Append(" ? "); - break; - - - case (char)(Token.OBJECTLIT): - // pun OBJECTLIT to mean colon in objlit property - // initialization. - // This needs to be distinct from COLON in the general case - // to distinguish from the colon in a ternary... which needs - // different spacing. - result.Append(':'); - break; - - - case (char)(Token.COLON): - if (Token.EOL == GetNext(source, length, i2)) - // it's the end of a label - result.Append(':'); - // it's the middle part of a ternary - else - result.Append(" : "); - break; - - - case (char)(Token.OR): - result.Append(" || "); - break; - - - case (char)(Token.AND): - result.Append(" && "); - break; - - - case (char)(Token.BITOR): - result.Append(" | "); - break; - - - case (char)(Token.BITXOR): - result.Append(" ^ "); - break; - - - case (char)(Token.BITAND): - result.Append(" & "); - break; - - - case (char)(Token.SHEQ): - result.Append(" === "); - break; - - - case (char)(Token.SHNE): - result.Append(" !== "); - break; - - - case (char)(Token.EQ): - result.Append(" == "); - break; - - - case (char)(Token.NE): - result.Append(" != "); - break; - - - case (char)(Token.LE): - result.Append(" <= "); - break; - - - case (char)(Token.LT): - result.Append(" < "); - break; - - - case (char)(Token.GE): - result.Append(" >= "); - break; - - - case (char)(Token.GT): - result.Append(" > "); - break; - - - case (char)(Token.INSTANCEOF): - result.Append(" instanceof "); - break; - - - case (char)(Token.LSH): - result.Append(" << "); - break; - - - case (char)(Token.RSH): - result.Append(" >> "); - break; - - - case (char)(Token.URSH): - result.Append(" >>> "); - break; - - - case (char)(Token.TYPEOF): - result.Append("typeof "); - break; - - - case (char)(Token.VOID): - result.Append("void "); - break; - - - case (char)(Token.NOT): - result.Append('!'); - break; - - - case (char)(Token.BITNOT): - result.Append('~'); - break; - - - case (char)(Token.POS): - result.Append('+'); - break; - - - case (char)(Token.NEG): - result.Append('-'); - break; - - - case (char)(Token.INC): - result.Append("++"); - break; - - - case (char)(Token.DEC): - result.Append("--"); - break; - - - case (char)(Token.ADD): - result.Append(" + "); - break; - - - case (char)(Token.SUB): - result.Append(" - "); - break; - - - case (char)(Token.MUL): - result.Append(" * "); - break; - - - case (char)(Token.DIV): - result.Append(" / "); - break; - - - case (char)(Token.MOD): - result.Append(" % "); - break; - - - case (char)(Token.COLONCOLON): - result.Append("::"); - break; - - - case (char)(Token.DOTDOT): - result.Append(".."); - break; - - - case (char)(Token.DOTQUERY): - result.Append(".("); - break; - - - case (char)(Token.XMLATTR): - result.Append('@'); - break; - - - default: - // If we don't know how to decompile it, raise an exception. - throw new ApplicationException(); - - } - ++i2; - } - - if (!toSource) - { - // add that trailing newline if it's an outermost function. - if (!justFunctionBody && !toString) - result.Append('\n'); - } - else - { - if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION) - { - result.Append(')'); - } - } - - return result.ToString(); - } - - private static int GetNext(string source, int length, int i) - { - return (i + 1 < length) ? source[i + 1] : Token.EOF; - } - - private static int GetSourceStringEnd(string source, int offset) - { - return PrintSourceString(source, offset, false, null); - } - - private static int PrintSourceString(string source, int offset, bool asQuotedString, System.Text.StringBuilder sb) - { - int length = source[offset]; - ++offset; - if ((0x8000 & length) != 0) - { - length = ((0x7FFF & length) << 16) | source[offset]; - ++offset; - } - if (sb != null) - { - string str = source.Substring(offset, (offset + length) - (offset)); - if (!asQuotedString) - { - sb.Append(str); - } - else - { - sb.Append('"'); - sb.Append(ScriptRuntime.escapeString(str)); - sb.Append('"'); - } - } - return offset + length; - } - - private static int PrintSourceNumber(string source, int offset, System.Text.StringBuilder sb) - { - double number = 0.0; - char type = source[offset]; - ++offset; - if (type == 'S') - { - if (sb != null) - { - int ival = source[offset]; - number = ival; - } - ++offset; - } - else if (type == 'J' || type == 'D') - { - if (sb != null) - { - long lbits; - lbits = (long)source[offset] << 48; - lbits |= (long)source[offset + 1] << 32; - lbits |= (long)source[offset + 2] << 16; - lbits |= (long)source[offset + 3]; - if (type == 'J') - { - number = lbits; - } - else - { - number = BitConverter.Int64BitsToDouble(lbits); - } - } - offset += 4; - } - else - { - // Bad source - throw new ApplicationException(); - } - if (sb != null) - { - sb.Append(ScriptConvert.ToString(number, 10)); - } - return offset; - } - - private char[] sourceBuffer = new char[128]; - - // Per script/function source buffer top: parent source does not include a - // nested functions source and uses function index as a reference instead. - private int sourceTop; - - // whether to do a debug print of the source information, when decompiling. - private static bool printSource = false; // TODO: make preprocessor directive - - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +using EcmaScript.NET.Collections; + +namespace EcmaScript.NET +{ + + /// The following class save decompilation information about the source. + /// Source information is returned from the parser as a String + /// associated with function nodes and with the toplevel script. When + /// saved in the constant pool of a class, this string will be UTF-8 + /// encoded, and token values will occupy a single byte. + /// Source is saved (mostly) as token numbers. The tokens saved pretty + /// much correspond to the token stream of a 'canonical' representation + /// of the input program, as directed by the parser. (There were a few + /// cases where tokens could have been left out where decompiler could + /// easily reconstruct them, but I left them in for clarity). (I also + /// looked adding source collection to TokenStream instead, where I + /// could have limited the changes to a few lines in getToken... but + /// this wouldn't have saved any space in the resulting source + /// representation, and would have meant that I'd have to duplicate + /// parser logic in the decompiler to disambiguate situations where + /// newlines are important.) The function decompile expands the + /// tokens back into their string representations, using simple + /// lookahead to correct spacing and indentation. + /// + /// Assignments are saved as two-token pairs (Token.ASSIGN, op). Number tokens + /// are stored inline, as a NUMBER token, a character representing the type, and + /// either 1 or 4 characters representing the bit-encoding of the number. String + /// types NAME, STRING and OBJECT are currently stored as a token type, + /// followed by a character giving the length of the string (assumed to + /// be less than 2^16), followed by the characters of the string + /// inlined into the source string. Changing this to some reference to + /// to the string in the compiled class' constant pool would probably + /// save a lot of space... but would require some method of deriving + /// the final constant pool entry from information available at parse + /// time. + /// + public class Decompiler + { + internal string EncodedSource + { + get + { + return SourceToString(0); + } + + } + internal int CurrentOffset + { + get + { + return sourceTop; + } + + } + /// Flag to indicate that the decompilation should omit the + /// function header and trailing brace. + /// + public const int ONLY_BODY_FLAG = 1 << 0; + + /// Flag to indicate that the decompilation generates toSource result. + public const int TO_SOURCE_FLAG = 1 << 1; + + public const int TO_STRING_FLAG = 1 << 2; + + /// Decompilation property to specify initial ident value. + public const int INITIAL_INDENT_PROP = 1; + + /// Decompilation property to specify default identation offset. + public const int INDENT_GAP_PROP = 2; + + /// Decompilation property to specify identation offset for case labels. + public const int CASE_GAP_PROP = 3; + + // Marker to denote the last RC of function so it can be distinguished from + // the last RC of object literals in case of function expressions + private const int FUNCTION_END = 147; + + internal int MarkFunctionStart(int functionType) + { + int savedOffset = CurrentOffset; + AddToken(Token.FUNCTION); + Append((char)functionType); + return savedOffset; + } + + internal int MarkFunctionEnd(int functionStart) + { + int offset = CurrentOffset; + Append((char)FUNCTION_END); + return offset; + } + + internal void AddToken(int token) + { + if (!(0 <= token && token <= Token.LAST_TOKEN)) + throw new ArgumentException(); + + Append((char)token); + } + + internal void AddEol(int token) + { + if (!(0 <= token && token <= Token.LAST_TOKEN)) + throw new ArgumentException(); + + Append((char)token); + Append((char)Token.EOL); + } + + internal void AddName(string str) + { + AddToken(Token.NAME); + AppendString(str); + } + + internal void AddString(string str) + { + AddToken(Token.STRING); + AppendString(str); + } + + internal void AddRegexp(string regexp, string flags) + { + AddToken(Token.REGEXP); + AppendString('/' + regexp + '/' + flags); + } + + internal void AddJScriptConditionalComment(String str) + { + AddToken(Token.CONDCOMMENT); + AppendString(str); + } + + internal void AddPreservedComment(String str) + { + AddToken(Token.KEEPCOMMENT); + AppendString(str); + } + + internal void AddNumber(double n) + { + AddToken(Token.NUMBER); + + /* encode the number in the source stream. + * Save as NUMBER type (char | char char char char) + * where type is + * 'D' - double, 'S' - short, 'J' - long. + + * We need to retain float vs. integer type info to keep the + * behavior of liveconnect type-guessing the same after + * decompilation. (Liveconnect tries to present 1.0 to Java + * as a float/double) + * OPT: This is no longer true. We could compress the format. + + * This may not be the most space-efficient encoding; + * the chars created below may take up to 3 bytes in + * constant pool UTF-8 encoding, so a Double could take + * up to 12 bytes. + */ + + long lbits = (long)n; + if (lbits != n) + { + // if it's floating point, save as a Double bit pattern. + // (12/15/97 our scanner only returns Double for f.p.) + lbits = BitConverter.DoubleToInt64Bits(n); + Append('D'); + Append((char)(lbits >> 48)); + Append((char)(lbits >> 32)); + Append((char)(lbits >> 16)); + Append((char)lbits); + } + else + { + // we can ignore negative values, bc they're already prefixed + // by NEG + if (lbits < 0) + Context.CodeBug(); + + // will it fit in a char? + // this gives a short encoding for integer values up to 2^16. + if (lbits <= char.MaxValue) + { + Append('S'); + Append((char)lbits); + } + else + { + // Integral, but won't fit in a char. Store as a long. + Append('J'); + Append((char)(lbits >> 48)); + Append((char)(lbits >> 32)); + Append((char)(lbits >> 16)); + Append((char)lbits); + } + } + } + + private void AppendString(string str) + { + int L = str.Length; + int lengthEncodingSize = 1; + if (L >= 0x8000) + { + lengthEncodingSize = 2; + } + int nextTop = sourceTop + lengthEncodingSize + L; + if (nextTop > sourceBuffer.Length) + { + IncreaseSourceCapacity(nextTop); + } + if (L >= 0x8000) + { + // Use 2 chars to encode strings exceeding 32K, were the highest + // bit in the first char indicates presence of the next byte + sourceBuffer[sourceTop] = (char)(0x8000 | (int)((uint)L >> 16)); + ++sourceTop; + } + sourceBuffer[sourceTop] = (char)L; + ++sourceTop; + str.ToCharArray(0, L).CopyTo(sourceBuffer, sourceTop); + sourceTop = nextTop; + } + + private void Append(char c) + { + if (sourceTop == sourceBuffer.Length) + { + IncreaseSourceCapacity(sourceTop + 1); + } + sourceBuffer[sourceTop] = c; + ++sourceTop; + } + + private void IncreaseSourceCapacity(int minimalCapacity) + { + // Call this only when capacity increase is must + if (minimalCapacity <= sourceBuffer.Length) + Context.CodeBug(); + int newCapacity = sourceBuffer.Length * 2; + if (newCapacity < minimalCapacity) + { + newCapacity = minimalCapacity; + } + char[] tmp = new char[newCapacity]; + Array.Copy(sourceBuffer, 0, tmp, 0, sourceTop); + sourceBuffer = tmp; + } + + private string SourceToString(int offset) + { + if (offset < 0 || sourceTop < offset) + Context.CodeBug(); + return new string(sourceBuffer, offset, sourceTop - offset); + } + + /// Decompile the source information associated with this js + /// function/script back into a string. For the most part, this + /// just means translating tokens back to their string + /// representations; there's a little bit of lookahead logic to + /// decide the proper spacing/indentation. Most of the work in + /// mapping the original source to the prettyprinted decompiled + /// version is done by the parser. + /// + /// + /// encoded source tree presentation + /// + /// + /// flags to select output format + /// + /// + /// indentation properties + /// + /// + public static string Decompile(string source, int flags, UintMap properties) + { + int length = source.Length; + if (length == 0) + { + return ""; + } + + int indent = properties.getInt(INITIAL_INDENT_PROP, 0); + if (indent < 0) + throw new ArgumentException(); + int indentGap = properties.getInt(INDENT_GAP_PROP, 4); + if (indentGap < 0) + throw new ArgumentException(); + int caseGap = properties.getInt(CASE_GAP_PROP, 2); + if (caseGap < 0) + throw new ArgumentException(); + + System.Text.StringBuilder result = new System.Text.StringBuilder(); + bool justFunctionBody = (0 != (flags & Decompiler.ONLY_BODY_FLAG)); + bool toSource = (0 != (flags & Decompiler.TO_SOURCE_FLAG)); + bool toString = (0 != (flags & Decompiler.TO_STRING_FLAG)); + + // Spew tokens in source, for debugging. + // as TYPE number char + if (printSource) + { + System.Console.Error.WriteLine("length:" + length); + for (int i = 0; i < length; ++i) + { + // Note that tokenToName will fail unless Context.printTrees + // is true. + string tokenname = null; + if (Token.printNames) + { + tokenname = Token.name(source[i]); + } + if (tokenname == null) + { + tokenname = "---"; + } + string pad = tokenname.Length > 7 ? "\t" : "\t\t"; + System.Console.Error.WriteLine(tokenname + pad + (int)source[i] + "\t'" + ScriptRuntime.escapeString(source.Substring(i, (i + 1) - (i))) + "'"); + } + System.Console.Error.WriteLine(); + } + + int braceNesting = 0; + bool afterFirstEOL = false; + int i2 = 0; + int topFunctionType; + if (source[i2] == Token.SCRIPT) + { + ++i2; + topFunctionType = -1; + } + else + { + topFunctionType = source[i2 + 1]; + } + + if (!toSource) + { + if (!toString) + { + // add an initial newline to exactly match js. + result.Append('\n'); + } + for (int j = 0; j < indent; j++) + result.Append(' '); + } + else + { + if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION) + { + result.Append('('); + } + } + + while (i2 < length) + { + switch (source[i2]) + { + + case (char)(Token.NAME): + case (char)(Token.REGEXP): // re-wrapped in '/'s in parser... + i2 = PrintSourceString(source, i2 + 1, false, result); + continue; + + + case (char)(Token.STRING): + i2 = PrintSourceString(source, i2 + 1, true, result); + continue; + + + case (char)(Token.NUMBER): + i2 = PrintSourceNumber(source, i2 + 1, result); + continue; + + + case (char)(Token.TRUE): + result.Append("true"); + break; + + + case (char)(Token.FALSE): + result.Append("false"); + break; + + + case (char)(Token.NULL): + result.Append("null"); + break; + + + case (char)(Token.THIS): + result.Append("this"); + break; + + + case (char)(Token.FUNCTION): + ++i2; // skip function type + result.Append("function "); + break; + + + case (char)(FUNCTION_END): + // Do nothing + break; + + + case (char)(Token.COMMA): + result.Append(", "); + break; + + + case (char)(Token.LC): + ++braceNesting; + if (Token.EOL == GetNext(source, length, i2)) + indent += indentGap; + result.Append('{'); + break; + + + case (char)(Token.RC): + { + --braceNesting; + /* don't print the closing RC if it closes the + * toplevel function and we're called from + * decompileFunctionBody. + */ + if (justFunctionBody && braceNesting == 0) + break; + + result.Append('}'); + switch (GetNext(source, length, i2)) + { + + case Token.EOL: + case FUNCTION_END: + indent -= indentGap; + break; + + case Token.WHILE: + case Token.ELSE: + indent -= indentGap; + result.Append(' '); + break; + } + break; + } + + case (char)(Token.LP): + result.Append('('); + break; + + + case (char)(Token.RP): + result.Append(')'); + if (Token.LC == GetNext(source, length, i2)) + result.Append(' '); + break; + + + case (char)(Token.LB): + result.Append('['); + break; + + + case (char)(Token.RB): + result.Append(']'); + break; + + + case (char)(Token.EOL): + { + if (toSource) + break; + bool newLine = true; + if (!afterFirstEOL) + { + afterFirstEOL = true; + if (justFunctionBody) + { + /* throw away just added 'function name(...) {' + * and restore the original indent + */ + result.Length = 0; + indent -= indentGap; + newLine = false; + } + } + if (newLine) + { + result.Append('\n'); + } + + /* add indent if any tokens remain, + * less setback if next token is + * a label, case or default. + */ + if (i2 + 1 < length) + { + int less = 0; + int nextToken = source[i2 + 1]; + if (nextToken == Token.CASE || nextToken == Token.DEFAULT) + { + less = indentGap - caseGap; + } + else if (nextToken == Token.RC) + { + less = indentGap; + } + /* elaborate check against label... skip past a + * following inlined NAME and look for a COLON. + */ + else if (nextToken == Token.NAME) + { + int afterName = GetSourceStringEnd(source, i2 + 2); + if (source[afterName] == Token.COLON) + less = indentGap; + } + + for (; less < indent; less++) + result.Append(' '); + } + break; + } + + case (char)(Token.DOT): + result.Append('.'); + break; + + + case (char)(Token.NEW): + result.Append("new "); + break; + + + case (char)(Token.DELPROP): + result.Append("delete "); + break; + + + case (char)(Token.IF): + result.Append("if "); + break; + + + case (char)(Token.ELSE): + result.Append("else "); + break; + + + case (char)(Token.FOR): + result.Append("for "); + break; + + + case (char)(Token.IN): + result.Append(" in "); + break; + + + case (char)(Token.WITH): + result.Append("with "); + break; + + + case (char)(Token.WHILE): + result.Append("while "); + break; + + + case (char)(Token.DO): + result.Append("do "); + break; + + + case (char)(Token.TRY): + result.Append("try "); + break; + + + case (char)(Token.CATCH): + result.Append("catch "); + break; + + + case (char)(Token.FINALLY): + result.Append("finally "); + break; + + + case (char)(Token.THROW): + result.Append("throw "); + break; + + + case (char)(Token.SWITCH): + result.Append("switch "); + break; + + + case (char)(Token.BREAK): + result.Append("break"); + if (Token.NAME == GetNext(source, length, i2)) + result.Append(' '); + break; + + + case (char)(Token.CONTINUE): + result.Append("continue"); + if (Token.NAME == GetNext(source, length, i2)) + result.Append(' '); + break; + + + case (char)(Token.CASE): + result.Append("case "); + break; + + + case (char)(Token.DEFAULT): + result.Append("default"); + break; + + + case (char)(Token.RETURN): + result.Append("return"); + if (Token.SEMI != GetNext(source, length, i2)) + result.Append(' '); + break; + + + case (char)(Token.VAR): + result.Append("var "); + break; + + + case (char)(Token.SEMI): + result.Append(';'); + if (Token.EOL != GetNext(source, length, i2)) + { + // separators in FOR + result.Append(' '); + } + break; + + + case (char)(Token.ASSIGN): + result.Append(" = "); + break; + + + case (char)(Token.ASSIGN_ADD): + result.Append(" += "); + break; + + + case (char)(Token.ASSIGN_SUB): + result.Append(" -= "); + break; + + + case (char)(Token.ASSIGN_MUL): + result.Append(" *= "); + break; + + + case (char)(Token.ASSIGN_DIV): + result.Append(" /= "); + break; + + + case (char)(Token.ASSIGN_MOD): + result.Append(" %= "); + break; + + + case (char)(Token.ASSIGN_BITOR): + result.Append(" |= "); + break; + + + case (char)(Token.ASSIGN_BITXOR): + result.Append(" ^= "); + break; + + + case (char)(Token.ASSIGN_BITAND): + result.Append(" &= "); + break; + + + case (char)(Token.ASSIGN_LSH): + result.Append(" <<= "); + break; + + + case (char)(Token.ASSIGN_RSH): + result.Append(" >>= "); + break; + + + case (char)(Token.ASSIGN_URSH): + result.Append(" >>>= "); + break; + + + case (char)(Token.HOOK): + result.Append(" ? "); + break; + + + case (char)(Token.OBJECTLIT): + // pun OBJECTLIT to mean colon in objlit property + // initialization. + // This needs to be distinct from COLON in the general case + // to distinguish from the colon in a ternary... which needs + // different spacing. + result.Append(':'); + break; + + + case (char)(Token.COLON): + if (Token.EOL == GetNext(source, length, i2)) + // it's the end of a label + result.Append(':'); + // it's the middle part of a ternary + else + result.Append(" : "); + break; + + + case (char)(Token.OR): + result.Append(" || "); + break; + + + case (char)(Token.AND): + result.Append(" && "); + break; + + + case (char)(Token.BITOR): + result.Append(" | "); + break; + + + case (char)(Token.BITXOR): + result.Append(" ^ "); + break; + + + case (char)(Token.BITAND): + result.Append(" & "); + break; + + + case (char)(Token.SHEQ): + result.Append(" === "); + break; + + + case (char)(Token.SHNE): + result.Append(" !== "); + break; + + + case (char)(Token.EQ): + result.Append(" == "); + break; + + + case (char)(Token.NE): + result.Append(" != "); + break; + + + case (char)(Token.LE): + result.Append(" <= "); + break; + + + case (char)(Token.LT): + result.Append(" < "); + break; + + + case (char)(Token.GE): + result.Append(" >= "); + break; + + + case (char)(Token.GT): + result.Append(" > "); + break; + + + case (char)(Token.INSTANCEOF): + result.Append(" instanceof "); + break; + + + case (char)(Token.LSH): + result.Append(" << "); + break; + + + case (char)(Token.RSH): + result.Append(" >> "); + break; + + + case (char)(Token.URSH): + result.Append(" >>> "); + break; + + + case (char)(Token.TYPEOF): + result.Append("typeof "); + break; + + + case (char)(Token.VOID): + result.Append("void "); + break; + + + case (char)(Token.NOT): + result.Append('!'); + break; + + + case (char)(Token.BITNOT): + result.Append('~'); + break; + + + case (char)(Token.POS): + result.Append('+'); + break; + + + case (char)(Token.NEG): + result.Append('-'); + break; + + + case (char)(Token.INC): + result.Append("++"); + break; + + + case (char)(Token.DEC): + result.Append("--"); + break; + + + case (char)(Token.ADD): + result.Append(" + "); + break; + + + case (char)(Token.SUB): + result.Append(" - "); + break; + + + case (char)(Token.MUL): + result.Append(" * "); + break; + + + case (char)(Token.DIV): + result.Append(" / "); + break; + + + case (char)(Token.MOD): + result.Append(" % "); + break; + + + case (char)(Token.COLONCOLON): + result.Append("::"); + break; + + + case (char)(Token.DOTDOT): + result.Append(".."); + break; + + + case (char)(Token.DOTQUERY): + result.Append(".("); + break; + + + case (char)(Token.XMLATTR): + result.Append('@'); + break; + + + default: + // If we don't know how to decompile it, raise an exception. + throw new Exception(); + + } + ++i2; + } + + if (!toSource) + { + // add that trailing newline if it's an outermost function. + if (!justFunctionBody && !toString) + result.Append('\n'); + } + else + { + if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION) + { + result.Append(')'); + } + } + + return result.ToString(); + } + + private static int GetNext(string source, int length, int i) + { + return (i + 1 < length) ? source[i + 1] : Token.EOF; + } + + private static int GetSourceStringEnd(string source, int offset) + { + return PrintSourceString(source, offset, false, null); + } + + private static int PrintSourceString(string source, int offset, bool asQuotedString, System.Text.StringBuilder sb) + { + int length = source[offset]; + ++offset; + if ((0x8000 & length) != 0) + { + length = ((0x7FFF & length) << 16) | source[offset]; + ++offset; + } + if (sb != null) + { + string str = source.Substring(offset, (offset + length) - (offset)); + if (!asQuotedString) + { + sb.Append(str); + } + else + { + sb.Append('"'); + sb.Append(ScriptRuntime.escapeString(str)); + sb.Append('"'); + } + } + return offset + length; + } + + private static int PrintSourceNumber(string source, int offset, System.Text.StringBuilder sb) + { + double number = 0.0; + char type = source[offset]; + ++offset; + if (type == 'S') + { + if (sb != null) + { + int ival = source[offset]; + number = ival; + } + ++offset; + } + else if (type == 'J' || type == 'D') + { + if (sb != null) + { + long lbits; + lbits = (long)source[offset] << 48; + lbits |= (long)source[offset + 1] << 32; + lbits |= (long)source[offset + 2] << 16; + lbits |= (long)source[offset + 3]; + if (type == 'J') + { + number = lbits; + } + else + { + number = BitConverter.Int64BitsToDouble(lbits); + } + } + offset += 4; + } + else + { + // Bad source + throw new Exception(); + } + if (sb != null) + { + sb.Append(ScriptConvert.ToString(number, 10)); + } + return offset; + } + + private char[] sourceBuffer = new char[128]; + + // Per script/function source buffer top: parent source does not include a + // nested functions source and uses function index as a reference instead. + private int sourceTop; + + // whether to do a debug print of the source information, when decompiling. + private static bool printSource = false; // TODO: make preprocessor directive + + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/DefaultErrorReporter.cs b/src/EcmaScript.NET/DefaultErrorReporter.cs similarity index 97% rename from Code/EcmaScript.NET/DefaultErrorReporter.cs rename to src/EcmaScript.NET/DefaultErrorReporter.cs index 6e5fbc3..db2979a 100644 --- a/Code/EcmaScript.NET/DefaultErrorReporter.cs +++ b/src/EcmaScript.NET/DefaultErrorReporter.cs @@ -1,74 +1,74 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -namespace EcmaScript.NET -{ - - /// This is the default error reporter for JavaScript. - /// - /// - class DefaultErrorReporter : ErrorReporter - { - internal static readonly DefaultErrorReporter instance = new DefaultErrorReporter (); - - private bool forEval; - private ErrorReporter chainedReporter; - - private DefaultErrorReporter () - { - } - - internal static ErrorReporter ForEval (ErrorReporter reporter) - { - DefaultErrorReporter r = new DefaultErrorReporter (); - r.forEval = true; - r.chainedReporter = reporter; - return r; - } - - public virtual void Warning (string message, string sourceURI, int line, string lineText, int lineOffset) - { - if (chainedReporter != null) { - chainedReporter.Warning (message, sourceURI, line, lineText, lineOffset); - } - else { - Console.Error.WriteLine ("strict warning: " + message); - } - } - - public virtual void Error (string message, string sourceURI, int line, string lineText, int lineOffset) - { - if (forEval) { - throw ScriptRuntime.ConstructError ("SyntaxError", message, sourceURI, line, lineText, lineOffset); - } - if (chainedReporter != null) { - chainedReporter.Error (message, sourceURI, line, lineText, lineOffset); - } - else { - throw RuntimeError (message, sourceURI, line, lineText, lineOffset); - } - } - - public virtual EcmaScriptRuntimeException RuntimeError (string message, string sourceURI, int line, string lineText, int lineOffset) - { - if (chainedReporter != null) { - return chainedReporter.RuntimeError (message, sourceURI, line, lineText, lineOffset); - } - else { - return new EcmaScriptRuntimeException (message, sourceURI, line, lineText, lineOffset); - } - } - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +namespace EcmaScript.NET +{ + + /// This is the default error reporter for JavaScript. + /// + /// + class DefaultErrorReporter : ErrorReporter + { + internal static readonly DefaultErrorReporter instance = new DefaultErrorReporter (); + + private bool forEval; + private ErrorReporter chainedReporter; + + private DefaultErrorReporter () + { + } + + internal static ErrorReporter ForEval (ErrorReporter reporter) + { + DefaultErrorReporter r = new DefaultErrorReporter (); + r.forEval = true; + r.chainedReporter = reporter; + return r; + } + + public virtual void Warning (string message, string sourceURI, int line, string lineText, int lineOffset) + { + if (chainedReporter != null) { + chainedReporter.Warning (message, sourceURI, line, lineText, lineOffset); + } + else { + Console.Error.WriteLine ("strict warning: " + message); + } + } + + public virtual void Error (string message, string sourceURI, int line, string lineText, int lineOffset) + { + if (forEval) { + throw ScriptRuntime.ConstructError ("SyntaxError", message, sourceURI, line, lineText, lineOffset); + } + if (chainedReporter != null) { + chainedReporter.Error (message, sourceURI, line, lineText, lineOffset); + } + else { + throw RuntimeError (message, sourceURI, line, lineText, lineOffset); + } + } + + public virtual EcmaScriptRuntimeException RuntimeError (string message, string sourceURI, int line, string lineText, int lineOffset) + { + if (chainedReporter != null) { + return chainedReporter.RuntimeError (message, sourceURI, line, lineText, lineOffset); + } + else { + return new EcmaScriptRuntimeException (message, sourceURI, line, lineText, lineOffset); + } + } + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/Delegator.cs b/src/EcmaScript.NET/Delegator.cs similarity index 96% rename from Code/EcmaScript.NET/Delegator.cs rename to src/EcmaScript.NET/Delegator.cs index 3c10496..021fff4 100644 --- a/Code/EcmaScript.NET/Delegator.cs +++ b/src/EcmaScript.NET/Delegator.cs @@ -1,243 +1,243 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -using EcmaScript.NET.Types; - -namespace EcmaScript.NET -{ - - /// This is a helper class for implementing wrappers around Scriptable - /// objects. It implements the Function interface and delegates all - /// invocations to a delegee Scriptable object. The normal use of this - /// class involves creating a sub-class and overriding one or more of - /// the methods. - /// - /// A useful application is the implementation of interceptors, - /// pre/post conditions, debugging. - /// - /// - public class Delegator : IFunction - { - - /// Retrieve the delegee. - /// - /// - /// the delegee - /// - /// Set the delegee. - /// - /// - /// the delegee - /// - virtual public IScriptable Delegee - { - get - { - return obj; - } - - set - { - this.obj = value; - } - - } - - virtual public string ClassName - { - get - { - return obj.ClassName; - } - - } - - - virtual public IScriptable ParentScope - { - get - { - return obj.ParentScope; - } - - set - { - obj.ParentScope = value; - } - - } - - protected internal IScriptable obj = null; - - /// Create a Delegator prototype. - /// - /// This constructor should only be used for creating prototype - /// objects of Delegator. - /// - /// - - public Delegator () - { - } - - /// Create a new Delegator that forwards requests to a delegee - /// Scriptable object. - /// - /// - /// the delegee - /// - public Delegator (IScriptable obj) - { - this.obj = obj; - } - - /// Crete new Delegator instance. - /// The default implementation calls this.getClass().newInstance(). - /// - /// - protected internal virtual Delegator NewInstance () - { - try { - return (Delegator)System.Activator.CreateInstance (this.GetType ()); - } - catch (Exception ex) { - throw Context.ThrowAsScriptRuntimeEx (ex); - } - } - - public virtual object Get (string name, IScriptable start) - { - return obj.Get (name, start); - } - - public virtual object Get (int index, IScriptable start) - { - return obj.Get (index, start); - } - - public virtual bool Has (string name, IScriptable start) - { - return obj.Has (name, start); - } - - public virtual bool Has (int index, IScriptable start) - { - return obj.Has (index, start); - } - - public virtual object Put (string name, IScriptable start, object value) - { - return obj.Put (name, start, value); - } - - public virtual object Put (int index, IScriptable start, object value) - { - return obj.Put (index, start, value); - } - - public virtual void Delete (string name) - { - obj.Delete (name); - } - - public virtual void Delete (int index) - { - obj.Delete (index); - } - - public virtual IScriptable GetPrototype () - { - return obj.GetPrototype (); - } - - public virtual void SetPrototype (IScriptable prototype) - { - obj.SetPrototype (prototype); - } - - public virtual object [] GetIds () - { - return obj.GetIds (); - } - /// Note that this method does not get forwarded to the delegee if - /// the hint parameter is null, - /// typeof(Scriptable) or - /// typeof(Function). Instead the object - /// itself is returned. - /// - /// - /// the type hint - /// - /// the default value - /// - /// - public virtual object GetDefaultValue (Type hint) - { - return (hint == null - || hint == typeof (IScriptable) - || hint == typeof (IFunction)) - ? this : obj.GetDefaultValue (hint); - } - - public virtual bool HasInstance (IScriptable instance) - { - return obj.HasInstance (instance); - } - - public virtual object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args) - { - return ((IFunction)obj).Call (cx, scope, thisObj, args); - } - - /// Note that if the delegee is null, - /// this method creates a new instance of the Delegator itself - /// rathert than forwarding the call to the - /// delegee. This permits the use of Delegator - /// prototypes. - /// - /// - /// the current Context for this thread - /// - /// an enclosing scope of the caller except - /// when the function is called from a closure. - /// - /// the array of arguments - /// - /// the allocated object - /// - /// - - public virtual IScriptable Construct (Context cx, IScriptable scope, object [] args) - { - if (obj == null) { - //this little trick allows us to declare prototype objects for - //Delegators - Delegator n = NewInstance (); - IScriptable delegee; - if (args.Length == 0) { - delegee = new BuiltinObject (); - } - else { - delegee = ScriptConvert.ToObject (cx, scope, args [0]); - } - n.Delegee = delegee; - return n; - } - else { - return ((IFunction)obj).Construct (cx, scope, args); - } - } - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +using EcmaScript.NET.Types; + +namespace EcmaScript.NET +{ + + /// This is a helper class for implementing wrappers around Scriptable + /// objects. It implements the Function interface and delegates all + /// invocations to a delegee Scriptable object. The normal use of this + /// class involves creating a sub-class and overriding one or more of + /// the methods. + /// + /// A useful application is the implementation of interceptors, + /// pre/post conditions, debugging. + /// + /// + public class Delegator : IFunction + { + + /// Retrieve the delegee. + /// + /// + /// the delegee + /// + /// Set the delegee. + /// + /// + /// the delegee + /// + virtual public IScriptable Delegee + { + get + { + return obj; + } + + set + { + this.obj = value; + } + + } + + virtual public string ClassName + { + get + { + return obj.ClassName; + } + + } + + + virtual public IScriptable ParentScope + { + get + { + return obj.ParentScope; + } + + set + { + obj.ParentScope = value; + } + + } + + protected internal IScriptable obj = null; + + /// Create a Delegator prototype. + /// + /// This constructor should only be used for creating prototype + /// objects of Delegator. + /// + /// + + public Delegator () + { + } + + /// Create a new Delegator that forwards requests to a delegee + /// Scriptable object. + /// + /// + /// the delegee + /// + public Delegator (IScriptable obj) + { + this.obj = obj; + } + + /// Crete new Delegator instance. + /// The default implementation calls this.getClass().newInstance(). + /// + /// + protected internal virtual Delegator NewInstance () + { + try { + return (Delegator)System.Activator.CreateInstance (this.GetType ()); + } + catch (Exception ex) { + throw Context.ThrowAsScriptRuntimeEx (ex); + } + } + + public virtual object Get (string name, IScriptable start) + { + return obj.Get (name, start); + } + + public virtual object Get (int index, IScriptable start) + { + return obj.Get (index, start); + } + + public virtual bool Has (string name, IScriptable start) + { + return obj.Has (name, start); + } + + public virtual bool Has (int index, IScriptable start) + { + return obj.Has (index, start); + } + + public virtual object Put (string name, IScriptable start, object value) + { + return obj.Put (name, start, value); + } + + public virtual object Put (int index, IScriptable start, object value) + { + return obj.Put (index, start, value); + } + + public virtual void Delete (string name) + { + obj.Delete (name); + } + + public virtual void Delete (int index) + { + obj.Delete (index); + } + + public virtual IScriptable GetPrototype () + { + return obj.GetPrototype (); + } + + public virtual void SetPrototype (IScriptable prototype) + { + obj.SetPrototype (prototype); + } + + public virtual object [] GetIds () + { + return obj.GetIds (); + } + /// Note that this method does not get forwarded to the delegee if + /// the hint parameter is null, + /// typeof(Scriptable) or + /// typeof(Function). Instead the object + /// itself is returned. + /// + /// + /// the type hint + /// + /// the default value + /// + /// + public virtual object GetDefaultValue (Type hint) + { + return (hint == null + || hint == typeof (IScriptable) + || hint == typeof (IFunction)) + ? this : obj.GetDefaultValue (hint); + } + + public virtual bool HasInstance (IScriptable instance) + { + return obj.HasInstance (instance); + } + + public virtual object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args) + { + return ((IFunction)obj).Call (cx, scope, thisObj, args); + } + + /// Note that if the delegee is null, + /// this method creates a new instance of the Delegator itself + /// rathert than forwarding the call to the + /// delegee. This permits the use of Delegator + /// prototypes. + /// + /// + /// the current Context for this thread + /// + /// an enclosing scope of the caller except + /// when the function is called from a closure. + /// + /// the array of arguments + /// + /// the allocated object + /// + /// + + public virtual IScriptable Construct (Context cx, IScriptable scope, object [] args) + { + if (obj == null) { + //this little trick allows us to declare prototype objects for + //Delegators + Delegator n = NewInstance (); + IScriptable delegee; + if (args.Length == 0) { + delegee = new BuiltinObject (); + } + else { + delegee = ScriptConvert.ToObject (cx, scope, args [0]); + } + n.Delegee = delegee; + return n; + } + else { + return ((IFunction)obj).Construct (cx, scope, args); + } + } + } } \ No newline at end of file diff --git a/src/EcmaScript.NET/EcmaScript.NET.csproj b/src/EcmaScript.NET/EcmaScript.NET.csproj new file mode 100644 index 0000000..1fb4d0a --- /dev/null +++ b/src/EcmaScript.NET/EcmaScript.NET.csproj @@ -0,0 +1,21 @@ + + + + netstandard2.0;net45 + 0.0.0 + Pure Krome + World Domination Technologies + This is a custom modified version of the EcmaScript code, mainly created for YUICompressor.NET. + 2011 + https://github.com/PureKrome/EcmaScript.NET/blob/master/License.txt + https://github.com/PureKrome/EcmaScript.NET + https://github.com/PureKrome/EcmaScript.NET + .net c# + ecmascript, javascript + + + + + + + diff --git a/Code/EcmaScript.NET/EcmaScriptError.cs b/src/EcmaScript.NET/EcmaScriptError.cs similarity index 97% rename from Code/EcmaScript.NET/EcmaScriptError.cs rename to src/EcmaScript.NET/EcmaScriptError.cs index ebe0713..aa71673 100644 --- a/Code/EcmaScript.NET/EcmaScriptError.cs +++ b/src/EcmaScript.NET/EcmaScriptError.cs @@ -1,99 +1,99 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -namespace EcmaScript.NET -{ - - /// The class of exceptions raised by the engine as described in - /// ECMA edition 3. See section 15.11.6 in particular. - /// - public class EcmaScriptError : EcmaScriptException - { - /// Gets the name of the error. - /// - /// ECMA edition 3 defines the following - /// errors: EvalError, RangeError, ReferenceError, - /// SyntaxError, TypeError, and URIError. Additional error names - /// may be added in the future. - /// - /// See ECMA edition 3, 15.11.7.9. - /// - /// - /// the name of the error. - /// - public virtual string Name - { - get - { - return m_ErrorName; - } - - } - - public override string Message - { - get - { - return string.Format ( - "\"{0}\", {1} at line {2}: {3}", - base.SourceName, Name, base.LineNumber, ErrorMessage); - } - } - - /// Gets the message corresponding to the error. - /// - /// See ECMA edition 3, 15.11.7.10. - /// - /// - /// an implemenation-defined string describing the error. - /// - public virtual string ErrorMessage - { - get - { - return m_ErrorMessage; - } - - } - - string m_ErrorName; - string m_ErrorMessage; - - /// Create an exception with the specified detail message. - /// - /// Errors internal to the JavaScript engine will simply throw a - /// RuntimeException. - /// - /// - /// the name of the source reponsible for the error - /// - /// the line number of the source - /// - /// the columnNumber of the source (may be zero if - /// unknown) - /// - /// the source of the line containing the error (may be - /// null if unknown) - /// - internal EcmaScriptError (string errorName, string errorMessage, string sourceName, int lineNumber, string lineSource, int columnNumber) - { - RecordErrorOrigin (sourceName, lineNumber, lineSource, columnNumber); - this.m_ErrorName = errorName; - this.m_ErrorMessage = errorMessage; - } - - } - +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +namespace EcmaScript.NET +{ + + /// The class of exceptions raised by the engine as described in + /// ECMA edition 3. See section 15.11.6 in particular. + /// + public class EcmaScriptError : EcmaScriptException + { + /// Gets the name of the error. + /// + /// ECMA edition 3 defines the following + /// errors: EvalError, RangeError, ReferenceError, + /// SyntaxError, TypeError, and URIError. Additional error names + /// may be added in the future. + /// + /// See ECMA edition 3, 15.11.7.9. + /// + /// + /// the name of the error. + /// + public virtual string Name + { + get + { + return m_ErrorName; + } + + } + + public override string Message + { + get + { + return string.Format ( + "\"{0}\", {1} at line {2}: {3}", + base.SourceName, Name, base.LineNumber, ErrorMessage); + } + } + + /// Gets the message corresponding to the error. + /// + /// See ECMA edition 3, 15.11.7.10. + /// + /// + /// an implemenation-defined string describing the error. + /// + public virtual string ErrorMessage + { + get + { + return m_ErrorMessage; + } + + } + + string m_ErrorName; + string m_ErrorMessage; + + /// Create an exception with the specified detail message. + /// + /// Errors internal to the JavaScript engine will simply throw a + /// RuntimeException. + /// + /// + /// the name of the source reponsible for the error + /// + /// the line number of the source + /// + /// the columnNumber of the source (may be zero if + /// unknown) + /// + /// the source of the line containing the error (may be + /// null if unknown) + /// + internal EcmaScriptError (string errorName, string errorMessage, string sourceName, int lineNumber, string lineSource, int columnNumber) + { + RecordErrorOrigin (sourceName, lineNumber, lineSource, columnNumber); + this.m_ErrorName = errorName; + this.m_ErrorMessage = errorMessage; + } + + } + } \ No newline at end of file diff --git a/Code/EcmaScript.NET/EcmaScriptException.cs b/src/EcmaScript.NET/EcmaScriptException.cs similarity index 94% rename from Code/EcmaScript.NET/EcmaScriptException.cs rename to src/EcmaScript.NET/EcmaScriptException.cs index 7b42740..bb75e19 100644 --- a/Code/EcmaScript.NET/EcmaScriptException.cs +++ b/src/EcmaScript.NET/EcmaScriptException.cs @@ -1,221 +1,220 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; -using System.IO; -using System.Text; - -namespace EcmaScript.NET -{ - - /// - /// The class of exceptions thrown by the JavaScript engine. - /// - public abstract class EcmaScriptException : ApplicationException - { - - public override string Message - { - get - { - string details = base.Message; - if (m_SourceName == null || m_LineNumber <= 0) { - return details; - } - StringBuilder buf = new StringBuilder (details); - buf.Append (" ("); - if (m_SourceName != null) { - buf.Append (m_SourceName); - } - if (m_LineNumber > 0) { - buf.Append ('#'); - buf.Append (m_LineNumber); - } - buf.Append (')'); - return buf.ToString (); - } - - } - - internal EcmaScriptException () - { - Interpreter.captureInterpreterStackInfo (this); - } - - internal EcmaScriptException (string details) - : base (details) - { - Interpreter.captureInterpreterStackInfo (this); - } - - - internal EcmaScriptException (string details, Exception innerException) - : base (details, innerException) - { - Interpreter.captureInterpreterStackInfo (this); - } - /// Get the uri of the script source containing the error, or null - /// if that information is not available. - /// - public virtual string SourceName - { - get - { - return m_SourceName; - } - } - - /// Initialize the uri of the script source containing the error. - /// - /// - /// the uri of the script source reponsible for the error. - /// It should not be null. - /// - /// - /// IllegalStateException if the method is called more then once. - public void InitSourceName (string sourceName) - { - if (sourceName == null) - throw new ArgumentException (); - if (this.m_SourceName != null) - throw new ApplicationException (); - this.m_SourceName = sourceName; - } - - /// Returns the line number of the statement causing the error, - /// or zero if not available. - /// - public int LineNumber - { - get - { - return m_LineNumber; - } - } - - /// Initialize the line number of the script statement causing the error. - /// - /// - /// the line number in the script source. - /// It should be positive number. - /// - /// - /// IllegalStateException if the method is called more then once. - public void InitLineNumber (int lineNumber) - { - if (lineNumber <= 0) - throw new ArgumentException (Convert.ToString (lineNumber)); - if (this.m_LineNumber > 0) - throw new ApplicationException (); - this.m_LineNumber = lineNumber; - } - - /// The column number of the location of the error, or zero if unknown. - public int ColumnNumber - { - get - { - return m_ColumnNumber; - } - } - - /// Initialize the column number of the script statement causing the error. - /// - /// - /// the column number in the script source. - /// It should be positive number. - /// - /// - /// IllegalStateException if the method is called more then once. - public void InitColumnNumber (int columnNumber) - { - if (columnNumber <= 0) - throw new ArgumentException (Convert.ToString (columnNumber)); - if (this.m_ColumnNumber > 0) - throw new ApplicationException (); - this.m_ColumnNumber = columnNumber; - } - - /// The source text of the line causing the error, or null if unknown. - public string LineSource - { - get - { - return m_LineSource; - } - } - - /// Initialize the text of the source line containing the error. - /// - /// - /// the text of the source line reponsible for the error. - /// It should not be null. - /// - /// - /// IllegalStateException if the method is called more then once. - public void InitLineSource (string lineSource) - { - if (lineSource == null) - throw new ArgumentException (); - if (this.m_LineSource != null) - throw new ApplicationException (); - this.m_LineSource = lineSource; - } - - internal void RecordErrorOrigin (string sourceName, int lineNumber, string lineSource, int columnNumber) - { - if (sourceName != null) { - InitSourceName (sourceName); - } - if (lineNumber != 0) { - InitLineNumber (lineNumber); - } - if (lineSource != null) { - InitLineSource (lineSource); - } - if (columnNumber != 0) { - InitColumnNumber (columnNumber); - } - InitScriptStackTrace (); - } - - private string m_SourceName; - private int m_LineNumber; - private string m_LineSource; - private int m_ColumnNumber; - - internal object m_InterpreterStackInfo; - internal int [] m_InterpreterLineData; - - private void InitScriptStackTrace () { - m_ScriptStackTrace = Interpreter.GetStack (this); - } - private string m_ScriptStackTrace = null; - public string ScriptStackTrace - { - get - { - - return m_ScriptStackTrace; - } - } - - public override string ToString () - { - if (this.StackTrace != null) - return Interpreter.getPatchedStack (this, this.StackTrace.ToString ()); - return ScriptStackTrace; - } - - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; +using System.Text; + +namespace EcmaScript.NET +{ + + /// + /// The class of exceptions thrown by the JavaScript engine. + /// + public abstract class EcmaScriptException : Exception + { + + public override string Message + { + get + { + string details = base.Message; + if (m_SourceName == null || m_LineNumber <= 0) { + return details; + } + StringBuilder buf = new StringBuilder (details); + buf.Append (" ("); + if (m_SourceName != null) { + buf.Append (m_SourceName); + } + if (m_LineNumber > 0) { + buf.Append ('#'); + buf.Append (m_LineNumber); + } + buf.Append (')'); + return buf.ToString (); + } + + } + + internal EcmaScriptException () + { + Interpreter.captureInterpreterStackInfo (this); + } + + internal EcmaScriptException (string details) + : base (details) + { + Interpreter.captureInterpreterStackInfo (this); + } + + + internal EcmaScriptException (string details, Exception innerException) + : base (details, innerException) + { + Interpreter.captureInterpreterStackInfo (this); + } + /// Get the uri of the script source containing the error, or null + /// if that information is not available. + /// + public virtual string SourceName + { + get + { + return m_SourceName; + } + } + + /// Initialize the uri of the script source containing the error. + /// + /// + /// the uri of the script source reponsible for the error. + /// It should not be null. + /// + /// + /// IllegalStateException if the method is called more then once. + public void InitSourceName (string sourceName) + { + if (sourceName == null) + throw new ArgumentException (); + if (this.m_SourceName != null) + throw new Exception (); + this.m_SourceName = sourceName; + } + + /// Returns the line number of the statement causing the error, + /// or zero if not available. + /// + public int LineNumber + { + get + { + return m_LineNumber; + } + } + + /// Initialize the line number of the script statement causing the error. + /// + /// + /// the line number in the script source. + /// It should be positive number. + /// + /// + /// IllegalStateException if the method is called more then once. + public void InitLineNumber (int lineNumber) + { + if (lineNumber <= 0) + throw new ArgumentException (Convert.ToString (lineNumber)); + if (this.m_LineNumber > 0) + throw new Exception (); + this.m_LineNumber = lineNumber; + } + + /// The column number of the location of the error, or zero if unknown. + public int ColumnNumber + { + get + { + return m_ColumnNumber; + } + } + + /// Initialize the column number of the script statement causing the error. + /// + /// + /// the column number in the script source. + /// It should be positive number. + /// + /// + /// IllegalStateException if the method is called more then once. + public void InitColumnNumber (int columnNumber) + { + if (columnNumber <= 0) + throw new ArgumentException (Convert.ToString (columnNumber)); + if (this.m_ColumnNumber > 0) + throw new Exception (); + this.m_ColumnNumber = columnNumber; + } + + /// The source text of the line causing the error, or null if unknown. + public string LineSource + { + get + { + return m_LineSource; + } + } + + /// Initialize the text of the source line containing the error. + /// + /// + /// the text of the source line reponsible for the error. + /// It should not be null. + /// + /// + /// IllegalStateException if the method is called more then once. + public void InitLineSource (string lineSource) + { + if (lineSource == null) + throw new ArgumentException (); + if (this.m_LineSource != null) + throw new Exception (); + this.m_LineSource = lineSource; + } + + internal void RecordErrorOrigin (string sourceName, int lineNumber, string lineSource, int columnNumber) + { + if (sourceName != null) { + InitSourceName (sourceName); + } + if (lineNumber != 0) { + InitLineNumber (lineNumber); + } + if (lineSource != null) { + InitLineSource (lineSource); + } + if (columnNumber != 0) { + InitColumnNumber (columnNumber); + } + InitScriptStackTrace (); + } + + private string m_SourceName; + private int m_LineNumber; + private string m_LineSource; + private int m_ColumnNumber; + + internal object m_InterpreterStackInfo; + internal int [] m_InterpreterLineData; + + private void InitScriptStackTrace () { + m_ScriptStackTrace = Interpreter.GetStack (this); + } + private string m_ScriptStackTrace = null; + public string ScriptStackTrace + { + get + { + + return m_ScriptStackTrace; + } + } + + public override string ToString () + { + if (this.StackTrace != null) + return Interpreter.getPatchedStack (this, this.StackTrace.ToString ()); + return ScriptStackTrace; + } + + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/EcmaScriptRuntimeException.cs b/src/EcmaScript.NET/EcmaScriptRuntimeException.cs similarity index 97% rename from Code/EcmaScript.NET/EcmaScriptRuntimeException.cs rename to src/EcmaScript.NET/EcmaScriptRuntimeException.cs index 6ff1f34..a67999a 100644 --- a/Code/EcmaScript.NET/EcmaScriptRuntimeException.cs +++ b/src/EcmaScript.NET/EcmaScriptRuntimeException.cs @@ -1,84 +1,84 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -namespace EcmaScript.NET -{ - - /// The class of exceptions thrown by the JavaScript engine. - - public class EcmaScriptRuntimeException : EcmaScriptException - { - - public EcmaScriptRuntimeException (Exception innerException) - : base (innerException.Message, innerException) - { - int [] linep = new int [] { 0 }; - string sourceName = Context.GetSourcePositionFromStack (linep); - int lineNumber = linep [0]; - if (sourceName != null) { - InitSourceName (sourceName); - } - if (lineNumber != 0) { - InitLineNumber (lineNumber); - } - } - - public EcmaScriptRuntimeException (string detail) - : base (detail) - { - } - - /// Create an exception with the specified detail message. - /// - /// Errors internal to the JavaScript engine will simply throw a - /// RuntimeException. - /// - /// - /// the error message - /// - /// the name of the source reponsible for the error - /// - /// the line number of the source - /// - public EcmaScriptRuntimeException (string detail, string sourceName, int lineNumber) - : this (detail, sourceName, lineNumber, null, 0) - { - } - - /// Create an exception with the specified detail message. - /// - /// Errors internal to the JavaScript engine will simply throw a - /// RuntimeException. - /// - /// - /// the error message - /// - /// the name of the source reponsible for the error - /// - /// the line number of the source - /// - /// the columnNumber of the source (may be zero if - /// unknown) - /// - /// the source of the line containing the error (may be - /// null if unknown) - /// - public EcmaScriptRuntimeException (string detail, string sourceName, int lineNumber, string lineSource, int columnNumber) - : base (detail) - { - RecordErrorOrigin (sourceName, lineNumber, lineSource, columnNumber); - } - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +namespace EcmaScript.NET +{ + + /// The class of exceptions thrown by the JavaScript engine. + + public class EcmaScriptRuntimeException : EcmaScriptException + { + + public EcmaScriptRuntimeException (Exception innerException) + : base (innerException.Message, innerException) + { + int [] linep = new int [] { 0 }; + string sourceName = Context.GetSourcePositionFromStack (linep); + int lineNumber = linep [0]; + if (sourceName != null) { + InitSourceName (sourceName); + } + if (lineNumber != 0) { + InitLineNumber (lineNumber); + } + } + + public EcmaScriptRuntimeException (string detail) + : base (detail) + { + } + + /// Create an exception with the specified detail message. + /// + /// Errors internal to the JavaScript engine will simply throw a + /// RuntimeException. + /// + /// + /// the error message + /// + /// the name of the source reponsible for the error + /// + /// the line number of the source + /// + public EcmaScriptRuntimeException (string detail, string sourceName, int lineNumber) + : this (detail, sourceName, lineNumber, null, 0) + { + } + + /// Create an exception with the specified detail message. + /// + /// Errors internal to the JavaScript engine will simply throw a + /// RuntimeException. + /// + /// + /// the error message + /// + /// the name of the source reponsible for the error + /// + /// the line number of the source + /// + /// the columnNumber of the source (may be zero if + /// unknown) + /// + /// the source of the line containing the error (may be + /// null if unknown) + /// + public EcmaScriptRuntimeException (string detail, string sourceName, int lineNumber, string lineSource, int columnNumber) + : base (detail) + { + RecordErrorOrigin (sourceName, lineNumber, lineSource, columnNumber); + } + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/EcmaScriptThrow.cs b/src/EcmaScript.NET/EcmaScriptThrow.cs similarity index 96% rename from Code/EcmaScript.NET/EcmaScriptThrow.cs rename to src/EcmaScript.NET/EcmaScriptThrow.cs index a52b857..451c147 100644 --- a/Code/EcmaScript.NET/EcmaScriptThrow.cs +++ b/src/EcmaScript.NET/EcmaScriptThrow.cs @@ -1,63 +1,63 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -namespace EcmaScript.NET -{ - - /// Java reflection of JavaScript exceptions. - /// Instances of this class are thrown by the JavaScript 'throw' keyword. - /// - /// - - public class EcmaScriptThrow : EcmaScriptException - { - - /// the value wrapped by this exception - /// - public virtual object Value - { - get - { - return value; - } - - } - - /// - /// Create a JavaScript exception wrapping the given JavaScript value - /// - /// the JavaScript value thrown. - public EcmaScriptThrow (object value, string sourceName, int lineNumber) - { - RecordErrorOrigin (sourceName, lineNumber, null, 0); - this.value = value; - } - - public override string Message - { - get - { - IScriptable scriptable = (value as IScriptable); - if (scriptable != null) { - // to prevent potential of evaluation and throwing more exceptions - return ScriptRuntime.DefaultObjectToString (scriptable); - } - return ScriptConvert.ToString (value); - } - } - - private object value; - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +namespace EcmaScript.NET +{ + + /// Java reflection of JavaScript exceptions. + /// Instances of this class are thrown by the JavaScript 'throw' keyword. + /// + /// + + public class EcmaScriptThrow : EcmaScriptException + { + + /// the value wrapped by this exception + /// + public virtual object Value + { + get + { + return value; + } + + } + + /// + /// Create a JavaScript exception wrapping the given JavaScript value + /// + /// the JavaScript value thrown. + public EcmaScriptThrow (object value, string sourceName, int lineNumber) + { + RecordErrorOrigin (sourceName, lineNumber, null, 0); + this.value = value; + } + + public override string Message + { + get + { + IScriptable scriptable = (value as IScriptable); + if (scriptable != null) { + // to prevent potential of evaluation and throwing more exceptions + return ScriptRuntime.DefaultObjectToString (scriptable); + } + return ScriptConvert.ToString (value); + } + } + + private object value; + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/ErrorReporter.cs b/src/EcmaScript.NET/ErrorReporter.cs similarity index 97% rename from Code/EcmaScript.NET/ErrorReporter.cs rename to src/EcmaScript.NET/ErrorReporter.cs index 608442c..a8a9d45 100644 --- a/Code/EcmaScript.NET/ErrorReporter.cs +++ b/src/EcmaScript.NET/ErrorReporter.cs @@ -1,91 +1,91 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -namespace EcmaScript.NET -{ - - /// This is interface defines a protocol for the reporting of - /// errors during JavaScript translation or execution. - /// - /// - - public interface ErrorReporter - { - - /// Report a warning. - /// - /// The implementing class may choose to ignore the warning - /// if it desires. - /// - /// - /// a String describing the warning - /// - /// a String describing the JavaScript source - /// where the warning occured; typically a filename or URL - /// - /// the line number associated with the warning - /// - /// the text of the line (may be null) - /// - /// the offset into lineSource where problem was detected - /// - void Warning (string message, string sourceName, int line, string lineSource, int lineOffset); - - /// Report an error. - /// - /// The implementing class is free to throw an exception if - /// it desires. - /// - /// If execution has not yet begun, the JavaScript engine is - /// free to find additional errors rather than terminating - /// the translation. It will not execute a script that had - /// errors, however. - /// - /// - /// a String describing the error - /// - /// a String describing the JavaScript source - /// where the error occured; typically a filename or URL - /// - /// the line number associated with the error - /// - /// the text of the line (may be null) - /// - /// the offset into lineSource where problem was detected - /// - void Error (string message, string sourceName, int line, string lineSource, int lineOffset); - - /// Creates an EvaluatorException that may be thrown. - /// - /// runtimeErrors, unlike errors, will always terminate the - /// current script. - /// - /// - /// a String describing the error - /// - /// a String describing the JavaScript source - /// where the error occured; typically a filename or URL - /// - /// the line number associated with the error - /// - /// the text of the line (may be null) - /// - /// the offset into lineSource where problem was detected - /// - /// an EvaluatorException that will be thrown. - /// - EcmaScriptRuntimeException RuntimeError (string message, string sourceName, int line, string lineSource, int lineOffset); - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +namespace EcmaScript.NET +{ + + /// This is interface defines a protocol for the reporting of + /// errors during JavaScript translation or execution. + /// + /// + + public interface ErrorReporter + { + + /// Report a warning. + /// + /// The implementing class may choose to ignore the warning + /// if it desires. + /// + /// + /// a String describing the warning + /// + /// a String describing the JavaScript source + /// where the warning occured; typically a filename or URL + /// + /// the line number associated with the warning + /// + /// the text of the line (may be null) + /// + /// the offset into lineSource where problem was detected + /// + void Warning (string message, string sourceName, int line, string lineSource, int lineOffset); + + /// Report an error. + /// + /// The implementing class is free to throw an exception if + /// it desires. + /// + /// If execution has not yet begun, the JavaScript engine is + /// free to find additional errors rather than terminating + /// the translation. It will not execute a script that had + /// errors, however. + /// + /// + /// a String describing the error + /// + /// a String describing the JavaScript source + /// where the error occured; typically a filename or URL + /// + /// the line number associated with the error + /// + /// the text of the line (may be null) + /// + /// the offset into lineSource where problem was detected + /// + void Error (string message, string sourceName, int line, string lineSource, int lineOffset); + + /// Creates an EvaluatorException that may be thrown. + /// + /// runtimeErrors, unlike errors, will always terminate the + /// current script. + /// + /// + /// a String describing the error + /// + /// a String describing the JavaScript source + /// where the error occured; typically a filename or URL + /// + /// the line number associated with the error + /// + /// the text of the line (may be null) + /// + /// the offset into lineSource where problem was detected + /// + /// an EvaluatorException that will be thrown. + /// + EcmaScriptRuntimeException RuntimeError (string message, string sourceName, int line, string lineSource, int lineOffset); + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/FunctionNode.cs b/src/EcmaScript.NET/FunctionNode.cs similarity index 96% rename from Code/EcmaScript.NET/FunctionNode.cs rename to src/EcmaScript.NET/FunctionNode.cs index 0861b42..74bee4b 100644 --- a/Code/EcmaScript.NET/FunctionNode.cs +++ b/src/EcmaScript.NET/FunctionNode.cs @@ -1,85 +1,85 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -namespace EcmaScript.NET -{ - - public class FunctionNode : ScriptOrFnNode - { - virtual public string FunctionName - { - get - { - return functionName; - } - - } - virtual public bool IgnoreDynamicScope - { - get - { - return itsIgnoreDynamicScope; - } - - } - virtual public int FunctionType - { - get - { - return itsFunctionType; - } - - } - - public FunctionNode (string name) - : base (Token.FUNCTION) - { - functionName = name; - } - - public virtual bool RequiresActivation - { - - get - { - return itsNeedsActivation; - } - } - - /// - /// There are three types of functions that can be defined. The first - /// is a function statement. This is a function appearing as a top-level - /// statement (i.e., not nested inside some other statement) in either a - /// script or a function. - /// - /// The second is a function expression, which is a function appearing in - /// an expression except for the third type, which is... - /// - /// The third type is a function expression where the expression is the - /// top-level expression in an expression statement. - /// - /// The three types of functions have different treatment and must be - /// distinquished. - /// - public const int FUNCTION_STATEMENT = 1; - public const int FUNCTION_EXPRESSION = 2; - public const int FUNCTION_EXPRESSION_STATEMENT = 3; - - internal string functionName; - internal bool itsNeedsActivation; - internal int itsFunctionType; - internal bool itsIgnoreDynamicScope; - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +namespace EcmaScript.NET +{ + + public class FunctionNode : ScriptOrFnNode + { + virtual public string FunctionName + { + get + { + return functionName; + } + + } + virtual public bool IgnoreDynamicScope + { + get + { + return itsIgnoreDynamicScope; + } + + } + virtual public int FunctionType + { + get + { + return itsFunctionType; + } + + } + + public FunctionNode (string name) + : base (Token.FUNCTION) + { + functionName = name; + } + + public virtual bool RequiresActivation + { + + get + { + return itsNeedsActivation; + } + } + + /// + /// There are three types of functions that can be defined. The first + /// is a function statement. This is a function appearing as a top-level + /// statement (i.e., not nested inside some other statement) in either a + /// script or a function. + /// + /// The second is a function expression, which is a function appearing in + /// an expression except for the third type, which is... + /// + /// The third type is a function expression where the expression is the + /// top-level expression in an expression statement. + /// + /// The three types of functions have different treatment and must be + /// distinquished. + /// + public const int FUNCTION_STATEMENT = 1; + public const int FUNCTION_EXPRESSION = 2; + public const int FUNCTION_EXPRESSION_STATEMENT = 3; + + internal string functionName; + internal bool itsNeedsActivation; + internal int itsFunctionType; + internal bool itsIgnoreDynamicScope; + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/Helpers/CliHelper.cs b/src/EcmaScript.NET/Helpers/CliHelper.cs similarity index 96% rename from Code/EcmaScript.NET/Helpers/CliHelper.cs rename to src/EcmaScript.NET/Helpers/CliHelper.cs index f743f93..71238c0 100644 --- a/Code/EcmaScript.NET/Helpers/CliHelper.cs +++ b/src/EcmaScript.NET/Helpers/CliHelper.cs @@ -1,286 +1,286 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; -using System.Text; -using System.Reflection; -using System.Collections; -using System.Runtime.InteropServices; - -namespace EcmaScript.NET -{ - - sealed class CliHelper - { - - private CliHelper () - { - ; - } - - internal static Type GetType (string className) - { - try { - return Type.GetType (className); - } - catch { - ; - } - return null; - } - - internal static bool IsNegativeZero (double d) - { - if (double.IsNaN (d)) - return false; - if (d != 0.0) - return false; - return (double.PositiveInfinity / d) == double.NegativeInfinity; - } - - internal static bool IsPositiveZero (double d) - { - if (double.IsNaN (d)) - return false; - if (d != 0.0) - return false; - return (double.PositiveInfinity / d) == double.PositiveInfinity; - } - - internal static new bool Equals (object o1, object o2) - { - if (o1 == null && o2 == null) - return true; - if (o1 == null || o2 == null) - return false; - return o1.Equals (o2); - } - - internal static string ToSignature (ConstructorInfo ci) - { - StringBuilder sb = new StringBuilder (); - sb.Append (ToSignature (ci.DeclaringType)); - sb.Append (ToSignature ('(', ci.GetParameters (), ')')); - return sb.ToString (); - } - internal static string ToSignature (PropertyInfo pi) - { - StringBuilder sb = new StringBuilder (); - sb.Append (ToSignature (pi.PropertyType)); - sb.Append (" "); - sb.Append (ToSignature (pi.DeclaringType)); - sb.Append ("."); - sb.Append (pi.Name); - sb.Append (ToSignature ('[', pi.GetIndexParameters (), ']')); - return sb.ToString (); - } - - internal static string ToSignature (FieldInfo fi) - { - StringBuilder sb = new StringBuilder (); - sb.Append (ToSignature (fi.FieldType)); - sb.Append (" "); - sb.Append (ToSignature (fi.DeclaringType)); - sb.Append ("."); - sb.Append (fi.Name); - return sb.ToString (); - } - - internal static string ToSignature (object [] args) - { - StringBuilder sb = new StringBuilder (); - for (int i = 0; i < args.Length; i++) { - if (i > 0) - sb.Append (", "); - sb.Append (ToSignature (args [0].GetType ())); - } - return sb.ToString (); - } - - internal static string ToSignature (MemberInfo mi) - { - if (mi is PropertyInfo) - return ToSignature ((PropertyInfo)mi); - if (mi is FieldInfo) - return ToSignature ((FieldInfo)mi); - if (mi is ConstructorInfo) - return ToSignature ((ConstructorInfo)mi); - if (mi is MethodInfo) - return ToSignature ((MethodInfo)mi); - return "[unknown: " + mi.GetType ().FullName + "]"; - } - - internal static string ToSignature (char parenOpen, ParameterInfo [] pi, char parenClose) - { - StringBuilder sb = new StringBuilder (); - sb.Append (parenOpen); - for (int i = 0; i < pi.Length; i++) { - if (i > 0) - sb.Append (", "); - if (pi [i].IsOut) - sb.Append ("out "); - if (pi [i].IsIn) - sb.Append ("in "); - if (IsParamsParameter (pi [i])) - sb.Append ("params "); - sb.Append (ToSignature (pi [i].ParameterType)); - sb.Append (" "); - sb.Append (pi [i].Name); - } - sb.Append (parenClose); - return sb.ToString (); - } - - - internal static string ToSignature (MethodInfo mi) - { - StringBuilder sb = new StringBuilder (); - sb.Append (ToSignature (mi.ReturnType)); - sb.Append (" "); - sb.Append (ToSignature (mi.DeclaringType)); - sb.Append ("."); - sb.Append (mi.Name); - sb.Append (ToSignature ('(', mi.GetParameters (), ')')); - return sb.ToString (); - } - - internal static bool HasParamsParameter (MethodBase mb) - { - return HasParamsParameter (mb.GetParameters ()); - } - - internal static bool HasParamsParameter (ParameterInfo [] pis) - { - for (int i = 0; i < pis.Length; i++) - if (IsParamsParameter (pis [i])) - return true; - return false; - } - - internal static bool IsParamsParameter (ParameterInfo pi) - { - ParamArrayAttribute attr = (ParamArrayAttribute) - CliHelper.GetCustomAttribute (typeof (ParamArrayAttribute), pi); - return (attr != null); - } - - - internal static string ToSignature (Type type) - { - if (type.IsArray) { - string ret = ToSignature (type.GetElementType ()); - for (int i = 0; i < type.GetArrayRank (); i++) - ret += "[]"; - return ret; - } - if (type == typeof (short)) - return "short"; - if (type == typeof (ushort)) - return "ushort"; - if (type == typeof (int)) - return "int"; - if (type == typeof (uint)) - return "uint"; - if (type == typeof (ulong)) - return "ulong"; - if (type == typeof (long)) - return "long"; - if (type == typeof (void)) - return "void"; - if (type == typeof (bool)) - return "bool"; - if (type == typeof (double)) - return "double"; - if (type == typeof (decimal)) - return "decimal"; - if (type == typeof (object)) - return "object"; - return type.FullName; - } - - internal static bool IsNumberType (Type type) - { - return ( - type == typeof (Int16) - || type == typeof (UInt16) - || type == typeof (Int32) - || type == typeof (UInt32) - || type == typeof (Int64) - || type == typeof (UInt64) - || type == typeof (Single) - || type == typeof (Double) - || type == typeof (Decimal)); - } - - internal static bool IsNumber (object value) - { - return ( - value is Int16 - || value is UInt16 - || value is Int32 - || value is UInt32 - || value is Int64 - || value is UInt64 - || value is Single - || value is Double - || value is Decimal); - } - - internal static object CreateInstance (Type cl) - { - try { - return System.Activator.CreateInstance (cl); - } - catch { - ; - } - return null; - } - - internal static object GetCustomAttribute (Type type, Type attribute) - { - object [] attributes = type.GetCustomAttributes (attribute, true); - if (attributes.Length < 1) - return null; - return attributes [0]; - } - - internal static object GetCustomAttribute (Type type, MemberInfo mi) - { - object attribute = null; - object [] attributes = mi.GetCustomAttributes (type, true); - if (attributes.Length > 0) - attribute = attributes [0]; - return attribute; - } - - internal static object GetCustomAttribute (Type type, ParameterInfo pi) - { - object [] attributes = pi.GetCustomAttributes (type, true); - if (attributes.Length < 1) - return null; - return attributes [0]; - } - - internal static Type [] GetParameterTypes (ParameterInfo [] parameters) - { - Type [] types = new Type [parameters.Length]; - for (int i = 0; i < types.Length; i++) { - types [i] = parameters [i].ParameterType; - } - return types; - } - - } - -} +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; +using System.Text; +using System.Reflection; +using System.Collections; +using System.Runtime.InteropServices; + +namespace EcmaScript.NET +{ + + sealed class CliHelper + { + + private CliHelper () + { + ; + } + + internal static Type GetType (string className) + { + try { + return Type.GetType (className); + } + catch { + ; + } + return null; + } + + internal static bool IsNegativeZero (double d) + { + if (double.IsNaN (d)) + return false; + if (d != 0.0) + return false; + return (double.PositiveInfinity / d) == double.NegativeInfinity; + } + + internal static bool IsPositiveZero (double d) + { + if (double.IsNaN (d)) + return false; + if (d != 0.0) + return false; + return (double.PositiveInfinity / d) == double.PositiveInfinity; + } + + internal static new bool Equals (object o1, object o2) + { + if (o1 == null && o2 == null) + return true; + if (o1 == null || o2 == null) + return false; + return o1.Equals (o2); + } + + internal static string ToSignature (ConstructorInfo ci) + { + StringBuilder sb = new StringBuilder (); + sb.Append (ToSignature (ci.DeclaringType)); + sb.Append (ToSignature ('(', ci.GetParameters (), ')')); + return sb.ToString (); + } + internal static string ToSignature (PropertyInfo pi) + { + StringBuilder sb = new StringBuilder (); + sb.Append (ToSignature (pi.PropertyType)); + sb.Append (" "); + sb.Append (ToSignature (pi.DeclaringType)); + sb.Append ("."); + sb.Append (pi.Name); + sb.Append (ToSignature ('[', pi.GetIndexParameters (), ']')); + return sb.ToString (); + } + + internal static string ToSignature (FieldInfo fi) + { + StringBuilder sb = new StringBuilder (); + sb.Append (ToSignature (fi.FieldType)); + sb.Append (" "); + sb.Append (ToSignature (fi.DeclaringType)); + sb.Append ("."); + sb.Append (fi.Name); + return sb.ToString (); + } + + internal static string ToSignature (object [] args) + { + StringBuilder sb = new StringBuilder (); + for (int i = 0; i < args.Length; i++) { + if (i > 0) + sb.Append (", "); + sb.Append (ToSignature (args [0].GetType ())); + } + return sb.ToString (); + } + + internal static string ToSignature (MemberInfo mi) + { + if (mi is PropertyInfo) + return ToSignature ((PropertyInfo)mi); + if (mi is FieldInfo) + return ToSignature ((FieldInfo)mi); + if (mi is ConstructorInfo) + return ToSignature ((ConstructorInfo)mi); + if (mi is MethodInfo) + return ToSignature ((MethodInfo)mi); + return "[unknown: " + mi.GetType ().FullName + "]"; + } + + internal static string ToSignature (char parenOpen, ParameterInfo [] pi, char parenClose) + { + StringBuilder sb = new StringBuilder (); + sb.Append (parenOpen); + for (int i = 0; i < pi.Length; i++) { + if (i > 0) + sb.Append (", "); + if (pi [i].IsOut) + sb.Append ("out "); + if (pi [i].IsIn) + sb.Append ("in "); + if (IsParamsParameter (pi [i])) + sb.Append ("params "); + sb.Append (ToSignature (pi [i].ParameterType)); + sb.Append (" "); + sb.Append (pi [i].Name); + } + sb.Append (parenClose); + return sb.ToString (); + } + + + internal static string ToSignature (MethodInfo mi) + { + StringBuilder sb = new StringBuilder (); + sb.Append (ToSignature (mi.ReturnType)); + sb.Append (" "); + sb.Append (ToSignature (mi.DeclaringType)); + sb.Append ("."); + sb.Append (mi.Name); + sb.Append (ToSignature ('(', mi.GetParameters (), ')')); + return sb.ToString (); + } + + internal static bool HasParamsParameter (MethodBase mb) + { + return HasParamsParameter (mb.GetParameters ()); + } + + internal static bool HasParamsParameter (ParameterInfo [] pis) + { + for (int i = 0; i < pis.Length; i++) + if (IsParamsParameter (pis [i])) + return true; + return false; + } + + internal static bool IsParamsParameter (ParameterInfo pi) + { + ParamArrayAttribute attr = (ParamArrayAttribute) + CliHelper.GetCustomAttribute (typeof (ParamArrayAttribute), pi); + return (attr != null); + } + + + internal static string ToSignature (Type type) + { + if (type.IsArray) { + string ret = ToSignature (type.GetElementType ()); + for (int i = 0; i < type.GetArrayRank (); i++) + ret += "[]"; + return ret; + } + if (type == typeof (short)) + return "short"; + if (type == typeof (ushort)) + return "ushort"; + if (type == typeof (int)) + return "int"; + if (type == typeof (uint)) + return "uint"; + if (type == typeof (ulong)) + return "ulong"; + if (type == typeof (long)) + return "long"; + if (type == typeof (void)) + return "void"; + if (type == typeof (bool)) + return "bool"; + if (type == typeof (double)) + return "double"; + if (type == typeof (decimal)) + return "decimal"; + if (type == typeof (object)) + return "object"; + return type.FullName; + } + + internal static bool IsNumberType (Type type) + { + return ( + type == typeof (Int16) + || type == typeof (UInt16) + || type == typeof (Int32) + || type == typeof (UInt32) + || type == typeof (Int64) + || type == typeof (UInt64) + || type == typeof (Single) + || type == typeof (Double) + || type == typeof (Decimal)); + } + + internal static bool IsNumber (object value) + { + return ( + value is Int16 + || value is UInt16 + || value is Int32 + || value is UInt32 + || value is Int64 + || value is UInt64 + || value is Single + || value is Double + || value is Decimal); + } + + internal static object CreateInstance (Type cl) + { + try { + return System.Activator.CreateInstance (cl); + } + catch { + ; + } + return null; + } + + internal static object GetCustomAttribute (Type type, Type attribute) + { + object [] attributes = type.GetCustomAttributes (attribute, true); + if (attributes.Length < 1) + return null; + return attributes [0]; + } + + internal static object GetCustomAttribute (Type type, MemberInfo mi) + { + object attribute = null; + object [] attributes = mi.GetCustomAttributes (type, true); + if (attributes.Length > 0) + attribute = attributes [0]; + return attribute; + } + + internal static object GetCustomAttribute (Type type, ParameterInfo pi) + { + object [] attributes = pi.GetCustomAttributes (type, true); + if (attributes.Length < 1) + return null; + return attributes [0]; + } + + internal static Type [] GetParameterTypes (ParameterInfo [] parameters) + { + Type [] types = new Type [parameters.Length]; + for (int i = 0; i < types.Length; i++) { + types [i] = parameters [i].ParameterType; + } + return types; + } + + } + +} diff --git a/Code/EcmaScript.NET/Helpers/StackOverflowVerifier.cs b/src/EcmaScript.NET/Helpers/StackOverflowVerifier.cs similarity index 95% rename from Code/EcmaScript.NET/Helpers/StackOverflowVerifier.cs rename to src/EcmaScript.NET/Helpers/StackOverflowVerifier.cs index 3ae9a6f..a28a48f 100644 --- a/Code/EcmaScript.NET/Helpers/StackOverflowVerifier.cs +++ b/src/EcmaScript.NET/Helpers/StackOverflowVerifier.cs @@ -1,39 +1,39 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace EcmaScript.NET.Helpers -{ - - public class StackOverflowVerifier : IDisposable - { - - [ThreadStatic] - private static long m_Counter = long.MinValue; - - private int m_MaxStackSize = 0; - - public StackOverflowVerifier (int maxStackSize) - { - m_MaxStackSize = maxStackSize; - - ChangeStackDepth (+1); - } - - public void Dispose () - { - ChangeStackDepth (-1); - } - - void ChangeStackDepth (int offset) - { - if (m_Counter == long.MinValue) - m_Counter = 0; - m_Counter += offset; - if (m_Counter > m_MaxStackSize) - throw new StackOverflowVerifierException (); - } - - } - -} +using System; +using System.Collections.Generic; +using System.Text; + +namespace EcmaScript.NET.Helpers +{ + + public class StackOverflowVerifier : IDisposable + { + + [ThreadStatic] + private static long m_Counter = long.MinValue; + + private int m_MaxStackSize = 0; + + public StackOverflowVerifier (int maxStackSize) + { + m_MaxStackSize = maxStackSize; + + ChangeStackDepth (+1); + } + + public void Dispose () + { + ChangeStackDepth (-1); + } + + void ChangeStackDepth (int offset) + { + if (m_Counter == long.MinValue) + m_Counter = 0; + m_Counter += offset; + if (m_Counter > m_MaxStackSize) + throw new StackOverflowVerifierException (); + } + + } + +} diff --git a/Code/EcmaScript.NET/Helpers/StackOverflowVerifierException.cs b/src/EcmaScript.NET/Helpers/StackOverflowVerifierException.cs similarity index 64% rename from Code/EcmaScript.NET/Helpers/StackOverflowVerifierException.cs rename to src/EcmaScript.NET/Helpers/StackOverflowVerifierException.cs index e7fdbe6..adc29ec 100644 --- a/Code/EcmaScript.NET/Helpers/StackOverflowVerifierException.cs +++ b/src/EcmaScript.NET/Helpers/StackOverflowVerifierException.cs @@ -1,10 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace EcmaScript.NET.Helpers -{ - class StackOverflowVerifierException : ApplicationException - { - } -} +using System; +using System.Collections.Generic; +using System.Text; + +namespace EcmaScript.NET.Helpers +{ + class StackOverflowVerifierException : Exception + { + } +} diff --git a/Code/EcmaScript.NET/ICallable.cs b/src/EcmaScript.NET/ICallable.cs similarity index 97% rename from Code/EcmaScript.NET/ICallable.cs rename to src/EcmaScript.NET/ICallable.cs index ce66138..81ae0c8 100644 --- a/Code/EcmaScript.NET/ICallable.cs +++ b/src/EcmaScript.NET/ICallable.cs @@ -1,39 +1,39 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -namespace EcmaScript.NET -{ - - /// Generic notion of callable object that can execute some script-related code - /// upon request with specified values for script scope and this objects. - /// - public interface ICallable - { - /// Perform the call. - /// - /// - /// the current Context for this thread - /// - /// the scope to use to resolve properties. - /// - /// the JavaScript this object - /// - /// the array of arguments - /// - /// the result of the call - /// - object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args); - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +namespace EcmaScript.NET +{ + + /// Generic notion of callable object that can execute some script-related code + /// upon request with specified values for script scope and this objects. + /// + public interface ICallable + { + /// Perform the call. + /// + /// + /// the current Context for this thread + /// + /// the scope to use to resolve properties. + /// + /// the JavaScript this object + /// + /// the array of arguments + /// + /// the result of the call + /// + object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args); + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/IFunction.cs b/src/EcmaScript.NET/IFunction.cs similarity index 97% rename from Code/EcmaScript.NET/IFunction.cs rename to src/EcmaScript.NET/IFunction.cs index 6060edb..bf14607 100644 --- a/Code/EcmaScript.NET/IFunction.cs +++ b/src/EcmaScript.NET/IFunction.cs @@ -1,44 +1,44 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -namespace EcmaScript.NET -{ - - /// This is interface that all functions in JavaScript must implement. - /// The interface provides for calling functions and constructors. - /// - /// - public interface IFunction : IScriptable, ICallable - { - - /// Call the function as a constructor. - /// - /// This method is invoked by the runtime in order to satisfy a use - /// of the JavaScript new operator. This method is - /// expected to create a new object and return it. - /// - /// - /// the current Context for this thread - /// - /// an enclosing scope of the caller except - /// when the function is called from a closure. - /// - /// the array of arguments - /// - /// the allocated object - /// - IScriptable Construct (Context cx, IScriptable scope, object [] args); - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +namespace EcmaScript.NET +{ + + /// This is interface that all functions in JavaScript must implement. + /// The interface provides for calling functions and constructors. + /// + /// + public interface IFunction : IScriptable, ICallable + { + + /// Call the function as a constructor. + /// + /// This method is invoked by the runtime in order to satisfy a use + /// of the JavaScript new operator. This method is + /// expected to create a new object and return it. + /// + /// + /// the current Context for this thread + /// + /// an enclosing scope of the caller except + /// when the function is called from a closure. + /// + /// the array of arguments + /// + /// the allocated object + /// + IScriptable Construct (Context cx, IScriptable scope, object [] args); + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/IIdEnumerable.cs b/src/EcmaScript.NET/IIdEnumerable.cs similarity index 96% rename from Code/EcmaScript.NET/IIdEnumerable.cs rename to src/EcmaScript.NET/IIdEnumerable.cs index a841d2a..7261c9b 100644 --- a/Code/EcmaScript.NET/IIdEnumerable.cs +++ b/src/EcmaScript.NET/IIdEnumerable.cs @@ -1,27 +1,27 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ -using System; - -namespace EcmaScript.NET -{ - - /// - /// Summary description for IdEnumerable. - /// - internal interface IIdEnumerable - { - - IdEnumeration GetEnumeration (Context cx, bool enumValues); - - } -} +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ +using System; + +namespace EcmaScript.NET +{ + + /// + /// Summary description for IdEnumerable. + /// + internal interface IIdEnumerable + { + + IdEnumeration GetEnumeration (Context cx, bool enumValues); + + } +} diff --git a/Code/EcmaScript.NET/IIdFunctionCall.cs b/src/EcmaScript.NET/IIdFunctionCall.cs similarity index 97% rename from Code/EcmaScript.NET/IIdFunctionCall.cs rename to src/EcmaScript.NET/IIdFunctionCall.cs index ff07c09..93736f9 100644 --- a/Code/EcmaScript.NET/IIdFunctionCall.cs +++ b/src/EcmaScript.NET/IIdFunctionCall.cs @@ -1,34 +1,34 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -namespace EcmaScript.NET -{ - - /// - /// Master for id-based functions that knows their properties and how to - /// execute them. - /// - public interface IIdFunctionCall - { - - /// - /// 'thisObj' will be null if invoked as constructor, in which case - /// instance of Scriptable should be returned - /// - object ExecIdCall (IdFunctionObject f, Context cx, IScriptable scope, IScriptable thisObj, object [] args); - - } - +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +namespace EcmaScript.NET +{ + + /// + /// Master for id-based functions that knows their properties and how to + /// execute them. + /// + public interface IIdFunctionCall + { + + /// + /// 'thisObj' will be null if invoked as constructor, in which case + /// instance of Scriptable should be returned + /// + object ExecIdCall (IdFunctionObject f, Context cx, IScriptable scope, IScriptable thisObj, object [] args); + + } + } \ No newline at end of file diff --git a/Code/EcmaScript.NET/IRef.cs b/src/EcmaScript.NET/IRef.cs similarity index 96% rename from Code/EcmaScript.NET/IRef.cs rename to src/EcmaScript.NET/IRef.cs index 3729177..36f0510 100644 --- a/Code/EcmaScript.NET/IRef.cs +++ b/src/EcmaScript.NET/IRef.cs @@ -1,34 +1,34 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -namespace EcmaScript.NET -{ - - /// Generic notion of reference object that know how to query/modify the - /// target objects based on some property/index. - /// - - public interface IRef - { - bool Has (Context cx); - - object Get (Context cx); - - object Set (Context cx, object value); - - bool Delete (Context cx); - - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +namespace EcmaScript.NET +{ + + /// Generic notion of reference object that know how to query/modify the + /// target objects based on some property/index. + /// + + public interface IRef + { + bool Has (Context cx); + + object Get (Context cx); + + object Set (Context cx, object value); + + bool Delete (Context cx); + + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/IRefCallable.cs b/src/EcmaScript.NET/IRefCallable.cs similarity index 97% rename from Code/EcmaScript.NET/IRefCallable.cs rename to src/EcmaScript.NET/IRefCallable.cs index 7300ca0..2e676e1 100644 --- a/Code/EcmaScript.NET/IRefCallable.cs +++ b/src/EcmaScript.NET/IRefCallable.cs @@ -1,39 +1,39 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -namespace EcmaScript.NET -{ - - /// - /// Object that can allows assignments to the result of function calls. - /// - public interface IRefCallable : ICallable - { - /// Perform function call in reference context. - /// The args array reference should not be stored in any object that is - /// can be GC-reachable after this method returns. If this is necessary, - /// for example, to implement {@link Ref} methods, then store args.clone(), - /// not args array itself. - /// - /// - /// the current Context for this thread - /// - /// the JavaScript this object - /// - /// the array of arguments - /// - IRef RefCall (Context cx, IScriptable thisObj, object [] args); - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +namespace EcmaScript.NET +{ + + /// + /// Object that can allows assignments to the result of function calls. + /// + public interface IRefCallable : ICallable + { + /// Perform function call in reference context. + /// The args array reference should not be stored in any object that is + /// can be GC-reachable after this method returns. If this is necessary, + /// for example, to implement {@link Ref} methods, then store args.clone(), + /// not args array itself. + /// + /// + /// the current Context for this thread + /// + /// the JavaScript this object + /// + /// the array of arguments + /// + IRef RefCall (Context cx, IScriptable thisObj, object [] args); + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/IScript.cs b/src/EcmaScript.NET/IScript.cs similarity index 97% rename from Code/EcmaScript.NET/IScript.cs rename to src/EcmaScript.NET/IScript.cs index bab0195..124b23c 100644 --- a/Code/EcmaScript.NET/IScript.cs +++ b/src/EcmaScript.NET/IScript.cs @@ -1,47 +1,47 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -namespace EcmaScript.NET -{ - - /// All compiled scripts implement this interface. - ///

- /// This class encapsulates script execution relative to an - /// object scope. - ///

- public interface IScript - { - - /// Execute the script. - ///

- /// The script is executed in a particular runtime Context, which - /// must be associated with the current thread. - /// The script is executed relative to a scope--definitions and - /// uses of global top-level variables and functions will access - /// properties of the scope object. For compliant ECMA - /// programs, the scope must be an object that has been initialized - /// as a global object using Context.initStandardObjects. - ///

- /// - ///

- /// the Context associated with the current thread - /// - /// the scope to execute relative to - /// - /// the result of executing the script - /// - object Exec (Context cx, IScriptable scope); - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +namespace EcmaScript.NET +{ + + /// All compiled scripts implement this interface. + ///

+ /// This class encapsulates script execution relative to an + /// object scope. + ///

+ public interface IScript + { + + /// Execute the script. + ///

+ /// The script is executed in a particular runtime Context, which + /// must be associated with the current thread. + /// The script is executed relative to a scope--definitions and + /// uses of global top-level variables and functions will access + /// properties of the scope object. For compliant ECMA + /// programs, the scope must be an object that has been initialized + /// as a global object using Context.initStandardObjects. + ///

+ /// + ///

+ /// the Context associated with the current thread + /// + /// the scope to execute relative to + /// + /// the result of executing the script + /// + object Exec (Context cx, IScriptable scope); + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/IScriptable.cs b/src/EcmaScript.NET/IScriptable.cs similarity index 97% rename from Code/EcmaScript.NET/IScriptable.cs rename to src/EcmaScript.NET/IScriptable.cs index 5ec92d8..5523082 100644 --- a/Code/EcmaScript.NET/IScriptable.cs +++ b/src/EcmaScript.NET/IScriptable.cs @@ -1,306 +1,306 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -// API class -using System; - -namespace EcmaScript.NET -{ - - /// - /// This is interface that all objects in JavaScript must implement. - /// The interface provides for the management of properties and for - /// performing conversions. - ///

- /// Host system implementors may find it easier to extend the ScriptableObject - /// class rather than implementing Scriptable when writing host objects. - ///

- /// There are many static methods defined in ScriptableObject that perform - /// the multiple calls to the Scriptable interface needed in order to - /// manipulate properties in prototype chains. - ///

- /// - ///

- public interface IScriptable - { - - /// Get the name of the set of objects implemented by this Java class. - /// This corresponds to the [[Class]] operation in ECMA and is used - /// by Object.prototype.toString() in ECMA.

- /// See ECMA 8.6.2 and 15.2.4.2. - ///

- string ClassName - { - get; - - } - - /// Get the parent scope of the object. - /// the parent scope - /// - /// Set the parent scope of the object. - /// the parent scope to set - /// - IScriptable ParentScope - { - get; - set; - } - - /// Get a named property from the object. - /// - /// Looks property up in this object and returns the associated value - /// if found. Returns NOT_FOUND if not found. - /// Note that this method is not expected to traverse the prototype - /// chain. This is different from the ECMA [[Get]] operation. - /// - /// Depending on the property selector, the runtime will call - /// this method or the form of get that takes an - /// integer: - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///
JavaScript codeJava code
a.b a.get("b", a)
a["foo"] a.get("foo", a)
a[3] a.get(3, a)
a["3"] a.get(3, a)
a[3.0] a.get(3, a)
a["3.0"] a.get("3.0", a)
a[1.1] a.get("1.1", a)
a[-4] a.get(-4, a)
- ///

- /// The values that may be returned are limited to the following: - ///

    - ///
  • java.lang.Boolean objects
  • - ///
  • java.lang.String objects
  • - ///
  • java.lang.Number objects
  • - ///
  • EcmaScript.NET.Scriptable objects
  • - ///
  • null
  • - ///
  • The value returned by Context.getUndefinedValue()
  • - ///
  • NOT_FOUND
  • - ///
- ///
- /// the name of the property - /// - /// the object in which the lookup began - /// - /// the value of the property (may be null), or NOT_FOUND - /// - object Get (string name, IScriptable start); - - /// Get a property from the object selected by an integral index. - /// - /// Identical to get(String, Scriptable) except that - /// an integral index is used to select the property. - /// - /// - /// the numeric index for the property - /// - /// the object in which the lookup began - /// - /// the value of the property (may be null), or NOT_FOUND - /// - object Get (int index, IScriptable start); - - /// Indicates whether or not a named property is defined in an object. - /// - /// Does not traverse the prototype chain.

- /// - /// The property is specified by a String name - /// as defined for the get method.

- /// - ///

- /// the name of the property - /// - /// the object in which the lookup began - /// - /// true if and only if the named property is found in the object - /// - bool Has (string name, IScriptable start); - - /// Indicates whether or not an indexed property is defined in an object. - /// - /// Does not traverse the prototype chain.

- /// - /// The property is specified by an integral index - /// as defined for the get method.

- /// - ///

- /// the numeric index for the property - /// - /// the object in which the lookup began - /// - /// true if and only if the indexed property is found in the object - /// - bool Has (int index, IScriptable start); - - /// Sets a named property in this object. - ///

- /// The property is specified by a string name - /// as defined for get. - ///

- /// The possible values that may be passed in are as defined for - /// get. A class that implements this method may choose - /// to ignore calls to set certain properties, in which case those - /// properties are effectively read-only.

- /// For properties defined in a prototype chain, - /// use putProperty in ScriptableObject.

- /// Note that if a property a is defined in the prototype p - /// of an object o, then evaluating o.a = 23 will cause - /// set to be called on the prototype p with - /// o as the start parameter. - /// To preserve JavaScript semantics, it is the Scriptable - /// object's responsibility to modify o.

- /// This design allows properties to be defined in prototypes and implemented - /// in terms of getters and setters of Java values without consuming slots - /// in each instance.

- ///

- /// The values that may be set are limited to the following: - ///

    - ///
  • java.lang.Boolean objects
  • - ///
  • java.lang.String objects
  • - ///
  • java.lang.Number objects
  • - ///
  • EcmaScript.NET.Scriptable objects
  • - ///
  • null
  • - ///
  • The value returned by Context.getUndefinedValue()
  • - ///

- /// Arbitrary Java objects may be wrapped in a Scriptable by first calling - /// Context.toObject. This allows the property of a JavaScript - /// object to contain an arbitrary Java object as a value.

- /// Note that has will be called by the runtime first before - /// set is called to determine in which object the - /// property is defined. - /// Note that this method is not expected to traverse the prototype chain, - /// which is different from the ECMA [[Put]] operation. - ///

- /// the name of the property - /// - /// the object whose property is being set - /// - /// value to set the property to - /// - object Put (string name, IScriptable start, object value); - - /// Sets an indexed property in this object. - ///

- /// The property is specified by an integral index - /// as defined for get.

- /// - /// Identical to put(String, Scriptable, Object) except that - /// an integral index is used to select the property. - /// - ///

- /// the numeric index for the property - /// - /// the object whose property is being set - /// - /// value to set the property to - /// - object Put (int index, IScriptable start, object value); - - /// Removes a property from this object. - /// This operation corresponds to the ECMA [[Delete]] except that - /// the no result is returned. The runtime will guarantee that this - /// method is called only if the property exists. After this method - /// is called, the runtime will call Scriptable.has to see if the - /// property has been removed in order to determine the boolean - /// result of the delete operator as defined by ECMA 11.4.1. - ///

- /// A property can be made permanent by ignoring calls to remove - /// it.

- /// The property is specified by a String name - /// as defined for get. - ///

- /// To delete properties defined in a prototype chain, - /// see deleteProperty in ScriptableObject. - ///

- /// the identifier for the property - /// - void Delete (string name); - - /// Removes a property from this object. - /// - /// The property is specified by an integral index - /// as defined for get. - ///

- /// To delete properties defined in a prototype chain, - /// see deleteProperty in ScriptableObject. - /// - /// Identical to delete(String) except that - /// an integral index is used to select the property. - /// - ///

- /// the numeric index for the property - /// - void Delete (int index); - - /// Get the prototype of the object. - /// the prototype - /// - IScriptable GetPrototype (); - - /// Set the prototype of the object. - /// the prototype to set - /// - void SetPrototype (IScriptable prototype); - - /// Get an array of property ids. - /// - /// Not all property ids need be returned. Those properties - /// whose ids are not returned are considered non-enumerable. - /// - /// - /// an array of Objects. Each entry in the array is either - /// a java.lang.String or a java.lang.Number - /// - object [] GetIds (); - - /// Get the default value of the object with a given hint. - /// The hints are String.class for type String, Number.class for type - /// Number, Scriptable.class for type Object, and Boolean.class for - /// type Boolean.

- /// - /// A hint of null means "no hint". - /// - /// See ECMA 8.6.2.6. - /// - ///

- /// the type hint - /// - /// the default value - /// - object GetDefaultValue (Type hint); - - /// The instanceof operator. - /// - ///

- /// The JavaScript code "lhs instanceof rhs" causes rhs.hasInstance(lhs) to - /// be called. - /// - ///

- /// The return value is implementation dependent so that embedded host objects can - /// return an appropriate value. See the JS 1.3 language documentation for more - /// detail. - /// - ///

This operator corresponds to the proposed EMCA [[HasInstance]] operator. - /// - ///

- /// The value that appeared on the LHS of the instanceof - /// operator - /// - /// - /// an implementation dependent value - /// - bool HasInstance (IScriptable instance); - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +// API class +using System; + +namespace EcmaScript.NET +{ + + /// + /// This is interface that all objects in JavaScript must implement. + /// The interface provides for the management of properties and for + /// performing conversions. + ///

+ /// Host system implementors may find it easier to extend the ScriptableObject + /// class rather than implementing Scriptable when writing host objects. + ///

+ /// There are many static methods defined in ScriptableObject that perform + /// the multiple calls to the Scriptable interface needed in order to + /// manipulate properties in prototype chains. + ///

+ /// + ///

+ public interface IScriptable + { + + /// Get the name of the set of objects implemented by this Java class. + /// This corresponds to the [[Class]] operation in ECMA and is used + /// by Object.prototype.toString() in ECMA.

+ /// See ECMA 8.6.2 and 15.2.4.2. + ///

+ string ClassName + { + get; + + } + + /// Get the parent scope of the object. + /// the parent scope + /// + /// Set the parent scope of the object. + /// the parent scope to set + /// + IScriptable ParentScope + { + get; + set; + } + + /// Get a named property from the object. + /// + /// Looks property up in this object and returns the associated value + /// if found. Returns NOT_FOUND if not found. + /// Note that this method is not expected to traverse the prototype + /// chain. This is different from the ECMA [[Get]] operation. + /// + /// Depending on the property selector, the runtime will call + /// this method or the form of get that takes an + /// integer: + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + ///
JavaScript codeJava code
a.b a.get("b", a)
a["foo"] a.get("foo", a)
a[3] a.get(3, a)
a["3"] a.get(3, a)
a[3.0] a.get(3, a)
a["3.0"] a.get("3.0", a)
a[1.1] a.get("1.1", a)
a[-4] a.get(-4, a)
+ ///

+ /// The values that may be returned are limited to the following: + ///

    + ///
  • java.lang.Boolean objects
  • + ///
  • java.lang.String objects
  • + ///
  • java.lang.Number objects
  • + ///
  • EcmaScript.NET.Scriptable objects
  • + ///
  • null
  • + ///
  • The value returned by Context.getUndefinedValue()
  • + ///
  • NOT_FOUND
  • + ///
+ ///
+ /// the name of the property + /// + /// the object in which the lookup began + /// + /// the value of the property (may be null), or NOT_FOUND + /// + object Get (string name, IScriptable start); + + /// Get a property from the object selected by an integral index. + /// + /// Identical to get(String, Scriptable) except that + /// an integral index is used to select the property. + /// + /// + /// the numeric index for the property + /// + /// the object in which the lookup began + /// + /// the value of the property (may be null), or NOT_FOUND + /// + object Get (int index, IScriptable start); + + /// Indicates whether or not a named property is defined in an object. + /// + /// Does not traverse the prototype chain.

+ /// + /// The property is specified by a String name + /// as defined for the get method.

+ /// + ///

+ /// the name of the property + /// + /// the object in which the lookup began + /// + /// true if and only if the named property is found in the object + /// + bool Has (string name, IScriptable start); + + /// Indicates whether or not an indexed property is defined in an object. + /// + /// Does not traverse the prototype chain.

+ /// + /// The property is specified by an integral index + /// as defined for the get method.

+ /// + ///

+ /// the numeric index for the property + /// + /// the object in which the lookup began + /// + /// true if and only if the indexed property is found in the object + /// + bool Has (int index, IScriptable start); + + /// Sets a named property in this object. + ///

+ /// The property is specified by a string name + /// as defined for get. + ///

+ /// The possible values that may be passed in are as defined for + /// get. A class that implements this method may choose + /// to ignore calls to set certain properties, in which case those + /// properties are effectively read-only.

+ /// For properties defined in a prototype chain, + /// use putProperty in ScriptableObject.

+ /// Note that if a property a is defined in the prototype p + /// of an object o, then evaluating o.a = 23 will cause + /// set to be called on the prototype p with + /// o as the start parameter. + /// To preserve JavaScript semantics, it is the Scriptable + /// object's responsibility to modify o.

+ /// This design allows properties to be defined in prototypes and implemented + /// in terms of getters and setters of Java values without consuming slots + /// in each instance.

+ ///

+ /// The values that may be set are limited to the following: + ///

    + ///
  • java.lang.Boolean objects
  • + ///
  • java.lang.String objects
  • + ///
  • java.lang.Number objects
  • + ///
  • EcmaScript.NET.Scriptable objects
  • + ///
  • null
  • + ///
  • The value returned by Context.getUndefinedValue()
  • + ///

+ /// Arbitrary Java objects may be wrapped in a Scriptable by first calling + /// Context.toObject. This allows the property of a JavaScript + /// object to contain an arbitrary Java object as a value.

+ /// Note that has will be called by the runtime first before + /// set is called to determine in which object the + /// property is defined. + /// Note that this method is not expected to traverse the prototype chain, + /// which is different from the ECMA [[Put]] operation. + ///

+ /// the name of the property + /// + /// the object whose property is being set + /// + /// value to set the property to + /// + object Put (string name, IScriptable start, object value); + + /// Sets an indexed property in this object. + ///

+ /// The property is specified by an integral index + /// as defined for get.

+ /// + /// Identical to put(String, Scriptable, Object) except that + /// an integral index is used to select the property. + /// + ///

+ /// the numeric index for the property + /// + /// the object whose property is being set + /// + /// value to set the property to + /// + object Put (int index, IScriptable start, object value); + + /// Removes a property from this object. + /// This operation corresponds to the ECMA [[Delete]] except that + /// the no result is returned. The runtime will guarantee that this + /// method is called only if the property exists. After this method + /// is called, the runtime will call Scriptable.has to see if the + /// property has been removed in order to determine the boolean + /// result of the delete operator as defined by ECMA 11.4.1. + ///

+ /// A property can be made permanent by ignoring calls to remove + /// it.

+ /// The property is specified by a String name + /// as defined for get. + ///

+ /// To delete properties defined in a prototype chain, + /// see deleteProperty in ScriptableObject. + ///

+ /// the identifier for the property + /// + void Delete (string name); + + /// Removes a property from this object. + /// + /// The property is specified by an integral index + /// as defined for get. + ///

+ /// To delete properties defined in a prototype chain, + /// see deleteProperty in ScriptableObject. + /// + /// Identical to delete(String) except that + /// an integral index is used to select the property. + /// + ///

+ /// the numeric index for the property + /// + void Delete (int index); + + /// Get the prototype of the object. + /// the prototype + /// + IScriptable GetPrototype (); + + /// Set the prototype of the object. + /// the prototype to set + /// + void SetPrototype (IScriptable prototype); + + /// Get an array of property ids. + /// + /// Not all property ids need be returned. Those properties + /// whose ids are not returned are considered non-enumerable. + /// + /// + /// an array of Objects. Each entry in the array is either + /// a java.lang.String or a java.lang.Number + /// + object [] GetIds (); + + /// Get the default value of the object with a given hint. + /// The hints are String.class for type String, Number.class for type + /// Number, Scriptable.class for type Object, and Boolean.class for + /// type Boolean.

+ /// + /// A hint of null means "no hint". + /// + /// See ECMA 8.6.2.6. + /// + ///

+ /// the type hint + /// + /// the default value + /// + object GetDefaultValue (Type hint); + + /// The instanceof operator. + /// + ///

+ /// The JavaScript code "lhs instanceof rhs" causes rhs.hasInstance(lhs) to + /// be called. + /// + ///

+ /// The return value is implementation dependent so that embedded host objects can + /// return an appropriate value. See the JS 1.3 language documentation for more + /// detail. + /// + ///

This operator corresponds to the proposed EMCA [[HasInstance]] operator. + /// + ///

+ /// The value that appeared on the LHS of the instanceof + /// operator + /// + /// + /// an implementation dependent value + /// + bool HasInstance (IScriptable instance); + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/IdEnumeration.cs b/src/EcmaScript.NET/IdEnumeration.cs similarity index 96% rename from Code/EcmaScript.NET/IdEnumeration.cs rename to src/EcmaScript.NET/IdEnumeration.cs index e80f5e2..2f069a4 100644 --- a/Code/EcmaScript.NET/IdEnumeration.cs +++ b/src/EcmaScript.NET/IdEnumeration.cs @@ -1,144 +1,144 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ -using System; - -using EcmaScript.NET.Collections; - -namespace EcmaScript.NET -{ - - /// - /// This is the enumeration needed by the for..in statement. - /// - /// See ECMA 12.6.3. - /// - /// IdEnumeration maintains a ObjToIntMap to make sure a given - /// id is enumerated only once across multiple objects in a - /// prototype chain. - /// - /// ECMA delete doesn't hide properties in the prototype, - /// but js/ref does. This means that the js/ref for..in can - /// avoid maintaining a hash table and instead perform lookups - /// to see if a given property has already been enumerated. - /// - /// - public class IdEnumeration - { - - protected IdEnumeration () - { - ; - } - - public IdEnumeration (object value, Context cx, bool enumValues) - { - obj = ScriptConvert.ToObjectOrNull (cx, value); - if (obj != null) { - // null or undefined do not cause errors but rather lead to empty - // "for in" loop - this.enumValues = enumValues; - - // enumInit should read all initial ids before returning - // or "for (a.i in a)" would wrongly enumerate i in a as well - ChangeObject (); - } - } - - private IScriptable obj; - private object [] ids; - private int index; - private ObjToIntMap used; - private string currentId; - private bool enumValues; - - public virtual bool MoveNext () - { - // OPT this could be more efficient - bool result; - for (; ; ) { - if (obj == null) { - result = false; - break; - } - if (index == ids.Length) { - obj = obj.GetPrototype (); - this.ChangeObject (); - continue; - } - object id = ids [index++]; - if (used != null && used.has (id)) { - continue; - } - if (id is string) { - string strId = (string)id; - if (!obj.Has (strId, obj)) - continue; // must have been deleted - currentId = strId; - } - else { - int intId = Convert.ToInt32 (id); - if (!obj.Has (intId, obj)) - continue; // must have been deleted - currentId = Convert.ToString (intId); - } - result = true; - break; - } - return result; - } - - public virtual object Current (Context cx) - { - if (!enumValues) - return currentId; - - object result; - - string s = ScriptRuntime.ToStringIdOrIndex (cx, currentId); - if (s == null) { - int index = ScriptRuntime.lastIndexResult (cx); - result = obj.Get (index, obj); - } - else { - result = obj.Get (s, obj); - } - - return result; - } - - private void ChangeObject () - { - object [] ids = null; - while (obj != null) { - ids = obj.GetIds (); - if (ids.Length != 0) { - break; - } - obj = obj.GetPrototype (); - } - if (obj != null && this.ids != null) { - object [] previous = this.ids; - int L = previous.Length; - if (used == null) { - used = new ObjToIntMap (L); - } - for (int i = 0; i != L; ++i) { - used.intern (previous [i]); - } - } - this.ids = ids; - this.index = 0; - } - - } -} +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ +using System; + +using EcmaScript.NET.Collections; + +namespace EcmaScript.NET +{ + + /// + /// This is the enumeration needed by the for..in statement. + /// + /// See ECMA 12.6.3. + /// + /// IdEnumeration maintains a ObjToIntMap to make sure a given + /// id is enumerated only once across multiple objects in a + /// prototype chain. + /// + /// ECMA delete doesn't hide properties in the prototype, + /// but js/ref does. This means that the js/ref for..in can + /// avoid maintaining a hash table and instead perform lookups + /// to see if a given property has already been enumerated. + /// + /// + public class IdEnumeration + { + + protected IdEnumeration () + { + ; + } + + public IdEnumeration (object value, Context cx, bool enumValues) + { + obj = ScriptConvert.ToObjectOrNull (cx, value); + if (obj != null) { + // null or undefined do not cause errors but rather lead to empty + // "for in" loop + this.enumValues = enumValues; + + // enumInit should read all initial ids before returning + // or "for (a.i in a)" would wrongly enumerate i in a as well + ChangeObject (); + } + } + + private IScriptable obj; + private object [] ids; + private int index; + private ObjToIntMap used; + private string currentId; + private bool enumValues; + + public virtual bool MoveNext () + { + // OPT this could be more efficient + bool result; + for (; ; ) { + if (obj == null) { + result = false; + break; + } + if (index == ids.Length) { + obj = obj.GetPrototype (); + this.ChangeObject (); + continue; + } + object id = ids [index++]; + if (used != null && used.has (id)) { + continue; + } + if (id is string) { + string strId = (string)id; + if (!obj.Has (strId, obj)) + continue; // must have been deleted + currentId = strId; + } + else { + int intId = Convert.ToInt32 (id); + if (!obj.Has (intId, obj)) + continue; // must have been deleted + currentId = Convert.ToString (intId); + } + result = true; + break; + } + return result; + } + + public virtual object Current (Context cx) + { + if (!enumValues) + return currentId; + + object result; + + string s = ScriptRuntime.ToStringIdOrIndex (cx, currentId); + if (s == null) { + int index = ScriptRuntime.lastIndexResult (cx); + result = obj.Get (index, obj); + } + else { + result = obj.Get (s, obj); + } + + return result; + } + + private void ChangeObject () + { + object [] ids = null; + while (obj != null) { + ids = obj.GetIds (); + if (ids.Length != 0) { + break; + } + obj = obj.GetPrototype (); + } + if (obj != null && this.ids != null) { + object [] previous = this.ids; + int L = previous.Length; + if (used == null) { + used = new ObjToIntMap (L); + } + for (int i = 0; i != L; ++i) { + used.intern (previous [i]); + } + } + this.ids = ids; + this.index = 0; + } + + } +} diff --git a/Code/EcmaScript.NET/IdFunctionObject.cs b/src/EcmaScript.NET/IdFunctionObject.cs similarity index 94% rename from Code/EcmaScript.NET/IdFunctionObject.cs rename to src/EcmaScript.NET/IdFunctionObject.cs index 96def15..ba33259 100644 --- a/Code/EcmaScript.NET/IdFunctionObject.cs +++ b/src/EcmaScript.NET/IdFunctionObject.cs @@ -1,196 +1,196 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -namespace EcmaScript.NET -{ - - - public class IdFunctionObject : BaseFunction - { - - public IdFunctionObject () - { - ; - } - - override public int Arity - { - get - { - return arity; - } - - } - override public int Length - { - get - { - return Arity; - } - - } - override public string FunctionName - { - get - { - return (functionName == null) ? "" : functionName; - } - } - - public IdFunctionObject (IIdFunctionCall idcall, object tag, int id, int arity) - { - if (arity < 0) - throw new ArgumentException (); - - this.idcall = idcall; - this.tag = tag; - this.m_MethodId = id; - this.arity = arity; - if (arity < 0) - throw new ArgumentException (); - } - - public IdFunctionObject (IIdFunctionCall idcall, object tag, int id, string name, int arity, IScriptable scope) - : base (scope, null) - { - - if (arity < 0) - throw new ArgumentException (); - if (name == null) - throw new ArgumentException (); - - this.idcall = idcall; - this.tag = tag; - this.m_MethodId = id; - this.arity = arity; - this.functionName = name; - } - - public virtual void InitFunction (string name, IScriptable scope) - { - if (name == null) - throw new ArgumentException (); - if (scope == null) - throw new ArgumentException (); - this.functionName = name; - ParentScope = scope; - } - - public bool HasTag (object tag) - { - return this.tag == tag; - } - - public int MethodId - { - get - { - return m_MethodId; - } - } - - public void MarkAsConstructor (IScriptable prototypeProperty) - { - useCallAsConstructor = true; - ImmunePrototypeProperty = prototypeProperty; - } - - public void AddAsProperty (IScriptable target) - { - AddAsProperty (target, ScriptableObject.DONTENUM); - } - - public void AddAsProperty (IScriptable target, int attributes) - { - ScriptableObject.DefineProperty (target, functionName, this, attributes); - } - - public virtual void ExportAsScopeProperty () - { - AddAsProperty (ParentScope); - } - - public virtual void ExportAsScopeProperty (int attributes) - { - AddAsProperty (ParentScope, attributes); - } - - public override IScriptable GetPrototype () - { - // Lazy initialization of prototype: for native functions this - // may not be called at all - IScriptable proto = base.GetPrototype (); - if (proto == null) { - proto = GetFunctionPrototype (ParentScope); - SetPrototype (proto); - } - return proto; - } - - public override object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args) - { - return idcall.ExecIdCall (this, cx, scope, thisObj, args); - } - - public override IScriptable CreateObject (Context cx, IScriptable scope) - { - if (useCallAsConstructor) { - return null; - } - // Throw error if not explicitly coded to be used as constructor, - // to satisfy ECMAScript standard (see bugzilla 202019). - // To follow current (2003-05-01) SpiderMonkey behavior, change it to: - // return super.createObject(cx, scope); - throw ScriptRuntime.TypeErrorById ("msg.not.ctor", functionName); - } - - internal override string Decompile (int indent, int flags) - { - System.Text.StringBuilder sb = new System.Text.StringBuilder (); - bool justbody = (0 != (flags & Decompiler.ONLY_BODY_FLAG)); - if (!justbody) { - sb.Append ("function "); - sb.Append (FunctionName); - sb.Append ("() { "); - } - sb.Append ("[native code for "); - if (idcall is IScriptable) { - IScriptable sobj = (IScriptable)idcall; - sb.Append (sobj.ClassName); - sb.Append ('.'); - } - sb.Append (FunctionName); - sb.Append (", arity="); - sb.Append (Arity); - sb.Append (justbody ? "]\n" : "] }\n"); - return sb.ToString (); - } - - public ApplicationException Unknown () - { - // It is program error to call id-like methods for unknown function - return new ApplicationException ("BAD FUNCTION ID=" + m_MethodId + " MASTER=" + idcall); - } - - private IIdFunctionCall idcall; - private object tag; - private int m_MethodId; - private int arity; - private bool useCallAsConstructor; - private string functionName; - - - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +namespace EcmaScript.NET +{ + + + public class IdFunctionObject : BaseFunction + { + + public IdFunctionObject () + { + ; + } + + override public int Arity + { + get + { + return arity; + } + + } + override public int Length + { + get + { + return Arity; + } + + } + override public string FunctionName + { + get + { + return (functionName == null) ? "" : functionName; + } + } + + public IdFunctionObject (IIdFunctionCall idcall, object tag, int id, int arity) + { + if (arity < 0) + throw new ArgumentException (); + + this.idcall = idcall; + this.tag = tag; + this.m_MethodId = id; + this.arity = arity; + if (arity < 0) + throw new ArgumentException (); + } + + public IdFunctionObject (IIdFunctionCall idcall, object tag, int id, string name, int arity, IScriptable scope) + : base (scope, null) + { + + if (arity < 0) + throw new ArgumentException (); + if (name == null) + throw new ArgumentException (); + + this.idcall = idcall; + this.tag = tag; + this.m_MethodId = id; + this.arity = arity; + this.functionName = name; + } + + public virtual void InitFunction (string name, IScriptable scope) + { + if (name == null) + throw new ArgumentException (); + if (scope == null) + throw new ArgumentException (); + this.functionName = name; + ParentScope = scope; + } + + public bool HasTag (object tag) + { + return this.tag == tag; + } + + public int MethodId + { + get + { + return m_MethodId; + } + } + + public void MarkAsConstructor (IScriptable prototypeProperty) + { + useCallAsConstructor = true; + ImmunePrototypeProperty = prototypeProperty; + } + + public void AddAsProperty (IScriptable target) + { + AddAsProperty (target, ScriptableObject.DONTENUM); + } + + public void AddAsProperty (IScriptable target, int attributes) + { + ScriptableObject.DefineProperty (target, functionName, this, attributes); + } + + public virtual void ExportAsScopeProperty () + { + AddAsProperty (ParentScope); + } + + public virtual void ExportAsScopeProperty (int attributes) + { + AddAsProperty (ParentScope, attributes); + } + + public override IScriptable GetPrototype () + { + // Lazy initialization of prototype: for native functions this + // may not be called at all + IScriptable proto = base.GetPrototype (); + if (proto == null) { + proto = GetFunctionPrototype (ParentScope); + SetPrototype (proto); + } + return proto; + } + + public override object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args) + { + return idcall.ExecIdCall (this, cx, scope, thisObj, args); + } + + public override IScriptable CreateObject (Context cx, IScriptable scope) + { + if (useCallAsConstructor) { + return null; + } + // Throw error if not explicitly coded to be used as constructor, + // to satisfy ECMAScript standard (see bugzilla 202019). + // To follow current (2003-05-01) SpiderMonkey behavior, change it to: + // return super.createObject(cx, scope); + throw ScriptRuntime.TypeErrorById ("msg.not.ctor", functionName); + } + + internal override string Decompile (int indent, int flags) + { + System.Text.StringBuilder sb = new System.Text.StringBuilder (); + bool justbody = (0 != (flags & Decompiler.ONLY_BODY_FLAG)); + if (!justbody) { + sb.Append ("function "); + sb.Append (FunctionName); + sb.Append ("() { "); + } + sb.Append ("[native code for "); + if (idcall is IScriptable) { + IScriptable sobj = (IScriptable)idcall; + sb.Append (sobj.ClassName); + sb.Append ('.'); + } + sb.Append (FunctionName); + sb.Append (", arity="); + sb.Append (Arity); + sb.Append (justbody ? "]\n" : "] }\n"); + return sb.ToString (); + } + + public Exception Unknown () + { + // It is program error to call id-like methods for unknown function + return new Exception ("BAD FUNCTION ID=" + m_MethodId + " MASTER=" + idcall); + } + + private IIdFunctionCall idcall; + private object tag; + private int m_MethodId; + private int arity; + private bool useCallAsConstructor; + private string functionName; + + + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/IdScriptableObject.cs b/src/EcmaScript.NET/IdScriptableObject.cs similarity index 94% rename from Code/EcmaScript.NET/IdScriptableObject.cs rename to src/EcmaScript.NET/IdScriptableObject.cs index c4b332d..7162271 100644 --- a/Code/EcmaScript.NET/IdScriptableObject.cs +++ b/src/EcmaScript.NET/IdScriptableObject.cs @@ -1,694 +1,694 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; -using System.Runtime.InteropServices; - -namespace EcmaScript.NET -{ - - /// - /// Base class for native object implementation that uses IdFunctionObject to export its methods to script via .prototype object. - /// Any descendant should implement at least the following methods: - /// findInstanceIdInfo - /// getInstanceIdName - /// execIdCall - /// methodArity - /// To define non-function properties, the descendant should override - /// getInstanceIdValue - /// setInstanceIdValue - /// to get/set property value and provide its default attributes. - /// To customize initializition of constructor and protype objects, descendant - /// may override scopeInit or fillConstructorProperties methods. - /// - public abstract class IdScriptableObject : ScriptableObject, IIdFunctionCall - { - - /// - /// Get maximum id findInstanceIdInfo can generate. - /// - protected virtual internal int MaxInstanceId - { - get - { - return 0; - } - } - - private volatile PrototypeValues prototypeValues; - - private sealed class PrototypeValues - { - - internal int MaxId - { - get - { - return maxId; - } - - } - - private const int VALUE_SLOT = 0; - private const int NAME_SLOT = 1; - private const int SLOT_SPAN = 2; - - private IdScriptableObject obj; - private int maxId; - private volatile object [] valueArray; - private volatile short [] attributeArray; - private volatile int lastFoundId = 1; - - // The following helps to avoid creation of valueArray during runtime - // initialization for common case of "constructor" property - internal int constructorId; - private IdFunctionObject constructor; - private short constructorAttrs; - - internal PrototypeValues (IdScriptableObject obj, int maxId) - { - if (obj == null) - throw new ArgumentNullException ("obj"); - if (maxId < 1) - throw new ArgumentException ("maxId may not lower than 1"); - this.obj = obj; - this.maxId = maxId; - } - - internal void InitValue (int id, string name, object value, int attributes) - { - if (!(1 <= id && id <= maxId)) - throw new ArgumentException (); - if (name == null) - throw new ArgumentException (); - if (value == UniqueTag.NotFound) - throw new ArgumentException (); - ScriptableObject.CheckValidAttributes (attributes); - if (obj.FindPrototypeId (name) != id) - throw new ArgumentException (name); - - if (id == constructorId) { - if (!(value is IdFunctionObject)) { - throw new ArgumentException ("consructor should be initialized with IdFunctionObject"); - } - constructor = (IdFunctionObject)value; - constructorAttrs = (short)attributes; - return; - } - - InitSlot (id, name, value, attributes); - } - - private void InitSlot (int id, string name, object value, int attributes) - { - object [] array = valueArray; - if (array == null) - throw new ArgumentNullException ("array"); - - if (value == null) { - value = UniqueTag.NullValue; - } - int index = (id - 1) * SLOT_SPAN; - lock (this) { - object value2 = array [index + VALUE_SLOT]; - if (value2 == null) { - array [index + VALUE_SLOT] = value; - array [index + NAME_SLOT] = name; - attributeArray [id - 1] = (short)attributes; - } - else { - if (!name.Equals (array [index + NAME_SLOT])) - throw new ApplicationException (); - } - } - } - - internal IdFunctionObject createPrecachedConstructor () - { - if (constructorId != 0) - throw new ApplicationException (); - constructorId = obj.FindPrototypeId ("constructor"); - if (constructorId == 0) { - throw new ApplicationException ("No id for constructor property"); - } - obj.InitPrototypeId (constructorId); - if (constructor == null) { - throw new ApplicationException (obj.GetType ().FullName + ".initPrototypeId() did not " + "initialize id=" + constructorId); - } - constructor.InitFunction (obj.ClassName, ScriptableObject.GetTopLevelScope (obj)); - constructor.MarkAsConstructor (obj); - return constructor; - } - - internal int FindId (string name) - { - object [] array = valueArray; - if (array == null) { - return obj.FindPrototypeId (name); - } - int id = lastFoundId; - if ((object)name == array [(id - 1) * SLOT_SPAN + NAME_SLOT]) { - return id; - } - id = obj.FindPrototypeId (name); - if (id != 0) { - int nameSlot = (id - 1) * SLOT_SPAN + NAME_SLOT; - // Make cache to work! - array [nameSlot] = name; - lastFoundId = id; - } - return id; - } - - internal bool Has (int id) - { - object [] array = valueArray; - if (array == null) { - // Not yet initialized, assume all exists - return true; - } - int valueSlot = (id - 1) * SLOT_SPAN + VALUE_SLOT; - object value = array [valueSlot]; - if (value == null) { - // The particular entry has not been yet initialized - return true; - } - return value != UniqueTag.NotFound; - } - - internal object Get (int id) - { - object value = EnsureId (id); - if (value == UniqueTag.NullValue) { - value = null; - } - return value; - } - - internal void Set (int id, IScriptable start, object value) - { - if (value == UniqueTag.NotFound) - throw new ArgumentException (); - EnsureId (id); - int attr = attributeArray [id - 1]; - if ((attr & ScriptableObject.READONLY) == 0) { - if (start == obj) { - if (value == null) { - value = UniqueTag.NullValue; - } - int valueSlot = (id - 1) * SLOT_SPAN + VALUE_SLOT; - lock (this) { - valueArray [valueSlot] = value; - } - } - else { - int nameSlot = (id - 1) * SLOT_SPAN + NAME_SLOT; - string name = (string)valueArray [nameSlot]; - start.Put (name, start, value); - } - } - } - - internal void Delete (int id) - { - EnsureId (id); - int attr = attributeArray [id - 1]; - if ((attr & ScriptableObject.PERMANENT) == 0) { - int valueSlot = (id - 1) * SLOT_SPAN + VALUE_SLOT; - lock (this) { - valueArray [valueSlot] = UniqueTag.NotFound; - attributeArray [id - 1] = (short)(ScriptableObject.EMPTY); - } - } - } - - internal int GetAttributes (int id) - { - EnsureId (id); - return attributeArray [id - 1]; - } - - internal void SetAttributes (int id, int attributes) - { - ScriptableObject.CheckValidAttributes (attributes); - EnsureId (id); - lock (this) { - attributeArray [id - 1] = (short)attributes; - } - } - - internal object [] GetNames (bool getAll, object [] extraEntries) - { - object [] names = null; - int count = 0; - - for (int id = 1; id <= maxId; ++id) { - - object value = EnsureId (id); - if (getAll || (attributeArray [id - 1] & ScriptableObject.DONTENUM) == 0) { - if (value != UniqueTag.NotFound) { - int nameSlot = (id - 1) * SLOT_SPAN + NAME_SLOT; - string name = (string)valueArray [nameSlot]; - if (names == null) { - names = new object [maxId]; - } - names [count++] = name; - } - } - } - if (count == 0) { - return extraEntries; - } - else if (extraEntries == null || extraEntries.Length == 0) { - if (count != names.Length) { - object [] tmp = new object [count]; - Array.Copy (names, 0, tmp, 0, count); - names = tmp; - } - return names; - } - else { - int extra = extraEntries.Length; - object [] tmp = new object [extra + count]; - Array.Copy (extraEntries, 0, tmp, 0, extra); - Array.Copy (names, 0, tmp, extra, count); - return tmp; - } - } - - private object EnsureId (int id) - { - object [] array = valueArray; - if (array == null) { - lock (this) { - array = valueArray; - if (array == null) { - array = new object [maxId * SLOT_SPAN]; - valueArray = array; - attributeArray = new short [maxId]; - } - } - } - int valueSlot = (id - 1) * SLOT_SPAN + VALUE_SLOT; - object value = array [valueSlot]; - - if (value == null) { - if (id == constructorId) { - InitSlot (constructorId, "constructor", constructor, constructorAttrs); - constructor = null; // no need to refer it any longer - } - else { - obj.InitPrototypeId (id); - } - value = array [valueSlot]; - if (value == null) { - throw new ApplicationException (obj.GetType ().FullName + ".initPrototypeId(int id) " + "did not initialize id=" + id); - } - } - return value; - } - } - - public IdScriptableObject () - { - ; - } - - public IdScriptableObject (IScriptable scope, IScriptable prototype) - : base (scope, prototype) - { - ; - } - - protected internal object DefaultGet (string name) - { - return base.Get (name, this); - } - - protected internal void DefaultPut (string name, object value) - { - base.Put (name, this, value); - } - - public override bool Has (string name, IScriptable start) - { - int info = FindInstanceIdInfo (name); - if (info != 0) { - int attr = (int)((uint)info >> 16); - if ((attr & PERMANENT) != 0) { - return true; - } - int id = (info & 0xFFFF); - return UniqueTag.NotFound != GetInstanceIdValue (id); - } - if (prototypeValues != null) { - int id = prototypeValues.FindId (name); - if (id != 0) { - return prototypeValues.Has (id); - } - } - return base.Has (name, start); - } - - public override object Get (string name, IScriptable start) - { - int info = FindInstanceIdInfo (name); - if (info != 0) { - int id = (info & 0xFFFF); - return GetInstanceIdValue (id); - } - if (prototypeValues != null) { - int id = prototypeValues.FindId (name); - if (id != 0) { - return prototypeValues.Get (id); - } - } - return base.Get (name, start); - } - - public override object Put (string name, IScriptable start, object value) - { - int info = FindInstanceIdInfo (name); - if (info != 0) { - if (start == this && Sealed) { - throw Context.ReportRuntimeErrorById ("msg.modify.sealed", name); - } - int attr = (int)((uint)info >> 16); - if ((attr & READONLY) == 0) { - if (start == this) { - int id = (info & 0xFFFF); - SetInstanceIdValue (id, value); - } - else { - return start.Put (name, start, value); - } - } - return value; - } - if (prototypeValues != null) { - int id = prototypeValues.FindId (name); - if (id != 0) { - if (start == this && Sealed) { - throw Context.ReportRuntimeErrorById ("msg.modify.sealed", name); - } - prototypeValues.Set (id, start, value); - return value; - } - } - return base.Put (name, start, value); - } - - public override void Delete (string name) - { - int info = FindInstanceIdInfo (name); - if (info != 0) { - // Let the super class to throw exceptions for sealed objects - if (!Sealed) { - int attr = (int)((uint)info >> 16); - if ((attr & PERMANENT) == 0) { - int id = (info & 0xFFFF); - SetInstanceIdValue (id, UniqueTag.NotFound); - } - return; - } - } - if (prototypeValues != null) { - int id = prototypeValues.FindId (name); - if (id != 0) { - if (!Sealed) { - prototypeValues.Delete (id); - } - return; - } - } - base.Delete (name); - } - - public override int GetAttributes (string name) - { - int info = FindInstanceIdInfo (name); - if (info != 0) { - int attr = (int)((uint)info >> 16); - return attr; - } - if (prototypeValues != null) { - int id = prototypeValues.FindId (name); - if (id != 0) { - return prototypeValues.GetAttributes (id); - } - } - return base.GetAttributes (name); - } - - public override void SetAttributes (string name, int attributes) - { - ScriptableObject.CheckValidAttributes (attributes); - int info = FindInstanceIdInfo (name); - if (info != 0) { - int currentAttributes = (int)((uint)info >> 16); - if (attributes != currentAttributes) { - throw new ApplicationException ("Change of attributes for this id is not supported"); - } - return; - } - if (prototypeValues != null) { - int id = prototypeValues.FindId (name); - if (id != 0) { - prototypeValues.SetAttributes (id, attributes); - return; - } - } - base.SetAttributes (name, attributes); - } - - internal override object [] GetIds (bool getAll) - { - object [] result = base.GetIds (getAll); - - if (prototypeValues != null) { - result = prototypeValues.GetNames (getAll, result); - } - - int maxInstanceId = MaxInstanceId; - if (maxInstanceId != 0) { - object [] ids = null; - int count = 0; - - for (int id = maxInstanceId; id != 0; --id) { - string name = GetInstanceIdName (id); - int info = FindInstanceIdInfo (name); - if (info != 0) { - int attr = (int)((uint)info >> 16); - if ((attr & PERMANENT) == 0) { - if (UniqueTag.NotFound == GetInstanceIdValue (id)) { - continue; - } - } - if (getAll || (attr & DONTENUM) == 0) { - if (count == 0) { - // Need extra room for no more then [1..id] names - ids = new object [id]; - } - ids [count++] = name; - } - } - } - if (count != 0) { - if (result.Length == 0 && ids.Length == count) { - result = ids; - } - else { - object [] tmp = new object [result.Length + count]; - Array.Copy (result, 0, tmp, 0, result.Length); - Array.Copy (ids, 0, tmp, result.Length, count); - result = tmp; - } - } - } - return result; - } - - protected internal static int InstanceIdInfo (int attributes, int id) - { - return (attributes << 16) | id; - } - - /// - /// Map name to id of instance property. - /// Should return 0 if not found or the result of - /// {@link #instanceIdInfo(int, int)}. - /// - protected internal virtual int FindInstanceIdInfo (string name) - { - return 0; - } - - /// - /// Map id back to property name it defines. - /// - protected internal virtual string GetInstanceIdName (int id) - { - throw new ArgumentException (Convert.ToString (id)); - } - - /// - /// Get id value. - /// * If id value is constant, descendant can call cacheIdValue to store - /// * value in the permanent cache. - /// * Default implementation creates IdFunctionObject instance for given id - /// * and cache its value - /// - protected internal virtual object GetInstanceIdValue (int id) - { - throw new ApplicationException (Convert.ToString (id)); - } - - /// - /// Set or delete id value. If value == NOT_FOUND , the implementation - /// should make sure that the following getInstanceIdValue return NOT_FOUND. - /// - protected internal virtual void SetInstanceIdValue (int id, object value) - { - throw new ApplicationException (Convert.ToString (id)); - } - - /// 'thisObj' will be null if invoked as constructor, in which case - /// * instance of Scriptable should be returned. - /// - public virtual object ExecIdCall (IdFunctionObject f, Context cx, IScriptable scope, IScriptable thisObj, object [] args) - { - throw f.Unknown (); - } - - public IdFunctionObject ExportAsJSClass (int maxPrototypeId, IScriptable scope, bool zealed) - { - return ExportAsJSClass (maxPrototypeId, scope, zealed, ScriptableObject.DONTENUM); - } - - public IdFunctionObject ExportAsJSClass (int maxPrototypeId, IScriptable scope, bool zealed, int attributes) - { - // Set scope and prototype unless this is top level scope itself - if (scope != this && scope != null) { - ParentScope = scope; - SetPrototype (GetObjectPrototype (scope)); - } - - ActivatePrototypeMap (maxPrototypeId); - IdFunctionObject ctor = prototypeValues.createPrecachedConstructor (); - if (zealed) { - SealObject (); - } - FillConstructorProperties (ctor); - if (zealed) { - ctor.SealObject (); - } - ctor.ExportAsScopeProperty (attributes); - return ctor; - } - - public void ActivatePrototypeMap (int maxPrototypeId) - { - PrototypeValues values = new PrototypeValues (this, maxPrototypeId); - lock (this) { - if (prototypeValues != null) - throw new ApplicationException (); - prototypeValues = values; - } - } - - public void InitPrototypeMethod (object tag, int id, string name, int arity) - { - IScriptable scope = ScriptableObject.GetTopLevelScope (this); - IdFunctionObject f = NewIdFunction (tag, id, name, arity, scope); - prototypeValues.InitValue (id, name, f, DONTENUM); - } - - public void InitPrototypeConstructor (IdFunctionObject f) - { - int id = prototypeValues.constructorId; - if (id == 0) - throw new ApplicationException (); - if (f.MethodId != id) - throw new ArgumentException (); - if (Sealed) { - f.SealObject (); - } - prototypeValues.InitValue (id, "constructor", f, DONTENUM); - } - - public void InitPrototypeValue (int id, string name, object value, int attributes) - { - prototypeValues.InitValue (id, name, value, attributes); - } - - protected internal virtual void InitPrototypeId (int id) - { - throw new ApplicationException (Convert.ToString (id)); - } - - protected internal virtual int FindPrototypeId (string name) - { - throw new ApplicationException (name); - } - - protected internal virtual void FillConstructorProperties (IdFunctionObject ctor) - { - } - - protected internal virtual void AddIdFunctionProperty (IScriptable obj, object tag, int id, string name, int arity) - { - IScriptable scope = ScriptableObject.GetTopLevelScope (obj); - IdFunctionObject f = NewIdFunction (tag, id, name, arity, scope); - f.AddAsProperty (obj); - } - - /// - /// Utility method to construct type error to indicate incompatible call - /// when converting script thisObj to a particular type is not possible. - /// Possible usage would be to have a private function like realThis: - ///
-        /// private static NativeSomething realThis(Scriptable thisObj,
-        /// IdFunctionObject f)
-        /// {
-        /// if (!(thisObj instanceof NativeSomething))
-        /// throw incompatibleCallError(f);
-        /// return (NativeSomething)thisObj;
-        /// }
-        /// 
- /// Note that although such function can be implemented universally via - /// java.lang.Class.isInstance(), it would be much more slower. - ///
- /// specify if the function f does not change state of - /// object. - /// - /// Scriptable object suitable for a check by the instanceof - /// operator. - /// - /// RuntimeException if no more instanceof target can be found - protected internal static EcmaScriptError IncompatibleCallError (IdFunctionObject f) - { - throw ScriptRuntime.TypeErrorById ("msg.incompat.call", f.FunctionName); - } - - private IdFunctionObject NewIdFunction (object tag, int id, string name, int arity, IScriptable scope) - { - IdFunctionObject f = new IdFunctionObject (this, tag, id, name, arity, scope); - if (Sealed) { - f.SealObject (); - } - return f; - } - - - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; +using System.Runtime.InteropServices; + +namespace EcmaScript.NET +{ + + /// + /// Base class for native object implementation that uses IdFunctionObject to export its methods to script via .prototype object. + /// Any descendant should implement at least the following methods: + /// findInstanceIdInfo + /// getInstanceIdName + /// execIdCall + /// methodArity + /// To define non-function properties, the descendant should override + /// getInstanceIdValue + /// setInstanceIdValue + /// to get/set property value and provide its default attributes. + /// To customize initializition of constructor and protype objects, descendant + /// may override scopeInit or fillConstructorProperties methods. + /// + public abstract class IdScriptableObject : ScriptableObject, IIdFunctionCall + { + + /// + /// Get maximum id findInstanceIdInfo can generate. + /// + protected virtual internal int MaxInstanceId + { + get + { + return 0; + } + } + + private volatile PrototypeValues prototypeValues; + + private sealed class PrototypeValues + { + + internal int MaxId + { + get + { + return maxId; + } + + } + + private const int VALUE_SLOT = 0; + private const int NAME_SLOT = 1; + private const int SLOT_SPAN = 2; + + private IdScriptableObject obj; + private int maxId; + private volatile object [] valueArray; + private volatile short [] attributeArray; + private volatile int lastFoundId = 1; + + // The following helps to avoid creation of valueArray during runtime + // initialization for common case of "constructor" property + internal int constructorId; + private IdFunctionObject constructor; + private short constructorAttrs; + + internal PrototypeValues (IdScriptableObject obj, int maxId) + { + if (obj == null) + throw new ArgumentNullException ("obj"); + if (maxId < 1) + throw new ArgumentException ("maxId may not lower than 1"); + this.obj = obj; + this.maxId = maxId; + } + + internal void InitValue (int id, string name, object value, int attributes) + { + if (!(1 <= id && id <= maxId)) + throw new ArgumentException (); + if (name == null) + throw new ArgumentException (); + if (value == UniqueTag.NotFound) + throw new ArgumentException (); + ScriptableObject.CheckValidAttributes (attributes); + if (obj.FindPrototypeId (name) != id) + throw new ArgumentException (name); + + if (id == constructorId) { + if (!(value is IdFunctionObject)) { + throw new ArgumentException ("consructor should be initialized with IdFunctionObject"); + } + constructor = (IdFunctionObject)value; + constructorAttrs = (short)attributes; + return; + } + + InitSlot (id, name, value, attributes); + } + + private void InitSlot (int id, string name, object value, int attributes) + { + object [] array = valueArray; + if (array == null) + throw new ArgumentNullException ("array"); + + if (value == null) { + value = UniqueTag.NullValue; + } + int index = (id - 1) * SLOT_SPAN; + lock (this) { + object value2 = array [index + VALUE_SLOT]; + if (value2 == null) { + array [index + VALUE_SLOT] = value; + array [index + NAME_SLOT] = name; + attributeArray [id - 1] = (short)attributes; + } + else { + if (!name.Equals (array [index + NAME_SLOT])) + throw new Exception (); + } + } + } + + internal IdFunctionObject createPrecachedConstructor () + { + if (constructorId != 0) + throw new Exception (); + constructorId = obj.FindPrototypeId ("constructor"); + if (constructorId == 0) { + throw new Exception ("No id for constructor property"); + } + obj.InitPrototypeId (constructorId); + if (constructor == null) { + throw new Exception (obj.GetType ().FullName + ".initPrototypeId() did not " + "initialize id=" + constructorId); + } + constructor.InitFunction (obj.ClassName, ScriptableObject.GetTopLevelScope (obj)); + constructor.MarkAsConstructor (obj); + return constructor; + } + + internal int FindId (string name) + { + object [] array = valueArray; + if (array == null) { + return obj.FindPrototypeId (name); + } + int id = lastFoundId; + if ((object)name == array [(id - 1) * SLOT_SPAN + NAME_SLOT]) { + return id; + } + id = obj.FindPrototypeId (name); + if (id != 0) { + int nameSlot = (id - 1) * SLOT_SPAN + NAME_SLOT; + // Make cache to work! + array [nameSlot] = name; + lastFoundId = id; + } + return id; + } + + internal bool Has (int id) + { + object [] array = valueArray; + if (array == null) { + // Not yet initialized, assume all exists + return true; + } + int valueSlot = (id - 1) * SLOT_SPAN + VALUE_SLOT; + object value = array [valueSlot]; + if (value == null) { + // The particular entry has not been yet initialized + return true; + } + return value != UniqueTag.NotFound; + } + + internal object Get (int id) + { + object value = EnsureId (id); + if (value == UniqueTag.NullValue) { + value = null; + } + return value; + } + + internal void Set (int id, IScriptable start, object value) + { + if (value == UniqueTag.NotFound) + throw new ArgumentException (); + EnsureId (id); + int attr = attributeArray [id - 1]; + if ((attr & ScriptableObject.READONLY) == 0) { + if (start == obj) { + if (value == null) { + value = UniqueTag.NullValue; + } + int valueSlot = (id - 1) * SLOT_SPAN + VALUE_SLOT; + lock (this) { + valueArray [valueSlot] = value; + } + } + else { + int nameSlot = (id - 1) * SLOT_SPAN + NAME_SLOT; + string name = (string)valueArray [nameSlot]; + start.Put (name, start, value); + } + } + } + + internal void Delete (int id) + { + EnsureId (id); + int attr = attributeArray [id - 1]; + if ((attr & ScriptableObject.PERMANENT) == 0) { + int valueSlot = (id - 1) * SLOT_SPAN + VALUE_SLOT; + lock (this) { + valueArray [valueSlot] = UniqueTag.NotFound; + attributeArray [id - 1] = (short)(ScriptableObject.EMPTY); + } + } + } + + internal int GetAttributes (int id) + { + EnsureId (id); + return attributeArray [id - 1]; + } + + internal void SetAttributes (int id, int attributes) + { + ScriptableObject.CheckValidAttributes (attributes); + EnsureId (id); + lock (this) { + attributeArray [id - 1] = (short)attributes; + } + } + + internal object [] GetNames (bool getAll, object [] extraEntries) + { + object [] names = null; + int count = 0; + + for (int id = 1; id <= maxId; ++id) { + + object value = EnsureId (id); + if (getAll || (attributeArray [id - 1] & ScriptableObject.DONTENUM) == 0) { + if (value != UniqueTag.NotFound) { + int nameSlot = (id - 1) * SLOT_SPAN + NAME_SLOT; + string name = (string)valueArray [nameSlot]; + if (names == null) { + names = new object [maxId]; + } + names [count++] = name; + } + } + } + if (count == 0) { + return extraEntries; + } + else if (extraEntries == null || extraEntries.Length == 0) { + if (count != names.Length) { + object [] tmp = new object [count]; + Array.Copy (names, 0, tmp, 0, count); + names = tmp; + } + return names; + } + else { + int extra = extraEntries.Length; + object [] tmp = new object [extra + count]; + Array.Copy (extraEntries, 0, tmp, 0, extra); + Array.Copy (names, 0, tmp, extra, count); + return tmp; + } + } + + private object EnsureId (int id) + { + object [] array = valueArray; + if (array == null) { + lock (this) { + array = valueArray; + if (array == null) { + array = new object [maxId * SLOT_SPAN]; + valueArray = array; + attributeArray = new short [maxId]; + } + } + } + int valueSlot = (id - 1) * SLOT_SPAN + VALUE_SLOT; + object value = array [valueSlot]; + + if (value == null) { + if (id == constructorId) { + InitSlot (constructorId, "constructor", constructor, constructorAttrs); + constructor = null; // no need to refer it any longer + } + else { + obj.InitPrototypeId (id); + } + value = array [valueSlot]; + if (value == null) { + throw new Exception (obj.GetType ().FullName + ".initPrototypeId(int id) " + "did not initialize id=" + id); + } + } + return value; + } + } + + public IdScriptableObject () + { + ; + } + + public IdScriptableObject (IScriptable scope, IScriptable prototype) + : base (scope, prototype) + { + ; + } + + protected internal object DefaultGet (string name) + { + return base.Get (name, this); + } + + protected internal void DefaultPut (string name, object value) + { + base.Put (name, this, value); + } + + public override bool Has (string name, IScriptable start) + { + int info = FindInstanceIdInfo (name); + if (info != 0) { + int attr = (int)((uint)info >> 16); + if ((attr & PERMANENT) != 0) { + return true; + } + int id = (info & 0xFFFF); + return UniqueTag.NotFound != GetInstanceIdValue (id); + } + if (prototypeValues != null) { + int id = prototypeValues.FindId (name); + if (id != 0) { + return prototypeValues.Has (id); + } + } + return base.Has (name, start); + } + + public override object Get (string name, IScriptable start) + { + int info = FindInstanceIdInfo (name); + if (info != 0) { + int id = (info & 0xFFFF); + return GetInstanceIdValue (id); + } + if (prototypeValues != null) { + int id = prototypeValues.FindId (name); + if (id != 0) { + return prototypeValues.Get (id); + } + } + return base.Get (name, start); + } + + public override object Put (string name, IScriptable start, object value) + { + int info = FindInstanceIdInfo (name); + if (info != 0) { + if (start == this && Sealed) { + throw Context.ReportRuntimeErrorById ("msg.modify.sealed", name); + } + int attr = (int)((uint)info >> 16); + if ((attr & READONLY) == 0) { + if (start == this) { + int id = (info & 0xFFFF); + SetInstanceIdValue (id, value); + } + else { + return start.Put (name, start, value); + } + } + return value; + } + if (prototypeValues != null) { + int id = prototypeValues.FindId (name); + if (id != 0) { + if (start == this && Sealed) { + throw Context.ReportRuntimeErrorById ("msg.modify.sealed", name); + } + prototypeValues.Set (id, start, value); + return value; + } + } + return base.Put (name, start, value); + } + + public override void Delete (string name) + { + int info = FindInstanceIdInfo (name); + if (info != 0) { + // Let the super class to throw exceptions for sealed objects + if (!Sealed) { + int attr = (int)((uint)info >> 16); + if ((attr & PERMANENT) == 0) { + int id = (info & 0xFFFF); + SetInstanceIdValue (id, UniqueTag.NotFound); + } + return; + } + } + if (prototypeValues != null) { + int id = prototypeValues.FindId (name); + if (id != 0) { + if (!Sealed) { + prototypeValues.Delete (id); + } + return; + } + } + base.Delete (name); + } + + public override int GetAttributes (string name) + { + int info = FindInstanceIdInfo (name); + if (info != 0) { + int attr = (int)((uint)info >> 16); + return attr; + } + if (prototypeValues != null) { + int id = prototypeValues.FindId (name); + if (id != 0) { + return prototypeValues.GetAttributes (id); + } + } + return base.GetAttributes (name); + } + + public override void SetAttributes (string name, int attributes) + { + ScriptableObject.CheckValidAttributes (attributes); + int info = FindInstanceIdInfo (name); + if (info != 0) { + int currentAttributes = (int)((uint)info >> 16); + if (attributes != currentAttributes) { + throw new Exception ("Change of attributes for this id is not supported"); + } + return; + } + if (prototypeValues != null) { + int id = prototypeValues.FindId (name); + if (id != 0) { + prototypeValues.SetAttributes (id, attributes); + return; + } + } + base.SetAttributes (name, attributes); + } + + internal override object [] GetIds (bool getAll) + { + object [] result = base.GetIds (getAll); + + if (prototypeValues != null) { + result = prototypeValues.GetNames (getAll, result); + } + + int maxInstanceId = MaxInstanceId; + if (maxInstanceId != 0) { + object [] ids = null; + int count = 0; + + for (int id = maxInstanceId; id != 0; --id) { + string name = GetInstanceIdName (id); + int info = FindInstanceIdInfo (name); + if (info != 0) { + int attr = (int)((uint)info >> 16); + if ((attr & PERMANENT) == 0) { + if (UniqueTag.NotFound == GetInstanceIdValue (id)) { + continue; + } + } + if (getAll || (attr & DONTENUM) == 0) { + if (count == 0) { + // Need extra room for no more then [1..id] names + ids = new object [id]; + } + ids [count++] = name; + } + } + } + if (count != 0) { + if (result.Length == 0 && ids.Length == count) { + result = ids; + } + else { + object [] tmp = new object [result.Length + count]; + Array.Copy (result, 0, tmp, 0, result.Length); + Array.Copy (ids, 0, tmp, result.Length, count); + result = tmp; + } + } + } + return result; + } + + protected internal static int InstanceIdInfo (int attributes, int id) + { + return (attributes << 16) | id; + } + + /// + /// Map name to id of instance property. + /// Should return 0 if not found or the result of + /// {@link #instanceIdInfo(int, int)}. + /// + protected internal virtual int FindInstanceIdInfo (string name) + { + return 0; + } + + /// + /// Map id back to property name it defines. + /// + protected internal virtual string GetInstanceIdName (int id) + { + throw new ArgumentException (Convert.ToString (id)); + } + + /// + /// Get id value. + /// * If id value is constant, descendant can call cacheIdValue to store + /// * value in the permanent cache. + /// * Default implementation creates IdFunctionObject instance for given id + /// * and cache its value + /// + protected internal virtual object GetInstanceIdValue (int id) + { + throw new Exception (Convert.ToString (id)); + } + + /// + /// Set or delete id value. If value == NOT_FOUND , the implementation + /// should make sure that the following getInstanceIdValue return NOT_FOUND. + /// + protected internal virtual void SetInstanceIdValue (int id, object value) + { + throw new Exception (Convert.ToString (id)); + } + + /// 'thisObj' will be null if invoked as constructor, in which case + /// * instance of Scriptable should be returned. + /// + public virtual object ExecIdCall (IdFunctionObject f, Context cx, IScriptable scope, IScriptable thisObj, object [] args) + { + throw f.Unknown (); + } + + public IdFunctionObject ExportAsJSClass (int maxPrototypeId, IScriptable scope, bool zealed) + { + return ExportAsJSClass (maxPrototypeId, scope, zealed, ScriptableObject.DONTENUM); + } + + public IdFunctionObject ExportAsJSClass (int maxPrototypeId, IScriptable scope, bool zealed, int attributes) + { + // Set scope and prototype unless this is top level scope itself + if (scope != this && scope != null) { + ParentScope = scope; + SetPrototype (GetObjectPrototype (scope)); + } + + ActivatePrototypeMap (maxPrototypeId); + IdFunctionObject ctor = prototypeValues.createPrecachedConstructor (); + if (zealed) { + SealObject (); + } + FillConstructorProperties (ctor); + if (zealed) { + ctor.SealObject (); + } + ctor.ExportAsScopeProperty (attributes); + return ctor; + } + + public void ActivatePrototypeMap (int maxPrototypeId) + { + PrototypeValues values = new PrototypeValues (this, maxPrototypeId); + lock (this) { + if (prototypeValues != null) + throw new Exception (); + prototypeValues = values; + } + } + + public void InitPrototypeMethod (object tag, int id, string name, int arity) + { + IScriptable scope = ScriptableObject.GetTopLevelScope (this); + IdFunctionObject f = NewIdFunction (tag, id, name, arity, scope); + prototypeValues.InitValue (id, name, f, DONTENUM); + } + + public void InitPrototypeConstructor (IdFunctionObject f) + { + int id = prototypeValues.constructorId; + if (id == 0) + throw new Exception (); + if (f.MethodId != id) + throw new ArgumentException (); + if (Sealed) { + f.SealObject (); + } + prototypeValues.InitValue (id, "constructor", f, DONTENUM); + } + + public void InitPrototypeValue (int id, string name, object value, int attributes) + { + prototypeValues.InitValue (id, name, value, attributes); + } + + protected internal virtual void InitPrototypeId (int id) + { + throw new Exception (Convert.ToString (id)); + } + + protected internal virtual int FindPrototypeId (string name) + { + throw new Exception (name); + } + + protected internal virtual void FillConstructorProperties (IdFunctionObject ctor) + { + } + + protected internal virtual void AddIdFunctionProperty (IScriptable obj, object tag, int id, string name, int arity) + { + IScriptable scope = ScriptableObject.GetTopLevelScope (obj); + IdFunctionObject f = NewIdFunction (tag, id, name, arity, scope); + f.AddAsProperty (obj); + } + + /// + /// Utility method to construct type error to indicate incompatible call + /// when converting script thisObj to a particular type is not possible. + /// Possible usage would be to have a private function like realThis: + ///
+        /// private static NativeSomething realThis(Scriptable thisObj,
+        /// IdFunctionObject f)
+        /// {
+        /// if (!(thisObj instanceof NativeSomething))
+        /// throw incompatibleCallError(f);
+        /// return (NativeSomething)thisObj;
+        /// }
+        /// 
+ /// Note that although such function can be implemented universally via + /// java.lang.Class.isInstance(), it would be much more slower. + ///
+ /// specify if the function f does not change state of + /// object. + /// + /// Scriptable object suitable for a check by the instanceof + /// operator. + /// + /// RuntimeException if no more instanceof target can be found + protected internal static EcmaScriptError IncompatibleCallError (IdFunctionObject f) + { + throw ScriptRuntime.TypeErrorById ("msg.incompat.call", f.FunctionName); + } + + private IdFunctionObject NewIdFunction (object tag, int id, string name, int arity, IScriptable scope) + { + IdFunctionObject f = new IdFunctionObject (this, tag, id, name, arity, scope); + if (Sealed) { + f.SealObject (); + } + return f; + } + + + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/InterpretedFunction.cs b/src/EcmaScript.NET/InterpretedFunction.cs similarity index 96% rename from Code/EcmaScript.NET/InterpretedFunction.cs rename to src/EcmaScript.NET/InterpretedFunction.cs index f966257..f48c36a 100644 --- a/Code/EcmaScript.NET/InterpretedFunction.cs +++ b/src/EcmaScript.NET/InterpretedFunction.cs @@ -1,186 +1,186 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -using EcmaScript.NET.Debugging; -using EcmaScript.NET.Types; - -namespace EcmaScript.NET -{ - - - sealed class InterpretedFunction : BuiltinFunction, IScript - { - override public string FunctionName - { - get - { - return (idata.itsName == null) ? "" : idata.itsName; - } - - } - - override public string EncodedSource - { - get - { - return Interpreter.GetEncodedSource (idata); - } - - } - override public DebuggableScript DebuggableView - { - get - { - return idata; - } - - } - override protected internal Context.Versions LanguageVersion - { - get - { - return idata.languageVersion; - } - - } - override protected internal int ParamCount - { - get - { - return idata.argCount; - } - - } - override protected internal int ParamAndVarCount - { - get - { - return idata.argNames.Length; - } - - } - - internal InterpreterData idata; - internal SecurityController securityController; - internal object securityDomain; - internal IScriptable [] functionRegExps; - - private InterpretedFunction (InterpreterData idata, object staticSecurityDomain) - { - this.idata = idata; - - // Always get Context from the current thread to - // avoid security breaches via passing mangled Context instances - // with bogus SecurityController - Context cx = Context.CurrentContext; - SecurityController sc = cx.SecurityController; - object dynamicDomain; - if (sc != null) { - dynamicDomain = sc.getDynamicSecurityDomain (staticSecurityDomain); - } - else { - if (staticSecurityDomain != null) { - throw new ArgumentException (); - } - dynamicDomain = null; - } - - this.securityController = sc; - this.securityDomain = dynamicDomain; - } - - private InterpretedFunction (InterpretedFunction parent, int index) - { - this.idata = parent.idata.itsNestedFunctions [index]; - this.securityController = parent.securityController; - this.securityDomain = parent.securityDomain; - } - - /// Create script from compiled bytecode. - internal static InterpretedFunction createScript (InterpreterData idata, object staticSecurityDomain) - { - InterpretedFunction f; - f = new InterpretedFunction (idata, staticSecurityDomain); - return f; - } - - /// Create function compiled from Function(...) constructor. - internal static InterpretedFunction createFunction (Context cx, IScriptable scope, InterpreterData idata, object staticSecurityDomain) - { - InterpretedFunction f; - f = new InterpretedFunction (idata, staticSecurityDomain); - f.initInterpretedFunction (cx, scope); - return f; - } - - /// Create function embedded in script or another function. - internal static InterpretedFunction createFunction (Context cx, IScriptable scope, InterpretedFunction parent, int index) - { - InterpretedFunction f = new InterpretedFunction (parent, index); - f.initInterpretedFunction (cx, scope); - return f; - } - - internal IScriptable [] createRegExpWraps (Context cx, IScriptable scope) - { - if (idata.itsRegExpLiterals == null) - Context.CodeBug (); - - RegExpProxy rep = cx.RegExpProxy; - int N = idata.itsRegExpLiterals.Length; - IScriptable [] array = new IScriptable [N]; - for (int i = 0; i != N; ++i) { - array [i] = rep.Wrap (cx, scope, idata.itsRegExpLiterals [i]); - } - return array; - } - - private void initInterpretedFunction (Context cx, IScriptable scope) - { - initScriptFunction (cx, scope); - if (idata.itsRegExpLiterals != null) { - functionRegExps = createRegExpWraps (cx, scope); - } - } - - public override object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args) - { - if (!ScriptRuntime.hasTopCall (cx)) { - return ScriptRuntime.DoTopCall (this, cx, scope, thisObj, args); - } - return Interpreter.Interpret (this, cx, scope, thisObj, args); - } - - public object Exec (Context cx, IScriptable scope) - { - if (idata.itsFunctionType != 0) { - // Can only be applied to scripts - throw new ApplicationException (); - } - if (!ScriptRuntime.hasTopCall (cx)) { - // It will go through "call" path. but they are equivalent - return ScriptRuntime.DoTopCall (this, cx, scope, scope, ScriptRuntime.EmptyArgs); - } - return Interpreter.Interpret (this, cx, scope, scope, ScriptRuntime.EmptyArgs); - } - - protected internal override string getParamOrVarName (int index) - { - return idata.argNames [index]; - } - - - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +using EcmaScript.NET.Debugging; +using EcmaScript.NET.Types; + +namespace EcmaScript.NET +{ + + + sealed class InterpretedFunction : BuiltinFunction, IScript + { + override public string FunctionName + { + get + { + return (idata.itsName == null) ? "" : idata.itsName; + } + + } + + override public string EncodedSource + { + get + { + return Interpreter.GetEncodedSource (idata); + } + + } + override public DebuggableScript DebuggableView + { + get + { + return idata; + } + + } + override protected internal Context.Versions LanguageVersion + { + get + { + return idata.languageVersion; + } + + } + override protected internal int ParamCount + { + get + { + return idata.argCount; + } + + } + override protected internal int ParamAndVarCount + { + get + { + return idata.argNames.Length; + } + + } + + internal InterpreterData idata; + internal SecurityController securityController; + internal object securityDomain; + internal IScriptable [] functionRegExps; + + private InterpretedFunction (InterpreterData idata, object staticSecurityDomain) + { + this.idata = idata; + + // Always get Context from the current thread to + // avoid security breaches via passing mangled Context instances + // with bogus SecurityController + Context cx = Context.CurrentContext; + SecurityController sc = cx.SecurityController; + object dynamicDomain; + if (sc != null) { + dynamicDomain = sc.getDynamicSecurityDomain (staticSecurityDomain); + } + else { + if (staticSecurityDomain != null) { + throw new ArgumentException (); + } + dynamicDomain = null; + } + + this.securityController = sc; + this.securityDomain = dynamicDomain; + } + + private InterpretedFunction (InterpretedFunction parent, int index) + { + this.idata = parent.idata.itsNestedFunctions [index]; + this.securityController = parent.securityController; + this.securityDomain = parent.securityDomain; + } + + /// Create script from compiled bytecode. + internal static InterpretedFunction createScript (InterpreterData idata, object staticSecurityDomain) + { + InterpretedFunction f; + f = new InterpretedFunction (idata, staticSecurityDomain); + return f; + } + + /// Create function compiled from Function(...) constructor. + internal static InterpretedFunction createFunction (Context cx, IScriptable scope, InterpreterData idata, object staticSecurityDomain) + { + InterpretedFunction f; + f = new InterpretedFunction (idata, staticSecurityDomain); + f.initInterpretedFunction (cx, scope); + return f; + } + + /// Create function embedded in script or another function. + internal static InterpretedFunction createFunction (Context cx, IScriptable scope, InterpretedFunction parent, int index) + { + InterpretedFunction f = new InterpretedFunction (parent, index); + f.initInterpretedFunction (cx, scope); + return f; + } + + internal IScriptable [] createRegExpWraps (Context cx, IScriptable scope) + { + if (idata.itsRegExpLiterals == null) + Context.CodeBug (); + + RegExpProxy rep = cx.RegExpProxy; + int N = idata.itsRegExpLiterals.Length; + IScriptable [] array = new IScriptable [N]; + for (int i = 0; i != N; ++i) { + array [i] = rep.Wrap (cx, scope, idata.itsRegExpLiterals [i]); + } + return array; + } + + private void initInterpretedFunction (Context cx, IScriptable scope) + { + initScriptFunction (cx, scope); + if (idata.itsRegExpLiterals != null) { + functionRegExps = createRegExpWraps (cx, scope); + } + } + + public override object Call (Context cx, IScriptable scope, IScriptable thisObj, object [] args) + { + if (!ScriptRuntime.hasTopCall (cx)) { + return ScriptRuntime.DoTopCall (this, cx, scope, thisObj, args); + } + return Interpreter.Interpret (this, cx, scope, thisObj, args); + } + + public object Exec (Context cx, IScriptable scope) + { + if (idata.itsFunctionType != 0) { + // Can only be applied to scripts + throw new Exception (); + } + if (!ScriptRuntime.hasTopCall (cx)) { + // It will go through "call" path. but they are equivalent + return ScriptRuntime.DoTopCall (this, cx, scope, scope, ScriptRuntime.EmptyArgs); + } + return Interpreter.Interpret (this, cx, scope, scope, ScriptRuntime.EmptyArgs); + } + + protected internal override string getParamOrVarName (int index) + { + return idata.argNames [index]; + } + + + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/Interpreter.cs b/src/EcmaScript.NET/Interpreter.cs similarity index 97% rename from Code/EcmaScript.NET/Interpreter.cs rename to src/EcmaScript.NET/Interpreter.cs index 05cb879..ea601da 100644 --- a/Code/EcmaScript.NET/Interpreter.cs +++ b/src/EcmaScript.NET/Interpreter.cs @@ -1,4755 +1,4755 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -using EcmaScript.NET.Debugging; -using EcmaScript.NET.Collections; - -namespace EcmaScript.NET -{ - - public class Interpreter - { - - // Additional interpreter-specific codes - - const int Icode_DUP = -1; - const int Icode_DUP2 = -2; - const int Icode_SWAP = -3; - const int Icode_POP = -4; - const int Icode_POP_RESULT = -5; - const int Icode_IFEQ_POP = -6; - const int Icode_VAR_INC_DEC = -7; - const int Icode_NAME_INC_DEC = -8; - const int Icode_PROP_INC_DEC = -9; - const int Icode_ELEM_INC_DEC = -10; - const int Icode_REF_INC_DEC = -11; - const int Icode_SCOPE_LOAD = -12; - const int Icode_SCOPE_SAVE = -13; - const int Icode_TYPEOFNAME = -14; - const int Icode_NAME_AND_THIS = -15; - const int Icode_PROP_AND_THIS = -16; - const int Icode_ELEM_AND_THIS = -17; - const int Icode_VALUE_AND_THIS = -18; - const int Icode_CLOSURE_EXPR = -19; - const int Icode_CLOSURE_STMT = -20; - const int Icode_CALLSPECIAL = -21; - const int Icode_RETUNDEF = -22; - const int Icode_GOSUB = -23; - const int Icode_STARTSUB = -24; - const int Icode_RETSUB = -25; - const int Icode_LINE = -26; - const int Icode_SHORTNUMBER = -27; - const int Icode_INTNUMBER = -28; - const int Icode_LITERAL_NEW = -29; - const int Icode_LITERAL_SET = -30; - const int Icode_SPARE_ARRAYLIT = -31; - const int Icode_REG_IND_C0 = -32; - const int Icode_REG_IND_C1 = -33; - const int Icode_REG_IND_C2 = -34; - const int Icode_REG_IND_C3 = -35; - const int Icode_REG_IND_C4 = -36; - const int Icode_REG_IND_C5 = -37; - const int Icode_REG_IND1 = -38; - const int Icode_REG_IND2 = -39; - const int Icode_REG_IND4 = -40; - const int Icode_REG_STR_C0 = -41; - const int Icode_REG_STR_C1 = -42; - const int Icode_REG_STR_C2 = -43; - const int Icode_REG_STR_C3 = -44; - const int Icode_REG_STR1 = -45; - const int Icode_REG_STR2 = -46; - const int Icode_REG_STR4 = -47; - const int Icode_GETVAR1 = -48; - const int Icode_SETVAR1 = -49; - const int Icode_UNDEF = -50; - const int Icode_ZERO = -51; - const int Icode_ONE = -52; - const int Icode_ENTERDQ = -53; - const int Icode_LEAVEDQ = -54; - const int Icode_TAIL_CALL = -55; - const int Icode_LOCAL_CLEAR = -56; - const int Icode_DEBUGGER = -57; - - // Last icode - const int MIN_ICODE = -57; - - - // data for parsing - - CompilerEnvirons compilerEnv; - - bool itsInFunctionFlag; - - InterpreterData itsData; - ScriptOrFnNode scriptOrFn; - int itsICodeTop; - int itsStackDepth; - int itsLineNumber; - int itsDoubleTableTop; - ObjToIntMap itsStrings = new ObjToIntMap (20); - int itsLocalTop; - - const int MIN_LABEL_TABLE_SIZE = 32; - const int MIN_FIXUP_TABLE_SIZE = 40; - int [] itsLabelTable; - int itsLabelTableTop; - // itsFixupTable[i] = (label_index << 32) | fixup_site - long [] itsFixupTable; - int itsFixupTableTop; - ObjArray itsLiteralIds = new ObjArray (); - - int itsExceptionTableTop; - const int EXCEPTION_TRY_START_SLOT = 0; - const int EXCEPTION_TRY_END_SLOT = 1; - const int EXCEPTION_HANDLER_SLOT = 2; - const int EXCEPTION_TYPE_SLOT = 3; - const int EXCEPTION_LOCAL_SLOT = 4; - const int EXCEPTION_SCOPE_SLOT = 5; - // SLOT_SIZE: space for try start/end, handler, start, handler type, - // exception local and scope local - const int EXCEPTION_SLOT_SIZE = 6; - - // ECF_ or Expression Context Flags constants: for now only TAIL is available - const int ECF_TAIL = 1 << 0; - - - internal class CallFrame : System.ICloneable - { - - internal CallFrame parentFrame; - // amount of stack frames before this one on the interpretation stack - internal int frameIndex; - // If true indicates read-only frame that is a part of continuation - internal bool frozen; - - internal InterpretedFunction fnOrScript; - internal InterpreterData idata; - - // Stack structure - // stack[0 <= i < localShift]: arguments and local variables - // stack[localShift <= i <= emptyStackTop]: used for local temporaries - // stack[emptyStackTop < i < stack.length]: stack data - // sDbl[i]: if stack[i] is UniqueTag.DoubleMark, sDbl[i] holds the number value - - internal object [] stack; - internal double [] sDbl; - - internal CallFrame varSource; // defaults to this unless continuation frame - internal int localShift; - internal int emptyStackTop; - - internal DebugFrame debuggerFrame; - internal bool useActivation; - - internal IScriptable thisObj; - internal IScriptable [] scriptRegExps; - - // The values that change during interpretation - - internal object result; - internal double resultDbl; - internal int pc; - internal int pcPrevBranch; - internal int pcSourceLineStart; - internal IScriptable scope; - - internal int savedStackTop; - internal int savedCallOp; - - internal virtual CallFrame cloneFrozen () - { - if (!frozen) - Context.CodeBug (); - - CallFrame copy = (CallFrame)Clone (); - - // clone stack but keep varSource to point to values - // from this frame to share variables. - - // TODO: STACK - copy.stack = new object [stack.Length]; - stack.CopyTo (copy.stack, 0); - copy.sDbl = new double [sDbl.Length]; - sDbl.CopyTo (copy.sDbl, 0); - - copy.frozen = false; - return copy; - } - - virtual public object Clone () - { - return base.MemberwiseClone (); - } - } - - - sealed class ContinuationJump - { - - internal CallFrame capturedFrame; - internal CallFrame branchFrame; - internal object result; - internal double resultDbl; - - internal ContinuationJump (Continuation c, CallFrame current) - { - this.capturedFrame = (CallFrame)c.Implementation; - if (this.capturedFrame == null || current == null) { - // Continuation and current execution does not share - // any frames if there is nothing to capture or - // if there is no currently executed frames - this.branchFrame = null; - } - else { - // Search for branch frame where parent frame chains starting - // from captured and current meet. - CallFrame chain1 = this.capturedFrame; - CallFrame chain2 = current; - - // First work parents of chain1 or chain2 until the same - // frame depth. - int diff = chain1.frameIndex - chain2.frameIndex; - if (diff != 0) { - if (diff < 0) { - // swap to make sure that - // chain1.frameIndex > chain2.frameIndex and diff > 0 - chain1 = current; - chain2 = this.capturedFrame; - diff = -diff; - } - do { - chain1 = chain1.parentFrame; - } - while (--diff != 0); - if (chain1.frameIndex != chain2.frameIndex) - Context.CodeBug (); - } - - // Now walk parents in parallel until a shared frame is found - // or until the root is reached. - while (chain1 != chain2 && chain1 != null) { - chain1 = chain1.parentFrame; - chain2 = chain2.parentFrame; - } - - this.branchFrame = chain1; - if (this.branchFrame != null && !this.branchFrame.frozen) - Context.CodeBug (); - } - } - } - - static string bytecodeName (int bytecode) - { - if (!validBytecode (bytecode)) { - throw new ArgumentException (Convert.ToString (bytecode)); - } - - if (!Token.printICode) { - return Convert.ToString (bytecode); - } - - if (ValidTokenCode (bytecode)) { - return Token.name (bytecode); - } - - switch (bytecode) { - - case Icode_DUP: - return "DUP"; - - case Icode_DUP2: - return "DUP2"; - - case Icode_SWAP: - return "SWAP"; - - case Icode_POP: - return "POP"; - - case Icode_POP_RESULT: - return "POP_RESULT"; - - case Icode_IFEQ_POP: - return "IFEQ_POP"; - - case Icode_VAR_INC_DEC: - return "VAR_INC_DEC"; - - case Icode_NAME_INC_DEC: - return "NAME_INC_DEC"; - - case Icode_PROP_INC_DEC: - return "PROP_INC_DEC"; - - case Icode_ELEM_INC_DEC: - return "ELEM_INC_DEC"; - - case Icode_REF_INC_DEC: - return "REF_INC_DEC"; - - case Icode_SCOPE_LOAD: - return "SCOPE_LOAD"; - - case Icode_SCOPE_SAVE: - return "SCOPE_SAVE"; - - case Icode_TYPEOFNAME: - return "TYPEOFNAME"; - - case Icode_NAME_AND_THIS: - return "NAME_AND_THIS"; - - case Icode_PROP_AND_THIS: - return "PROP_AND_THIS"; - - case Icode_ELEM_AND_THIS: - return "ELEM_AND_THIS"; - - case Icode_VALUE_AND_THIS: - return "VALUE_AND_THIS"; - - case Icode_CLOSURE_EXPR: - return "CLOSURE_EXPR"; - - case Icode_CLOSURE_STMT: - return "CLOSURE_STMT"; - - case Icode_CALLSPECIAL: - return "CALLSPECIAL"; - - case Icode_RETUNDEF: - return "RETUNDEF"; - - case Icode_GOSUB: - return "GOSUB"; - - case Icode_STARTSUB: - return "STARTSUB"; - - case Icode_RETSUB: - return "RETSUB"; - - case Icode_LINE: - return "LINE"; - - case Icode_SHORTNUMBER: - return "SHORTNUMBER"; - - case Icode_INTNUMBER: - return "INTNUMBER"; - - case Icode_LITERAL_NEW: - return "LITERAL_NEW"; - - case Icode_LITERAL_SET: - return "LITERAL_SET"; - - case Icode_SPARE_ARRAYLIT: - return "SPARE_ARRAYLIT"; - - case Icode_REG_IND_C0: - return "REG_IND_C0"; - - case Icode_REG_IND_C1: - return "REG_IND_C1"; - - case Icode_REG_IND_C2: - return "REG_IND_C2"; - - case Icode_REG_IND_C3: - return "REG_IND_C3"; - - case Icode_REG_IND_C4: - return "REG_IND_C4"; - - case Icode_REG_IND_C5: - return "REG_IND_C5"; - - case Icode_REG_IND1: - return "LOAD_IND1"; - - case Icode_REG_IND2: - return "LOAD_IND2"; - - case Icode_REG_IND4: - return "LOAD_IND4"; - - case Icode_REG_STR_C0: - return "REG_STR_C0"; - - case Icode_REG_STR_C1: - return "REG_STR_C1"; - - case Icode_REG_STR_C2: - return "REG_STR_C2"; - - case Icode_REG_STR_C3: - return "REG_STR_C3"; - - case Icode_REG_STR1: - return "LOAD_STR1"; - - case Icode_REG_STR2: - return "LOAD_STR2"; - - case Icode_REG_STR4: - return "LOAD_STR4"; - - case Icode_GETVAR1: - return "GETVAR1"; - - case Icode_SETVAR1: - return "SETVAR1"; - - case Icode_UNDEF: - return "UNDEF"; - - case Icode_ZERO: - return "ZERO"; - - case Icode_ONE: - return "ONE"; - - case Icode_ENTERDQ: - return "ENTERDQ"; - - case Icode_LEAVEDQ: - return "LEAVEDQ"; - - case Icode_TAIL_CALL: - return "TAIL_CALL"; - - case Icode_LOCAL_CLEAR: - return "LOCAL_CLEAR"; - - case Icode_DEBUGGER: - return "DEBUGGER"; - } - - // icode without name - throw new ApplicationException (Convert.ToString (bytecode)); - } - - static bool validIcode (int icode) - { - return MIN_ICODE <= icode && icode <= -1; - } - - static bool ValidTokenCode (int token) - { - return Token.FIRST_BYTECODE_TOKEN <= token && token <= Token.LAST_BYTECODE_TOKEN; - } - - static bool validBytecode (int bytecode) - { - return validIcode (bytecode) || ValidTokenCode (bytecode); - } - - public virtual object Compile (CompilerEnvirons compilerEnv, ScriptOrFnNode tree, string encodedSource, bool returnFunction) - { - this.compilerEnv = compilerEnv; - new NodeTransformer ().transform (tree); - - if (Token.printTrees) { - System.Console.Out.WriteLine (tree.toStringTree (tree)); - } - - if (returnFunction) { - tree = tree.getFunctionNode (0); - } - - scriptOrFn = tree; - itsData = new InterpreterData (compilerEnv.LanguageVersion, scriptOrFn.SourceName, encodedSource); - itsData.topLevel = true; - - if (returnFunction) { - generateFunctionICode (); - } - else { - generateICodeFromTree (scriptOrFn); - } - - return itsData; - } - - public virtual IScript CreateScriptObject (object bytecode, object staticSecurityDomain) - { - InterpreterData idata = (InterpreterData)bytecode; - return InterpretedFunction.createScript (itsData, staticSecurityDomain); - } - - public virtual IFunction CreateFunctionObject (Context cx, IScriptable scope, object bytecode, object staticSecurityDomain) - { - InterpreterData idata = (InterpreterData)bytecode; - return InterpretedFunction.createFunction (cx, scope, itsData, staticSecurityDomain); - } - - void generateFunctionICode () - { - itsInFunctionFlag = true; - - FunctionNode theFunction = (FunctionNode)scriptOrFn; - - itsData.itsFunctionType = theFunction.FunctionType; - itsData.itsNeedsActivation = theFunction.RequiresActivation; - itsData.itsName = theFunction.FunctionName; - if (!theFunction.IgnoreDynamicScope) { - if (compilerEnv.UseDynamicScope) { - itsData.useDynamicScope = true; - } - } - - generateICodeFromTree (theFunction.LastChild); - } - - void generateICodeFromTree (Node tree) - { - generateNestedFunctions (); - - generateRegExpLiterals (); - - VisitStatement (tree); - fixLabelGotos (); - // add RETURN_RESULT only to scripts as function always ends with RETURN - if (itsData.itsFunctionType == 0) { - addToken (Token.RETURN_RESULT); - } - - if (itsData.itsICode.Length != itsICodeTop) { - // Make itsData.itsICode length exactly itsICodeTop to save memory - // and catch bugs with jumps beyound icode as early as possible - sbyte [] tmp = new sbyte [itsICodeTop]; - Array.Copy (itsData.itsICode, 0, tmp, 0, itsICodeTop); - itsData.itsICode = tmp; - } - if (itsStrings.size () == 0) { - itsData.itsStringTable = null; - } - else { - itsData.itsStringTable = new string [itsStrings.size ()]; - ObjToIntMap.Iterator iter = itsStrings.newIterator (); - for (iter.start (); !iter.done (); iter.next ()) { - string str = (string)iter.Key; - int index = iter.Value; - if (itsData.itsStringTable [index] != null) - Context.CodeBug (); - itsData.itsStringTable [index] = str; - } - } - if (itsDoubleTableTop == 0) { - itsData.itsDoubleTable = null; - } - else if (itsData.itsDoubleTable.Length != itsDoubleTableTop) { - double [] tmp = new double [itsDoubleTableTop]; - Array.Copy (itsData.itsDoubleTable, 0, tmp, 0, itsDoubleTableTop); - itsData.itsDoubleTable = tmp; - } - if (itsExceptionTableTop != 0 && itsData.itsExceptionTable.Length != itsExceptionTableTop) { - int [] tmp = new int [itsExceptionTableTop]; - Array.Copy (itsData.itsExceptionTable, 0, tmp, 0, itsExceptionTableTop); - itsData.itsExceptionTable = tmp; - } - - itsData.itsMaxVars = scriptOrFn.ParamAndVarCount; - // itsMaxFrameArray: interpret method needs this amount for its - // stack and sDbl arrays - itsData.itsMaxFrameArray = itsData.itsMaxVars + itsData.itsMaxLocals + itsData.itsMaxStack; - - itsData.argNames = scriptOrFn.ParamAndVarNames; - itsData.argCount = scriptOrFn.ParamCount; - - itsData.encodedSourceStart = scriptOrFn.EncodedSourceStart; - itsData.encodedSourceEnd = scriptOrFn.EncodedSourceEnd; - - if (itsLiteralIds.size () != 0) { - itsData.literalIds = itsLiteralIds.ToArray (); - } - - if (Token.printICode) - dumpICode (itsData); - } - - void generateNestedFunctions () - { - int functionCount = scriptOrFn.FunctionCount; - if (functionCount == 0) - return; - - InterpreterData [] array = new InterpreterData [functionCount]; - for (int i = 0; i != functionCount; i++) { - FunctionNode def = scriptOrFn.getFunctionNode (i); - Interpreter jsi = new Interpreter (); - jsi.compilerEnv = compilerEnv; - jsi.scriptOrFn = def; - jsi.itsData = new InterpreterData (itsData); - jsi.generateFunctionICode (); - array [i] = jsi.itsData; - } - itsData.itsNestedFunctions = array; - } - - void generateRegExpLiterals () - { - int N = scriptOrFn.RegexpCount; - if (N == 0) - return; - - Context cx = Context.CurrentContext; - RegExpProxy rep = cx.RegExpProxy; - object [] array = new object [N]; - for (int i = 0; i != N; i++) { - string str = scriptOrFn.getRegexpString (i); - string flags = scriptOrFn.getRegexpFlags (i); - array [i] = rep.Compile (cx, str, flags); - } - itsData.itsRegExpLiterals = array; - } - - void updateLineNumber (Node node) - { - int lineno = node.Lineno; - if (lineno != itsLineNumber && lineno >= 0) { - if (itsData.firstLinePC < 0) { - itsData.firstLinePC = lineno; - } - itsLineNumber = lineno; - addIcode (Icode_LINE); - addUint16 (lineno & 0xFFFF); - } - } - - ApplicationException badTree (Node node) - { - throw new ApplicationException (node.ToString ()); - } - - void VisitStatement (Node node) - { - int type = node.Type; - Node child = node.FirstChild; - switch (type) { - - - case Token.FUNCTION: { - int fnIndex = node.getExistingIntProp (Node.FUNCTION_PROP); - int fnType = scriptOrFn.getFunctionNode (fnIndex).FunctionType; - // Only function expressions or function expression - // statements needs closure code creating new function - // object on stack as function statements are initialized - // at script/function start - // In addition function expression can not present here - // at statement level, they must only present as expressions. - if (fnType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) { - addIndexOp (Icode_CLOSURE_STMT, fnIndex); - } - else { - if (fnType != FunctionNode.FUNCTION_STATEMENT) { - throw Context.CodeBug (); - } - } - } - break; - - - case Token.SCRIPT: - case Token.LABEL: - case Token.LOOP: - case Token.BLOCK: - case Token.EMPTY: - case Token.WITH: - updateLineNumber (node); - while (child != null) { - VisitStatement (child); - child = child.Next; - } - break; - - - case Token.ENTERWITH: - VisitExpression (child, 0); - addToken (Token.ENTERWITH); - stackChange (-1); - break; - - - case Token.LEAVEWITH: - addToken (Token.LEAVEWITH); - break; - - - case Token.LOCAL_BLOCK: { - int local = allocLocal (); - node.putIntProp (Node.LOCAL_PROP, local); - updateLineNumber (node); - while (child != null) { - VisitStatement (child); - child = child.Next; - } - addIndexOp (Icode_LOCAL_CLEAR, local); - releaseLocal (local); - } - break; - - case Token.DEBUGGER: - updateLineNumber (node); - addIcode (Icode_DEBUGGER); - break; - - case Token.SWITCH: - updateLineNumber (node); { - // See comments in IRFactory.createSwitch() for description - // of SWITCH node - Node switchNode = (Node.Jump)node; - VisitExpression (child, 0); - for (Node.Jump caseNode = (Node.Jump)child.Next; caseNode != null; caseNode = (Node.Jump)caseNode.Next) { - if (caseNode.Type != Token.CASE) - throw badTree (caseNode); - Node test = caseNode.FirstChild; - addIcode (Icode_DUP); - stackChange (1); - VisitExpression (test, 0); - addToken (Token.SHEQ); - stackChange (-1); - // If true, Icode_IFEQ_POP will jump and remove case - // value from stack - addGoto (caseNode.target, Icode_IFEQ_POP); - stackChange (-1); - } - addIcode (Icode_POP); - stackChange (-1); - } - break; - - - case Token.TARGET: - markTargetLabel (node); - break; - - - case Token.IFEQ: - case Token.IFNE: { - Node target = ((Node.Jump)node).target; - VisitExpression (child, 0); - addGoto (target, type); - stackChange (-1); - } - break; - - - case Token.GOTO: { - Node target = ((Node.Jump)node).target; - addGoto (target, type); - } - break; - - - case Token.JSR: { - Node target = ((Node.Jump)node).target; - addGoto (target, Icode_GOSUB); - } - break; - - - case Token.FINALLY: { - // Account for incomming GOTOSUB address - stackChange (1); - int finallyRegister = getLocalBlockRef (node); - addIndexOp (Icode_STARTSUB, finallyRegister); - stackChange (-1); - while (child != null) { - VisitStatement (child); - child = child.Next; - } - addIndexOp (Icode_RETSUB, finallyRegister); - } - break; - - - case Token.EXPR_VOID: - case Token.EXPR_RESULT: - updateLineNumber (node); - VisitExpression (child, 0); - addIcode ((type == Token.EXPR_VOID) ? Icode_POP : Icode_POP_RESULT); - stackChange (-1); - break; - - - case Token.TRY: { - Node.Jump tryNode = (Node.Jump)node; - int exceptionObjectLocal = getLocalBlockRef (tryNode); - int scopeLocal = allocLocal (); - - addIndexOp (Icode_SCOPE_SAVE, scopeLocal); - - int tryStart = itsICodeTop; - while (child != null) { - VisitStatement (child); - child = child.Next; - } - - Node catchTarget = tryNode.target; - if (catchTarget != null) { - int catchStartPC = itsLabelTable [getTargetLabel (catchTarget)]; - addExceptionHandler (tryStart, catchStartPC, catchStartPC, false, exceptionObjectLocal, scopeLocal); - } - Node finallyTarget = tryNode.Finally; - if (finallyTarget != null) { - int finallyStartPC = itsLabelTable [getTargetLabel (finallyTarget)]; - addExceptionHandler (tryStart, finallyStartPC, finallyStartPC, true, exceptionObjectLocal, scopeLocal); - } - - addIndexOp (Icode_LOCAL_CLEAR, scopeLocal); - releaseLocal (scopeLocal); - } - break; - - - case Token.CATCH_SCOPE: { - int localIndex = getLocalBlockRef (node); - int scopeIndex = node.getExistingIntProp (Node.CATCH_SCOPE_PROP); - string name = child.String; - child = child.Next; - VisitExpression (child, 0); // load expression object - addStringPrefix (name); - addIndexPrefix (localIndex); - addToken (Token.CATCH_SCOPE); - addUint8 (scopeIndex != 0 ? 1 : 0); - stackChange (-1); - } - break; - - - case Token.THROW: - updateLineNumber (node); - VisitExpression (child, 0); - addToken (Token.THROW); - addUint16 (itsLineNumber & 0xFFFF); - stackChange (-1); - break; - - - case Token.RETHROW: - updateLineNumber (node); - addIndexOp (Token.RETHROW, getLocalBlockRef (node)); - break; - - - case Token.RETURN: - updateLineNumber (node); - if (child != null) { - VisitExpression (child, ECF_TAIL); - addToken (Token.RETURN); - stackChange (-1); - } - else { - addIcode (Icode_RETUNDEF); - } - break; - - - case Token.RETURN_RESULT: - updateLineNumber (node); - addToken (Token.RETURN_RESULT); - break; - - - case Token.ENUM_INIT_KEYS: - case Token.ENUM_INIT_VALUES: - VisitExpression (child, 0); - addIndexOp (type, getLocalBlockRef (node)); - stackChange (-1); - break; - - - default: - throw badTree (node); - - } - - if (itsStackDepth != 0) { - throw Context.CodeBug (); - } - } - - bool VisitExpressionOptimized (Node node, int contextFlags) - { - return false; -#if FALKSE - if (node.Type == Token.ADD) { - Node next = node.Next; - if (next == null) - return false; - switch (next.Type) { - case Token.NAME: - case Token.STRING: - return true; - } - } - return false; -#endif - } - - void VisitExpression (Node node, int contextFlags) - { - if (VisitExpressionOptimized (node, contextFlags)) - return; - - int type = node.Type; - Node child = node.FirstChild; - int savedStackDepth = itsStackDepth; - switch (type) { - - - case Token.FUNCTION: { - int fnIndex = node.getExistingIntProp (Node.FUNCTION_PROP); - FunctionNode fn = scriptOrFn.getFunctionNode (fnIndex); - - // See comments in visitStatement for Token.FUNCTION case - switch (fn.FunctionType) { - case FunctionNode.FUNCTION_EXPRESSION: - addIndexOp (Icode_CLOSURE_EXPR, fnIndex); - break; - default: - throw Context.CodeBug (); - } - - stackChange (1); - } - break; - - - case Token.LOCAL_LOAD: { - int localIndex = getLocalBlockRef (node); - addIndexOp (Token.LOCAL_LOAD, localIndex); - stackChange (1); - } - break; - - - case Token.COMMA: { - Node lastChild = node.LastChild; - while (child != lastChild) { - VisitExpression (child, 0); - addIcode (Icode_POP); - stackChange (-1); - child = child.Next; - } - // Preserve tail context flag if any - VisitExpression (child, contextFlags & ECF_TAIL); - } - break; - - - case Token.USE_STACK: - // Indicates that stack was modified externally, - // like placed catch object - stackChange (1); - break; - - - case Token.REF_CALL: - case Token.CALL: - case Token.NEW: { - if (type == Token.NEW) { - VisitExpression (child, 0); - } - else { - generateCallFunAndThis (child); - } - int argCount = 0; - while ((child = child.Next) != null) { - VisitExpression (child, 0); - ++argCount; - } - int callType = node.getIntProp (Node.SPECIALCALL_PROP, Node.NON_SPECIALCALL); - if (callType != Node.NON_SPECIALCALL) { - // embed line number and source filename - addIndexOp (Icode_CALLSPECIAL, argCount); - addUint8 (callType); - addUint8 (type == Token.NEW ? 1 : 0); - addUint16 (itsLineNumber & 0xFFFF); - } - else { - if (type == Token.CALL) { - if ((contextFlags & ECF_TAIL) != 0) { - type = Icode_TAIL_CALL; - } - } - addIndexOp (type, argCount); - } - // adjust stack - if (type == Token.NEW) { - // new: f, args -> result - stackChange (-argCount); - } - else { - // call: f, thisObj, args -> result - // ref_call: f, thisObj, args -> ref - stackChange (-1 - argCount); - } - if (argCount > itsData.itsMaxCalleeArgs) { - itsData.itsMaxCalleeArgs = argCount; - } - } - break; - - - case Token.AND: - case Token.OR: { - VisitExpression (child, 0); - addIcode (Icode_DUP); - stackChange (1); - int afterSecondJumpStart = itsICodeTop; - int jump = (type == Token.AND) ? Token.IFNE : Token.IFEQ; - addGotoOp (jump); - stackChange (-1); - addIcode (Icode_POP); - stackChange (-1); - child = child.Next; - // Preserve tail context flag if any - VisitExpression (child, contextFlags & ECF_TAIL); - resolveForwardGoto (afterSecondJumpStart); - } - break; - - - case Token.HOOK: { - Node ifThen = child.Next; - Node ifElse = ifThen.Next; - VisitExpression (child, 0); - int elseJumpStart = itsICodeTop; - addGotoOp (Token.IFNE); - ; - stackChange (-1); - // Preserve tail context flag if any - VisitExpression (ifThen, contextFlags & ECF_TAIL); - int afterElseJumpStart = itsICodeTop; - addGotoOp (Token.GOTO); - resolveForwardGoto (elseJumpStart); - itsStackDepth = savedStackDepth; - // Preserve tail context flag if any - VisitExpression (ifElse, contextFlags & ECF_TAIL); - resolveForwardGoto (afterElseJumpStart); - } - break; - - - case Token.GETPROP: - VisitExpression (child, 0); - child = child.Next; - addStringOp (Token.GETPROP, child.String); - break; - - - case Token.ADD: - case Token.GETELEM: - case Token.DELPROP: - case Token.BITAND: - case Token.BITOR: - case Token.BITXOR: - case Token.LSH: - case Token.RSH: - case Token.URSH: - case Token.SUB: - case Token.MOD: - case Token.DIV: - case Token.MUL: - case Token.EQ: - case Token.NE: - case Token.SHEQ: - case Token.SHNE: - case Token.IN: - case Token.INSTANCEOF: - case Token.LE: - case Token.LT: - case Token.GE: - case Token.GT: - VisitExpression (child, 0); - VisitExpression (child.Next, 0); - addToken (type); - stackChange (-1); - break; - - - case Token.POS: - case Token.NEG: - case Token.NOT: - case Token.BITNOT: - case Token.TYPEOF: - case Token.VOID: - VisitExpression (child, 0); - if (type == Token.VOID) { - addIcode (Icode_POP); - addIcode (Icode_UNDEF); - } - else { - addToken (type); - } - break; - - - case Token.GET_REF: - case Token.DEL_REF: - VisitExpression (child, 0); - addToken (type); - break; - - - case Token.SETPROP: - case Token.SETPROP_OP: - case Token.SETPROP_GETTER: - case Token.SETPROP_SETTER: - { - VisitExpression (child, 0); - child = child.Next; - string property = child.String; - child = child.Next; - if (type == Token.SETPROP_OP) { - addIcode (Icode_DUP); - stackChange (1); - addStringOp (Token.GETPROP, property); - // Compensate for the following USE_STACK - stackChange (-1); - } - VisitExpression (child, 0); - addStringOp ((type == Token.SETPROP_OP) ? Token.SETPROP : type, property); - stackChange (-1); - } - break; - - - case Token.SETELEM: - case Token.SETELEM_OP: - VisitExpression (child, 0); - child = child.Next; - VisitExpression (child, 0); - child = child.Next; - if (type == Token.SETELEM_OP) { - addIcode (Icode_DUP2); - stackChange (2); - addToken (Token.GETELEM); - stackChange (-1); - // Compensate for the following USE_STACK - stackChange (-1); - } - VisitExpression (child, 0); - addToken (Token.SETELEM); - stackChange (-2); - break; - - - case Token.SET_REF: - case Token.SET_REF_OP: - VisitExpression (child, 0); - child = child.Next; - if (type == Token.SET_REF_OP) { - addIcode (Icode_DUP); - stackChange (1); - addToken (Token.GET_REF); - // Compensate for the following USE_STACK - stackChange (-1); - } - VisitExpression (child, 0); - addToken (Token.SET_REF); - stackChange (-1); - break; - - - case Token.SETNAME: { - string name = child.String; - VisitExpression (child, 0); - child = child.Next; - VisitExpression (child, 0); - addStringOp (Token.SETNAME, name); - stackChange (-1); - } - break; - - - case Token.TYPEOFNAME: { - string name = node.String; - int index = -1; - // use typeofname if an activation frame exists - // since the vars all exist there instead of in jregs - if (itsInFunctionFlag && !itsData.itsNeedsActivation) - index = scriptOrFn.getParamOrVarIndex (name); - if (index == -1) { - addStringOp (Icode_TYPEOFNAME, name); - stackChange (1); - } - else { - addVarOp (Token.GETVAR, index); - stackChange (1); - addToken (Token.TYPEOF); - } - } - break; - - - case Token.BINDNAME: - case Token.NAME: - case Token.STRING: - addStringOp (type, node.String); - stackChange (1); - break; - - - case Token.INC: - case Token.DEC: - VisitIncDec (node, child); - break; - - - case Token.NUMBER: { - double num = node.Double; - int inum = (int)num; - if (inum == num) { - if (inum == 0) { - addIcode (Icode_ZERO); - // Check for negative zero - if (1.0 / num < 0.0) { - addToken (Token.NEG); - } - } - else if (inum == 1) { - addIcode (Icode_ONE); - } - else if ((short)inum == inum) { - addIcode (Icode_SHORTNUMBER); - // write short as uin16 bit pattern - addUint16 (inum & 0xFFFF); - } - else { - addIcode (Icode_INTNUMBER); - addInt (inum); - } - } - else { - int index = GetDoubleIndex (num); - addIndexOp (Token.NUMBER, index); - } - stackChange (1); - } - break; - - - case Token.GETVAR: { - if (itsData.itsNeedsActivation) - Context.CodeBug (); - string name = node.String; - int index = scriptOrFn.getParamOrVarIndex (name); - addVarOp (Token.GETVAR, index); - stackChange (1); - } - break; - - - case Token.SETVAR: { - if (itsData.itsNeedsActivation) - Context.CodeBug (); - string name = child.String; - child = child.Next; - VisitExpression (child, 0); - int index = scriptOrFn.getParamOrVarIndex (name); - addVarOp (Token.SETVAR, index); - } - break; - - - - case Token.NULL: - case Token.THIS: - case Token.THISFN: - case Token.FALSE: - case Token.TRUE: - addToken (type); - stackChange (1); - break; - - - case Token.ENUM_NEXT: - case Token.ENUM_ID: - addIndexOp (type, getLocalBlockRef (node)); - stackChange (1); - break; - - - case Token.REGEXP: { - int index = node.getExistingIntProp (Node.REGEXP_PROP); - addIndexOp (Token.REGEXP, index); - stackChange (1); - } - break; - - - case Token.ARRAYLIT: - case Token.OBJECTLIT: - VisitLiteral (node, child); - break; - - - case Token.REF_SPECIAL: - VisitExpression (child, 0); - addStringOp (type, (string)node.getProp (Node.NAME_PROP)); - break; - - - case Token.REF_MEMBER: - case Token.REF_NS_MEMBER: - case Token.REF_NAME: - case Token.REF_NS_NAME: { - int memberTypeFlags = node.getIntProp (Node.MEMBER_TYPE_PROP, 0); - // generate possible target, possible namespace and member - int childCount = 0; - do { - VisitExpression (child, 0); - ++childCount; - child = child.Next; - } - while (child != null); - addIndexOp (type, memberTypeFlags); - stackChange (1 - childCount); - } - break; - - - case Token.DOTQUERY: { - int queryPC; - updateLineNumber (node); - VisitExpression (child, 0); - addIcode (Icode_ENTERDQ); - stackChange (-1); - queryPC = itsICodeTop; - VisitExpression (child.Next, 0); - addBackwardGoto (Icode_LEAVEDQ, queryPC); - } - break; - - - case Token.DEFAULTNAMESPACE: - case Token.ESCXMLATTR: - case Token.ESCXMLTEXT: - VisitExpression (child, 0); - addToken (type); - break; - - default: - throw badTree (node); - - } - //if (savedStackDepth + 1 != itsStackDepth) { - // EcmaScriptHelper.CodeBug(); - //} - } - - void generateCallFunAndThis (Node left) - { - // Generate code to place on stack function and thisObj - int type = left.Type; - switch (type) { - - case Token.NAME: { - string name = left.String; - // stack: ... -> ... function thisObj - addStringOp (Icode_NAME_AND_THIS, name); - stackChange (2); - break; - } - - case Token.GETPROP: - case Token.GETELEM: { - Node target = left.FirstChild; - VisitExpression (target, 0); - Node id = target.Next; - if (type == Token.GETPROP) { - string property = id.String; - // stack: ... target -> ... function thisObj - addStringOp (Icode_PROP_AND_THIS, property); - stackChange (1); - } - else { - VisitExpression (id, 0); - // stack: ... target id -> ... function thisObj - addIcode (Icode_ELEM_AND_THIS); - } - break; - } - - default: - // Including Token.GETVAR - VisitExpression (left, 0); - // stack: ... value -> ... function thisObj - addIcode (Icode_VALUE_AND_THIS); - stackChange (1); - break; - - } - } - - void VisitIncDec (Node node, Node child) - { - int incrDecrMask = node.getExistingIntProp (Node.INCRDECR_PROP); - int childType = child.Type; - switch (childType) { - - case Token.GETVAR: { - if (itsData.itsNeedsActivation) - Context.CodeBug (); - string name = child.String; - int i = scriptOrFn.getParamOrVarIndex (name); - addVarOp (Icode_VAR_INC_DEC, i); - addUint8 (incrDecrMask); - stackChange (1); - break; - } - - case Token.NAME: { - string name = child.String; - addStringOp (Icode_NAME_INC_DEC, name); - addUint8 (incrDecrMask); - stackChange (1); - break; - } - - case Token.GETPROP: { - Node obj = child.FirstChild; - VisitExpression (obj, 0); - string property = obj.Next.String; - addStringOp (Icode_PROP_INC_DEC, property); - addUint8 (incrDecrMask); - break; - } - - case Token.GETELEM: { - Node obj = child.FirstChild; - VisitExpression (obj, 0); - Node index = obj.Next; - VisitExpression (index, 0); - addIcode (Icode_ELEM_INC_DEC); - addUint8 (incrDecrMask); - stackChange (-1); - break; - } - - case Token.GET_REF: { - Node rf = child.FirstChild; - VisitExpression (rf, 0); - addIcode (Icode_REF_INC_DEC); - addUint8 (incrDecrMask); - break; - } - - default: { - throw badTree (node); - } - - } - } - - void VisitLiteral (Node node, Node child) - { - int type = node.Type; - int count; - object [] propertyIds = null; - if (type == Token.ARRAYLIT) { - count = 0; - for (Node n = child; n != null; n = n.Next) { - ++count; - } - } - else if (type == Token.OBJECTLIT) { - propertyIds = (object [])node.getProp (Node.OBJECT_IDS_PROP); - count = propertyIds.Length; - } - else { - throw badTree (node); - } - addIndexOp (Icode_LITERAL_NEW, count); - stackChange (1); - while (child != null) { - VisitExpression (child, 0); - addIcode (Icode_LITERAL_SET); - stackChange (-1); - child = child.Next; - } - if (type == Token.ARRAYLIT) { - int [] skipIndexes = (int [])node.getProp (Node.SKIP_INDEXES_PROP); - if (skipIndexes == null) { - addToken (Token.ARRAYLIT); - } - else { - int index = itsLiteralIds.size (); - itsLiteralIds.add (skipIndexes); - addIndexOp (Icode_SPARE_ARRAYLIT, index); - } - } - else { - int index = itsLiteralIds.size (); - itsLiteralIds.add (propertyIds); - addIndexOp (Token.OBJECTLIT, index); - } - } - - int getLocalBlockRef (Node node) - { - Node localBlock = (Node)node.getProp (Node.LOCAL_BLOCK_PROP); - return localBlock.getExistingIntProp (Node.LOCAL_PROP); - } - - int getTargetLabel (Node target) - { - int label = target.labelId (); - if (label != -1) { - return label; - } - label = itsLabelTableTop; - if (itsLabelTable == null || label == itsLabelTable.Length) { - if (itsLabelTable == null) { - itsLabelTable = new int [MIN_LABEL_TABLE_SIZE]; - } - else { - int [] tmp = new int [itsLabelTable.Length * 2]; - Array.Copy (itsLabelTable, 0, tmp, 0, label); - itsLabelTable = tmp; - } - } - itsLabelTableTop = label + 1; - itsLabelTable [label] = -1; - - target.labelId (label); - return label; - } - - void markTargetLabel (Node target) - { - int label = getTargetLabel (target); - if (itsLabelTable [label] != -1) { - // Can mark label only once - Context.CodeBug (); - } - itsLabelTable [label] = itsICodeTop; - } - - void addGoto (Node target, int gotoOp) - { - int label = getTargetLabel (target); - if (!(label < itsLabelTableTop)) - Context.CodeBug (); - int targetPC = itsLabelTable [label]; - - if (targetPC != -1) { - addBackwardGoto (gotoOp, targetPC); - } - else { - int gotoPC = itsICodeTop; - addGotoOp (gotoOp); - int top = itsFixupTableTop; - if (itsFixupTable == null || top == itsFixupTable.Length) { - if (itsFixupTable == null) { - itsFixupTable = new long [MIN_FIXUP_TABLE_SIZE]; - } - else { - long [] tmp = new long [itsFixupTable.Length * 2]; - Array.Copy (itsFixupTable, 0, tmp, 0, top); - itsFixupTable = tmp; - } - } - itsFixupTableTop = top + 1; - itsFixupTable [top] = ((long)label << 32) | (uint)gotoPC; - } - } - - void fixLabelGotos () - { - for (int i = 0; i < itsFixupTableTop; i++) { - long fixup = itsFixupTable [i]; - int label = (int)(fixup >> 32); - int jumpSource = (int)fixup; - int pc = itsLabelTable [label]; - if (pc == -1) { - // Unlocated label - throw Context.CodeBug (); - } - resolveGoto (jumpSource, pc); - } - itsFixupTableTop = 0; - } - - void addBackwardGoto (int gotoOp, int jumpPC) - { - int fromPC = itsICodeTop; - // Ensure that this is a jump backward - if (fromPC <= jumpPC) - throw Context.CodeBug (); - addGotoOp (gotoOp); - resolveGoto (fromPC, jumpPC); - } - - - void resolveForwardGoto (int fromPC) - { - // Ensure that forward jump skips at least self bytecode - if (itsICodeTop < fromPC + 3) - throw Context.CodeBug (); - resolveGoto (fromPC, itsICodeTop); - } - - void resolveGoto (int fromPC, int jumpPC) - { - int offset = jumpPC - fromPC; - // Ensure that jumps do not overlap - if (0 <= offset && offset <= 2) - throw Context.CodeBug (); - int offsetSite = fromPC + 1; - if (offset != (short)offset) { - if (itsData.longJumps == null) { - itsData.longJumps = new UintMap (); - } - itsData.longJumps.put (offsetSite, jumpPC); - offset = 0; - } - sbyte [] array = itsData.itsICode; - array [offsetSite] = (sbyte)(offset >> 8); - array [offsetSite + 1] = (sbyte)offset; - } - - void addToken (int token) - { - if (!ValidTokenCode (token)) - throw Context.CodeBug (); - addUint8 (token); - } - - void addIcode (int icode) - { - if (!validIcode (icode)) - throw Context.CodeBug (); - // Write negative icode as uint8 bits - addUint8 (icode & 0xFF); - } - - void addUint8 (int value) - { - if ((value & ~0xFF) != 0) - throw Context.CodeBug (); - sbyte [] array = itsData.itsICode; - int top = itsICodeTop; - if (top == array.Length) { - array = increaseICodeCapasity (1); - } - array [top] = (sbyte)value; - itsICodeTop = top + 1; - } - - void addUint16 (int value) - { - if ((value & ~0xFFFF) != 0) - throw Context.CodeBug (); - sbyte [] array = itsData.itsICode; - int top = itsICodeTop; - if (top + 2 > array.Length) { - array = increaseICodeCapasity (2); - } - array [top] = (sbyte)((uint)value >> 8); - array [top + 1] = (sbyte)value; - itsICodeTop = top + 2; - } - - void addInt (int i) - { - sbyte [] array = itsData.itsICode; - int top = itsICodeTop; - if (top + 4 > array.Length) { - array = increaseICodeCapasity (4); - } - array [top] = (sbyte)((uint)i >> 24); - array [top + 1] = (sbyte)((uint)i >> 16); - array [top + 2] = (sbyte)((uint)i >> 8); - array [top + 3] = (sbyte)i; - itsICodeTop = top + 4; - } - - int GetDoubleIndex (double num) - { - int index = itsDoubleTableTop; - if (index == 0) { - itsData.itsDoubleTable = new double [64]; - } - else if (itsData.itsDoubleTable.Length == index) { - double [] na = new double [index * 2]; - Array.Copy (itsData.itsDoubleTable, 0, na, 0, index); - itsData.itsDoubleTable = na; - } - itsData.itsDoubleTable [index] = num; - itsDoubleTableTop = index + 1; - return index; - } - - void addVarOp (int op, int varIndex) - { - switch (op) { - - case Token.GETVAR: - case Token.SETVAR: - if (varIndex < 128) { - addIcode (op == Token.GETVAR ? Icode_GETVAR1 : Icode_SETVAR1); - addUint8 (varIndex); - return; - } - // fallthrough - goto case Icode_VAR_INC_DEC; - - case Icode_VAR_INC_DEC: - addIndexOp (op, varIndex); - return; - } - throw Context.CodeBug (); - } - - void addStringOp (int op, string str) - { - addStringPrefix (str); - if (validIcode (op)) { - addIcode (op); - } - else { - addToken (op); - } - } - - void addIndexOp (int op, int index) - { - addIndexPrefix (index); - if (validIcode (op)) { - addIcode (op); - } - else { - addToken (op); - } - } - - void addStringPrefix (string str) - { - int index = itsStrings.Get (str, -1); - if (index == -1) { - index = itsStrings.size (); - itsStrings.put (str, index); - } - if (index < 4) { - addIcode (Icode_REG_STR_C0 - index); - } - else if (index <= 0xFF) { - addIcode (Icode_REG_STR1); - addUint8 (index); - } - else if (index <= 0xFFFF) { - addIcode (Icode_REG_STR2); - addUint16 (index); - } - else { - addIcode (Icode_REG_STR4); - addInt (index); - } - } - - void addIndexPrefix (int index) - { - if (index < 0) - Context.CodeBug (); - if (index < 6) { - addIcode (Icode_REG_IND_C0 - index); - } - else if (index <= 0xFF) { - addIcode (Icode_REG_IND1); - addUint8 (index); - } - else if (index <= 0xFFFF) { - addIcode (Icode_REG_IND2); - addUint16 (index); - } - else { - addIcode (Icode_REG_IND4); - addInt (index); - } - } - - void addExceptionHandler (int icodeStart, int icodeEnd, int handlerStart, bool isFinally, int exceptionObjectLocal, int scopeLocal) - { - int top = itsExceptionTableTop; - int [] table = itsData.itsExceptionTable; - if (table == null) { - if (top != 0) - Context.CodeBug (); - table = new int [EXCEPTION_SLOT_SIZE * 2]; - itsData.itsExceptionTable = table; - } - else if (table.Length == top) { - table = new int [table.Length * 2]; - Array.Copy (itsData.itsExceptionTable, 0, table, 0, top); - itsData.itsExceptionTable = table; - } - table [top + EXCEPTION_TRY_START_SLOT] = icodeStart; - table [top + EXCEPTION_TRY_END_SLOT] = icodeEnd; - table [top + EXCEPTION_HANDLER_SLOT] = handlerStart; - table [top + EXCEPTION_TYPE_SLOT] = isFinally ? 1 : 0; - table [top + EXCEPTION_LOCAL_SLOT] = exceptionObjectLocal; - table [top + EXCEPTION_SCOPE_SLOT] = scopeLocal; - - itsExceptionTableTop = top + EXCEPTION_SLOT_SIZE; - } - - sbyte [] increaseICodeCapasity (int extraSize) - { - int capacity = itsData.itsICode.Length; - int top = itsICodeTop; - if (top + extraSize <= capacity) - throw Context.CodeBug (); - capacity *= 2; - if (top + extraSize > capacity) { - capacity = top + extraSize; - } - sbyte [] array = new sbyte [capacity]; - Array.Copy (itsData.itsICode, 0, array, 0, top); - itsData.itsICode = array; - return array; - } - - void stackChange (int change) - { - if (change <= 0) { - itsStackDepth += change; - } - else { - int newDepth = itsStackDepth + change; - if (newDepth > itsData.itsMaxStack) { - itsData.itsMaxStack = newDepth; - } - itsStackDepth = newDepth; - } - } - - int allocLocal () - { - int localSlot = itsLocalTop; - ++itsLocalTop; - if (itsLocalTop > itsData.itsMaxLocals) { - itsData.itsMaxLocals = itsLocalTop; - } - return localSlot; - } - - void releaseLocal (int localSlot) - { - --itsLocalTop; - if (localSlot != itsLocalTop) - Context.CodeBug (); - } - - static int GetShort (sbyte [] iCode, int pc) - { - return (iCode [pc] << 8) | (iCode [pc + 1] & 0xFF); - } - - static int GetIndex (sbyte [] iCode, int pc) - { - return ((iCode [pc] & 0xFF) << 8) | (iCode [pc + 1] & 0xFF); - } - - static int GetInt (sbyte [] iCode, int pc) - { - return (iCode [pc] << 24) | ((iCode [pc + 1] & 0xFF) << 16) | ((iCode [pc + 2] & 0xFF) << 8) | (iCode [pc + 3] & 0xFF); - } - - static int getExceptionHandler (CallFrame frame, bool onlyFinally) - { - int [] exceptionTable = frame.idata.itsExceptionTable; - if (exceptionTable == null) { - // No exception handlers - return -1; - } - - // Icode switch in the interpreter increments PC immediately - // and it is necessary to subtract 1 from the saved PC - // to point it before the start of the next instruction. - int pc = frame.pc - 1; - - // OPT: use binary search - int best = -1, bestStart = 0, bestEnd = 0; - for (int i = 0; i != exceptionTable.Length; i += EXCEPTION_SLOT_SIZE) { - int start = exceptionTable [i + EXCEPTION_TRY_START_SLOT]; - int end = exceptionTable [i + EXCEPTION_TRY_END_SLOT]; - if (!(start <= pc && pc < end)) { - continue; - } - if (onlyFinally && exceptionTable [i + EXCEPTION_TYPE_SLOT] != 1) { - continue; - } - if (best >= 0) { - // Since handlers always nest and they never have shared end - // although they can share start it is sufficient to compare - // handlers ends - if (bestEnd < end) { - continue; - } - // Check the above assumption - if (bestStart > start) - Context.CodeBug (); // should be nested - if (bestEnd == end) - Context.CodeBug (); // no ens sharing - } - best = i; - bestStart = start; - bestEnd = end; - } - return best; - } - - static void dumpICode (InterpreterData idata) - { - if (!Token.printICode) { - return; - } - - sbyte [] iCode = idata.itsICode; - int iCodeLength = iCode.Length; - string [] strings = idata.itsStringTable; - - System.IO.TextWriter sw = Console.Out; - sw.WriteLine ("ICode dump, for " + idata.itsName + ", length = " + iCodeLength); - sw.WriteLine ("MaxStack = " + idata.itsMaxStack); - - int indexReg = 0; - for (int pc = 0; pc < iCodeLength; ) { - sw.Flush (); - sw.Write (" [" + pc + "] "); - int token = iCode [pc]; - int icodeLength = bytecodeSpan (token); - string tname = bytecodeName (token); - int old_pc = pc; - ++pc; - switch (token) { - - default: - if (icodeLength != 1) - Context.CodeBug (); - sw.WriteLine (tname); - break; - - - - case Icode_GOSUB: - case Token.GOTO: - case Token.IFEQ: - case Token.IFNE: - case Icode_IFEQ_POP: - case Icode_LEAVEDQ: { - int newPC = pc + GetShort (iCode, pc) - 1; - sw.WriteLine (tname + " " + newPC); - pc += 2; - break; - } - - case Icode_VAR_INC_DEC: - case Icode_NAME_INC_DEC: - case Icode_PROP_INC_DEC: - case Icode_ELEM_INC_DEC: - case Icode_REF_INC_DEC: { - int incrDecrType = iCode [pc]; - sw.WriteLine (tname + " " + incrDecrType); - ++pc; - break; - } - - - case Icode_CALLSPECIAL: { - int callType = iCode [pc] & 0xFF; - bool isNew = (iCode [pc + 1] != 0); - int line = GetIndex (iCode, pc + 2); - sw.WriteLine (tname + " " + callType + " " + isNew + " " + indexReg + " " + line); - pc += 4; - break; - } - - - case Token.CATCH_SCOPE: { - bool afterFisrtFlag = (iCode [pc] != 0); - sw.WriteLine (tname + " " + afterFisrtFlag); - ++pc; - } - break; - - case Token.REGEXP: - sw.WriteLine (tname + " " + idata.itsRegExpLiterals [indexReg]); - break; - - case Token.OBJECTLIT: - case Icode_SPARE_ARRAYLIT: - sw.WriteLine (tname + " " + idata.literalIds [indexReg]); - break; - - case Icode_CLOSURE_EXPR: - case Icode_CLOSURE_STMT: - sw.WriteLine (tname + " " + idata.itsNestedFunctions [indexReg]); - break; - - case Token.CALL: - case Icode_TAIL_CALL: - case Token.REF_CALL: - case Token.NEW: - sw.WriteLine (tname + ' ' + indexReg); - break; - - case Token.THROW: { - int line = GetIndex (iCode, pc); - sw.WriteLine (tname + " : " + line); - pc += 2; - break; - } - - case Icode_SHORTNUMBER: { - int value = GetShort (iCode, pc); - sw.WriteLine (tname + " " + value); - pc += 2; - break; - } - - case Icode_INTNUMBER: { - int value = GetInt (iCode, pc); - sw.WriteLine (tname + " " + value); - pc += 4; - break; - } - - case Token.NUMBER: { - double value = idata.itsDoubleTable [indexReg]; - sw.WriteLine (tname + " " + value); - pc += 2; - break; - } - - case Icode_LINE: { - int line = GetIndex (iCode, pc); - sw.WriteLine (tname + " : " + line); - pc += 2; - break; - } - - case Icode_REG_STR1: { - string str = strings [0xFF & iCode [pc]]; - sw.WriteLine (tname + " \"" + str + '"'); - ++pc; - break; - } - - case Icode_REG_STR2: { - string str = strings [GetIndex (iCode, pc)]; - sw.WriteLine (tname + " \"" + str + '"'); - pc += 2; - break; - } - - case Icode_REG_STR4: { - string str = strings [GetInt (iCode, pc)]; - sw.WriteLine (tname + " \"" + str + '"'); - pc += 4; - break; - } - - case Icode_REG_IND1: { - indexReg = 0xFF & iCode [pc]; - sw.WriteLine (tname + " " + indexReg); - ++pc; - break; - } - - case Icode_REG_IND2: { - indexReg = GetIndex (iCode, pc); - sw.WriteLine (tname + " " + indexReg); - pc += 2; - break; - } - - case Icode_REG_IND4: { - indexReg = GetInt (iCode, pc); - sw.WriteLine (tname + " " + indexReg); - pc += 4; - break; - } - - case Icode_GETVAR1: - case Icode_SETVAR1: - indexReg = iCode [pc]; - sw.WriteLine (tname + " " + indexReg); - ++pc; - break; - } - if (old_pc + icodeLength != pc) - Context.CodeBug (); - } - - int [] table = idata.itsExceptionTable; - if (table != null) { - sw.WriteLine ("Exception handlers: " + table.Length / EXCEPTION_SLOT_SIZE); - for (int i = 0; i != table.Length; i += EXCEPTION_SLOT_SIZE) { - int tryStart = table [i + EXCEPTION_TRY_START_SLOT]; - int tryEnd = table [i + EXCEPTION_TRY_END_SLOT]; - int handlerStart = table [i + EXCEPTION_HANDLER_SLOT]; - int type = table [i + EXCEPTION_TYPE_SLOT]; - int exceptionLocal = table [i + EXCEPTION_LOCAL_SLOT]; - int scopeLocal = table [i + EXCEPTION_SCOPE_SLOT]; - - sw.WriteLine (" tryStart=" + tryStart + " tryEnd=" + tryEnd + " handlerStart=" + handlerStart + " type=" + (type == 0 ? "catch" : "finally") + " exceptionLocal=" + exceptionLocal); - } - } - sw.Flush (); - } - - static int bytecodeSpan (int bytecode) - { - switch (bytecode) { - - case Token.THROW: - // source line - return 1 + 2; - - - case Icode_GOSUB: - case Token.GOTO: - case Token.IFEQ: - case Token.IFNE: - case Icode_IFEQ_POP: - case Icode_LEAVEDQ: - // target pc offset - return 1 + 2; - - - case Icode_CALLSPECIAL: - // call type - // is new - // line number - return 1 + 1 + 1 + 2; - - - case Token.CATCH_SCOPE: - // scope flag - return 1 + 1; - - - case Icode_VAR_INC_DEC: - case Icode_NAME_INC_DEC: - case Icode_PROP_INC_DEC: - case Icode_ELEM_INC_DEC: - case Icode_REF_INC_DEC: - // type of ++/-- - return 1 + 1; - - - case Icode_SHORTNUMBER: - // short number - return 1 + 2; - - - case Icode_INTNUMBER: - // int number - return 1 + 4; - - - case Icode_REG_IND1: - // ubyte index - return 1 + 1; - - - case Icode_REG_IND2: - // ushort index - return 1 + 2; - - - case Icode_REG_IND4: - // int index - return 1 + 4; - - - case Icode_REG_STR1: - // ubyte string index - return 1 + 1; - - - case Icode_REG_STR2: - // ushort string index - return 1 + 2; - - - case Icode_REG_STR4: - // int string index - return 1 + 4; - - - case Icode_GETVAR1: - case Icode_SETVAR1: - // byte var index - return 1 + 1; - - - case Icode_LINE: - // line number - return 1 + 2; - } - - if (!validBytecode (bytecode)) - throw Context.CodeBug (); - - return 1; - } - - internal static int [] getLineNumbers (InterpreterData data) - { - UintMap presentLines = new UintMap (); - - sbyte [] iCode = data.itsICode; - int iCodeLength = iCode.Length; - for (int pc = 0; pc != iCodeLength; ) { - int bytecode = iCode [pc]; - int span = bytecodeSpan (bytecode); - if (bytecode == Icode_LINE) { - if (span != 3) - Context.CodeBug (); - int line = GetIndex (iCode, pc + 1); - presentLines.put (line, 0); - } - pc += span; - } - - return presentLines.Keys; - } - - internal static void captureInterpreterStackInfo (EcmaScriptException ex) - { - Context cx = Context.CurrentContext; - if (cx == null || cx.lastInterpreterFrame == null) { - // No interpreter invocations - ex.m_InterpreterStackInfo = null; - ex.m_InterpreterLineData = null; - return; - } - // has interpreter frame on the stack - CallFrame [] array; - if (cx.previousInterpreterInvocations == null || cx.previousInterpreterInvocations.size () == 0) { - array = new CallFrame [1]; - } - else { - int previousCount = cx.previousInterpreterInvocations.size (); - if (cx.previousInterpreterInvocations.peek () == cx.lastInterpreterFrame) { - // It can happen if exception was generated after - // frame was pushed to cx.previousInterpreterInvocations - // but before assignment to cx.lastInterpreterFrame. - // In this case frames has to be ignored. - --previousCount; - } - array = new CallFrame [previousCount + 1]; - cx.previousInterpreterInvocations.ToArray (array); - } - array [array.Length - 1] = (CallFrame)cx.lastInterpreterFrame; - - int interpreterFrameCount = 0; - for (int i = 0; i != array.Length; ++i) { - interpreterFrameCount += 1 + array [i].frameIndex; - } - - int [] linePC = new int [interpreterFrameCount]; - // Fill linePC with pc positions from all interpreter frames. - // Start from the most nested frame - int linePCIndex = interpreterFrameCount; - for (int i = array.Length; i != 0; ) { - --i; - CallFrame frame = array [i]; - while (frame != null) { - --linePCIndex; - linePC [linePCIndex] = frame.pcSourceLineStart; - frame = frame.parentFrame; - } - } - if (linePCIndex != 0) - Context.CodeBug (); - - ex.m_InterpreterStackInfo = array; - ex.m_InterpreterLineData = linePC; - } - - internal static string GetSourcePositionFromStack (Context cx, int [] linep) - { - CallFrame frame = (CallFrame)cx.lastInterpreterFrame; - InterpreterData idata = frame.idata; - if (frame.pcSourceLineStart >= 0) { - linep [0] = GetIndex (idata.itsICode, frame.pcSourceLineStart); - } - else { - linep [0] = 0; - } - return idata.itsSourceFile; - } - - - internal static string GetStack (EcmaScriptException ex) - { - System.Text.StringBuilder sb = new System.Text.StringBuilder (); - - CallFrame [] array = (CallFrame [])ex.m_InterpreterStackInfo; - if (array == null) // TODO: When does this happen? - return sb.ToString (); - - int [] linePC = ex.m_InterpreterLineData; - int arrayIndex = array.Length; - int linePCIndex = linePC.Length; - - while (arrayIndex != 0) { - --arrayIndex; - - CallFrame frame = array [arrayIndex]; - while (frame != null) { - if (linePCIndex == 0) - Context.CodeBug (); - --linePCIndex; - InterpreterData idata = frame.idata; - - if (sb.Length > 0) - sb.Append (Environment.NewLine); - sb.Append ("\tat script"); - if (idata.itsName != null && idata.itsName.Length != 0) { - sb.Append ('.'); - sb.Append (idata.itsName); - } - sb.Append ('('); - sb.Append (idata.itsSourceFile); - int pc = linePC [linePCIndex]; - if (pc >= 0) { - // Include line info only if available - sb.Append (':'); - sb.Append (GetIndex (idata.itsICode, pc)); - } - sb.Append (')'); - - - frame = frame.parentFrame; - - - } - } - - return sb.ToString (); - } - - internal static string getPatchedStack (EcmaScriptException ex, string nativeStackTrace) - { - string tag = "EcmaScript.NET.Interpreter.interpretLoop"; - System.Text.StringBuilder sb = new System.Text.StringBuilder (nativeStackTrace.Length + 1000); - string lineSeparator = System.Environment.NewLine; - - CallFrame [] array = (CallFrame [])ex.m_InterpreterStackInfo; - if (array == null) // TODO: when does this happen? - return sb.ToString (); - - int [] linePC = ex.m_InterpreterLineData; - int arrayIndex = array.Length; - int linePCIndex = linePC.Length; - int offset = 0; - while (arrayIndex != 0) { - --arrayIndex; - int pos = nativeStackTrace.IndexOf (tag, offset); - if (pos < 0) { - break; - } - - // Skip tag length - pos += tag.Length; - // Skip until the end of line - for (; pos != nativeStackTrace.Length; ++pos) { - char c = nativeStackTrace [pos]; - if (c == '\n' || c == '\r') { - break; - } - } - sb.Append (nativeStackTrace.Substring (offset, (pos) - (offset))); - offset = pos; - - CallFrame frame = array [arrayIndex]; - while (frame != null) { - if (linePCIndex == 0) - Context.CodeBug (); - --linePCIndex; - InterpreterData idata = frame.idata; - sb.Append (lineSeparator); - sb.Append ("\tat script"); - if (idata.itsName != null && idata.itsName.Length != 0) { - sb.Append ('.'); - sb.Append (idata.itsName); - } - sb.Append ('('); - sb.Append (idata.itsSourceFile); - int pc = linePC [linePCIndex]; - if (pc >= 0) { - // Include line info only if available - sb.Append (':'); - sb.Append (GetIndex (idata.itsICode, pc)); - } - sb.Append (')'); - frame = frame.parentFrame; - } - } - sb.Append (nativeStackTrace.Substring (offset)); - - return sb.ToString (); - } - - internal static string GetEncodedSource (InterpreterData idata) - { - if (idata.encodedSource == null) { - return null; - } - return idata.encodedSource.Substring (idata.encodedSourceStart, (idata.encodedSourceEnd) - (idata.encodedSourceStart)); - } - - static void initFunction (Context cx, IScriptable scope, InterpretedFunction parent, int index) - { - InterpretedFunction fn; - fn = InterpretedFunction.createFunction (cx, scope, parent, index); - ScriptRuntime.initFunction (cx, scope, fn, fn.idata.itsFunctionType, parent.idata.evalScriptFlag); - } - - internal static object Interpret (InterpretedFunction ifun, Context cx, IScriptable scope, IScriptable thisObj, object [] args) - { - using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier (128)) { - if (!ScriptRuntime.hasTopCall (cx)) - Context.CodeBug (); - - if (cx.interpreterSecurityDomain != ifun.securityDomain) { - object savedDomain = cx.interpreterSecurityDomain; - cx.interpreterSecurityDomain = ifun.securityDomain; - try { - return ifun.securityController.callWithDomain (ifun.securityDomain, cx, ifun, scope, thisObj, args); - } - finally { - cx.interpreterSecurityDomain = savedDomain; - } - } - - CallFrame frame = new CallFrame (); - initFrame (cx, scope, thisObj, args, null, 0, args.Length, ifun, null, frame); - - return InterpretLoop (cx, frame, (object)null); - } - } - - public static object restartContinuation (Continuation c, Context cx, IScriptable scope, object [] args) - { - if (!ScriptRuntime.hasTopCall (cx)) { - return ScriptRuntime.DoTopCall (c, cx, scope, null, args); - } - - object arg; - if (args.Length == 0) { - arg = Undefined.Value; - } - else { - arg = args [0]; - } - - CallFrame capturedFrame = (CallFrame)c.Implementation; - if (capturedFrame == null) { - // No frames to restart - return arg; - } - - ContinuationJump cjump = new ContinuationJump (c, null); - - cjump.result = arg; - return InterpretLoop (cx, null, cjump); - } - - static object InterpretLoop (Context cx, CallFrame frame, object throwable) - { - // throwable holds exception object to rethrow or catch - // It is also used for continuation restart in which case - // it holds ContinuationJump - - object DBL_MRK = UniqueTag.DoubleMark; - object undefined = Undefined.Value; - - bool instructionCounting = (cx.instructionThreshold != 0); - // arbitrary number to add to instructionCount when calling - // other functions - const int INVOCATION_COST = 100; - - // arbitrary exception cost for instruction counting - const int EXCEPTION_COST = 100; - - string stringReg = null; - int indexReg = -1; - - if (cx.lastInterpreterFrame != null) { - // save the top frame from the previous interpreterLoop - // invocation on the stack - if (cx.previousInterpreterInvocations == null) { - cx.previousInterpreterInvocations = new ObjArray (); - } - cx.previousInterpreterInvocations.push (cx.lastInterpreterFrame); - } - - // When restarting continuation throwable is not null and to jump - // to the code that rewind continuation state indexReg should be set - // to -1. - // With the normal call throable == null and indexReg == -1 allows to - // catch bugs with using indeReg to access array eleemnts before - // initializing indexReg. - - if (throwable != null) { - // Assert assumptions - if (!(throwable is ContinuationJump)) { - // It should be continuation - Context.CodeBug (); - } - } - - object interpreterResult = null; - double interpreterResultDbl = 0.0; - - for (; ; ) { - - try { - - if (throwable != null) { - // Recovering from exception, indexReg contains - // the index of handler - - if (indexReg >= 0) { - // Normal excepton handler, transfer - // control appropriately - - if (frame.frozen) { - // TODO: Deal with exceptios!!! - frame = frame.cloneFrozen (); - } - - int [] table = frame.idata.itsExceptionTable; - - frame.pc = table [indexReg + EXCEPTION_HANDLER_SLOT]; - if (instructionCounting) { - frame.pcPrevBranch = frame.pc; - } - - frame.savedStackTop = frame.emptyStackTop; - int scopeLocal = frame.localShift + table [indexReg + EXCEPTION_SCOPE_SLOT]; - int exLocal = frame.localShift + table [indexReg + EXCEPTION_LOCAL_SLOT]; - frame.scope = (IScriptable)frame.stack [scopeLocal]; - frame.stack [exLocal] = throwable; - - throwable = null; - } - else { - // Continuation restoration - ContinuationJump cjump = (ContinuationJump)throwable; - - // Clear throwable to indicate that execptions are OK - throwable = null; - - if (cjump.branchFrame != frame) - Context.CodeBug (); - - // Check that we have at least one frozen frame - // in the case of detached continuation restoration: - // unwind code ensure that - if (cjump.capturedFrame == null) - Context.CodeBug (); - - // Need to rewind branchFrame, capturedFrame - // and all frames in between - int rewindCount = cjump.capturedFrame.frameIndex + 1; - if (cjump.branchFrame != null) { - rewindCount -= cjump.branchFrame.frameIndex; - } - - int enterCount = 0; - CallFrame [] enterFrames = null; - - CallFrame x = cjump.capturedFrame; - for (int i = 0; i != rewindCount; ++i) { - if (!x.frozen) - Context.CodeBug (); - if (isFrameEnterExitRequired (x)) { - if (enterFrames == null) { - // Allocate enough space to store the rest - // of rewind frames in case all of them - // would require to enter - enterFrames = new CallFrame [rewindCount - i]; - } - enterFrames [enterCount] = x; - ++enterCount; - } - x = x.parentFrame; - } - - while (enterCount != 0) { - // execute enter: walk enterFrames in the reverse - // order since they were stored starting from - // the capturedFrame, not branchFrame - --enterCount; - x = enterFrames [enterCount]; - EnterFrame (cx, x, ScriptRuntime.EmptyArgs); - } - - // Continuation jump is almost done: capturedFrame - // points to the call to the function that captured - // continuation, so clone capturedFrame and - // emulate return that function with the suplied result - frame = cjump.capturedFrame.cloneFrozen (); - setCallResult (frame, cjump.result, cjump.resultDbl); - // restart the execution - } - - // Should be already cleared - if (throwable != null) - Context.CodeBug (); - } - else { - if (frame.frozen) - Context.CodeBug (); - } - - // Use local variables for constant values in frame - // for faster access - object [] stack = frame.stack; - double [] sDbl = frame.sDbl; - object [] vars = frame.varSource.stack; - double [] varDbls = frame.varSource.sDbl; - - sbyte [] iCode = frame.idata.itsICode; - string [] strings = frame.idata.itsStringTable; - - // Use local for stackTop as well. Since execption handlers - // can only exist at statement level where stack is empty, - // it is necessary to save/restore stackTop only accross - // function calls and normal returns. - int stackTop = frame.savedStackTop; - - // Store new frame in cx which is used for error reporting etc. - cx.lastInterpreterFrame = frame; - - for (; ; ) { - - // Exception handler assumes that PC is already incremented - // pass the instruction start when it searches the - // exception handler - int op = iCode [frame.pc++]; - { - switch (op) { - - case Token.THROW: { - object value = stack [stackTop]; - if (value == DBL_MRK) - value = sDbl [stackTop]; - stackTop--; - - int sourceLine = GetIndex (iCode, frame.pc); - throwable = new EcmaScriptThrow ( - value, frame.idata.itsSourceFile, sourceLine); - goto withoutExceptions_brk; - } - - case Token.RETHROW: { - indexReg += frame.localShift; - throwable = stack [indexReg]; - break; - } - - case Token.GE: - case Token.LE: - case Token.GT: - case Token.LT: { - --stackTop; - object rhs = stack [stackTop + 1]; - object lhs = stack [stackTop]; - bool valBln; - { - { - double rDbl, lDbl; - if (rhs == DBL_MRK) { - rDbl = sDbl [stackTop + 1]; - lDbl = stack_double (frame, stackTop); - } - else if (lhs == DBL_MRK) { - rDbl = ScriptConvert.ToNumber (rhs); - lDbl = sDbl [stackTop]; - } - else { - - goto number_compare_brk; - } - switch (op) { - - case Token.GE: - valBln = (lDbl >= rDbl); - - goto object_compare_brk; - - case Token.LE: - valBln = (lDbl <= rDbl); - - goto object_compare_brk; - - case Token.GT: - valBln = (lDbl > rDbl); - - goto object_compare_brk; - - case Token.LT: - valBln = (lDbl < rDbl); - - goto object_compare_brk; - - default: - throw Context.CodeBug (); - - } - } - - number_compare_brk: - ; - - switch (op) { - - case Token.GE: - valBln = ScriptRuntime.cmp_LE (rhs, lhs); - break; - - case Token.LE: - valBln = ScriptRuntime.cmp_LE (lhs, rhs); - break; - - case Token.GT: - valBln = ScriptRuntime.cmp_LT (rhs, lhs); - break; - - case Token.LT: - valBln = ScriptRuntime.cmp_LT (lhs, rhs); - break; - - default: - throw Context.CodeBug (); - - } - } - - object_compare_brk: - ; - - stack [stackTop] = valBln; - - goto Loop; - } - goto case Token.IN; - - case Token.IN: - case Token.INSTANCEOF: { - object rhs = stack [stackTop]; - if (rhs == DBL_MRK) - rhs = sDbl [stackTop]; - --stackTop; - object lhs = stack [stackTop]; - if (lhs == DBL_MRK) - lhs = sDbl [stackTop]; - bool valBln; - if (op == Token.IN) { - valBln = ScriptRuntime.In (lhs, rhs, cx); - } - else { - valBln = ScriptRuntime.InstanceOf (lhs, rhs, cx); - } - stack [stackTop] = valBln; - - goto Loop; - } - goto case Token.EQ; - - case Token.EQ: - case Token.NE: { - --stackTop; - bool valBln; - object rhs = stack [stackTop + 1]; - object lhs = stack [stackTop]; - if (rhs == DBL_MRK) { - if (lhs == DBL_MRK) { - valBln = (sDbl [stackTop] == sDbl [stackTop + 1]); - } - else { - valBln = ScriptRuntime.eqNumber (sDbl [stackTop + 1], lhs); - } - } - else { - if (lhs == DBL_MRK) { - valBln = ScriptRuntime.eqNumber (sDbl [stackTop], rhs); - } - else { - valBln = ScriptRuntime.eq (lhs, rhs); - } - } - valBln ^= (op == Token.NE); - stack [stackTop] = valBln; - - goto Loop; - } - goto case Token.SHEQ; - - case Token.SHEQ: - case Token.SHNE: { - --stackTop; - object rhs = stack [stackTop + 1]; - object lhs = stack [stackTop]; - bool valBln; - { - double rdbl, ldbl; - if (rhs == DBL_MRK) { - rdbl = sDbl [stackTop + 1]; - if (lhs == DBL_MRK) { - ldbl = sDbl [stackTop]; - } - else if (CliHelper.IsNumber (lhs)) { - ldbl = Convert.ToDouble (lhs); - } - else { - valBln = false; - - goto shallow_compare_brk; - } - } - else if (lhs == DBL_MRK) { - ldbl = sDbl [stackTop]; - if (rhs == DBL_MRK) { - rdbl = sDbl [stackTop + 1]; - } - else if (CliHelper.IsNumber (rhs)) { - rdbl = Convert.ToDouble (rhs); - } - else { - valBln = false; - - goto shallow_compare_brk; - } - } - else { - valBln = ScriptRuntime.shallowEq (lhs, rhs); - - goto shallow_compare_brk; - } - valBln = (ldbl == rdbl); - } - - shallow_compare_brk: - ; - - valBln ^= (op == Token.SHNE); - stack [stackTop] = valBln; - - goto Loop; - } - goto case Token.IFNE; - - case Token.IFNE: - if (stack_boolean (frame, stackTop--)) { - frame.pc += 2; - - goto Loop; - } - - goto jumplessRun_brk; - - case Token.IFEQ: - if (!stack_boolean (frame, stackTop--)) { - frame.pc += 2; - - goto Loop; - } - - goto jumplessRun_brk; - - case Icode_IFEQ_POP: - if (!stack_boolean (frame, stackTop--)) { - frame.pc += 2; - - goto Loop; - } - stack [stackTop--] = null; - - goto jumplessRun_brk; - - case Token.GOTO: - - goto jumplessRun_brk; - - case Icode_GOSUB: - ++stackTop; - stack [stackTop] = DBL_MRK; - sDbl [stackTop] = frame.pc + 2; - - goto jumplessRun_brk; - - case Icode_STARTSUB: - if (stackTop == frame.emptyStackTop + 1) { - // Call from Icode_GOSUB: store return PC address in the local - indexReg += frame.localShift; - stack [indexReg] = stack [stackTop]; - sDbl [indexReg] = sDbl [stackTop]; - --stackTop; - } - else { - // Call from exception handler: exception object is already stored - // in the local - if (stackTop != frame.emptyStackTop) - Context.CodeBug (); - } - - goto Loop; - goto case Icode_RETSUB; - - case Icode_RETSUB: { - // indexReg: local to store return address - if (instructionCounting) { - addInstructionCount (cx, frame, 0); - } - indexReg += frame.localShift; - object value = stack [indexReg]; - if (value != DBL_MRK) { - // Invocation from exception handler, restore object to rethrow - throwable = value; - goto withoutExceptions_brk; - } - // Normal return from GOSUB - frame.pc = (int)sDbl [indexReg]; - if (instructionCounting) { - frame.pcPrevBranch = frame.pc; - } - - goto Loop; - } - goto case Icode_POP; - - case Icode_POP: - stack [stackTop] = null; - stackTop--; - - goto Loop; - goto case Icode_POP_RESULT; - - case Icode_POP_RESULT: - frame.result = stack [stackTop]; - frame.resultDbl = sDbl [stackTop]; - stack [stackTop] = null; - --stackTop; - - goto Loop; - goto case Icode_DUP; - - case Icode_DUP: - stack [stackTop + 1] = stack [stackTop]; - sDbl [stackTop + 1] = sDbl [stackTop]; - stackTop++; - - goto Loop; - goto case Icode_DUP2; - - case Icode_DUP2: - stack [stackTop + 1] = stack [stackTop - 1]; - sDbl [stackTop + 1] = sDbl [stackTop - 1]; - stack [stackTop + 2] = stack [stackTop]; - sDbl [stackTop + 2] = sDbl [stackTop]; - stackTop += 2; - - goto Loop; - goto case Icode_SWAP; - - case Icode_SWAP: { - object o = stack [stackTop]; - stack [stackTop] = stack [stackTop - 1]; - stack [stackTop - 1] = o; - double d = sDbl [stackTop]; - sDbl [stackTop] = sDbl [stackTop - 1]; - sDbl [stackTop - 1] = d; - - goto Loop; - } - goto case Token.RETURN; - - case Token.RETURN: - frame.result = stack [stackTop]; - frame.resultDbl = sDbl [stackTop]; - --stackTop; - - goto Loop_brk; - - case Token.RETURN_RESULT: - - goto Loop_brk; - - case Icode_RETUNDEF: - frame.result = undefined; - - goto Loop_brk; - - case Token.BITNOT: { - int rIntValue = stack_int32 (frame, stackTop); - stack [stackTop] = DBL_MRK; - sDbl [stackTop] = ~rIntValue; - - goto Loop; - } - goto case Token.BITAND; - - case Token.BITAND: - case Token.BITOR: - case Token.BITXOR: - case Token.LSH: - case Token.RSH: { - int rIntValue = stack_int32 (frame, stackTop); - --stackTop; - int lIntValue = stack_int32 (frame, stackTop); - stack [stackTop] = DBL_MRK; - switch (op) { - - case Token.BITAND: - lIntValue &= rIntValue; - break; - - case Token.BITOR: - lIntValue |= rIntValue; - break; - - case Token.BITXOR: - lIntValue ^= rIntValue; - break; - - case Token.LSH: - lIntValue <<= rIntValue; - break; - - case Token.RSH: - lIntValue >>= rIntValue; - break; - } - sDbl [stackTop] = lIntValue; - - goto Loop; - } - goto case Token.URSH; - - case Token.URSH: { - int rIntValue = stack_int32 (frame, stackTop) & 0x1F; - --stackTop; - double lDbl = stack_double (frame, stackTop); - stack [stackTop] = DBL_MRK; - uint i = (uint)ScriptConvert.ToUint32 (lDbl); - sDbl [stackTop] = i >> rIntValue; - - goto Loop; - } - goto case Token.NEG; - - case Token.NEG: - case Token.POS: { - double rDbl = stack_double (frame, stackTop); - stack [stackTop] = DBL_MRK; - if (op == Token.NEG) { - rDbl = -rDbl; - } - sDbl [stackTop] = rDbl; - - goto Loop; - } - goto case Token.ADD; - - case Token.ADD: - --stackTop; - DoAdd (stack, sDbl, stackTop, cx); - - goto Loop; - goto case Token.SUB; - - case Token.SUB: - case Token.MUL: - case Token.DIV: - case Token.MOD: { - double rDbl = stack_double (frame, stackTop); - --stackTop; - double lDbl = stack_double (frame, stackTop); - stack [stackTop] = DBL_MRK; - switch (op) { - - case Token.SUB: - lDbl -= rDbl; - break; - - case Token.MUL: - lDbl *= rDbl; - break; - - case Token.DIV: - lDbl /= rDbl; - break; - - case Token.MOD: - lDbl %= rDbl; - break; - } - sDbl [stackTop] = lDbl; - - goto Loop; - } - goto case Token.NOT; - - case Token.NOT: - stack [stackTop] = !stack_boolean (frame, stackTop); - - goto Loop; - goto case Token.BINDNAME; - - case Token.BINDNAME: - stack [++stackTop] = ScriptRuntime.bind (cx, frame.scope, stringReg); - - goto Loop; - goto case Token.SETNAME; - - case Token.SETNAME: { - object rhs = stack [stackTop]; - if (rhs == DBL_MRK) - rhs = sDbl [stackTop]; - --stackTop; - IScriptable lhs = (IScriptable)stack [stackTop]; - stack [stackTop] = ScriptRuntime.setName (lhs, rhs, cx, frame.scope, stringReg); - - goto Loop; - } - goto case Token.DELPROP; - - case Token.DELPROP: { - object rhs = stack [stackTop]; - if (rhs == DBL_MRK) - rhs = sDbl [stackTop]; - --stackTop; - object lhs = stack [stackTop]; - if (lhs == DBL_MRK) - lhs = sDbl [stackTop]; - stack [stackTop] = ScriptRuntime.delete (lhs, rhs, cx); - - goto Loop; - } - goto case Token.GETPROP; - - case Token.GETPROP: { - object lhs = stack [stackTop]; - if (lhs == DBL_MRK) - lhs = sDbl [stackTop]; - stack [stackTop] = ScriptRuntime.getObjectProp (lhs, stringReg, cx); - - goto Loop; - } - goto case Token.SETPROP; - - case Token.SETPROP_GETTER: - case Token.SETPROP_SETTER: - case Token.SETPROP: { - object rhs = stack [stackTop]; - if (rhs == DBL_MRK) - rhs = sDbl [stackTop]; - --stackTop; - object lhs = stack [stackTop]; - if (lhs == DBL_MRK) - lhs = sDbl [stackTop]; - - switch (op) { - case Token.SETPROP_GETTER: - ((ScriptableObject)lhs).DefineGetter(stringReg, ((ICallable)rhs)); - stack[stackTop] = rhs; - break; - - case Token.SETPROP_SETTER: - ((ScriptableObject)lhs).DefineSetter(stringReg, ((ICallable)rhs)); - stack[stackTop] = rhs; - break; - - - default: - stack [stackTop] = ScriptRuntime.setObjectProp (lhs, stringReg, rhs, cx); - break; - } - - goto Loop; - } - goto case Icode_PROP_INC_DEC; - - case Icode_PROP_INC_DEC: { - object lhs = stack [stackTop]; - if (lhs == DBL_MRK) - lhs = sDbl [stackTop]; - stack [stackTop] = ScriptRuntime.propIncrDecr (lhs, stringReg, cx, iCode [frame.pc]); - ++frame.pc; - - goto Loop; - } - goto case Token.GETELEM; - - case Token.GETELEM: { - --stackTop; - object lhs = stack [stackTop]; - if (lhs == DBL_MRK) { - lhs = sDbl [stackTop]; - } - object value; - object id = stack [stackTop + 1]; - if (id != DBL_MRK) { - value = ScriptRuntime.getObjectElem (lhs, id, cx); - } - else { - double d = sDbl [stackTop + 1]; - value = ScriptRuntime.getObjectIndex (lhs, d, cx); - } - stack [stackTop] = value; - - goto Loop; - } - goto case Token.SETELEM; - - case Token.SETELEM: { - stackTop -= 2; - object rhs = stack [stackTop + 2]; - if (rhs == DBL_MRK) { - rhs = sDbl [stackTop + 2]; - } - object lhs = stack [stackTop]; - if (lhs == DBL_MRK) { - lhs = sDbl [stackTop]; - } - object value; - object id = stack [stackTop + 1]; - if (id != DBL_MRK) { - value = ScriptRuntime.setObjectElem (lhs, id, rhs, cx); - } - else { - double d = sDbl [stackTop + 1]; - value = ScriptRuntime.setObjectIndex (lhs, d, rhs, cx); - } - stack [stackTop] = value; - - goto Loop; - } - goto case Icode_ELEM_INC_DEC; - - case Icode_ELEM_INC_DEC: { - object rhs = stack [stackTop]; - if (rhs == DBL_MRK) - rhs = sDbl [stackTop]; - --stackTop; - object lhs = stack [stackTop]; - if (lhs == DBL_MRK) - lhs = sDbl [stackTop]; - stack [stackTop] = ScriptRuntime.elemIncrDecr (lhs, rhs, cx, iCode [frame.pc]); - ++frame.pc; - - goto Loop; - } - goto case Token.GET_REF; - - case Token.GET_REF: { - IRef rf = (IRef)stack [stackTop]; - stack [stackTop] = ScriptRuntime.refGet (rf, cx); - - goto Loop; - } - goto case Token.SET_REF; - - case Token.SET_REF: { - object value = stack [stackTop]; - if (value == DBL_MRK) - value = sDbl [stackTop]; - --stackTop; - IRef rf = (IRef)stack [stackTop]; - stack [stackTop] = ScriptRuntime.refSet (rf, value, cx); - - goto Loop; - } - goto case Token.DEL_REF; - - case Token.DEL_REF: { - IRef rf = (IRef)stack [stackTop]; - stack [stackTop] = ScriptRuntime.refDel (rf, cx); - - goto Loop; - } - goto case Icode_REF_INC_DEC; - - case Icode_REF_INC_DEC: { - IRef rf = (IRef)stack [stackTop]; - stack [stackTop] = ScriptRuntime.refIncrDecr (rf, cx, iCode [frame.pc]); - ++frame.pc; - - goto Loop; - } - goto case Token.LOCAL_LOAD; - - case Token.LOCAL_LOAD: - ++stackTop; - indexReg += frame.localShift; - stack [stackTop] = stack [indexReg]; - sDbl [stackTop] = sDbl [indexReg]; - - goto Loop; - goto case Icode_LOCAL_CLEAR; - - case Icode_LOCAL_CLEAR: - indexReg += frame.localShift; - stack [indexReg] = null; - - goto Loop; - goto case Icode_NAME_AND_THIS; - - case Icode_NAME_AND_THIS: - // stringReg: name - ++stackTop; - stack [stackTop] = ScriptRuntime.getNameFunctionAndThis (stringReg, cx, frame.scope); - ++stackTop; - stack [stackTop] = ScriptRuntime.lastStoredScriptable (cx); - - goto Loop; - goto case Icode_PROP_AND_THIS; - - case Icode_PROP_AND_THIS: { - object obj = stack [stackTop]; - if (obj == DBL_MRK) - obj = sDbl [stackTop]; - // stringReg: property - stack [stackTop] = ScriptRuntime.getPropFunctionAndThis (obj, stringReg, cx); - ++stackTop; - stack [stackTop] = ScriptRuntime.lastStoredScriptable (cx); - - goto Loop; - } - goto case Icode_ELEM_AND_THIS; - - case Icode_ELEM_AND_THIS: { - object obj = stack [stackTop - 1]; - if (obj == DBL_MRK) - obj = sDbl [stackTop - 1]; - object id = stack [stackTop]; - if (id == DBL_MRK) - id = sDbl [stackTop]; - stack [stackTop - 1] = ScriptRuntime.GetElemFunctionAndThis (obj, id, cx); - stack [stackTop] = ScriptRuntime.lastStoredScriptable (cx); - - goto Loop; - } - goto case Icode_VALUE_AND_THIS; - - case Icode_VALUE_AND_THIS: { - object value = stack [stackTop]; - if (value == DBL_MRK) - value = sDbl [stackTop]; - stack [stackTop] = ScriptRuntime.getValueFunctionAndThis (value, cx); - ++stackTop; - stack [stackTop] = ScriptRuntime.lastStoredScriptable (cx); - - goto Loop; - } - goto case Icode_CALLSPECIAL; - - case Icode_CALLSPECIAL: { - if (instructionCounting) { - cx.instructionCount += INVOCATION_COST; - } - int callType = iCode [frame.pc] & 0xFF; - bool isNew = (iCode [frame.pc + 1] != 0); - int sourceLine = GetIndex (iCode, frame.pc + 2); - - // indexReg: number of arguments - if (isNew) { - // stack change: function arg0 .. argN -> newResult - stackTop -= indexReg; - - object function = stack [stackTop]; - if (function == DBL_MRK) - function = sDbl [stackTop]; - object [] outArgs = GetArgsArray (stack, sDbl, stackTop + 1, indexReg); - stack [stackTop] = ScriptRuntime.newSpecial (cx, function, outArgs, frame.scope, callType); - } - else { - // stack change: function thisObj arg0 .. argN -> result - stackTop -= (1 + indexReg); - - // Call code generation ensure that stack here - // is ... Callable Scriptable - IScriptable functionThis = (IScriptable)stack [stackTop + 1]; - ICallable function = (ICallable)stack [stackTop]; - object [] outArgs = GetArgsArray (stack, sDbl, stackTop + 2, indexReg); - stack [stackTop] = ScriptRuntime.callSpecial (cx, function, functionThis, outArgs, frame.scope, frame.thisObj, callType, frame.idata.itsSourceFile, sourceLine); - } - frame.pc += 4; - - goto Loop; - } - goto case Token.CALL; - - case Token.CALL: - case Icode_TAIL_CALL: - case Token.REF_CALL: { - if (instructionCounting) { - cx.instructionCount += INVOCATION_COST; - } - // stack change: function thisObj arg0 .. argN -> result - // indexReg: number of arguments - stackTop -= (1 + indexReg); - - // CALL generation ensures that fun and funThisObj - // are already Scriptable and Callable objects respectively - ICallable fun = (ICallable)stack [stackTop]; - IScriptable funThisObj = (IScriptable)stack [stackTop + 1]; - if (op == Token.REF_CALL) { - object [] outArgs = GetArgsArray (stack, sDbl, stackTop + 2, indexReg); - stack [stackTop] = ScriptRuntime.callRef (fun, funThisObj, outArgs, cx); - - goto Loop; - } - IScriptable calleeScope = frame.scope; - if (frame.useActivation) { - calleeScope = ScriptableObject.GetTopLevelScope (frame.scope); - } - if (fun is InterpretedFunction) { - InterpretedFunction ifun = (InterpretedFunction)fun; - if (frame.fnOrScript.securityDomain == ifun.securityDomain) { - CallFrame callParentFrame = frame; - CallFrame calleeFrame = new CallFrame (); - if (op == Icode_TAIL_CALL) { - // In principle tail call can re-use the current - // frame and its stack arrays but it is hard to - // do properly. Any exceptions that can legally - // happen during frame re-initialization including - // StackOverflowException during innocent looking - // System.arraycopy may leave the current frame - // data corrupted leading to undefined behaviour - // in the catch code bellow that unwinds JS stack - // on exceptions. Then there is issue about frame release - // end exceptions there. - // To avoid frame allocation a released frame - // can be cached for re-use which would also benefit - // non-tail calls but it is not clear that this caching - // would gain in performance due to potentially - // bad iteraction with GC. - callParentFrame = frame.parentFrame; - } - initFrame (cx, calleeScope, funThisObj, stack, sDbl, stackTop + 2, indexReg, ifun, callParentFrame, calleeFrame); - if (op == Icode_TAIL_CALL) { - // Release the parent - ExitFrame (cx, frame, (object)null); - } - else { - frame.savedStackTop = stackTop; - frame.savedCallOp = op; - } - frame = calleeFrame; - - goto StateLoop; - } - } - - if (fun is Continuation) { - // Jump to the captured continuation - ContinuationJump cjump; - cjump = new ContinuationJump ((Continuation)fun, frame); - - // continuation result is the first argument if any - // of contination call - if (indexReg == 0) { - cjump.result = undefined; - } - else { - cjump.result = stack [stackTop + 2]; - cjump.resultDbl = sDbl [stackTop + 2]; - } - - // Start the real unwind job - throwable = cjump; - break; - } - - if (fun is IdFunctionObject) { - IdFunctionObject ifun = (IdFunctionObject)fun; - if (Continuation.IsContinuationConstructor (ifun)) { - captureContinuation (cx, frame, stackTop); - - goto Loop; - } - } - - object [] outArgs2 = GetArgsArray (stack, sDbl, stackTop + 2, indexReg); - stack [stackTop] = fun.Call (cx, calleeScope, funThisObj, outArgs2); - - - goto Loop; - } - goto case Token.NEW; - - case Token.NEW: { - if (instructionCounting) { - cx.instructionCount += INVOCATION_COST; - } - // stack change: function arg0 .. argN -> newResult - // indexReg: number of arguments - stackTop -= indexReg; - - object lhs = stack [stackTop]; - if (lhs is InterpretedFunction) { - InterpretedFunction f = (InterpretedFunction)lhs; - if (frame.fnOrScript.securityDomain == f.securityDomain) { - IScriptable newInstance = f.CreateObject (cx, frame.scope); - CallFrame calleeFrame = new CallFrame (); - initFrame (cx, frame.scope, newInstance, stack, sDbl, stackTop + 1, indexReg, f, frame, calleeFrame); - - stack [stackTop] = newInstance; - frame.savedStackTop = stackTop; - frame.savedCallOp = op; - frame = calleeFrame; - - goto StateLoop; - } - } - if (!(lhs is IFunction)) { - if (lhs == DBL_MRK) - lhs = sDbl [stackTop]; - throw ScriptRuntime.NotFunctionError (lhs); - } - IFunction fun = (IFunction)lhs; - - if (fun is IdFunctionObject) { - IdFunctionObject ifun = (IdFunctionObject)fun; - if (Continuation.IsContinuationConstructor (ifun)) { - captureContinuation (cx, frame, stackTop); - - goto Loop; - } - } - - object [] outArgs = GetArgsArray (stack, sDbl, stackTop + 1, indexReg); - stack [stackTop] = fun.Construct (cx, frame.scope, outArgs); - - goto Loop; - } - goto case Token.TYPEOF; - - case Token.TYPEOF: { - object lhs = stack [stackTop]; - if (lhs == DBL_MRK) - lhs = sDbl [stackTop]; - stack [stackTop] = ScriptRuntime.Typeof (lhs); - - goto Loop; - } - goto case Icode_TYPEOFNAME; - - case Icode_TYPEOFNAME: - stack [++stackTop] = ScriptRuntime.TypeofName (frame.scope, stringReg); - - goto Loop; - goto case Token.STRING; - - case Token.STRING: - stack [++stackTop] = stringReg; - - goto Loop; - goto case Icode_SHORTNUMBER; - - case Icode_SHORTNUMBER: - ++stackTop; - stack [stackTop] = DBL_MRK; - sDbl [stackTop] = GetShort (iCode, frame.pc); - frame.pc += 2; - - goto Loop; - goto case Icode_INTNUMBER; - - case Icode_INTNUMBER: - ++stackTop; - stack [stackTop] = DBL_MRK; - sDbl [stackTop] = GetInt (iCode, frame.pc); - frame.pc += 4; - - goto Loop; - goto case Token.NUMBER; - - case Token.NUMBER: - ++stackTop; - stack [stackTop] = DBL_MRK; - sDbl [stackTop] = frame.idata.itsDoubleTable [indexReg]; - - goto Loop; - goto case Token.NAME; - - case Token.NAME: - stack [++stackTop] = ScriptRuntime.name (cx, frame.scope, stringReg); - - goto Loop; - goto case Icode_NAME_INC_DEC; - - case Icode_NAME_INC_DEC: - stack [++stackTop] = ScriptRuntime.nameIncrDecr (frame.scope, stringReg, iCode [frame.pc]); - ++frame.pc; - - goto Loop; - goto case Icode_SETVAR1; - - case Icode_SETVAR1: - indexReg = iCode [frame.pc++]; - // fallthrough - goto case Token.SETVAR; - - case Token.SETVAR: - if (!frame.useActivation) { - vars [indexReg] = stack [stackTop]; - varDbls [indexReg] = sDbl [stackTop]; - } - else { - object val = stack [stackTop]; - if (val == DBL_MRK) - val = sDbl [stackTop]; - stringReg = frame.idata.argNames [indexReg]; - frame.scope.Put (stringReg, frame.scope, val); - } - - goto Loop; - goto case Icode_GETVAR1; - - case Icode_GETVAR1: - indexReg = iCode [frame.pc++]; - // fallthrough - goto case Token.GETVAR; - - case Token.GETVAR: - ++stackTop; - if (!frame.useActivation) { - stack [stackTop] = vars [indexReg]; - sDbl [stackTop] = varDbls [indexReg]; - } - else { - stringReg = frame.idata.argNames [indexReg]; - stack [stackTop] = frame.scope.Get (stringReg, frame.scope); - } - - goto Loop; - goto case Icode_VAR_INC_DEC; - - case Icode_VAR_INC_DEC: { - // indexReg : varindex - ++stackTop; - int incrDecrMask = iCode [frame.pc]; - if (!frame.useActivation) { - stack [stackTop] = DBL_MRK; - object varValue = vars [indexReg]; - double d; - if (varValue == DBL_MRK) { - d = varDbls [indexReg]; - } - else { - d = ScriptConvert.ToNumber (varValue); - vars [indexReg] = DBL_MRK; - } - double d2 = ((incrDecrMask & Node.DECR_FLAG) == 0) ? d + 1.0 : d - 1.0; - varDbls [indexReg] = d2; - sDbl [stackTop] = ((incrDecrMask & Node.POST_FLAG) == 0) ? d2 : d; - } - else { - string varName = frame.idata.argNames [indexReg]; - stack [stackTop] = ScriptRuntime.nameIncrDecr (frame.scope, varName, incrDecrMask); - } - ++frame.pc; - - goto Loop; - } - goto case Icode_ZERO; - - case Icode_ZERO: - ++stackTop; - stack [stackTop] = DBL_MRK; - sDbl [stackTop] = 0; - - goto Loop; - goto case Icode_ONE; - - case Icode_ONE: - ++stackTop; - stack [stackTop] = DBL_MRK; - sDbl [stackTop] = 1; - - goto Loop; - goto case Token.NULL; - - case Token.NULL: - stack [++stackTop] = null; - - goto Loop; - goto case Token.THIS; - - case Token.THIS: - stack [++stackTop] = frame.thisObj; - - goto Loop; - goto case Token.THISFN; - - case Token.THISFN: - stack [++stackTop] = frame.fnOrScript; - - goto Loop; - goto case Token.FALSE; - - case Token.FALSE: - stack [++stackTop] = false; - - goto Loop; - goto case Token.TRUE; - - case Token.TRUE: - stack [++stackTop] = true; - - goto Loop; - goto case Icode_UNDEF; - - case Icode_UNDEF: - stack [++stackTop] = undefined; - - goto Loop; - goto case Token.ENTERWITH; - - case Token.ENTERWITH: { - object lhs = stack [stackTop]; - if (lhs == DBL_MRK) - lhs = sDbl [stackTop]; - --stackTop; - frame.scope = ScriptRuntime.enterWith (lhs, cx, frame.scope); - - goto Loop; - } - goto case Token.LEAVEWITH; - - case Token.LEAVEWITH: - frame.scope = ScriptRuntime.leaveWith (frame.scope); - - goto Loop; - goto case Token.CATCH_SCOPE; - - case Token.CATCH_SCOPE: { - // stack top: exception object - // stringReg: name of exception variable - // indexReg: local for exception scope - --stackTop; - indexReg += frame.localShift; - - bool afterFirstScope = (frame.idata.itsICode [frame.pc] != 0); - - Exception caughtException = (Exception)stack [stackTop + 1]; - IScriptable lastCatchScope; - if (!afterFirstScope) { - lastCatchScope = null; - } - else { - lastCatchScope = (IScriptable)stack [indexReg]; - } - stack [indexReg] = ScriptRuntime.NewCatchScope (caughtException, lastCatchScope, stringReg, cx, frame.scope); - ++frame.pc; - - goto Loop; - } - goto case Token.ENUM_INIT_KEYS; - - case Token.ENUM_INIT_KEYS: - case Token.ENUM_INIT_VALUES: { - object lhs = stack [stackTop]; - if (lhs == DBL_MRK) - lhs = sDbl [stackTop]; - --stackTop; - indexReg += frame.localShift; - - if (lhs is IIdEnumerable) { - stack [indexReg] = ((IIdEnumerable)lhs).GetEnumeration (cx, (op == Token.ENUM_INIT_VALUES)); - } - else { - stack [indexReg] = new IdEnumeration (lhs, cx, (op == Token.ENUM_INIT_VALUES)); - } - - - goto Loop; - } - goto case Token.ENUM_NEXT; - - case Token.ENUM_NEXT: - case Token.ENUM_ID: { - indexReg += frame.localShift; - IdEnumeration val = (IdEnumeration)stack [indexReg]; - ++stackTop; - stack [stackTop] = (op == Token.ENUM_NEXT) ? val.MoveNext () : val.Current (cx); - - goto Loop; - } - goto case Token.REF_SPECIAL; - - case Token.REF_SPECIAL: { - //stringReg: name of special property - object obj = stack [stackTop]; - if (obj == DBL_MRK) - obj = sDbl [stackTop]; - stack [stackTop] = ScriptRuntime.specialRef (obj, stringReg, cx); - - goto Loop; - } - goto case Token.REF_MEMBER; - - case Token.REF_MEMBER: { - //indexReg: flags - object elem = stack [stackTop]; - if (elem == DBL_MRK) - elem = sDbl [stackTop]; - --stackTop; - object obj = stack [stackTop]; - if (obj == DBL_MRK) - obj = sDbl [stackTop]; - stack [stackTop] = ScriptRuntime.memberRef (obj, elem, cx, indexReg); - - goto Loop; - } - goto case Token.REF_NS_MEMBER; - - case Token.REF_NS_MEMBER: { - //indexReg: flags - object elem = stack [stackTop]; - if (elem == DBL_MRK) - elem = sDbl [stackTop]; - --stackTop; - object ns = stack [stackTop]; - if (ns == DBL_MRK) - ns = sDbl [stackTop]; - --stackTop; - object obj = stack [stackTop]; - if (obj == DBL_MRK) - obj = sDbl [stackTop]; - stack [stackTop] = ScriptRuntime.memberRef (obj, ns, elem, cx, indexReg); - - goto Loop; - } - goto case Token.REF_NAME; - - case Token.REF_NAME: { - //indexReg: flags - object name = stack [stackTop]; - if (name == DBL_MRK) - name = sDbl [stackTop]; - stack [stackTop] = ScriptRuntime.nameRef (name, cx, frame.scope, indexReg); - - goto Loop; - } - goto case Token.REF_NS_NAME; - - case Token.REF_NS_NAME: { - //indexReg: flags - object name = stack [stackTop]; - if (name == DBL_MRK) - name = sDbl [stackTop]; - --stackTop; - object ns = stack [stackTop]; - if (ns == DBL_MRK) - ns = sDbl [stackTop]; - stack [stackTop] = ScriptRuntime.nameRef (ns, name, cx, frame.scope, indexReg); - - goto Loop; - } - goto case Icode_SCOPE_LOAD; - - case Icode_SCOPE_LOAD: - indexReg += frame.localShift; - frame.scope = (IScriptable)stack [indexReg]; - - goto Loop; - goto case Icode_SCOPE_SAVE; - - case Icode_SCOPE_SAVE: - indexReg += frame.localShift; - stack [indexReg] = frame.scope; - - goto Loop; - goto case Icode_CLOSURE_EXPR; - - case Icode_CLOSURE_EXPR: { - InterpretedFunction fun = InterpretedFunction.createFunction (cx, frame.scope, frame.fnOrScript, indexReg); - stack [++stackTop] = fun; - } - goto Loop; - goto case Icode_CLOSURE_STMT; - - case Icode_CLOSURE_STMT: - initFunction (cx, frame.scope, frame.fnOrScript, indexReg); - - goto Loop; - goto case Token.REGEXP; - - case Token.REGEXP: - stack [++stackTop] = frame.scriptRegExps [indexReg]; - - goto Loop; - goto case Icode_LITERAL_NEW; - - case Icode_LITERAL_NEW: - // indexReg: number of values in the literal - ++stackTop; - stack [stackTop] = new object [indexReg]; - sDbl [stackTop] = 0; - - goto Loop; - goto case Icode_LITERAL_SET; - - case Icode_LITERAL_SET: { - object value = stack [stackTop]; - if (value == DBL_MRK) - value = sDbl [stackTop]; - --stackTop; - int i = (int)sDbl [stackTop]; - ((object [])stack [stackTop]) [i] = value; - sDbl [stackTop] = i + 1; - - goto Loop; - } - goto case Token.ARRAYLIT; - - case Token.ARRAYLIT: - case Icode_SPARE_ARRAYLIT: - case Token.OBJECTLIT: { - object [] data = (object [])stack [stackTop]; - object val; - if (op == Token.OBJECTLIT) { - object [] ids = (object [])frame.idata.literalIds [indexReg]; - val = ScriptRuntime.newObjectLiteral (ids, data, cx, frame.scope); - } - else { - int [] skipIndexces = null; - if (op == Icode_SPARE_ARRAYLIT) { - skipIndexces = (int [])frame.idata.literalIds [indexReg]; - } - val = ScriptRuntime.newArrayLiteral (data, skipIndexces, cx, frame.scope); - } - stack [stackTop] = val; - - goto Loop; - } - goto case Icode_ENTERDQ; - - case Icode_ENTERDQ: { - object lhs = stack [stackTop]; - if (lhs == DBL_MRK) - lhs = sDbl [stackTop]; - --stackTop; - frame.scope = ScriptRuntime.enterDotQuery (lhs, frame.scope); - - goto Loop; - } - goto case Icode_LEAVEDQ; - - case Icode_LEAVEDQ: { - bool valBln = stack_boolean (frame, stackTop); - object x = ScriptRuntime.updateDotQuery (valBln, frame.scope); - if (x != null) { - stack [stackTop] = x; - frame.scope = ScriptRuntime.leaveDotQuery (frame.scope); - frame.pc += 2; - - goto Loop; - } - // reset stack and PC to code after ENTERDQ - --stackTop; - - goto jumplessRun_brk; - } - - case Token.DEFAULTNAMESPACE: { - object value = stack [stackTop]; - if (value == DBL_MRK) - value = sDbl [stackTop]; - stack [stackTop] = ScriptRuntime.setDefaultNamespace (value, cx); - - goto Loop; - } - goto case Token.ESCXMLATTR; - - case Token.ESCXMLATTR: { - object value = stack [stackTop]; - if (value != DBL_MRK) { - stack [stackTop] = ScriptRuntime.escapeAttributeValue (value, cx); - } - - goto Loop; - } - goto case Token.ESCXMLTEXT; - - case Token.ESCXMLTEXT: { - object value = stack [stackTop]; - if (value != DBL_MRK) { - stack [stackTop] = ScriptRuntime.escapeTextValue (value, cx); - } - - goto Loop; - } - goto case Icode_LINE; - - case Icode_DEBUGGER: { - if (frame.debuggerFrame != null) { - frame.debuggerFrame.OnDebuggerStatement(cx); - } - break; - } - - case Icode_LINE: - frame.pcSourceLineStart = frame.pc; - if (frame.debuggerFrame != null) { - int line = GetIndex (iCode, frame.pc); - frame.debuggerFrame.OnLineChange (cx, line); - } - frame.pc += 2; - - goto Loop; - goto case Icode_REG_IND_C0; - - case Icode_REG_IND_C0: - indexReg = 0; - - goto Loop; - goto case Icode_REG_IND_C1; - - case Icode_REG_IND_C1: - indexReg = 1; - - goto Loop; - goto case Icode_REG_IND_C2; - - case Icode_REG_IND_C2: - indexReg = 2; - - goto Loop; - goto case Icode_REG_IND_C3; - - case Icode_REG_IND_C3: - indexReg = 3; - - goto Loop; - goto case Icode_REG_IND_C4; - - case Icode_REG_IND_C4: - indexReg = 4; - - goto Loop; - goto case Icode_REG_IND_C5; - - case Icode_REG_IND_C5: - indexReg = 5; - - goto Loop; - goto case Icode_REG_IND1; - - case Icode_REG_IND1: - indexReg = 0xFF & iCode [frame.pc]; - ++frame.pc; - - goto Loop; - goto case Icode_REG_IND2; - - case Icode_REG_IND2: - indexReg = GetIndex (iCode, frame.pc); - frame.pc += 2; - - goto Loop; - goto case Icode_REG_IND4; - - case Icode_REG_IND4: - indexReg = GetInt (iCode, frame.pc); - frame.pc += 4; - - goto Loop; - goto case Icode_REG_STR_C0; - - case Icode_REG_STR_C0: - stringReg = strings [0]; - - goto Loop; - goto case Icode_REG_STR_C1; - - case Icode_REG_STR_C1: - stringReg = strings [1]; - - goto Loop; - goto case Icode_REG_STR_C2; - - case Icode_REG_STR_C2: - stringReg = strings [2]; - - goto Loop; - goto case Icode_REG_STR_C3; - - case Icode_REG_STR_C3: - stringReg = strings [3]; - - goto Loop; - goto case Icode_REG_STR1; - - case Icode_REG_STR1: - stringReg = strings [0xFF & iCode [frame.pc]]; - ++frame.pc; - - goto Loop; - goto case Icode_REG_STR2; - - case Icode_REG_STR2: - stringReg = strings [GetIndex (iCode, frame.pc)]; - frame.pc += 2; - - goto Loop; - goto case Icode_REG_STR4; - - case Icode_REG_STR4: - stringReg = strings [GetInt (iCode, frame.pc)]; - frame.pc += 4; - - goto Loop; - goto default; - - default: - dumpICode (frame.idata); - throw new ApplicationException ("Unknown icode : " + op + " @ pc : " + (frame.pc - 1)); - - } // end of interpreter switch - } - - jumplessRun_brk: - ; - // end of jumplessRun label block - - // This should be reachable only for jump implementation - // when pc points to encoded target offset - if (instructionCounting) { - addInstructionCount (cx, frame, 2); - } - int offset = GetShort (iCode, frame.pc); - if (offset != 0) { - // -1 accounts for pc pointing to jump opcode + 1 - frame.pc += offset - 1; - } - else { - frame.pc = frame.idata.longJumps.getExistingInt (frame.pc); - } - if (instructionCounting) { - frame.pcPrevBranch = frame.pc; - } - - goto Loop; - - Loop: - ; - } - - Loop_brk: - ; - // end of Loop: for - - ExitFrame (cx, frame, (object)null); - interpreterResult = frame.result; - interpreterResultDbl = frame.resultDbl; - if (frame.parentFrame != null) { - frame = frame.parentFrame; - if (frame.frozen) { - frame = frame.cloneFrozen (); - } - setCallResult (frame, interpreterResult, interpreterResultDbl); - interpreterResult = null; // Help GC - - goto StateLoop; - } - - goto StateLoop_brk; - } - // end of interpreter withoutExceptions: try - catch (Exception ex) { - if (throwable != null) { - // This is serious bug and it is better to track it ASAP - throw new ApplicationException (); - } - throwable = ex; - } - - withoutExceptions_brk: - - // This should be reachable only after above catch or from - // finally when it needs to propagate exception or from - // explicit throw - if (throwable == null) - Context.CodeBug (); - - // Exception type - const int EX_CATCH_STATE = 2; // Can execute JS catch - const int EX_FINALLY_STATE = 1; // Can execute JS finally - const int EX_NO_JS_STATE = 0; // Terminate JS execution - - int exState; - ContinuationJump cjump2 = null; - - if (throwable is EcmaScriptThrow) { - exState = EX_CATCH_STATE; - } - else if (throwable is EcmaScriptError) { - // an offical ECMA error object, - exState = EX_CATCH_STATE; - } - else if (throwable is EcmaScriptRuntimeException) { - exState = EX_CATCH_STATE; - } - else if (throwable is EcmaScriptException) { - exState = EX_FINALLY_STATE; - } - else if (throwable is Exception) { - exState = EX_NO_JS_STATE; - } - else { - // It must be ContinuationJump - exState = EX_FINALLY_STATE; - cjump2 = (ContinuationJump)throwable; - } - - if (instructionCounting) { - try { - addInstructionCount (cx, frame, EXCEPTION_COST); - } - catch (ApplicationException ex) { - // Error from instruction counting - // => unconditionally terminate JS - throwable = ex; - cjump2 = null; - exState = EX_NO_JS_STATE; - } - } - if (frame.debuggerFrame != null && throwable is ApplicationException) { - // Call debugger only for RuntimeException - ApplicationException rex = (ApplicationException)throwable; - try { - frame.debuggerFrame.OnExceptionThrown (cx, rex); - } - catch (Exception ex) { - // Any exception from debugger - // => unconditionally terminate JS - throwable = ex; - cjump2 = null; - exState = EX_NO_JS_STATE; - } - } - - for (; ; ) { - if (exState != EX_NO_JS_STATE) { - bool onlyFinally = (exState != EX_CATCH_STATE); - indexReg = getExceptionHandler (frame, onlyFinally); - if (indexReg >= 0) { - // We caught an exception, restart the loop - // with exception pending the processing at the loop - // start - - goto StateLoop; - } - } - // No allowed execption handlers in this frame, unwind - // to parent and try to look there - - ExitFrame (cx, frame, throwable); - - frame = frame.parentFrame; - if (frame == null) { - break; - } - if (cjump2 != null && cjump2.branchFrame == frame) { - // Continuation branch point was hit, - // restart the state loop to reenter continuation - indexReg = -1; - - goto StateLoop; - } - } - - // No more frames, rethrow the exception or deal with continuation - if (cjump2 != null) { - if (cjump2.branchFrame != null) { - // The above loop should locate the top frame - Context.CodeBug (); - } - if (cjump2.capturedFrame != null) { - // Restarting detached continuation - indexReg = -1; - - goto StateLoop; - } - // Return continuation result to the caller - interpreterResult = cjump2.result; - interpreterResultDbl = cjump2.resultDbl; - throwable = null; - } - - goto StateLoop_brk; - - StateLoop: - ; - } - - StateLoop_brk: - ; - // end of StateLoop: for(;;) - - // Do cleanups/restorations before the final return or throw - - if (cx.previousInterpreterInvocations != null && cx.previousInterpreterInvocations.size () != 0) { - cx.lastInterpreterFrame = cx.previousInterpreterInvocations.pop (); - } - else { - // It was the last interpreter frame on the stack - cx.lastInterpreterFrame = null; - // Force GC of the value cx.previousInterpreterInvocations - cx.previousInterpreterInvocations = null; - } - - if (throwable != null) { - if (throwable is Helpers.StackOverflowVerifierException) { - throw Context.ReportRuntimeError ( - ScriptRuntime.GetMessage ("mag.too.deep.parser.recursion")); - } - throw (Exception)throwable; - } - - return (interpreterResult != DBL_MRK) ? interpreterResult : - interpreterResultDbl; - } - - static void initFrame (Context cx, IScriptable callerScope, IScriptable thisObj, object [] args, double [] argsDbl, int argShift, int argCount, InterpretedFunction fnOrScript, CallFrame parentFrame, CallFrame frame) - { - InterpreterData idata = fnOrScript.idata; - - bool useActivation = idata.itsNeedsActivation; - DebugFrame debuggerFrame = null; - if (cx.m_Debugger != null) { - debuggerFrame = cx.m_Debugger.GetFrame (cx, idata); - if (debuggerFrame != null) { - useActivation = true; - } - } - - if (useActivation) { - // Copy args to new array to pass to enterActivationFunction - // or debuggerFrame.onEnter - if (argsDbl != null) { - args = GetArgsArray (args, argsDbl, argShift, argCount); - } - argShift = 0; - argsDbl = null; - } - - IScriptable scope; - if (idata.itsFunctionType != 0) { - if (!idata.useDynamicScope) { - scope = fnOrScript.ParentScope; - } - else { - scope = callerScope; - } - - if (useActivation) { - scope = ScriptRuntime.createFunctionActivation (fnOrScript, scope, args); - } - } - else { - scope = callerScope; - ScriptRuntime.initScript (fnOrScript, thisObj, cx, scope, fnOrScript.idata.evalScriptFlag); - } - - if (idata.itsNestedFunctions != null) { - if (idata.itsFunctionType != 0 && !idata.itsNeedsActivation) - Context.CodeBug (); - for (int i = 0; i < idata.itsNestedFunctions.Length; i++) { - InterpreterData fdata = idata.itsNestedFunctions [i]; - if (fdata.itsFunctionType == FunctionNode.FUNCTION_STATEMENT) { - initFunction (cx, scope, fnOrScript, i); - } - } - } - - IScriptable [] scriptRegExps = null; - if (idata.itsRegExpLiterals != null) { - // Wrapped regexps for functions are stored in - // InterpretedFunction - // but for script which should not contain references to scope - // the regexps re-wrapped during each script execution - if (idata.itsFunctionType != 0) { - scriptRegExps = fnOrScript.functionRegExps; - } - else { - scriptRegExps = fnOrScript.createRegExpWraps (cx, scope); - } - } - - // Initialize args, vars, locals and stack - - int emptyStackTop = idata.itsMaxVars + idata.itsMaxLocals - 1; - int maxFrameArray = idata.itsMaxFrameArray; - if (maxFrameArray != emptyStackTop + idata.itsMaxStack + 1) - Context.CodeBug (); - - object [] stack; - double [] sDbl; - bool stackReuse; - if (frame.stack != null && maxFrameArray <= frame.stack.Length) { - // Reuse stacks from old frame - stackReuse = true; - stack = frame.stack; - sDbl = frame.sDbl; - } - else { - stackReuse = false; - stack = new object [maxFrameArray]; - sDbl = new double [maxFrameArray]; - } - - int definedArgs = idata.argCount; - if (definedArgs > argCount) { - definedArgs = argCount; - } - - // Fill the frame structure - - frame.parentFrame = parentFrame; - frame.frameIndex = (parentFrame == null) ? 0 : parentFrame.frameIndex + 1; - if (frame.frameIndex > cx.MaximumInterpreterStackDepth) - throw ScriptRuntime.TypeErrorById ("msg.stackoverflow"); - frame.frozen = false; - - frame.fnOrScript = fnOrScript; - frame.idata = idata; - - frame.stack = stack; - frame.sDbl = sDbl; - frame.varSource = frame; - frame.localShift = idata.itsMaxVars; - frame.emptyStackTop = emptyStackTop; - - frame.debuggerFrame = debuggerFrame; - frame.useActivation = useActivation; - - frame.thisObj = thisObj; - frame.scriptRegExps = scriptRegExps; - - // Initialize initial values of variables that change during - // interpretation. - frame.result = Undefined.Value; - frame.pc = 0; - frame.pcPrevBranch = 0; - frame.pcSourceLineStart = idata.firstLinePC; - frame.scope = scope; - - frame.savedStackTop = emptyStackTop; - frame.savedCallOp = 0; - - Array.Copy (args, argShift, stack, 0, definedArgs); - if (argsDbl != null) { - Array.Copy (argsDbl, argShift, sDbl, 0, definedArgs); - } - for (int i = definedArgs; i != idata.itsMaxVars; ++i) { - stack [i] = Undefined.Value; - } - if (stackReuse) { - // Clean the stack part and space beyond stack if any - // of the old array to allow to GC objects there - for (int i = emptyStackTop + 1; i != stack.Length; ++i) { - stack [i] = null; - } - } - - EnterFrame (cx, frame, args); - } - - static bool isFrameEnterExitRequired (CallFrame frame) - { - return frame.debuggerFrame != null || frame.idata.itsNeedsActivation; - } - - static void EnterFrame (Context cx, CallFrame frame, object [] args) - { - if (frame.debuggerFrame != null) { - frame.debuggerFrame.OnEnter (cx, frame.scope, frame.thisObj, args); - } - if (frame.idata.itsNeedsActivation) { - // Enter activation only when itsNeedsActivation true, not when - // useActivation holds since debugger should not interfere - // with activation chaining - ScriptRuntime.enterActivationFunction (cx, frame.scope); - } - } - - static void ExitFrame (Context cx, CallFrame frame, object throwable) - { - if (frame.idata.itsNeedsActivation) { - ScriptRuntime.exitActivationFunction (cx); - } - - if (frame.debuggerFrame != null) { - try { - if (throwable is Exception) { - frame.debuggerFrame.OnExit (cx, true, throwable); - } - else { - object result; - ContinuationJump cjump = (ContinuationJump)throwable; - if (cjump == null) { - result = frame.result; - } - else { - result = cjump.result; - } - if (result == UniqueTag.DoubleMark) { - double resultDbl; - if (cjump == null) { - resultDbl = frame.resultDbl; - } - else { - resultDbl = cjump.resultDbl; - } - result = resultDbl; - } - frame.debuggerFrame.OnExit (cx, false, result); - } - } - catch (Exception ex) { - Console.Error.WriteLine ("USAGE WARNING: onExit terminated with exception"); - Console.Error.WriteLine (ex.ToString ()); - } - } - } - - static void setCallResult (CallFrame frame, object callResult, double callResultDbl) - { - if (frame.savedCallOp == Token.CALL) { - frame.stack [frame.savedStackTop] = callResult; - frame.sDbl [frame.savedStackTop] = callResultDbl; - } - else if (frame.savedCallOp == Token.NEW) { - // If construct returns scriptable, - // then it replaces on stack top saved original instance - // of the object. - if (callResult is IScriptable) { - frame.stack [frame.savedStackTop] = callResult; - } - } - else { - Context.CodeBug (); - } - frame.savedCallOp = 0; - } - - static void captureContinuation (Context cx, CallFrame frame, int stackTop) - { - Continuation c = new Continuation (); - ScriptRuntime.setObjectProtoAndParent (c, ScriptRuntime.getTopCallScope (cx)); - - // Make sure that all frames upstack frames are frozen - CallFrame x = frame.parentFrame; - while (x != null && !x.frozen) { - x.frozen = true; - // Allow to GC unused stack space - for (int i = x.savedStackTop + 1; i != x.stack.Length; ++i) { - // Allow to GC unused stack space - x.stack [i] = null; - } - if (x.savedCallOp == Token.CALL) { - // the call will always overwrite the stack top with the result - x.stack [x.savedStackTop] = null; - } - else { - if (x.savedCallOp != Token.NEW) - Context.CodeBug (); - // the new operator uses stack top to store the constructed - // object so it shall not be cleared: see comments in - // setCallResult - } - x = x.parentFrame; - } - - c.initImplementation (frame.parentFrame); - frame.stack [stackTop] = c; - } - - static int stack_int32 (CallFrame frame, int i) - { - object x = frame.stack [i]; - double value; - if (x == UniqueTag.DoubleMark) { - value = frame.sDbl [i]; - } - else { - value = ScriptConvert.ToNumber (x); - } - return ScriptConvert.ToInt32 (value); - } - - static double stack_double (CallFrame frame, int i) - { - object x = frame.stack [i]; - if (x != UniqueTag.DoubleMark) { - return ScriptConvert.ToNumber (x); - } - else { - return frame.sDbl [i]; - } - } - - static bool stack_boolean (CallFrame frame, int i) - { - object x = frame.stack [i]; - if (x is bool) { - return (bool)x; - } - else if (x == UniqueTag.DoubleMark) { - double d = frame.sDbl [i]; - return !double.IsNaN (d) && d != 0.0; - } - else if (x == null || x == Undefined.Value) { - return false; - } - else if (CliHelper.IsNumber (x)) { - double d = Convert.ToDouble (x); - return (!double.IsNaN (d) && d != 0.0); - } - else { - return ScriptConvert.ToBoolean (x); - } - } - - static void DoAdd (object [] stack, double [] sDbl, int stackTop, Context cx) - { - object rhs = stack [stackTop + 1]; - object lhs = stack [stackTop]; - double d; - bool leftRightOrder; - if (rhs == UniqueTag.DoubleMark) { - d = sDbl [stackTop + 1]; - if (lhs == UniqueTag.DoubleMark) { - sDbl [stackTop] += d; - return; - } - leftRightOrder = true; - // fallthrough to object + number code - } - else if (lhs == UniqueTag.DoubleMark) { - d = sDbl [stackTop]; - lhs = rhs; - leftRightOrder = false; - // fallthrough to object + number code - } - else { - if (lhs is IScriptable || rhs is IScriptable) { - stack [stackTop] = ScriptRuntime.Add (lhs, rhs, cx); - } - else if (lhs is string) { - string lstr = (string)lhs; - string rstr = ScriptConvert.ToString (rhs); - stack [stackTop] = string.Concat (lstr, rstr); - } - else if (rhs is string) { - string lstr = ScriptConvert.ToString (lhs); - string rstr = (string)rhs; - stack [stackTop] = string.Concat (lstr, rstr); - } - else { - double lDbl = (CliHelper.IsNumber (lhs)) ? Convert.ToDouble (lhs) : ScriptConvert.ToNumber (lhs); - double rDbl = (CliHelper.IsNumber (rhs)) ? Convert.ToDouble (rhs) : ScriptConvert.ToNumber (rhs); - stack [stackTop] = UniqueTag.DoubleMark; - sDbl [stackTop] = lDbl + rDbl; - } - return; - } - - // handle object(lhs) + number(d) code - if (lhs is IScriptable) { - rhs = d; - if (!leftRightOrder) { - object tmp = lhs; - lhs = rhs; - rhs = tmp; - } - stack [stackTop] = ScriptRuntime.Add (lhs, rhs, cx); - } - else if (lhs is string) { - string lstr = (string)lhs; - string rstr = ScriptConvert.ToString (d); - if (leftRightOrder) { - stack [stackTop] = string.Concat (lstr, rstr); - } - else { - stack [stackTop] = string.Concat (rstr, lstr); - } - } - else { - double lDbl = (CliHelper.IsNumber (lhs)) ? Convert.ToDouble (lhs) : ScriptConvert.ToNumber (lhs); - stack [stackTop] = UniqueTag.DoubleMark; - sDbl [stackTop] = lDbl + d; - } - } - - void addGotoOp (int gotoOp) - { - sbyte [] array = itsData.itsICode; - int top = itsICodeTop; - if (top + 3 > array.Length) { - array = increaseICodeCapasity (3); - } - array [top] = (sbyte)gotoOp; - // Offset would written later - itsICodeTop = top + 1 + 2; - } - - - static object [] GetArgsArray (object [] stack, double [] sDbl, int shift, int count) - { - if (count == 0) { - return ScriptRuntime.EmptyArgs; - } - object [] args = new object [count]; - for (int i = 0; i != count; ++i, ++shift) { - object val = stack [shift]; - if (val == UniqueTag.DoubleMark) { - val = sDbl [shift]; - } - args [i] = val; - } - return args; - } - - static void addInstructionCount (Context cx, CallFrame frame, int extra) - { - cx.instructionCount += frame.pc - frame.pcPrevBranch + extra; - if (cx.instructionCount > cx.instructionThreshold) { - cx.ObserveInstructionCount (cx.instructionCount); - cx.instructionCount = 0; - } - } - - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +using EcmaScript.NET.Debugging; +using EcmaScript.NET.Collections; + +namespace EcmaScript.NET +{ + + public class Interpreter + { + + // Additional interpreter-specific codes + + const int Icode_DUP = -1; + const int Icode_DUP2 = -2; + const int Icode_SWAP = -3; + const int Icode_POP = -4; + const int Icode_POP_RESULT = -5; + const int Icode_IFEQ_POP = -6; + const int Icode_VAR_INC_DEC = -7; + const int Icode_NAME_INC_DEC = -8; + const int Icode_PROP_INC_DEC = -9; + const int Icode_ELEM_INC_DEC = -10; + const int Icode_REF_INC_DEC = -11; + const int Icode_SCOPE_LOAD = -12; + const int Icode_SCOPE_SAVE = -13; + const int Icode_TYPEOFNAME = -14; + const int Icode_NAME_AND_THIS = -15; + const int Icode_PROP_AND_THIS = -16; + const int Icode_ELEM_AND_THIS = -17; + const int Icode_VALUE_AND_THIS = -18; + const int Icode_CLOSURE_EXPR = -19; + const int Icode_CLOSURE_STMT = -20; + const int Icode_CALLSPECIAL = -21; + const int Icode_RETUNDEF = -22; + const int Icode_GOSUB = -23; + const int Icode_STARTSUB = -24; + const int Icode_RETSUB = -25; + const int Icode_LINE = -26; + const int Icode_SHORTNUMBER = -27; + const int Icode_INTNUMBER = -28; + const int Icode_LITERAL_NEW = -29; + const int Icode_LITERAL_SET = -30; + const int Icode_SPARE_ARRAYLIT = -31; + const int Icode_REG_IND_C0 = -32; + const int Icode_REG_IND_C1 = -33; + const int Icode_REG_IND_C2 = -34; + const int Icode_REG_IND_C3 = -35; + const int Icode_REG_IND_C4 = -36; + const int Icode_REG_IND_C5 = -37; + const int Icode_REG_IND1 = -38; + const int Icode_REG_IND2 = -39; + const int Icode_REG_IND4 = -40; + const int Icode_REG_STR_C0 = -41; + const int Icode_REG_STR_C1 = -42; + const int Icode_REG_STR_C2 = -43; + const int Icode_REG_STR_C3 = -44; + const int Icode_REG_STR1 = -45; + const int Icode_REG_STR2 = -46; + const int Icode_REG_STR4 = -47; + const int Icode_GETVAR1 = -48; + const int Icode_SETVAR1 = -49; + const int Icode_UNDEF = -50; + const int Icode_ZERO = -51; + const int Icode_ONE = -52; + const int Icode_ENTERDQ = -53; + const int Icode_LEAVEDQ = -54; + const int Icode_TAIL_CALL = -55; + const int Icode_LOCAL_CLEAR = -56; + const int Icode_DEBUGGER = -57; + + // Last icode + const int MIN_ICODE = -57; + + + // data for parsing + + CompilerEnvirons compilerEnv; + + bool itsInFunctionFlag; + + InterpreterData itsData; + ScriptOrFnNode scriptOrFn; + int itsICodeTop; + int itsStackDepth; + int itsLineNumber; + int itsDoubleTableTop; + ObjToIntMap itsStrings = new ObjToIntMap (20); + int itsLocalTop; + + const int MIN_LABEL_TABLE_SIZE = 32; + const int MIN_FIXUP_TABLE_SIZE = 40; + int [] itsLabelTable; + int itsLabelTableTop; + // itsFixupTable[i] = (label_index << 32) | fixup_site + long [] itsFixupTable; + int itsFixupTableTop; + ObjArray itsLiteralIds = new ObjArray (); + + int itsExceptionTableTop; + const int EXCEPTION_TRY_START_SLOT = 0; + const int EXCEPTION_TRY_END_SLOT = 1; + const int EXCEPTION_HANDLER_SLOT = 2; + const int EXCEPTION_TYPE_SLOT = 3; + const int EXCEPTION_LOCAL_SLOT = 4; + const int EXCEPTION_SCOPE_SLOT = 5; + // SLOT_SIZE: space for try start/end, handler, start, handler type, + // exception local and scope local + const int EXCEPTION_SLOT_SIZE = 6; + + // ECF_ or Expression Context Flags constants: for now only TAIL is available + const int ECF_TAIL = 1 << 0; + + + internal class CallFrame : System.ICloneable + { + + internal CallFrame parentFrame; + // amount of stack frames before this one on the interpretation stack + internal int frameIndex; + // If true indicates read-only frame that is a part of continuation + internal bool frozen; + + internal InterpretedFunction fnOrScript; + internal InterpreterData idata; + + // Stack structure + // stack[0 <= i < localShift]: arguments and local variables + // stack[localShift <= i <= emptyStackTop]: used for local temporaries + // stack[emptyStackTop < i < stack.length]: stack data + // sDbl[i]: if stack[i] is UniqueTag.DoubleMark, sDbl[i] holds the number value + + internal object [] stack; + internal double [] sDbl; + + internal CallFrame varSource; // defaults to this unless continuation frame + internal int localShift; + internal int emptyStackTop; + + internal DebugFrame debuggerFrame; + internal bool useActivation; + + internal IScriptable thisObj; + internal IScriptable [] scriptRegExps; + + // The values that change during interpretation + + internal object result; + internal double resultDbl; + internal int pc; + internal int pcPrevBranch; + internal int pcSourceLineStart; + internal IScriptable scope; + + internal int savedStackTop; + internal int savedCallOp; + + internal virtual CallFrame cloneFrozen () + { + if (!frozen) + Context.CodeBug (); + + CallFrame copy = (CallFrame)Clone (); + + // clone stack but keep varSource to point to values + // from this frame to share variables. + + // TODO: STACK + copy.stack = new object [stack.Length]; + stack.CopyTo (copy.stack, 0); + copy.sDbl = new double [sDbl.Length]; + sDbl.CopyTo (copy.sDbl, 0); + + copy.frozen = false; + return copy; + } + + virtual public object Clone () + { + return base.MemberwiseClone (); + } + } + + + sealed class ContinuationJump + { + + internal CallFrame capturedFrame; + internal CallFrame branchFrame; + internal object result; + internal double resultDbl; + + internal ContinuationJump (Continuation c, CallFrame current) + { + this.capturedFrame = (CallFrame)c.Implementation; + if (this.capturedFrame == null || current == null) { + // Continuation and current execution does not share + // any frames if there is nothing to capture or + // if there is no currently executed frames + this.branchFrame = null; + } + else { + // Search for branch frame where parent frame chains starting + // from captured and current meet. + CallFrame chain1 = this.capturedFrame; + CallFrame chain2 = current; + + // First work parents of chain1 or chain2 until the same + // frame depth. + int diff = chain1.frameIndex - chain2.frameIndex; + if (diff != 0) { + if (diff < 0) { + // swap to make sure that + // chain1.frameIndex > chain2.frameIndex and diff > 0 + chain1 = current; + chain2 = this.capturedFrame; + diff = -diff; + } + do { + chain1 = chain1.parentFrame; + } + while (--diff != 0); + if (chain1.frameIndex != chain2.frameIndex) + Context.CodeBug (); + } + + // Now walk parents in parallel until a shared frame is found + // or until the root is reached. + while (chain1 != chain2 && chain1 != null) { + chain1 = chain1.parentFrame; + chain2 = chain2.parentFrame; + } + + this.branchFrame = chain1; + if (this.branchFrame != null && !this.branchFrame.frozen) + Context.CodeBug (); + } + } + } + + static string bytecodeName (int bytecode) + { + if (!validBytecode (bytecode)) { + throw new ArgumentException (Convert.ToString (bytecode)); + } + + if (!Token.printICode) { + return Convert.ToString (bytecode); + } + + if (ValidTokenCode (bytecode)) { + return Token.name (bytecode); + } + + switch (bytecode) { + + case Icode_DUP: + return "DUP"; + + case Icode_DUP2: + return "DUP2"; + + case Icode_SWAP: + return "SWAP"; + + case Icode_POP: + return "POP"; + + case Icode_POP_RESULT: + return "POP_RESULT"; + + case Icode_IFEQ_POP: + return "IFEQ_POP"; + + case Icode_VAR_INC_DEC: + return "VAR_INC_DEC"; + + case Icode_NAME_INC_DEC: + return "NAME_INC_DEC"; + + case Icode_PROP_INC_DEC: + return "PROP_INC_DEC"; + + case Icode_ELEM_INC_DEC: + return "ELEM_INC_DEC"; + + case Icode_REF_INC_DEC: + return "REF_INC_DEC"; + + case Icode_SCOPE_LOAD: + return "SCOPE_LOAD"; + + case Icode_SCOPE_SAVE: + return "SCOPE_SAVE"; + + case Icode_TYPEOFNAME: + return "TYPEOFNAME"; + + case Icode_NAME_AND_THIS: + return "NAME_AND_THIS"; + + case Icode_PROP_AND_THIS: + return "PROP_AND_THIS"; + + case Icode_ELEM_AND_THIS: + return "ELEM_AND_THIS"; + + case Icode_VALUE_AND_THIS: + return "VALUE_AND_THIS"; + + case Icode_CLOSURE_EXPR: + return "CLOSURE_EXPR"; + + case Icode_CLOSURE_STMT: + return "CLOSURE_STMT"; + + case Icode_CALLSPECIAL: + return "CALLSPECIAL"; + + case Icode_RETUNDEF: + return "RETUNDEF"; + + case Icode_GOSUB: + return "GOSUB"; + + case Icode_STARTSUB: + return "STARTSUB"; + + case Icode_RETSUB: + return "RETSUB"; + + case Icode_LINE: + return "LINE"; + + case Icode_SHORTNUMBER: + return "SHORTNUMBER"; + + case Icode_INTNUMBER: + return "INTNUMBER"; + + case Icode_LITERAL_NEW: + return "LITERAL_NEW"; + + case Icode_LITERAL_SET: + return "LITERAL_SET"; + + case Icode_SPARE_ARRAYLIT: + return "SPARE_ARRAYLIT"; + + case Icode_REG_IND_C0: + return "REG_IND_C0"; + + case Icode_REG_IND_C1: + return "REG_IND_C1"; + + case Icode_REG_IND_C2: + return "REG_IND_C2"; + + case Icode_REG_IND_C3: + return "REG_IND_C3"; + + case Icode_REG_IND_C4: + return "REG_IND_C4"; + + case Icode_REG_IND_C5: + return "REG_IND_C5"; + + case Icode_REG_IND1: + return "LOAD_IND1"; + + case Icode_REG_IND2: + return "LOAD_IND2"; + + case Icode_REG_IND4: + return "LOAD_IND4"; + + case Icode_REG_STR_C0: + return "REG_STR_C0"; + + case Icode_REG_STR_C1: + return "REG_STR_C1"; + + case Icode_REG_STR_C2: + return "REG_STR_C2"; + + case Icode_REG_STR_C3: + return "REG_STR_C3"; + + case Icode_REG_STR1: + return "LOAD_STR1"; + + case Icode_REG_STR2: + return "LOAD_STR2"; + + case Icode_REG_STR4: + return "LOAD_STR4"; + + case Icode_GETVAR1: + return "GETVAR1"; + + case Icode_SETVAR1: + return "SETVAR1"; + + case Icode_UNDEF: + return "UNDEF"; + + case Icode_ZERO: + return "ZERO"; + + case Icode_ONE: + return "ONE"; + + case Icode_ENTERDQ: + return "ENTERDQ"; + + case Icode_LEAVEDQ: + return "LEAVEDQ"; + + case Icode_TAIL_CALL: + return "TAIL_CALL"; + + case Icode_LOCAL_CLEAR: + return "LOCAL_CLEAR"; + + case Icode_DEBUGGER: + return "DEBUGGER"; + } + + // icode without name + throw new Exception (Convert.ToString (bytecode)); + } + + static bool validIcode (int icode) + { + return MIN_ICODE <= icode && icode <= -1; + } + + static bool ValidTokenCode (int token) + { + return Token.FIRST_BYTECODE_TOKEN <= token && token <= Token.LAST_BYTECODE_TOKEN; + } + + static bool validBytecode (int bytecode) + { + return validIcode (bytecode) || ValidTokenCode (bytecode); + } + + public virtual object Compile (CompilerEnvirons compilerEnv, ScriptOrFnNode tree, string encodedSource, bool returnFunction) + { + this.compilerEnv = compilerEnv; + new NodeTransformer ().transform (tree); + + if (Token.printTrees) { + System.Console.Out.WriteLine (tree.toStringTree (tree)); + } + + if (returnFunction) { + tree = tree.getFunctionNode (0); + } + + scriptOrFn = tree; + itsData = new InterpreterData (compilerEnv.LanguageVersion, scriptOrFn.SourceName, encodedSource); + itsData.topLevel = true; + + if (returnFunction) { + generateFunctionICode (); + } + else { + generateICodeFromTree (scriptOrFn); + } + + return itsData; + } + + public virtual IScript CreateScriptObject (object bytecode, object staticSecurityDomain) + { + InterpreterData idata = (InterpreterData)bytecode; + return InterpretedFunction.createScript (itsData, staticSecurityDomain); + } + + public virtual IFunction CreateFunctionObject (Context cx, IScriptable scope, object bytecode, object staticSecurityDomain) + { + InterpreterData idata = (InterpreterData)bytecode; + return InterpretedFunction.createFunction (cx, scope, itsData, staticSecurityDomain); + } + + void generateFunctionICode () + { + itsInFunctionFlag = true; + + FunctionNode theFunction = (FunctionNode)scriptOrFn; + + itsData.itsFunctionType = theFunction.FunctionType; + itsData.itsNeedsActivation = theFunction.RequiresActivation; + itsData.itsName = theFunction.FunctionName; + if (!theFunction.IgnoreDynamicScope) { + if (compilerEnv.UseDynamicScope) { + itsData.useDynamicScope = true; + } + } + + generateICodeFromTree (theFunction.LastChild); + } + + void generateICodeFromTree (Node tree) + { + generateNestedFunctions (); + + generateRegExpLiterals (); + + VisitStatement (tree); + fixLabelGotos (); + // add RETURN_RESULT only to scripts as function always ends with RETURN + if (itsData.itsFunctionType == 0) { + addToken (Token.RETURN_RESULT); + } + + if (itsData.itsICode.Length != itsICodeTop) { + // Make itsData.itsICode length exactly itsICodeTop to save memory + // and catch bugs with jumps beyound icode as early as possible + sbyte [] tmp = new sbyte [itsICodeTop]; + Array.Copy (itsData.itsICode, 0, tmp, 0, itsICodeTop); + itsData.itsICode = tmp; + } + if (itsStrings.size () == 0) { + itsData.itsStringTable = null; + } + else { + itsData.itsStringTable = new string [itsStrings.size ()]; + ObjToIntMap.Iterator iter = itsStrings.newIterator (); + for (iter.start (); !iter.done (); iter.next ()) { + string str = (string)iter.Key; + int index = iter.Value; + if (itsData.itsStringTable [index] != null) + Context.CodeBug (); + itsData.itsStringTable [index] = str; + } + } + if (itsDoubleTableTop == 0) { + itsData.itsDoubleTable = null; + } + else if (itsData.itsDoubleTable.Length != itsDoubleTableTop) { + double [] tmp = new double [itsDoubleTableTop]; + Array.Copy (itsData.itsDoubleTable, 0, tmp, 0, itsDoubleTableTop); + itsData.itsDoubleTable = tmp; + } + if (itsExceptionTableTop != 0 && itsData.itsExceptionTable.Length != itsExceptionTableTop) { + int [] tmp = new int [itsExceptionTableTop]; + Array.Copy (itsData.itsExceptionTable, 0, tmp, 0, itsExceptionTableTop); + itsData.itsExceptionTable = tmp; + } + + itsData.itsMaxVars = scriptOrFn.ParamAndVarCount; + // itsMaxFrameArray: interpret method needs this amount for its + // stack and sDbl arrays + itsData.itsMaxFrameArray = itsData.itsMaxVars + itsData.itsMaxLocals + itsData.itsMaxStack; + + itsData.argNames = scriptOrFn.ParamAndVarNames; + itsData.argCount = scriptOrFn.ParamCount; + + itsData.encodedSourceStart = scriptOrFn.EncodedSourceStart; + itsData.encodedSourceEnd = scriptOrFn.EncodedSourceEnd; + + if (itsLiteralIds.size () != 0) { + itsData.literalIds = itsLiteralIds.ToArray (); + } + + if (Token.printICode) + dumpICode (itsData); + } + + void generateNestedFunctions () + { + int functionCount = scriptOrFn.FunctionCount; + if (functionCount == 0) + return; + + InterpreterData [] array = new InterpreterData [functionCount]; + for (int i = 0; i != functionCount; i++) { + FunctionNode def = scriptOrFn.getFunctionNode (i); + Interpreter jsi = new Interpreter (); + jsi.compilerEnv = compilerEnv; + jsi.scriptOrFn = def; + jsi.itsData = new InterpreterData (itsData); + jsi.generateFunctionICode (); + array [i] = jsi.itsData; + } + itsData.itsNestedFunctions = array; + } + + void generateRegExpLiterals () + { + int N = scriptOrFn.RegexpCount; + if (N == 0) + return; + + Context cx = Context.CurrentContext; + RegExpProxy rep = cx.RegExpProxy; + object [] array = new object [N]; + for (int i = 0; i != N; i++) { + string str = scriptOrFn.getRegexpString (i); + string flags = scriptOrFn.getRegexpFlags (i); + array [i] = rep.Compile (cx, str, flags); + } + itsData.itsRegExpLiterals = array; + } + + void updateLineNumber (Node node) + { + int lineno = node.Lineno; + if (lineno != itsLineNumber && lineno >= 0) { + if (itsData.firstLinePC < 0) { + itsData.firstLinePC = lineno; + } + itsLineNumber = lineno; + addIcode (Icode_LINE); + addUint16 (lineno & 0xFFFF); + } + } + + Exception badTree (Node node) + { + throw new Exception (node.ToString ()); + } + + void VisitStatement (Node node) + { + int type = node.Type; + Node child = node.FirstChild; + switch (type) { + + + case Token.FUNCTION: { + int fnIndex = node.getExistingIntProp (Node.FUNCTION_PROP); + int fnType = scriptOrFn.getFunctionNode (fnIndex).FunctionType; + // Only function expressions or function expression + // statements needs closure code creating new function + // object on stack as function statements are initialized + // at script/function start + // In addition function expression can not present here + // at statement level, they must only present as expressions. + if (fnType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) { + addIndexOp (Icode_CLOSURE_STMT, fnIndex); + } + else { + if (fnType != FunctionNode.FUNCTION_STATEMENT) { + throw Context.CodeBug (); + } + } + } + break; + + + case Token.SCRIPT: + case Token.LABEL: + case Token.LOOP: + case Token.BLOCK: + case Token.EMPTY: + case Token.WITH: + updateLineNumber (node); + while (child != null) { + VisitStatement (child); + child = child.Next; + } + break; + + + case Token.ENTERWITH: + VisitExpression (child, 0); + addToken (Token.ENTERWITH); + stackChange (-1); + break; + + + case Token.LEAVEWITH: + addToken (Token.LEAVEWITH); + break; + + + case Token.LOCAL_BLOCK: { + int local = allocLocal (); + node.putIntProp (Node.LOCAL_PROP, local); + updateLineNumber (node); + while (child != null) { + VisitStatement (child); + child = child.Next; + } + addIndexOp (Icode_LOCAL_CLEAR, local); + releaseLocal (local); + } + break; + + case Token.DEBUGGER: + updateLineNumber (node); + addIcode (Icode_DEBUGGER); + break; + + case Token.SWITCH: + updateLineNumber (node); { + // See comments in IRFactory.createSwitch() for description + // of SWITCH node + Node switchNode = (Node.Jump)node; + VisitExpression (child, 0); + for (Node.Jump caseNode = (Node.Jump)child.Next; caseNode != null; caseNode = (Node.Jump)caseNode.Next) { + if (caseNode.Type != Token.CASE) + throw badTree (caseNode); + Node test = caseNode.FirstChild; + addIcode (Icode_DUP); + stackChange (1); + VisitExpression (test, 0); + addToken (Token.SHEQ); + stackChange (-1); + // If true, Icode_IFEQ_POP will jump and remove case + // value from stack + addGoto (caseNode.target, Icode_IFEQ_POP); + stackChange (-1); + } + addIcode (Icode_POP); + stackChange (-1); + } + break; + + + case Token.TARGET: + markTargetLabel (node); + break; + + + case Token.IFEQ: + case Token.IFNE: { + Node target = ((Node.Jump)node).target; + VisitExpression (child, 0); + addGoto (target, type); + stackChange (-1); + } + break; + + + case Token.GOTO: { + Node target = ((Node.Jump)node).target; + addGoto (target, type); + } + break; + + + case Token.JSR: { + Node target = ((Node.Jump)node).target; + addGoto (target, Icode_GOSUB); + } + break; + + + case Token.FINALLY: { + // Account for incomming GOTOSUB address + stackChange (1); + int finallyRegister = getLocalBlockRef (node); + addIndexOp (Icode_STARTSUB, finallyRegister); + stackChange (-1); + while (child != null) { + VisitStatement (child); + child = child.Next; + } + addIndexOp (Icode_RETSUB, finallyRegister); + } + break; + + + case Token.EXPR_VOID: + case Token.EXPR_RESULT: + updateLineNumber (node); + VisitExpression (child, 0); + addIcode ((type == Token.EXPR_VOID) ? Icode_POP : Icode_POP_RESULT); + stackChange (-1); + break; + + + case Token.TRY: { + Node.Jump tryNode = (Node.Jump)node; + int exceptionObjectLocal = getLocalBlockRef (tryNode); + int scopeLocal = allocLocal (); + + addIndexOp (Icode_SCOPE_SAVE, scopeLocal); + + int tryStart = itsICodeTop; + while (child != null) { + VisitStatement (child); + child = child.Next; + } + + Node catchTarget = tryNode.target; + if (catchTarget != null) { + int catchStartPC = itsLabelTable [getTargetLabel (catchTarget)]; + addExceptionHandler (tryStart, catchStartPC, catchStartPC, false, exceptionObjectLocal, scopeLocal); + } + Node finallyTarget = tryNode.Finally; + if (finallyTarget != null) { + int finallyStartPC = itsLabelTable [getTargetLabel (finallyTarget)]; + addExceptionHandler (tryStart, finallyStartPC, finallyStartPC, true, exceptionObjectLocal, scopeLocal); + } + + addIndexOp (Icode_LOCAL_CLEAR, scopeLocal); + releaseLocal (scopeLocal); + } + break; + + + case Token.CATCH_SCOPE: { + int localIndex = getLocalBlockRef (node); + int scopeIndex = node.getExistingIntProp (Node.CATCH_SCOPE_PROP); + string name = child.String; + child = child.Next; + VisitExpression (child, 0); // load expression object + addStringPrefix (name); + addIndexPrefix (localIndex); + addToken (Token.CATCH_SCOPE); + addUint8 (scopeIndex != 0 ? 1 : 0); + stackChange (-1); + } + break; + + + case Token.THROW: + updateLineNumber (node); + VisitExpression (child, 0); + addToken (Token.THROW); + addUint16 (itsLineNumber & 0xFFFF); + stackChange (-1); + break; + + + case Token.RETHROW: + updateLineNumber (node); + addIndexOp (Token.RETHROW, getLocalBlockRef (node)); + break; + + + case Token.RETURN: + updateLineNumber (node); + if (child != null) { + VisitExpression (child, ECF_TAIL); + addToken (Token.RETURN); + stackChange (-1); + } + else { + addIcode (Icode_RETUNDEF); + } + break; + + + case Token.RETURN_RESULT: + updateLineNumber (node); + addToken (Token.RETURN_RESULT); + break; + + + case Token.ENUM_INIT_KEYS: + case Token.ENUM_INIT_VALUES: + VisitExpression (child, 0); + addIndexOp (type, getLocalBlockRef (node)); + stackChange (-1); + break; + + + default: + throw badTree (node); + + } + + if (itsStackDepth != 0) { + throw Context.CodeBug (); + } + } + + bool VisitExpressionOptimized (Node node, int contextFlags) + { + return false; +#if FALKSE + if (node.Type == Token.ADD) { + Node next = node.Next; + if (next == null) + return false; + switch (next.Type) { + case Token.NAME: + case Token.STRING: + return true; + } + } + return false; +#endif + } + + void VisitExpression (Node node, int contextFlags) + { + if (VisitExpressionOptimized (node, contextFlags)) + return; + + int type = node.Type; + Node child = node.FirstChild; + int savedStackDepth = itsStackDepth; + switch (type) { + + + case Token.FUNCTION: { + int fnIndex = node.getExistingIntProp (Node.FUNCTION_PROP); + FunctionNode fn = scriptOrFn.getFunctionNode (fnIndex); + + // See comments in visitStatement for Token.FUNCTION case + switch (fn.FunctionType) { + case FunctionNode.FUNCTION_EXPRESSION: + addIndexOp (Icode_CLOSURE_EXPR, fnIndex); + break; + default: + throw Context.CodeBug (); + } + + stackChange (1); + } + break; + + + case Token.LOCAL_LOAD: { + int localIndex = getLocalBlockRef (node); + addIndexOp (Token.LOCAL_LOAD, localIndex); + stackChange (1); + } + break; + + + case Token.COMMA: { + Node lastChild = node.LastChild; + while (child != lastChild) { + VisitExpression (child, 0); + addIcode (Icode_POP); + stackChange (-1); + child = child.Next; + } + // Preserve tail context flag if any + VisitExpression (child, contextFlags & ECF_TAIL); + } + break; + + + case Token.USE_STACK: + // Indicates that stack was modified externally, + // like placed catch object + stackChange (1); + break; + + + case Token.REF_CALL: + case Token.CALL: + case Token.NEW: { + if (type == Token.NEW) { + VisitExpression (child, 0); + } + else { + generateCallFunAndThis (child); + } + int argCount = 0; + while ((child = child.Next) != null) { + VisitExpression (child, 0); + ++argCount; + } + int callType = node.getIntProp (Node.SPECIALCALL_PROP, Node.NON_SPECIALCALL); + if (callType != Node.NON_SPECIALCALL) { + // embed line number and source filename + addIndexOp (Icode_CALLSPECIAL, argCount); + addUint8 (callType); + addUint8 (type == Token.NEW ? 1 : 0); + addUint16 (itsLineNumber & 0xFFFF); + } + else { + if (type == Token.CALL) { + if ((contextFlags & ECF_TAIL) != 0) { + type = Icode_TAIL_CALL; + } + } + addIndexOp (type, argCount); + } + // adjust stack + if (type == Token.NEW) { + // new: f, args -> result + stackChange (-argCount); + } + else { + // call: f, thisObj, args -> result + // ref_call: f, thisObj, args -> ref + stackChange (-1 - argCount); + } + if (argCount > itsData.itsMaxCalleeArgs) { + itsData.itsMaxCalleeArgs = argCount; + } + } + break; + + + case Token.AND: + case Token.OR: { + VisitExpression (child, 0); + addIcode (Icode_DUP); + stackChange (1); + int afterSecondJumpStart = itsICodeTop; + int jump = (type == Token.AND) ? Token.IFNE : Token.IFEQ; + addGotoOp (jump); + stackChange (-1); + addIcode (Icode_POP); + stackChange (-1); + child = child.Next; + // Preserve tail context flag if any + VisitExpression (child, contextFlags & ECF_TAIL); + resolveForwardGoto (afterSecondJumpStart); + } + break; + + + case Token.HOOK: { + Node ifThen = child.Next; + Node ifElse = ifThen.Next; + VisitExpression (child, 0); + int elseJumpStart = itsICodeTop; + addGotoOp (Token.IFNE); + ; + stackChange (-1); + // Preserve tail context flag if any + VisitExpression (ifThen, contextFlags & ECF_TAIL); + int afterElseJumpStart = itsICodeTop; + addGotoOp (Token.GOTO); + resolveForwardGoto (elseJumpStart); + itsStackDepth = savedStackDepth; + // Preserve tail context flag if any + VisitExpression (ifElse, contextFlags & ECF_TAIL); + resolveForwardGoto (afterElseJumpStart); + } + break; + + + case Token.GETPROP: + VisitExpression (child, 0); + child = child.Next; + addStringOp (Token.GETPROP, child.String); + break; + + + case Token.ADD: + case Token.GETELEM: + case Token.DELPROP: + case Token.BITAND: + case Token.BITOR: + case Token.BITXOR: + case Token.LSH: + case Token.RSH: + case Token.URSH: + case Token.SUB: + case Token.MOD: + case Token.DIV: + case Token.MUL: + case Token.EQ: + case Token.NE: + case Token.SHEQ: + case Token.SHNE: + case Token.IN: + case Token.INSTANCEOF: + case Token.LE: + case Token.LT: + case Token.GE: + case Token.GT: + VisitExpression (child, 0); + VisitExpression (child.Next, 0); + addToken (type); + stackChange (-1); + break; + + + case Token.POS: + case Token.NEG: + case Token.NOT: + case Token.BITNOT: + case Token.TYPEOF: + case Token.VOID: + VisitExpression (child, 0); + if (type == Token.VOID) { + addIcode (Icode_POP); + addIcode (Icode_UNDEF); + } + else { + addToken (type); + } + break; + + + case Token.GET_REF: + case Token.DEL_REF: + VisitExpression (child, 0); + addToken (type); + break; + + + case Token.SETPROP: + case Token.SETPROP_OP: + case Token.SETPROP_GETTER: + case Token.SETPROP_SETTER: + { + VisitExpression (child, 0); + child = child.Next; + string property = child.String; + child = child.Next; + if (type == Token.SETPROP_OP) { + addIcode (Icode_DUP); + stackChange (1); + addStringOp (Token.GETPROP, property); + // Compensate for the following USE_STACK + stackChange (-1); + } + VisitExpression (child, 0); + addStringOp ((type == Token.SETPROP_OP) ? Token.SETPROP : type, property); + stackChange (-1); + } + break; + + + case Token.SETELEM: + case Token.SETELEM_OP: + VisitExpression (child, 0); + child = child.Next; + VisitExpression (child, 0); + child = child.Next; + if (type == Token.SETELEM_OP) { + addIcode (Icode_DUP2); + stackChange (2); + addToken (Token.GETELEM); + stackChange (-1); + // Compensate for the following USE_STACK + stackChange (-1); + } + VisitExpression (child, 0); + addToken (Token.SETELEM); + stackChange (-2); + break; + + + case Token.SET_REF: + case Token.SET_REF_OP: + VisitExpression (child, 0); + child = child.Next; + if (type == Token.SET_REF_OP) { + addIcode (Icode_DUP); + stackChange (1); + addToken (Token.GET_REF); + // Compensate for the following USE_STACK + stackChange (-1); + } + VisitExpression (child, 0); + addToken (Token.SET_REF); + stackChange (-1); + break; + + + case Token.SETNAME: { + string name = child.String; + VisitExpression (child, 0); + child = child.Next; + VisitExpression (child, 0); + addStringOp (Token.SETNAME, name); + stackChange (-1); + } + break; + + + case Token.TYPEOFNAME: { + string name = node.String; + int index = -1; + // use typeofname if an activation frame exists + // since the vars all exist there instead of in jregs + if (itsInFunctionFlag && !itsData.itsNeedsActivation) + index = scriptOrFn.getParamOrVarIndex (name); + if (index == -1) { + addStringOp (Icode_TYPEOFNAME, name); + stackChange (1); + } + else { + addVarOp (Token.GETVAR, index); + stackChange (1); + addToken (Token.TYPEOF); + } + } + break; + + + case Token.BINDNAME: + case Token.NAME: + case Token.STRING: + addStringOp (type, node.String); + stackChange (1); + break; + + + case Token.INC: + case Token.DEC: + VisitIncDec (node, child); + break; + + + case Token.NUMBER: { + double num = node.Double; + int inum = (int)num; + if (inum == num) { + if (inum == 0) { + addIcode (Icode_ZERO); + // Check for negative zero + if (1.0 / num < 0.0) { + addToken (Token.NEG); + } + } + else if (inum == 1) { + addIcode (Icode_ONE); + } + else if ((short)inum == inum) { + addIcode (Icode_SHORTNUMBER); + // write short as uin16 bit pattern + addUint16 (inum & 0xFFFF); + } + else { + addIcode (Icode_INTNUMBER); + addInt (inum); + } + } + else { + int index = GetDoubleIndex (num); + addIndexOp (Token.NUMBER, index); + } + stackChange (1); + } + break; + + + case Token.GETVAR: { + if (itsData.itsNeedsActivation) + Context.CodeBug (); + string name = node.String; + int index = scriptOrFn.getParamOrVarIndex (name); + addVarOp (Token.GETVAR, index); + stackChange (1); + } + break; + + + case Token.SETVAR: { + if (itsData.itsNeedsActivation) + Context.CodeBug (); + string name = child.String; + child = child.Next; + VisitExpression (child, 0); + int index = scriptOrFn.getParamOrVarIndex (name); + addVarOp (Token.SETVAR, index); + } + break; + + + + case Token.NULL: + case Token.THIS: + case Token.THISFN: + case Token.FALSE: + case Token.TRUE: + addToken (type); + stackChange (1); + break; + + + case Token.ENUM_NEXT: + case Token.ENUM_ID: + addIndexOp (type, getLocalBlockRef (node)); + stackChange (1); + break; + + + case Token.REGEXP: { + int index = node.getExistingIntProp (Node.REGEXP_PROP); + addIndexOp (Token.REGEXP, index); + stackChange (1); + } + break; + + + case Token.ARRAYLIT: + case Token.OBJECTLIT: + VisitLiteral (node, child); + break; + + + case Token.REF_SPECIAL: + VisitExpression (child, 0); + addStringOp (type, (string)node.getProp (Node.NAME_PROP)); + break; + + + case Token.REF_MEMBER: + case Token.REF_NS_MEMBER: + case Token.REF_NAME: + case Token.REF_NS_NAME: { + int memberTypeFlags = node.getIntProp (Node.MEMBER_TYPE_PROP, 0); + // generate possible target, possible namespace and member + int childCount = 0; + do { + VisitExpression (child, 0); + ++childCount; + child = child.Next; + } + while (child != null); + addIndexOp (type, memberTypeFlags); + stackChange (1 - childCount); + } + break; + + + case Token.DOTQUERY: { + int queryPC; + updateLineNumber (node); + VisitExpression (child, 0); + addIcode (Icode_ENTERDQ); + stackChange (-1); + queryPC = itsICodeTop; + VisitExpression (child.Next, 0); + addBackwardGoto (Icode_LEAVEDQ, queryPC); + } + break; + + + case Token.DEFAULTNAMESPACE: + case Token.ESCXMLATTR: + case Token.ESCXMLTEXT: + VisitExpression (child, 0); + addToken (type); + break; + + default: + throw badTree (node); + + } + //if (savedStackDepth + 1 != itsStackDepth) { + // EcmaScriptHelper.CodeBug(); + //} + } + + void generateCallFunAndThis (Node left) + { + // Generate code to place on stack function and thisObj + int type = left.Type; + switch (type) { + + case Token.NAME: { + string name = left.String; + // stack: ... -> ... function thisObj + addStringOp (Icode_NAME_AND_THIS, name); + stackChange (2); + break; + } + + case Token.GETPROP: + case Token.GETELEM: { + Node target = left.FirstChild; + VisitExpression (target, 0); + Node id = target.Next; + if (type == Token.GETPROP) { + string property = id.String; + // stack: ... target -> ... function thisObj + addStringOp (Icode_PROP_AND_THIS, property); + stackChange (1); + } + else { + VisitExpression (id, 0); + // stack: ... target id -> ... function thisObj + addIcode (Icode_ELEM_AND_THIS); + } + break; + } + + default: + // Including Token.GETVAR + VisitExpression (left, 0); + // stack: ... value -> ... function thisObj + addIcode (Icode_VALUE_AND_THIS); + stackChange (1); + break; + + } + } + + void VisitIncDec (Node node, Node child) + { + int incrDecrMask = node.getExistingIntProp (Node.INCRDECR_PROP); + int childType = child.Type; + switch (childType) { + + case Token.GETVAR: { + if (itsData.itsNeedsActivation) + Context.CodeBug (); + string name = child.String; + int i = scriptOrFn.getParamOrVarIndex (name); + addVarOp (Icode_VAR_INC_DEC, i); + addUint8 (incrDecrMask); + stackChange (1); + break; + } + + case Token.NAME: { + string name = child.String; + addStringOp (Icode_NAME_INC_DEC, name); + addUint8 (incrDecrMask); + stackChange (1); + break; + } + + case Token.GETPROP: { + Node obj = child.FirstChild; + VisitExpression (obj, 0); + string property = obj.Next.String; + addStringOp (Icode_PROP_INC_DEC, property); + addUint8 (incrDecrMask); + break; + } + + case Token.GETELEM: { + Node obj = child.FirstChild; + VisitExpression (obj, 0); + Node index = obj.Next; + VisitExpression (index, 0); + addIcode (Icode_ELEM_INC_DEC); + addUint8 (incrDecrMask); + stackChange (-1); + break; + } + + case Token.GET_REF: { + Node rf = child.FirstChild; + VisitExpression (rf, 0); + addIcode (Icode_REF_INC_DEC); + addUint8 (incrDecrMask); + break; + } + + default: { + throw badTree (node); + } + + } + } + + void VisitLiteral (Node node, Node child) + { + int type = node.Type; + int count; + object [] propertyIds = null; + if (type == Token.ARRAYLIT) { + count = 0; + for (Node n = child; n != null; n = n.Next) { + ++count; + } + } + else if (type == Token.OBJECTLIT) { + propertyIds = (object [])node.getProp (Node.OBJECT_IDS_PROP); + count = propertyIds.Length; + } + else { + throw badTree (node); + } + addIndexOp (Icode_LITERAL_NEW, count); + stackChange (1); + while (child != null) { + VisitExpression (child, 0); + addIcode (Icode_LITERAL_SET); + stackChange (-1); + child = child.Next; + } + if (type == Token.ARRAYLIT) { + int [] skipIndexes = (int [])node.getProp (Node.SKIP_INDEXES_PROP); + if (skipIndexes == null) { + addToken (Token.ARRAYLIT); + } + else { + int index = itsLiteralIds.size (); + itsLiteralIds.add (skipIndexes); + addIndexOp (Icode_SPARE_ARRAYLIT, index); + } + } + else { + int index = itsLiteralIds.size (); + itsLiteralIds.add (propertyIds); + addIndexOp (Token.OBJECTLIT, index); + } + } + + int getLocalBlockRef (Node node) + { + Node localBlock = (Node)node.getProp (Node.LOCAL_BLOCK_PROP); + return localBlock.getExistingIntProp (Node.LOCAL_PROP); + } + + int getTargetLabel (Node target) + { + int label = target.labelId (); + if (label != -1) { + return label; + } + label = itsLabelTableTop; + if (itsLabelTable == null || label == itsLabelTable.Length) { + if (itsLabelTable == null) { + itsLabelTable = new int [MIN_LABEL_TABLE_SIZE]; + } + else { + int [] tmp = new int [itsLabelTable.Length * 2]; + Array.Copy (itsLabelTable, 0, tmp, 0, label); + itsLabelTable = tmp; + } + } + itsLabelTableTop = label + 1; + itsLabelTable [label] = -1; + + target.labelId (label); + return label; + } + + void markTargetLabel (Node target) + { + int label = getTargetLabel (target); + if (itsLabelTable [label] != -1) { + // Can mark label only once + Context.CodeBug (); + } + itsLabelTable [label] = itsICodeTop; + } + + void addGoto (Node target, int gotoOp) + { + int label = getTargetLabel (target); + if (!(label < itsLabelTableTop)) + Context.CodeBug (); + int targetPC = itsLabelTable [label]; + + if (targetPC != -1) { + addBackwardGoto (gotoOp, targetPC); + } + else { + int gotoPC = itsICodeTop; + addGotoOp (gotoOp); + int top = itsFixupTableTop; + if (itsFixupTable == null || top == itsFixupTable.Length) { + if (itsFixupTable == null) { + itsFixupTable = new long [MIN_FIXUP_TABLE_SIZE]; + } + else { + long [] tmp = new long [itsFixupTable.Length * 2]; + Array.Copy (itsFixupTable, 0, tmp, 0, top); + itsFixupTable = tmp; + } + } + itsFixupTableTop = top + 1; + itsFixupTable [top] = ((long)label << 32) | (uint)gotoPC; + } + } + + void fixLabelGotos () + { + for (int i = 0; i < itsFixupTableTop; i++) { + long fixup = itsFixupTable [i]; + int label = (int)(fixup >> 32); + int jumpSource = (int)fixup; + int pc = itsLabelTable [label]; + if (pc == -1) { + // Unlocated label + throw Context.CodeBug (); + } + resolveGoto (jumpSource, pc); + } + itsFixupTableTop = 0; + } + + void addBackwardGoto (int gotoOp, int jumpPC) + { + int fromPC = itsICodeTop; + // Ensure that this is a jump backward + if (fromPC <= jumpPC) + throw Context.CodeBug (); + addGotoOp (gotoOp); + resolveGoto (fromPC, jumpPC); + } + + + void resolveForwardGoto (int fromPC) + { + // Ensure that forward jump skips at least self bytecode + if (itsICodeTop < fromPC + 3) + throw Context.CodeBug (); + resolveGoto (fromPC, itsICodeTop); + } + + void resolveGoto (int fromPC, int jumpPC) + { + int offset = jumpPC - fromPC; + // Ensure that jumps do not overlap + if (0 <= offset && offset <= 2) + throw Context.CodeBug (); + int offsetSite = fromPC + 1; + if (offset != (short)offset) { + if (itsData.longJumps == null) { + itsData.longJumps = new UintMap (); + } + itsData.longJumps.put (offsetSite, jumpPC); + offset = 0; + } + sbyte [] array = itsData.itsICode; + array [offsetSite] = (sbyte)(offset >> 8); + array [offsetSite + 1] = (sbyte)offset; + } + + void addToken (int token) + { + if (!ValidTokenCode (token)) + throw Context.CodeBug (); + addUint8 (token); + } + + void addIcode (int icode) + { + if (!validIcode (icode)) + throw Context.CodeBug (); + // Write negative icode as uint8 bits + addUint8 (icode & 0xFF); + } + + void addUint8 (int value) + { + if ((value & ~0xFF) != 0) + throw Context.CodeBug (); + sbyte [] array = itsData.itsICode; + int top = itsICodeTop; + if (top == array.Length) { + array = increaseICodeCapasity (1); + } + array [top] = (sbyte)value; + itsICodeTop = top + 1; + } + + void addUint16 (int value) + { + if ((value & ~0xFFFF) != 0) + throw Context.CodeBug (); + sbyte [] array = itsData.itsICode; + int top = itsICodeTop; + if (top + 2 > array.Length) { + array = increaseICodeCapasity (2); + } + array [top] = (sbyte)((uint)value >> 8); + array [top + 1] = (sbyte)value; + itsICodeTop = top + 2; + } + + void addInt (int i) + { + sbyte [] array = itsData.itsICode; + int top = itsICodeTop; + if (top + 4 > array.Length) { + array = increaseICodeCapasity (4); + } + array [top] = (sbyte)((uint)i >> 24); + array [top + 1] = (sbyte)((uint)i >> 16); + array [top + 2] = (sbyte)((uint)i >> 8); + array [top + 3] = (sbyte)i; + itsICodeTop = top + 4; + } + + int GetDoubleIndex (double num) + { + int index = itsDoubleTableTop; + if (index == 0) { + itsData.itsDoubleTable = new double [64]; + } + else if (itsData.itsDoubleTable.Length == index) { + double [] na = new double [index * 2]; + Array.Copy (itsData.itsDoubleTable, 0, na, 0, index); + itsData.itsDoubleTable = na; + } + itsData.itsDoubleTable [index] = num; + itsDoubleTableTop = index + 1; + return index; + } + + void addVarOp (int op, int varIndex) + { + switch (op) { + + case Token.GETVAR: + case Token.SETVAR: + if (varIndex < 128) { + addIcode (op == Token.GETVAR ? Icode_GETVAR1 : Icode_SETVAR1); + addUint8 (varIndex); + return; + } + // fallthrough + goto case Icode_VAR_INC_DEC; + + case Icode_VAR_INC_DEC: + addIndexOp (op, varIndex); + return; + } + throw Context.CodeBug (); + } + + void addStringOp (int op, string str) + { + addStringPrefix (str); + if (validIcode (op)) { + addIcode (op); + } + else { + addToken (op); + } + } + + void addIndexOp (int op, int index) + { + addIndexPrefix (index); + if (validIcode (op)) { + addIcode (op); + } + else { + addToken (op); + } + } + + void addStringPrefix (string str) + { + int index = itsStrings.Get (str, -1); + if (index == -1) { + index = itsStrings.size (); + itsStrings.put (str, index); + } + if (index < 4) { + addIcode (Icode_REG_STR_C0 - index); + } + else if (index <= 0xFF) { + addIcode (Icode_REG_STR1); + addUint8 (index); + } + else if (index <= 0xFFFF) { + addIcode (Icode_REG_STR2); + addUint16 (index); + } + else { + addIcode (Icode_REG_STR4); + addInt (index); + } + } + + void addIndexPrefix (int index) + { + if (index < 0) + Context.CodeBug (); + if (index < 6) { + addIcode (Icode_REG_IND_C0 - index); + } + else if (index <= 0xFF) { + addIcode (Icode_REG_IND1); + addUint8 (index); + } + else if (index <= 0xFFFF) { + addIcode (Icode_REG_IND2); + addUint16 (index); + } + else { + addIcode (Icode_REG_IND4); + addInt (index); + } + } + + void addExceptionHandler (int icodeStart, int icodeEnd, int handlerStart, bool isFinally, int exceptionObjectLocal, int scopeLocal) + { + int top = itsExceptionTableTop; + int [] table = itsData.itsExceptionTable; + if (table == null) { + if (top != 0) + Context.CodeBug (); + table = new int [EXCEPTION_SLOT_SIZE * 2]; + itsData.itsExceptionTable = table; + } + else if (table.Length == top) { + table = new int [table.Length * 2]; + Array.Copy (itsData.itsExceptionTable, 0, table, 0, top); + itsData.itsExceptionTable = table; + } + table [top + EXCEPTION_TRY_START_SLOT] = icodeStart; + table [top + EXCEPTION_TRY_END_SLOT] = icodeEnd; + table [top + EXCEPTION_HANDLER_SLOT] = handlerStart; + table [top + EXCEPTION_TYPE_SLOT] = isFinally ? 1 : 0; + table [top + EXCEPTION_LOCAL_SLOT] = exceptionObjectLocal; + table [top + EXCEPTION_SCOPE_SLOT] = scopeLocal; + + itsExceptionTableTop = top + EXCEPTION_SLOT_SIZE; + } + + sbyte [] increaseICodeCapasity (int extraSize) + { + int capacity = itsData.itsICode.Length; + int top = itsICodeTop; + if (top + extraSize <= capacity) + throw Context.CodeBug (); + capacity *= 2; + if (top + extraSize > capacity) { + capacity = top + extraSize; + } + sbyte [] array = new sbyte [capacity]; + Array.Copy (itsData.itsICode, 0, array, 0, top); + itsData.itsICode = array; + return array; + } + + void stackChange (int change) + { + if (change <= 0) { + itsStackDepth += change; + } + else { + int newDepth = itsStackDepth + change; + if (newDepth > itsData.itsMaxStack) { + itsData.itsMaxStack = newDepth; + } + itsStackDepth = newDepth; + } + } + + int allocLocal () + { + int localSlot = itsLocalTop; + ++itsLocalTop; + if (itsLocalTop > itsData.itsMaxLocals) { + itsData.itsMaxLocals = itsLocalTop; + } + return localSlot; + } + + void releaseLocal (int localSlot) + { + --itsLocalTop; + if (localSlot != itsLocalTop) + Context.CodeBug (); + } + + static int GetShort (sbyte [] iCode, int pc) + { + return (iCode [pc] << 8) | (iCode [pc + 1] & 0xFF); + } + + static int GetIndex (sbyte [] iCode, int pc) + { + return ((iCode [pc] & 0xFF) << 8) | (iCode [pc + 1] & 0xFF); + } + + static int GetInt (sbyte [] iCode, int pc) + { + return (iCode [pc] << 24) | ((iCode [pc + 1] & 0xFF) << 16) | ((iCode [pc + 2] & 0xFF) << 8) | (iCode [pc + 3] & 0xFF); + } + + static int getExceptionHandler (CallFrame frame, bool onlyFinally) + { + int [] exceptionTable = frame.idata.itsExceptionTable; + if (exceptionTable == null) { + // No exception handlers + return -1; + } + + // Icode switch in the interpreter increments PC immediately + // and it is necessary to subtract 1 from the saved PC + // to point it before the start of the next instruction. + int pc = frame.pc - 1; + + // OPT: use binary search + int best = -1, bestStart = 0, bestEnd = 0; + for (int i = 0; i != exceptionTable.Length; i += EXCEPTION_SLOT_SIZE) { + int start = exceptionTable [i + EXCEPTION_TRY_START_SLOT]; + int end = exceptionTable [i + EXCEPTION_TRY_END_SLOT]; + if (!(start <= pc && pc < end)) { + continue; + } + if (onlyFinally && exceptionTable [i + EXCEPTION_TYPE_SLOT] != 1) { + continue; + } + if (best >= 0) { + // Since handlers always nest and they never have shared end + // although they can share start it is sufficient to compare + // handlers ends + if (bestEnd < end) { + continue; + } + // Check the above assumption + if (bestStart > start) + Context.CodeBug (); // should be nested + if (bestEnd == end) + Context.CodeBug (); // no ens sharing + } + best = i; + bestStart = start; + bestEnd = end; + } + return best; + } + + static void dumpICode (InterpreterData idata) + { + if (!Token.printICode) { + return; + } + + sbyte [] iCode = idata.itsICode; + int iCodeLength = iCode.Length; + string [] strings = idata.itsStringTable; + + System.IO.TextWriter sw = Console.Out; + sw.WriteLine ("ICode dump, for " + idata.itsName + ", length = " + iCodeLength); + sw.WriteLine ("MaxStack = " + idata.itsMaxStack); + + int indexReg = 0; + for (int pc = 0; pc < iCodeLength; ) { + sw.Flush (); + sw.Write (" [" + pc + "] "); + int token = iCode [pc]; + int icodeLength = bytecodeSpan (token); + string tname = bytecodeName (token); + int old_pc = pc; + ++pc; + switch (token) { + + default: + if (icodeLength != 1) + Context.CodeBug (); + sw.WriteLine (tname); + break; + + + + case Icode_GOSUB: + case Token.GOTO: + case Token.IFEQ: + case Token.IFNE: + case Icode_IFEQ_POP: + case Icode_LEAVEDQ: { + int newPC = pc + GetShort (iCode, pc) - 1; + sw.WriteLine (tname + " " + newPC); + pc += 2; + break; + } + + case Icode_VAR_INC_DEC: + case Icode_NAME_INC_DEC: + case Icode_PROP_INC_DEC: + case Icode_ELEM_INC_DEC: + case Icode_REF_INC_DEC: { + int incrDecrType = iCode [pc]; + sw.WriteLine (tname + " " + incrDecrType); + ++pc; + break; + } + + + case Icode_CALLSPECIAL: { + int callType = iCode [pc] & 0xFF; + bool isNew = (iCode [pc + 1] != 0); + int line = GetIndex (iCode, pc + 2); + sw.WriteLine (tname + " " + callType + " " + isNew + " " + indexReg + " " + line); + pc += 4; + break; + } + + + case Token.CATCH_SCOPE: { + bool afterFisrtFlag = (iCode [pc] != 0); + sw.WriteLine (tname + " " + afterFisrtFlag); + ++pc; + } + break; + + case Token.REGEXP: + sw.WriteLine (tname + " " + idata.itsRegExpLiterals [indexReg]); + break; + + case Token.OBJECTLIT: + case Icode_SPARE_ARRAYLIT: + sw.WriteLine (tname + " " + idata.literalIds [indexReg]); + break; + + case Icode_CLOSURE_EXPR: + case Icode_CLOSURE_STMT: + sw.WriteLine (tname + " " + idata.itsNestedFunctions [indexReg]); + break; + + case Token.CALL: + case Icode_TAIL_CALL: + case Token.REF_CALL: + case Token.NEW: + sw.WriteLine (tname + ' ' + indexReg); + break; + + case Token.THROW: { + int line = GetIndex (iCode, pc); + sw.WriteLine (tname + " : " + line); + pc += 2; + break; + } + + case Icode_SHORTNUMBER: { + int value = GetShort (iCode, pc); + sw.WriteLine (tname + " " + value); + pc += 2; + break; + } + + case Icode_INTNUMBER: { + int value = GetInt (iCode, pc); + sw.WriteLine (tname + " " + value); + pc += 4; + break; + } + + case Token.NUMBER: { + double value = idata.itsDoubleTable [indexReg]; + sw.WriteLine (tname + " " + value); + pc += 2; + break; + } + + case Icode_LINE: { + int line = GetIndex (iCode, pc); + sw.WriteLine (tname + " : " + line); + pc += 2; + break; + } + + case Icode_REG_STR1: { + string str = strings [0xFF & iCode [pc]]; + sw.WriteLine (tname + " \"" + str + '"'); + ++pc; + break; + } + + case Icode_REG_STR2: { + string str = strings [GetIndex (iCode, pc)]; + sw.WriteLine (tname + " \"" + str + '"'); + pc += 2; + break; + } + + case Icode_REG_STR4: { + string str = strings [GetInt (iCode, pc)]; + sw.WriteLine (tname + " \"" + str + '"'); + pc += 4; + break; + } + + case Icode_REG_IND1: { + indexReg = 0xFF & iCode [pc]; + sw.WriteLine (tname + " " + indexReg); + ++pc; + break; + } + + case Icode_REG_IND2: { + indexReg = GetIndex (iCode, pc); + sw.WriteLine (tname + " " + indexReg); + pc += 2; + break; + } + + case Icode_REG_IND4: { + indexReg = GetInt (iCode, pc); + sw.WriteLine (tname + " " + indexReg); + pc += 4; + break; + } + + case Icode_GETVAR1: + case Icode_SETVAR1: + indexReg = iCode [pc]; + sw.WriteLine (tname + " " + indexReg); + ++pc; + break; + } + if (old_pc + icodeLength != pc) + Context.CodeBug (); + } + + int [] table = idata.itsExceptionTable; + if (table != null) { + sw.WriteLine ("Exception handlers: " + table.Length / EXCEPTION_SLOT_SIZE); + for (int i = 0; i != table.Length; i += EXCEPTION_SLOT_SIZE) { + int tryStart = table [i + EXCEPTION_TRY_START_SLOT]; + int tryEnd = table [i + EXCEPTION_TRY_END_SLOT]; + int handlerStart = table [i + EXCEPTION_HANDLER_SLOT]; + int type = table [i + EXCEPTION_TYPE_SLOT]; + int exceptionLocal = table [i + EXCEPTION_LOCAL_SLOT]; + int scopeLocal = table [i + EXCEPTION_SCOPE_SLOT]; + + sw.WriteLine (" tryStart=" + tryStart + " tryEnd=" + tryEnd + " handlerStart=" + handlerStart + " type=" + (type == 0 ? "catch" : "finally") + " exceptionLocal=" + exceptionLocal); + } + } + sw.Flush (); + } + + static int bytecodeSpan (int bytecode) + { + switch (bytecode) { + + case Token.THROW: + // source line + return 1 + 2; + + + case Icode_GOSUB: + case Token.GOTO: + case Token.IFEQ: + case Token.IFNE: + case Icode_IFEQ_POP: + case Icode_LEAVEDQ: + // target pc offset + return 1 + 2; + + + case Icode_CALLSPECIAL: + // call type + // is new + // line number + return 1 + 1 + 1 + 2; + + + case Token.CATCH_SCOPE: + // scope flag + return 1 + 1; + + + case Icode_VAR_INC_DEC: + case Icode_NAME_INC_DEC: + case Icode_PROP_INC_DEC: + case Icode_ELEM_INC_DEC: + case Icode_REF_INC_DEC: + // type of ++/-- + return 1 + 1; + + + case Icode_SHORTNUMBER: + // short number + return 1 + 2; + + + case Icode_INTNUMBER: + // int number + return 1 + 4; + + + case Icode_REG_IND1: + // ubyte index + return 1 + 1; + + + case Icode_REG_IND2: + // ushort index + return 1 + 2; + + + case Icode_REG_IND4: + // int index + return 1 + 4; + + + case Icode_REG_STR1: + // ubyte string index + return 1 + 1; + + + case Icode_REG_STR2: + // ushort string index + return 1 + 2; + + + case Icode_REG_STR4: + // int string index + return 1 + 4; + + + case Icode_GETVAR1: + case Icode_SETVAR1: + // byte var index + return 1 + 1; + + + case Icode_LINE: + // line number + return 1 + 2; + } + + if (!validBytecode (bytecode)) + throw Context.CodeBug (); + + return 1; + } + + internal static int [] getLineNumbers (InterpreterData data) + { + UintMap presentLines = new UintMap (); + + sbyte [] iCode = data.itsICode; + int iCodeLength = iCode.Length; + for (int pc = 0; pc != iCodeLength; ) { + int bytecode = iCode [pc]; + int span = bytecodeSpan (bytecode); + if (bytecode == Icode_LINE) { + if (span != 3) + Context.CodeBug (); + int line = GetIndex (iCode, pc + 1); + presentLines.put (line, 0); + } + pc += span; + } + + return presentLines.Keys; + } + + internal static void captureInterpreterStackInfo (EcmaScriptException ex) + { + Context cx = Context.CurrentContext; + if (cx == null || cx.lastInterpreterFrame == null) { + // No interpreter invocations + ex.m_InterpreterStackInfo = null; + ex.m_InterpreterLineData = null; + return; + } + // has interpreter frame on the stack + CallFrame [] array; + if (cx.previousInterpreterInvocations == null || cx.previousInterpreterInvocations.size () == 0) { + array = new CallFrame [1]; + } + else { + int previousCount = cx.previousInterpreterInvocations.size (); + if (cx.previousInterpreterInvocations.peek () == cx.lastInterpreterFrame) { + // It can happen if exception was generated after + // frame was pushed to cx.previousInterpreterInvocations + // but before assignment to cx.lastInterpreterFrame. + // In this case frames has to be ignored. + --previousCount; + } + array = new CallFrame [previousCount + 1]; + cx.previousInterpreterInvocations.ToArray (array); + } + array [array.Length - 1] = (CallFrame)cx.lastInterpreterFrame; + + int interpreterFrameCount = 0; + for (int i = 0; i != array.Length; ++i) { + interpreterFrameCount += 1 + array [i].frameIndex; + } + + int [] linePC = new int [interpreterFrameCount]; + // Fill linePC with pc positions from all interpreter frames. + // Start from the most nested frame + int linePCIndex = interpreterFrameCount; + for (int i = array.Length; i != 0; ) { + --i; + CallFrame frame = array [i]; + while (frame != null) { + --linePCIndex; + linePC [linePCIndex] = frame.pcSourceLineStart; + frame = frame.parentFrame; + } + } + if (linePCIndex != 0) + Context.CodeBug (); + + ex.m_InterpreterStackInfo = array; + ex.m_InterpreterLineData = linePC; + } + + internal static string GetSourcePositionFromStack (Context cx, int [] linep) + { + CallFrame frame = (CallFrame)cx.lastInterpreterFrame; + InterpreterData idata = frame.idata; + if (frame.pcSourceLineStart >= 0) { + linep [0] = GetIndex (idata.itsICode, frame.pcSourceLineStart); + } + else { + linep [0] = 0; + } + return idata.itsSourceFile; + } + + + internal static string GetStack (EcmaScriptException ex) + { + System.Text.StringBuilder sb = new System.Text.StringBuilder (); + + CallFrame [] array = (CallFrame [])ex.m_InterpreterStackInfo; + if (array == null) // TODO: When does this happen? + return sb.ToString (); + + int [] linePC = ex.m_InterpreterLineData; + int arrayIndex = array.Length; + int linePCIndex = linePC.Length; + + while (arrayIndex != 0) { + --arrayIndex; + + CallFrame frame = array [arrayIndex]; + while (frame != null) { + if (linePCIndex == 0) + Context.CodeBug (); + --linePCIndex; + InterpreterData idata = frame.idata; + + if (sb.Length > 0) + sb.Append (Environment.NewLine); + sb.Append ("\tat script"); + if (idata.itsName != null && idata.itsName.Length != 0) { + sb.Append ('.'); + sb.Append (idata.itsName); + } + sb.Append ('('); + sb.Append (idata.itsSourceFile); + int pc = linePC [linePCIndex]; + if (pc >= 0) { + // Include line info only if available + sb.Append (':'); + sb.Append (GetIndex (idata.itsICode, pc)); + } + sb.Append (')'); + + + frame = frame.parentFrame; + + + } + } + + return sb.ToString (); + } + + internal static string getPatchedStack (EcmaScriptException ex, string nativeStackTrace) + { + string tag = "EcmaScript.NET.Interpreter.interpretLoop"; + System.Text.StringBuilder sb = new System.Text.StringBuilder (nativeStackTrace.Length + 1000); + string lineSeparator = System.Environment.NewLine; + + CallFrame [] array = (CallFrame [])ex.m_InterpreterStackInfo; + if (array == null) // TODO: when does this happen? + return sb.ToString (); + + int [] linePC = ex.m_InterpreterLineData; + int arrayIndex = array.Length; + int linePCIndex = linePC.Length; + int offset = 0; + while (arrayIndex != 0) { + --arrayIndex; + int pos = nativeStackTrace.IndexOf (tag, offset); + if (pos < 0) { + break; + } + + // Skip tag length + pos += tag.Length; + // Skip until the end of line + for (; pos != nativeStackTrace.Length; ++pos) { + char c = nativeStackTrace [pos]; + if (c == '\n' || c == '\r') { + break; + } + } + sb.Append (nativeStackTrace.Substring (offset, (pos) - (offset))); + offset = pos; + + CallFrame frame = array [arrayIndex]; + while (frame != null) { + if (linePCIndex == 0) + Context.CodeBug (); + --linePCIndex; + InterpreterData idata = frame.idata; + sb.Append (lineSeparator); + sb.Append ("\tat script"); + if (idata.itsName != null && idata.itsName.Length != 0) { + sb.Append ('.'); + sb.Append (idata.itsName); + } + sb.Append ('('); + sb.Append (idata.itsSourceFile); + int pc = linePC [linePCIndex]; + if (pc >= 0) { + // Include line info only if available + sb.Append (':'); + sb.Append (GetIndex (idata.itsICode, pc)); + } + sb.Append (')'); + frame = frame.parentFrame; + } + } + sb.Append (nativeStackTrace.Substring (offset)); + + return sb.ToString (); + } + + internal static string GetEncodedSource (InterpreterData idata) + { + if (idata.encodedSource == null) { + return null; + } + return idata.encodedSource.Substring (idata.encodedSourceStart, (idata.encodedSourceEnd) - (idata.encodedSourceStart)); + } + + static void initFunction (Context cx, IScriptable scope, InterpretedFunction parent, int index) + { + InterpretedFunction fn; + fn = InterpretedFunction.createFunction (cx, scope, parent, index); + ScriptRuntime.initFunction (cx, scope, fn, fn.idata.itsFunctionType, parent.idata.evalScriptFlag); + } + + internal static object Interpret (InterpretedFunction ifun, Context cx, IScriptable scope, IScriptable thisObj, object [] args) + { + using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier (128)) { + if (!ScriptRuntime.hasTopCall (cx)) + Context.CodeBug (); + + if (cx.interpreterSecurityDomain != ifun.securityDomain) { + object savedDomain = cx.interpreterSecurityDomain; + cx.interpreterSecurityDomain = ifun.securityDomain; + try { + return ifun.securityController.callWithDomain (ifun.securityDomain, cx, ifun, scope, thisObj, args); + } + finally { + cx.interpreterSecurityDomain = savedDomain; + } + } + + CallFrame frame = new CallFrame (); + initFrame (cx, scope, thisObj, args, null, 0, args.Length, ifun, null, frame); + + return InterpretLoop (cx, frame, (object)null); + } + } + + public static object restartContinuation (Continuation c, Context cx, IScriptable scope, object [] args) + { + if (!ScriptRuntime.hasTopCall (cx)) { + return ScriptRuntime.DoTopCall (c, cx, scope, null, args); + } + + object arg; + if (args.Length == 0) { + arg = Undefined.Value; + } + else { + arg = args [0]; + } + + CallFrame capturedFrame = (CallFrame)c.Implementation; + if (capturedFrame == null) { + // No frames to restart + return arg; + } + + ContinuationJump cjump = new ContinuationJump (c, null); + + cjump.result = arg; + return InterpretLoop (cx, null, cjump); + } + + static object InterpretLoop (Context cx, CallFrame frame, object throwable) + { + // throwable holds exception object to rethrow or catch + // It is also used for continuation restart in which case + // it holds ContinuationJump + + object DBL_MRK = UniqueTag.DoubleMark; + object undefined = Undefined.Value; + + bool instructionCounting = (cx.instructionThreshold != 0); + // arbitrary number to add to instructionCount when calling + // other functions + const int INVOCATION_COST = 100; + + // arbitrary exception cost for instruction counting + const int EXCEPTION_COST = 100; + + string stringReg = null; + int indexReg = -1; + + if (cx.lastInterpreterFrame != null) { + // save the top frame from the previous interpreterLoop + // invocation on the stack + if (cx.previousInterpreterInvocations == null) { + cx.previousInterpreterInvocations = new ObjArray (); + } + cx.previousInterpreterInvocations.push (cx.lastInterpreterFrame); + } + + // When restarting continuation throwable is not null and to jump + // to the code that rewind continuation state indexReg should be set + // to -1. + // With the normal call throable == null and indexReg == -1 allows to + // catch bugs with using indeReg to access array eleemnts before + // initializing indexReg. + + if (throwable != null) { + // Assert assumptions + if (!(throwable is ContinuationJump)) { + // It should be continuation + Context.CodeBug (); + } + } + + object interpreterResult = null; + double interpreterResultDbl = 0.0; + + for (; ; ) { + + try { + + if (throwable != null) { + // Recovering from exception, indexReg contains + // the index of handler + + if (indexReg >= 0) { + // Normal excepton handler, transfer + // control appropriately + + if (frame.frozen) { + // TODO: Deal with exceptios!!! + frame = frame.cloneFrozen (); + } + + int [] table = frame.idata.itsExceptionTable; + + frame.pc = table [indexReg + EXCEPTION_HANDLER_SLOT]; + if (instructionCounting) { + frame.pcPrevBranch = frame.pc; + } + + frame.savedStackTop = frame.emptyStackTop; + int scopeLocal = frame.localShift + table [indexReg + EXCEPTION_SCOPE_SLOT]; + int exLocal = frame.localShift + table [indexReg + EXCEPTION_LOCAL_SLOT]; + frame.scope = (IScriptable)frame.stack [scopeLocal]; + frame.stack [exLocal] = throwable; + + throwable = null; + } + else { + // Continuation restoration + ContinuationJump cjump = (ContinuationJump)throwable; + + // Clear throwable to indicate that execptions are OK + throwable = null; + + if (cjump.branchFrame != frame) + Context.CodeBug (); + + // Check that we have at least one frozen frame + // in the case of detached continuation restoration: + // unwind code ensure that + if (cjump.capturedFrame == null) + Context.CodeBug (); + + // Need to rewind branchFrame, capturedFrame + // and all frames in between + int rewindCount = cjump.capturedFrame.frameIndex + 1; + if (cjump.branchFrame != null) { + rewindCount -= cjump.branchFrame.frameIndex; + } + + int enterCount = 0; + CallFrame [] enterFrames = null; + + CallFrame x = cjump.capturedFrame; + for (int i = 0; i != rewindCount; ++i) { + if (!x.frozen) + Context.CodeBug (); + if (isFrameEnterExitRequired (x)) { + if (enterFrames == null) { + // Allocate enough space to store the rest + // of rewind frames in case all of them + // would require to enter + enterFrames = new CallFrame [rewindCount - i]; + } + enterFrames [enterCount] = x; + ++enterCount; + } + x = x.parentFrame; + } + + while (enterCount != 0) { + // execute enter: walk enterFrames in the reverse + // order since they were stored starting from + // the capturedFrame, not branchFrame + --enterCount; + x = enterFrames [enterCount]; + EnterFrame (cx, x, ScriptRuntime.EmptyArgs); + } + + // Continuation jump is almost done: capturedFrame + // points to the call to the function that captured + // continuation, so clone capturedFrame and + // emulate return that function with the suplied result + frame = cjump.capturedFrame.cloneFrozen (); + setCallResult (frame, cjump.result, cjump.resultDbl); + // restart the execution + } + + // Should be already cleared + if (throwable != null) + Context.CodeBug (); + } + else { + if (frame.frozen) + Context.CodeBug (); + } + + // Use local variables for constant values in frame + // for faster access + object [] stack = frame.stack; + double [] sDbl = frame.sDbl; + object [] vars = frame.varSource.stack; + double [] varDbls = frame.varSource.sDbl; + + sbyte [] iCode = frame.idata.itsICode; + string [] strings = frame.idata.itsStringTable; + + // Use local for stackTop as well. Since execption handlers + // can only exist at statement level where stack is empty, + // it is necessary to save/restore stackTop only accross + // function calls and normal returns. + int stackTop = frame.savedStackTop; + + // Store new frame in cx which is used for error reporting etc. + cx.lastInterpreterFrame = frame; + + for (; ; ) { + + // Exception handler assumes that PC is already incremented + // pass the instruction start when it searches the + // exception handler + int op = iCode [frame.pc++]; + { + switch (op) { + + case Token.THROW: { + object value = stack [stackTop]; + if (value == DBL_MRK) + value = sDbl [stackTop]; + stackTop--; + + int sourceLine = GetIndex (iCode, frame.pc); + throwable = new EcmaScriptThrow ( + value, frame.idata.itsSourceFile, sourceLine); + goto withoutExceptions_brk; + } + + case Token.RETHROW: { + indexReg += frame.localShift; + throwable = stack [indexReg]; + break; + } + + case Token.GE: + case Token.LE: + case Token.GT: + case Token.LT: { + --stackTop; + object rhs = stack [stackTop + 1]; + object lhs = stack [stackTop]; + bool valBln; + { + { + double rDbl, lDbl; + if (rhs == DBL_MRK) { + rDbl = sDbl [stackTop + 1]; + lDbl = stack_double (frame, stackTop); + } + else if (lhs == DBL_MRK) { + rDbl = ScriptConvert.ToNumber (rhs); + lDbl = sDbl [stackTop]; + } + else { + + goto number_compare_brk; + } + switch (op) { + + case Token.GE: + valBln = (lDbl >= rDbl); + + goto object_compare_brk; + + case Token.LE: + valBln = (lDbl <= rDbl); + + goto object_compare_brk; + + case Token.GT: + valBln = (lDbl > rDbl); + + goto object_compare_brk; + + case Token.LT: + valBln = (lDbl < rDbl); + + goto object_compare_brk; + + default: + throw Context.CodeBug (); + + } + } + + number_compare_brk: + ; + + switch (op) { + + case Token.GE: + valBln = ScriptRuntime.cmp_LE (rhs, lhs); + break; + + case Token.LE: + valBln = ScriptRuntime.cmp_LE (lhs, rhs); + break; + + case Token.GT: + valBln = ScriptRuntime.cmp_LT (rhs, lhs); + break; + + case Token.LT: + valBln = ScriptRuntime.cmp_LT (lhs, rhs); + break; + + default: + throw Context.CodeBug (); + + } + } + + object_compare_brk: + ; + + stack [stackTop] = valBln; + + goto Loop; + } + goto case Token.IN; + + case Token.IN: + case Token.INSTANCEOF: { + object rhs = stack [stackTop]; + if (rhs == DBL_MRK) + rhs = sDbl [stackTop]; + --stackTop; + object lhs = stack [stackTop]; + if (lhs == DBL_MRK) + lhs = sDbl [stackTop]; + bool valBln; + if (op == Token.IN) { + valBln = ScriptRuntime.In (lhs, rhs, cx); + } + else { + valBln = ScriptRuntime.InstanceOf (lhs, rhs, cx); + } + stack [stackTop] = valBln; + + goto Loop; + } + goto case Token.EQ; + + case Token.EQ: + case Token.NE: { + --stackTop; + bool valBln; + object rhs = stack [stackTop + 1]; + object lhs = stack [stackTop]; + if (rhs == DBL_MRK) { + if (lhs == DBL_MRK) { + valBln = (sDbl [stackTop] == sDbl [stackTop + 1]); + } + else { + valBln = ScriptRuntime.eqNumber (sDbl [stackTop + 1], lhs); + } + } + else { + if (lhs == DBL_MRK) { + valBln = ScriptRuntime.eqNumber (sDbl [stackTop], rhs); + } + else { + valBln = ScriptRuntime.eq (lhs, rhs); + } + } + valBln ^= (op == Token.NE); + stack [stackTop] = valBln; + + goto Loop; + } + goto case Token.SHEQ; + + case Token.SHEQ: + case Token.SHNE: { + --stackTop; + object rhs = stack [stackTop + 1]; + object lhs = stack [stackTop]; + bool valBln; + { + double rdbl, ldbl; + if (rhs == DBL_MRK) { + rdbl = sDbl [stackTop + 1]; + if (lhs == DBL_MRK) { + ldbl = sDbl [stackTop]; + } + else if (CliHelper.IsNumber (lhs)) { + ldbl = Convert.ToDouble (lhs); + } + else { + valBln = false; + + goto shallow_compare_brk; + } + } + else if (lhs == DBL_MRK) { + ldbl = sDbl [stackTop]; + if (rhs == DBL_MRK) { + rdbl = sDbl [stackTop + 1]; + } + else if (CliHelper.IsNumber (rhs)) { + rdbl = Convert.ToDouble (rhs); + } + else { + valBln = false; + + goto shallow_compare_brk; + } + } + else { + valBln = ScriptRuntime.shallowEq (lhs, rhs); + + goto shallow_compare_brk; + } + valBln = (ldbl == rdbl); + } + + shallow_compare_brk: + ; + + valBln ^= (op == Token.SHNE); + stack [stackTop] = valBln; + + goto Loop; + } + goto case Token.IFNE; + + case Token.IFNE: + if (stack_boolean (frame, stackTop--)) { + frame.pc += 2; + + goto Loop; + } + + goto jumplessRun_brk; + + case Token.IFEQ: + if (!stack_boolean (frame, stackTop--)) { + frame.pc += 2; + + goto Loop; + } + + goto jumplessRun_brk; + + case Icode_IFEQ_POP: + if (!stack_boolean (frame, stackTop--)) { + frame.pc += 2; + + goto Loop; + } + stack [stackTop--] = null; + + goto jumplessRun_brk; + + case Token.GOTO: + + goto jumplessRun_brk; + + case Icode_GOSUB: + ++stackTop; + stack [stackTop] = DBL_MRK; + sDbl [stackTop] = frame.pc + 2; + + goto jumplessRun_brk; + + case Icode_STARTSUB: + if (stackTop == frame.emptyStackTop + 1) { + // Call from Icode_GOSUB: store return PC address in the local + indexReg += frame.localShift; + stack [indexReg] = stack [stackTop]; + sDbl [indexReg] = sDbl [stackTop]; + --stackTop; + } + else { + // Call from exception handler: exception object is already stored + // in the local + if (stackTop != frame.emptyStackTop) + Context.CodeBug (); + } + + goto Loop; + goto case Icode_RETSUB; + + case Icode_RETSUB: { + // indexReg: local to store return address + if (instructionCounting) { + addInstructionCount (cx, frame, 0); + } + indexReg += frame.localShift; + object value = stack [indexReg]; + if (value != DBL_MRK) { + // Invocation from exception handler, restore object to rethrow + throwable = value; + goto withoutExceptions_brk; + } + // Normal return from GOSUB + frame.pc = (int)sDbl [indexReg]; + if (instructionCounting) { + frame.pcPrevBranch = frame.pc; + } + + goto Loop; + } + goto case Icode_POP; + + case Icode_POP: + stack [stackTop] = null; + stackTop--; + + goto Loop; + goto case Icode_POP_RESULT; + + case Icode_POP_RESULT: + frame.result = stack [stackTop]; + frame.resultDbl = sDbl [stackTop]; + stack [stackTop] = null; + --stackTop; + + goto Loop; + goto case Icode_DUP; + + case Icode_DUP: + stack [stackTop + 1] = stack [stackTop]; + sDbl [stackTop + 1] = sDbl [stackTop]; + stackTop++; + + goto Loop; + goto case Icode_DUP2; + + case Icode_DUP2: + stack [stackTop + 1] = stack [stackTop - 1]; + sDbl [stackTop + 1] = sDbl [stackTop - 1]; + stack [stackTop + 2] = stack [stackTop]; + sDbl [stackTop + 2] = sDbl [stackTop]; + stackTop += 2; + + goto Loop; + goto case Icode_SWAP; + + case Icode_SWAP: { + object o = stack [stackTop]; + stack [stackTop] = stack [stackTop - 1]; + stack [stackTop - 1] = o; + double d = sDbl [stackTop]; + sDbl [stackTop] = sDbl [stackTop - 1]; + sDbl [stackTop - 1] = d; + + goto Loop; + } + goto case Token.RETURN; + + case Token.RETURN: + frame.result = stack [stackTop]; + frame.resultDbl = sDbl [stackTop]; + --stackTop; + + goto Loop_brk; + + case Token.RETURN_RESULT: + + goto Loop_brk; + + case Icode_RETUNDEF: + frame.result = undefined; + + goto Loop_brk; + + case Token.BITNOT: { + int rIntValue = stack_int32 (frame, stackTop); + stack [stackTop] = DBL_MRK; + sDbl [stackTop] = ~rIntValue; + + goto Loop; + } + goto case Token.BITAND; + + case Token.BITAND: + case Token.BITOR: + case Token.BITXOR: + case Token.LSH: + case Token.RSH: { + int rIntValue = stack_int32 (frame, stackTop); + --stackTop; + int lIntValue = stack_int32 (frame, stackTop); + stack [stackTop] = DBL_MRK; + switch (op) { + + case Token.BITAND: + lIntValue &= rIntValue; + break; + + case Token.BITOR: + lIntValue |= rIntValue; + break; + + case Token.BITXOR: + lIntValue ^= rIntValue; + break; + + case Token.LSH: + lIntValue <<= rIntValue; + break; + + case Token.RSH: + lIntValue >>= rIntValue; + break; + } + sDbl [stackTop] = lIntValue; + + goto Loop; + } + goto case Token.URSH; + + case Token.URSH: { + int rIntValue = stack_int32 (frame, stackTop) & 0x1F; + --stackTop; + double lDbl = stack_double (frame, stackTop); + stack [stackTop] = DBL_MRK; + uint i = (uint)ScriptConvert.ToUint32 (lDbl); + sDbl [stackTop] = i >> rIntValue; + + goto Loop; + } + goto case Token.NEG; + + case Token.NEG: + case Token.POS: { + double rDbl = stack_double (frame, stackTop); + stack [stackTop] = DBL_MRK; + if (op == Token.NEG) { + rDbl = -rDbl; + } + sDbl [stackTop] = rDbl; + + goto Loop; + } + goto case Token.ADD; + + case Token.ADD: + --stackTop; + DoAdd (stack, sDbl, stackTop, cx); + + goto Loop; + goto case Token.SUB; + + case Token.SUB: + case Token.MUL: + case Token.DIV: + case Token.MOD: { + double rDbl = stack_double (frame, stackTop); + --stackTop; + double lDbl = stack_double (frame, stackTop); + stack [stackTop] = DBL_MRK; + switch (op) { + + case Token.SUB: + lDbl -= rDbl; + break; + + case Token.MUL: + lDbl *= rDbl; + break; + + case Token.DIV: + lDbl /= rDbl; + break; + + case Token.MOD: + lDbl %= rDbl; + break; + } + sDbl [stackTop] = lDbl; + + goto Loop; + } + goto case Token.NOT; + + case Token.NOT: + stack [stackTop] = !stack_boolean (frame, stackTop); + + goto Loop; + goto case Token.BINDNAME; + + case Token.BINDNAME: + stack [++stackTop] = ScriptRuntime.bind (cx, frame.scope, stringReg); + + goto Loop; + goto case Token.SETNAME; + + case Token.SETNAME: { + object rhs = stack [stackTop]; + if (rhs == DBL_MRK) + rhs = sDbl [stackTop]; + --stackTop; + IScriptable lhs = (IScriptable)stack [stackTop]; + stack [stackTop] = ScriptRuntime.setName (lhs, rhs, cx, frame.scope, stringReg); + + goto Loop; + } + goto case Token.DELPROP; + + case Token.DELPROP: { + object rhs = stack [stackTop]; + if (rhs == DBL_MRK) + rhs = sDbl [stackTop]; + --stackTop; + object lhs = stack [stackTop]; + if (lhs == DBL_MRK) + lhs = sDbl [stackTop]; + stack [stackTop] = ScriptRuntime.delete (lhs, rhs, cx); + + goto Loop; + } + goto case Token.GETPROP; + + case Token.GETPROP: { + object lhs = stack [stackTop]; + if (lhs == DBL_MRK) + lhs = sDbl [stackTop]; + stack [stackTop] = ScriptRuntime.getObjectProp (lhs, stringReg, cx); + + goto Loop; + } + goto case Token.SETPROP; + + case Token.SETPROP_GETTER: + case Token.SETPROP_SETTER: + case Token.SETPROP: { + object rhs = stack [stackTop]; + if (rhs == DBL_MRK) + rhs = sDbl [stackTop]; + --stackTop; + object lhs = stack [stackTop]; + if (lhs == DBL_MRK) + lhs = sDbl [stackTop]; + + switch (op) { + case Token.SETPROP_GETTER: + ((ScriptableObject)lhs).DefineGetter(stringReg, ((ICallable)rhs)); + stack[stackTop] = rhs; + break; + + case Token.SETPROP_SETTER: + ((ScriptableObject)lhs).DefineSetter(stringReg, ((ICallable)rhs)); + stack[stackTop] = rhs; + break; + + + default: + stack [stackTop] = ScriptRuntime.setObjectProp (lhs, stringReg, rhs, cx); + break; + } + + goto Loop; + } + goto case Icode_PROP_INC_DEC; + + case Icode_PROP_INC_DEC: { + object lhs = stack [stackTop]; + if (lhs == DBL_MRK) + lhs = sDbl [stackTop]; + stack [stackTop] = ScriptRuntime.propIncrDecr (lhs, stringReg, cx, iCode [frame.pc]); + ++frame.pc; + + goto Loop; + } + goto case Token.GETELEM; + + case Token.GETELEM: { + --stackTop; + object lhs = stack [stackTop]; + if (lhs == DBL_MRK) { + lhs = sDbl [stackTop]; + } + object value; + object id = stack [stackTop + 1]; + if (id != DBL_MRK) { + value = ScriptRuntime.getObjectElem (lhs, id, cx); + } + else { + double d = sDbl [stackTop + 1]; + value = ScriptRuntime.getObjectIndex (lhs, d, cx); + } + stack [stackTop] = value; + + goto Loop; + } + goto case Token.SETELEM; + + case Token.SETELEM: { + stackTop -= 2; + object rhs = stack [stackTop + 2]; + if (rhs == DBL_MRK) { + rhs = sDbl [stackTop + 2]; + } + object lhs = stack [stackTop]; + if (lhs == DBL_MRK) { + lhs = sDbl [stackTop]; + } + object value; + object id = stack [stackTop + 1]; + if (id != DBL_MRK) { + value = ScriptRuntime.setObjectElem (lhs, id, rhs, cx); + } + else { + double d = sDbl [stackTop + 1]; + value = ScriptRuntime.setObjectIndex (lhs, d, rhs, cx); + } + stack [stackTop] = value; + + goto Loop; + } + goto case Icode_ELEM_INC_DEC; + + case Icode_ELEM_INC_DEC: { + object rhs = stack [stackTop]; + if (rhs == DBL_MRK) + rhs = sDbl [stackTop]; + --stackTop; + object lhs = stack [stackTop]; + if (lhs == DBL_MRK) + lhs = sDbl [stackTop]; + stack [stackTop] = ScriptRuntime.elemIncrDecr (lhs, rhs, cx, iCode [frame.pc]); + ++frame.pc; + + goto Loop; + } + goto case Token.GET_REF; + + case Token.GET_REF: { + IRef rf = (IRef)stack [stackTop]; + stack [stackTop] = ScriptRuntime.refGet (rf, cx); + + goto Loop; + } + goto case Token.SET_REF; + + case Token.SET_REF: { + object value = stack [stackTop]; + if (value == DBL_MRK) + value = sDbl [stackTop]; + --stackTop; + IRef rf = (IRef)stack [stackTop]; + stack [stackTop] = ScriptRuntime.refSet (rf, value, cx); + + goto Loop; + } + goto case Token.DEL_REF; + + case Token.DEL_REF: { + IRef rf = (IRef)stack [stackTop]; + stack [stackTop] = ScriptRuntime.refDel (rf, cx); + + goto Loop; + } + goto case Icode_REF_INC_DEC; + + case Icode_REF_INC_DEC: { + IRef rf = (IRef)stack [stackTop]; + stack [stackTop] = ScriptRuntime.refIncrDecr (rf, cx, iCode [frame.pc]); + ++frame.pc; + + goto Loop; + } + goto case Token.LOCAL_LOAD; + + case Token.LOCAL_LOAD: + ++stackTop; + indexReg += frame.localShift; + stack [stackTop] = stack [indexReg]; + sDbl [stackTop] = sDbl [indexReg]; + + goto Loop; + goto case Icode_LOCAL_CLEAR; + + case Icode_LOCAL_CLEAR: + indexReg += frame.localShift; + stack [indexReg] = null; + + goto Loop; + goto case Icode_NAME_AND_THIS; + + case Icode_NAME_AND_THIS: + // stringReg: name + ++stackTop; + stack [stackTop] = ScriptRuntime.getNameFunctionAndThis (stringReg, cx, frame.scope); + ++stackTop; + stack [stackTop] = ScriptRuntime.lastStoredScriptable (cx); + + goto Loop; + goto case Icode_PROP_AND_THIS; + + case Icode_PROP_AND_THIS: { + object obj = stack [stackTop]; + if (obj == DBL_MRK) + obj = sDbl [stackTop]; + // stringReg: property + stack [stackTop] = ScriptRuntime.getPropFunctionAndThis (obj, stringReg, cx); + ++stackTop; + stack [stackTop] = ScriptRuntime.lastStoredScriptable (cx); + + goto Loop; + } + goto case Icode_ELEM_AND_THIS; + + case Icode_ELEM_AND_THIS: { + object obj = stack [stackTop - 1]; + if (obj == DBL_MRK) + obj = sDbl [stackTop - 1]; + object id = stack [stackTop]; + if (id == DBL_MRK) + id = sDbl [stackTop]; + stack [stackTop - 1] = ScriptRuntime.GetElemFunctionAndThis (obj, id, cx); + stack [stackTop] = ScriptRuntime.lastStoredScriptable (cx); + + goto Loop; + } + goto case Icode_VALUE_AND_THIS; + + case Icode_VALUE_AND_THIS: { + object value = stack [stackTop]; + if (value == DBL_MRK) + value = sDbl [stackTop]; + stack [stackTop] = ScriptRuntime.getValueFunctionAndThis (value, cx); + ++stackTop; + stack [stackTop] = ScriptRuntime.lastStoredScriptable (cx); + + goto Loop; + } + goto case Icode_CALLSPECIAL; + + case Icode_CALLSPECIAL: { + if (instructionCounting) { + cx.instructionCount += INVOCATION_COST; + } + int callType = iCode [frame.pc] & 0xFF; + bool isNew = (iCode [frame.pc + 1] != 0); + int sourceLine = GetIndex (iCode, frame.pc + 2); + + // indexReg: number of arguments + if (isNew) { + // stack change: function arg0 .. argN -> newResult + stackTop -= indexReg; + + object function = stack [stackTop]; + if (function == DBL_MRK) + function = sDbl [stackTop]; + object [] outArgs = GetArgsArray (stack, sDbl, stackTop + 1, indexReg); + stack [stackTop] = ScriptRuntime.newSpecial (cx, function, outArgs, frame.scope, callType); + } + else { + // stack change: function thisObj arg0 .. argN -> result + stackTop -= (1 + indexReg); + + // Call code generation ensure that stack here + // is ... Callable Scriptable + IScriptable functionThis = (IScriptable)stack [stackTop + 1]; + ICallable function = (ICallable)stack [stackTop]; + object [] outArgs = GetArgsArray (stack, sDbl, stackTop + 2, indexReg); + stack [stackTop] = ScriptRuntime.callSpecial (cx, function, functionThis, outArgs, frame.scope, frame.thisObj, callType, frame.idata.itsSourceFile, sourceLine); + } + frame.pc += 4; + + goto Loop; + } + goto case Token.CALL; + + case Token.CALL: + case Icode_TAIL_CALL: + case Token.REF_CALL: { + if (instructionCounting) { + cx.instructionCount += INVOCATION_COST; + } + // stack change: function thisObj arg0 .. argN -> result + // indexReg: number of arguments + stackTop -= (1 + indexReg); + + // CALL generation ensures that fun and funThisObj + // are already Scriptable and Callable objects respectively + ICallable fun = (ICallable)stack [stackTop]; + IScriptable funThisObj = (IScriptable)stack [stackTop + 1]; + if (op == Token.REF_CALL) { + object [] outArgs = GetArgsArray (stack, sDbl, stackTop + 2, indexReg); + stack [stackTop] = ScriptRuntime.callRef (fun, funThisObj, outArgs, cx); + + goto Loop; + } + IScriptable calleeScope = frame.scope; + if (frame.useActivation) { + calleeScope = ScriptableObject.GetTopLevelScope (frame.scope); + } + if (fun is InterpretedFunction) { + InterpretedFunction ifun = (InterpretedFunction)fun; + if (frame.fnOrScript.securityDomain == ifun.securityDomain) { + CallFrame callParentFrame = frame; + CallFrame calleeFrame = new CallFrame (); + if (op == Icode_TAIL_CALL) { + // In principle tail call can re-use the current + // frame and its stack arrays but it is hard to + // do properly. Any exceptions that can legally + // happen during frame re-initialization including + // StackOverflowException during innocent looking + // System.arraycopy may leave the current frame + // data corrupted leading to undefined behaviour + // in the catch code bellow that unwinds JS stack + // on exceptions. Then there is issue about frame release + // end exceptions there. + // To avoid frame allocation a released frame + // can be cached for re-use which would also benefit + // non-tail calls but it is not clear that this caching + // would gain in performance due to potentially + // bad iteraction with GC. + callParentFrame = frame.parentFrame; + } + initFrame (cx, calleeScope, funThisObj, stack, sDbl, stackTop + 2, indexReg, ifun, callParentFrame, calleeFrame); + if (op == Icode_TAIL_CALL) { + // Release the parent + ExitFrame (cx, frame, (object)null); + } + else { + frame.savedStackTop = stackTop; + frame.savedCallOp = op; + } + frame = calleeFrame; + + goto StateLoop; + } + } + + if (fun is Continuation) { + // Jump to the captured continuation + ContinuationJump cjump; + cjump = new ContinuationJump ((Continuation)fun, frame); + + // continuation result is the first argument if any + // of contination call + if (indexReg == 0) { + cjump.result = undefined; + } + else { + cjump.result = stack [stackTop + 2]; + cjump.resultDbl = sDbl [stackTop + 2]; + } + + // Start the real unwind job + throwable = cjump; + break; + } + + if (fun is IdFunctionObject) { + IdFunctionObject ifun = (IdFunctionObject)fun; + if (Continuation.IsContinuationConstructor (ifun)) { + captureContinuation (cx, frame, stackTop); + + goto Loop; + } + } + + object [] outArgs2 = GetArgsArray (stack, sDbl, stackTop + 2, indexReg); + stack [stackTop] = fun.Call (cx, calleeScope, funThisObj, outArgs2); + + + goto Loop; + } + goto case Token.NEW; + + case Token.NEW: { + if (instructionCounting) { + cx.instructionCount += INVOCATION_COST; + } + // stack change: function arg0 .. argN -> newResult + // indexReg: number of arguments + stackTop -= indexReg; + + object lhs = stack [stackTop]; + if (lhs is InterpretedFunction) { + InterpretedFunction f = (InterpretedFunction)lhs; + if (frame.fnOrScript.securityDomain == f.securityDomain) { + IScriptable newInstance = f.CreateObject (cx, frame.scope); + CallFrame calleeFrame = new CallFrame (); + initFrame (cx, frame.scope, newInstance, stack, sDbl, stackTop + 1, indexReg, f, frame, calleeFrame); + + stack [stackTop] = newInstance; + frame.savedStackTop = stackTop; + frame.savedCallOp = op; + frame = calleeFrame; + + goto StateLoop; + } + } + if (!(lhs is IFunction)) { + if (lhs == DBL_MRK) + lhs = sDbl [stackTop]; + throw ScriptRuntime.NotFunctionError (lhs); + } + IFunction fun = (IFunction)lhs; + + if (fun is IdFunctionObject) { + IdFunctionObject ifun = (IdFunctionObject)fun; + if (Continuation.IsContinuationConstructor (ifun)) { + captureContinuation (cx, frame, stackTop); + + goto Loop; + } + } + + object [] outArgs = GetArgsArray (stack, sDbl, stackTop + 1, indexReg); + stack [stackTop] = fun.Construct (cx, frame.scope, outArgs); + + goto Loop; + } + goto case Token.TYPEOF; + + case Token.TYPEOF: { + object lhs = stack [stackTop]; + if (lhs == DBL_MRK) + lhs = sDbl [stackTop]; + stack [stackTop] = ScriptRuntime.Typeof (lhs); + + goto Loop; + } + goto case Icode_TYPEOFNAME; + + case Icode_TYPEOFNAME: + stack [++stackTop] = ScriptRuntime.TypeofName (frame.scope, stringReg); + + goto Loop; + goto case Token.STRING; + + case Token.STRING: + stack [++stackTop] = stringReg; + + goto Loop; + goto case Icode_SHORTNUMBER; + + case Icode_SHORTNUMBER: + ++stackTop; + stack [stackTop] = DBL_MRK; + sDbl [stackTop] = GetShort (iCode, frame.pc); + frame.pc += 2; + + goto Loop; + goto case Icode_INTNUMBER; + + case Icode_INTNUMBER: + ++stackTop; + stack [stackTop] = DBL_MRK; + sDbl [stackTop] = GetInt (iCode, frame.pc); + frame.pc += 4; + + goto Loop; + goto case Token.NUMBER; + + case Token.NUMBER: + ++stackTop; + stack [stackTop] = DBL_MRK; + sDbl [stackTop] = frame.idata.itsDoubleTable [indexReg]; + + goto Loop; + goto case Token.NAME; + + case Token.NAME: + stack [++stackTop] = ScriptRuntime.name (cx, frame.scope, stringReg); + + goto Loop; + goto case Icode_NAME_INC_DEC; + + case Icode_NAME_INC_DEC: + stack [++stackTop] = ScriptRuntime.nameIncrDecr (frame.scope, stringReg, iCode [frame.pc]); + ++frame.pc; + + goto Loop; + goto case Icode_SETVAR1; + + case Icode_SETVAR1: + indexReg = iCode [frame.pc++]; + // fallthrough + goto case Token.SETVAR; + + case Token.SETVAR: + if (!frame.useActivation) { + vars [indexReg] = stack [stackTop]; + varDbls [indexReg] = sDbl [stackTop]; + } + else { + object val = stack [stackTop]; + if (val == DBL_MRK) + val = sDbl [stackTop]; + stringReg = frame.idata.argNames [indexReg]; + frame.scope.Put (stringReg, frame.scope, val); + } + + goto Loop; + goto case Icode_GETVAR1; + + case Icode_GETVAR1: + indexReg = iCode [frame.pc++]; + // fallthrough + goto case Token.GETVAR; + + case Token.GETVAR: + ++stackTop; + if (!frame.useActivation) { + stack [stackTop] = vars [indexReg]; + sDbl [stackTop] = varDbls [indexReg]; + } + else { + stringReg = frame.idata.argNames [indexReg]; + stack [stackTop] = frame.scope.Get (stringReg, frame.scope); + } + + goto Loop; + goto case Icode_VAR_INC_DEC; + + case Icode_VAR_INC_DEC: { + // indexReg : varindex + ++stackTop; + int incrDecrMask = iCode [frame.pc]; + if (!frame.useActivation) { + stack [stackTop] = DBL_MRK; + object varValue = vars [indexReg]; + double d; + if (varValue == DBL_MRK) { + d = varDbls [indexReg]; + } + else { + d = ScriptConvert.ToNumber (varValue); + vars [indexReg] = DBL_MRK; + } + double d2 = ((incrDecrMask & Node.DECR_FLAG) == 0) ? d + 1.0 : d - 1.0; + varDbls [indexReg] = d2; + sDbl [stackTop] = ((incrDecrMask & Node.POST_FLAG) == 0) ? d2 : d; + } + else { + string varName = frame.idata.argNames [indexReg]; + stack [stackTop] = ScriptRuntime.nameIncrDecr (frame.scope, varName, incrDecrMask); + } + ++frame.pc; + + goto Loop; + } + goto case Icode_ZERO; + + case Icode_ZERO: + ++stackTop; + stack [stackTop] = DBL_MRK; + sDbl [stackTop] = 0; + + goto Loop; + goto case Icode_ONE; + + case Icode_ONE: + ++stackTop; + stack [stackTop] = DBL_MRK; + sDbl [stackTop] = 1; + + goto Loop; + goto case Token.NULL; + + case Token.NULL: + stack [++stackTop] = null; + + goto Loop; + goto case Token.THIS; + + case Token.THIS: + stack [++stackTop] = frame.thisObj; + + goto Loop; + goto case Token.THISFN; + + case Token.THISFN: + stack [++stackTop] = frame.fnOrScript; + + goto Loop; + goto case Token.FALSE; + + case Token.FALSE: + stack [++stackTop] = false; + + goto Loop; + goto case Token.TRUE; + + case Token.TRUE: + stack [++stackTop] = true; + + goto Loop; + goto case Icode_UNDEF; + + case Icode_UNDEF: + stack [++stackTop] = undefined; + + goto Loop; + goto case Token.ENTERWITH; + + case Token.ENTERWITH: { + object lhs = stack [stackTop]; + if (lhs == DBL_MRK) + lhs = sDbl [stackTop]; + --stackTop; + frame.scope = ScriptRuntime.enterWith (lhs, cx, frame.scope); + + goto Loop; + } + goto case Token.LEAVEWITH; + + case Token.LEAVEWITH: + frame.scope = ScriptRuntime.leaveWith (frame.scope); + + goto Loop; + goto case Token.CATCH_SCOPE; + + case Token.CATCH_SCOPE: { + // stack top: exception object + // stringReg: name of exception variable + // indexReg: local for exception scope + --stackTop; + indexReg += frame.localShift; + + bool afterFirstScope = (frame.idata.itsICode [frame.pc] != 0); + + Exception caughtException = (Exception)stack [stackTop + 1]; + IScriptable lastCatchScope; + if (!afterFirstScope) { + lastCatchScope = null; + } + else { + lastCatchScope = (IScriptable)stack [indexReg]; + } + stack [indexReg] = ScriptRuntime.NewCatchScope (caughtException, lastCatchScope, stringReg, cx, frame.scope); + ++frame.pc; + + goto Loop; + } + goto case Token.ENUM_INIT_KEYS; + + case Token.ENUM_INIT_KEYS: + case Token.ENUM_INIT_VALUES: { + object lhs = stack [stackTop]; + if (lhs == DBL_MRK) + lhs = sDbl [stackTop]; + --stackTop; + indexReg += frame.localShift; + + if (lhs is IIdEnumerable) { + stack [indexReg] = ((IIdEnumerable)lhs).GetEnumeration (cx, (op == Token.ENUM_INIT_VALUES)); + } + else { + stack [indexReg] = new IdEnumeration (lhs, cx, (op == Token.ENUM_INIT_VALUES)); + } + + + goto Loop; + } + goto case Token.ENUM_NEXT; + + case Token.ENUM_NEXT: + case Token.ENUM_ID: { + indexReg += frame.localShift; + IdEnumeration val = (IdEnumeration)stack [indexReg]; + ++stackTop; + stack [stackTop] = (op == Token.ENUM_NEXT) ? val.MoveNext () : val.Current (cx); + + goto Loop; + } + goto case Token.REF_SPECIAL; + + case Token.REF_SPECIAL: { + //stringReg: name of special property + object obj = stack [stackTop]; + if (obj == DBL_MRK) + obj = sDbl [stackTop]; + stack [stackTop] = ScriptRuntime.specialRef (obj, stringReg, cx); + + goto Loop; + } + goto case Token.REF_MEMBER; + + case Token.REF_MEMBER: { + //indexReg: flags + object elem = stack [stackTop]; + if (elem == DBL_MRK) + elem = sDbl [stackTop]; + --stackTop; + object obj = stack [stackTop]; + if (obj == DBL_MRK) + obj = sDbl [stackTop]; + stack [stackTop] = ScriptRuntime.memberRef (obj, elem, cx, indexReg); + + goto Loop; + } + goto case Token.REF_NS_MEMBER; + + case Token.REF_NS_MEMBER: { + //indexReg: flags + object elem = stack [stackTop]; + if (elem == DBL_MRK) + elem = sDbl [stackTop]; + --stackTop; + object ns = stack [stackTop]; + if (ns == DBL_MRK) + ns = sDbl [stackTop]; + --stackTop; + object obj = stack [stackTop]; + if (obj == DBL_MRK) + obj = sDbl [stackTop]; + stack [stackTop] = ScriptRuntime.memberRef (obj, ns, elem, cx, indexReg); + + goto Loop; + } + goto case Token.REF_NAME; + + case Token.REF_NAME: { + //indexReg: flags + object name = stack [stackTop]; + if (name == DBL_MRK) + name = sDbl [stackTop]; + stack [stackTop] = ScriptRuntime.nameRef (name, cx, frame.scope, indexReg); + + goto Loop; + } + goto case Token.REF_NS_NAME; + + case Token.REF_NS_NAME: { + //indexReg: flags + object name = stack [stackTop]; + if (name == DBL_MRK) + name = sDbl [stackTop]; + --stackTop; + object ns = stack [stackTop]; + if (ns == DBL_MRK) + ns = sDbl [stackTop]; + stack [stackTop] = ScriptRuntime.nameRef (ns, name, cx, frame.scope, indexReg); + + goto Loop; + } + goto case Icode_SCOPE_LOAD; + + case Icode_SCOPE_LOAD: + indexReg += frame.localShift; + frame.scope = (IScriptable)stack [indexReg]; + + goto Loop; + goto case Icode_SCOPE_SAVE; + + case Icode_SCOPE_SAVE: + indexReg += frame.localShift; + stack [indexReg] = frame.scope; + + goto Loop; + goto case Icode_CLOSURE_EXPR; + + case Icode_CLOSURE_EXPR: { + InterpretedFunction fun = InterpretedFunction.createFunction (cx, frame.scope, frame.fnOrScript, indexReg); + stack [++stackTop] = fun; + } + goto Loop; + goto case Icode_CLOSURE_STMT; + + case Icode_CLOSURE_STMT: + initFunction (cx, frame.scope, frame.fnOrScript, indexReg); + + goto Loop; + goto case Token.REGEXP; + + case Token.REGEXP: + stack [++stackTop] = frame.scriptRegExps [indexReg]; + + goto Loop; + goto case Icode_LITERAL_NEW; + + case Icode_LITERAL_NEW: + // indexReg: number of values in the literal + ++stackTop; + stack [stackTop] = new object [indexReg]; + sDbl [stackTop] = 0; + + goto Loop; + goto case Icode_LITERAL_SET; + + case Icode_LITERAL_SET: { + object value = stack [stackTop]; + if (value == DBL_MRK) + value = sDbl [stackTop]; + --stackTop; + int i = (int)sDbl [stackTop]; + ((object [])stack [stackTop]) [i] = value; + sDbl [stackTop] = i + 1; + + goto Loop; + } + goto case Token.ARRAYLIT; + + case Token.ARRAYLIT: + case Icode_SPARE_ARRAYLIT: + case Token.OBJECTLIT: { + object [] data = (object [])stack [stackTop]; + object val; + if (op == Token.OBJECTLIT) { + object [] ids = (object [])frame.idata.literalIds [indexReg]; + val = ScriptRuntime.newObjectLiteral (ids, data, cx, frame.scope); + } + else { + int [] skipIndexces = null; + if (op == Icode_SPARE_ARRAYLIT) { + skipIndexces = (int [])frame.idata.literalIds [indexReg]; + } + val = ScriptRuntime.newArrayLiteral (data, skipIndexces, cx, frame.scope); + } + stack [stackTop] = val; + + goto Loop; + } + goto case Icode_ENTERDQ; + + case Icode_ENTERDQ: { + object lhs = stack [stackTop]; + if (lhs == DBL_MRK) + lhs = sDbl [stackTop]; + --stackTop; + frame.scope = ScriptRuntime.enterDotQuery (lhs, frame.scope); + + goto Loop; + } + goto case Icode_LEAVEDQ; + + case Icode_LEAVEDQ: { + bool valBln = stack_boolean (frame, stackTop); + object x = ScriptRuntime.updateDotQuery (valBln, frame.scope); + if (x != null) { + stack [stackTop] = x; + frame.scope = ScriptRuntime.leaveDotQuery (frame.scope); + frame.pc += 2; + + goto Loop; + } + // reset stack and PC to code after ENTERDQ + --stackTop; + + goto jumplessRun_brk; + } + + case Token.DEFAULTNAMESPACE: { + object value = stack [stackTop]; + if (value == DBL_MRK) + value = sDbl [stackTop]; + stack [stackTop] = ScriptRuntime.setDefaultNamespace (value, cx); + + goto Loop; + } + goto case Token.ESCXMLATTR; + + case Token.ESCXMLATTR: { + object value = stack [stackTop]; + if (value != DBL_MRK) { + stack [stackTop] = ScriptRuntime.escapeAttributeValue (value, cx); + } + + goto Loop; + } + goto case Token.ESCXMLTEXT; + + case Token.ESCXMLTEXT: { + object value = stack [stackTop]; + if (value != DBL_MRK) { + stack [stackTop] = ScriptRuntime.escapeTextValue (value, cx); + } + + goto Loop; + } + goto case Icode_LINE; + + case Icode_DEBUGGER: { + if (frame.debuggerFrame != null) { + frame.debuggerFrame.OnDebuggerStatement(cx); + } + break; + } + + case Icode_LINE: + frame.pcSourceLineStart = frame.pc; + if (frame.debuggerFrame != null) { + int line = GetIndex (iCode, frame.pc); + frame.debuggerFrame.OnLineChange (cx, line); + } + frame.pc += 2; + + goto Loop; + goto case Icode_REG_IND_C0; + + case Icode_REG_IND_C0: + indexReg = 0; + + goto Loop; + goto case Icode_REG_IND_C1; + + case Icode_REG_IND_C1: + indexReg = 1; + + goto Loop; + goto case Icode_REG_IND_C2; + + case Icode_REG_IND_C2: + indexReg = 2; + + goto Loop; + goto case Icode_REG_IND_C3; + + case Icode_REG_IND_C3: + indexReg = 3; + + goto Loop; + goto case Icode_REG_IND_C4; + + case Icode_REG_IND_C4: + indexReg = 4; + + goto Loop; + goto case Icode_REG_IND_C5; + + case Icode_REG_IND_C5: + indexReg = 5; + + goto Loop; + goto case Icode_REG_IND1; + + case Icode_REG_IND1: + indexReg = 0xFF & iCode [frame.pc]; + ++frame.pc; + + goto Loop; + goto case Icode_REG_IND2; + + case Icode_REG_IND2: + indexReg = GetIndex (iCode, frame.pc); + frame.pc += 2; + + goto Loop; + goto case Icode_REG_IND4; + + case Icode_REG_IND4: + indexReg = GetInt (iCode, frame.pc); + frame.pc += 4; + + goto Loop; + goto case Icode_REG_STR_C0; + + case Icode_REG_STR_C0: + stringReg = strings [0]; + + goto Loop; + goto case Icode_REG_STR_C1; + + case Icode_REG_STR_C1: + stringReg = strings [1]; + + goto Loop; + goto case Icode_REG_STR_C2; + + case Icode_REG_STR_C2: + stringReg = strings [2]; + + goto Loop; + goto case Icode_REG_STR_C3; + + case Icode_REG_STR_C3: + stringReg = strings [3]; + + goto Loop; + goto case Icode_REG_STR1; + + case Icode_REG_STR1: + stringReg = strings [0xFF & iCode [frame.pc]]; + ++frame.pc; + + goto Loop; + goto case Icode_REG_STR2; + + case Icode_REG_STR2: + stringReg = strings [GetIndex (iCode, frame.pc)]; + frame.pc += 2; + + goto Loop; + goto case Icode_REG_STR4; + + case Icode_REG_STR4: + stringReg = strings [GetInt (iCode, frame.pc)]; + frame.pc += 4; + + goto Loop; + goto default; + + default: + dumpICode (frame.idata); + throw new Exception ("Unknown icode : " + op + " @ pc : " + (frame.pc - 1)); + + } // end of interpreter switch + } + + jumplessRun_brk: + ; + // end of jumplessRun label block + + // This should be reachable only for jump implementation + // when pc points to encoded target offset + if (instructionCounting) { + addInstructionCount (cx, frame, 2); + } + int offset = GetShort (iCode, frame.pc); + if (offset != 0) { + // -1 accounts for pc pointing to jump opcode + 1 + frame.pc += offset - 1; + } + else { + frame.pc = frame.idata.longJumps.getExistingInt (frame.pc); + } + if (instructionCounting) { + frame.pcPrevBranch = frame.pc; + } + + goto Loop; + + Loop: + ; + } + + Loop_brk: + ; + // end of Loop: for + + ExitFrame (cx, frame, (object)null); + interpreterResult = frame.result; + interpreterResultDbl = frame.resultDbl; + if (frame.parentFrame != null) { + frame = frame.parentFrame; + if (frame.frozen) { + frame = frame.cloneFrozen (); + } + setCallResult (frame, interpreterResult, interpreterResultDbl); + interpreterResult = null; // Help GC + + goto StateLoop; + } + + goto StateLoop_brk; + } + // end of interpreter withoutExceptions: try + catch (Exception ex) { + if (throwable != null) { + // This is serious bug and it is better to track it ASAP + throw new Exception (); + } + throwable = ex; + } + + withoutExceptions_brk: + + // This should be reachable only after above catch or from + // finally when it needs to propagate exception or from + // explicit throw + if (throwable == null) + Context.CodeBug (); + + // Exception type + const int EX_CATCH_STATE = 2; // Can execute JS catch + const int EX_FINALLY_STATE = 1; // Can execute JS finally + const int EX_NO_JS_STATE = 0; // Terminate JS execution + + int exState; + ContinuationJump cjump2 = null; + + if (throwable is EcmaScriptThrow) { + exState = EX_CATCH_STATE; + } + else if (throwable is EcmaScriptError) { + // an offical ECMA error object, + exState = EX_CATCH_STATE; + } + else if (throwable is EcmaScriptRuntimeException) { + exState = EX_CATCH_STATE; + } + else if (throwable is EcmaScriptException) { + exState = EX_FINALLY_STATE; + } + else if (throwable is Exception) { + exState = EX_NO_JS_STATE; + } + else { + // It must be ContinuationJump + exState = EX_FINALLY_STATE; + cjump2 = (ContinuationJump)throwable; + } + + if (instructionCounting) { + try { + addInstructionCount (cx, frame, EXCEPTION_COST); + } + catch (Exception ex) { + // Error from instruction counting + // => unconditionally terminate JS + throwable = ex; + cjump2 = null; + exState = EX_NO_JS_STATE; + } + } + if (frame.debuggerFrame != null && throwable is Exception) { + // Call debugger only for RuntimeException + Exception rex = (Exception)throwable; + try { + frame.debuggerFrame.OnExceptionThrown (cx, rex); + } + catch (Exception ex) { + // Any exception from debugger + // => unconditionally terminate JS + throwable = ex; + cjump2 = null; + exState = EX_NO_JS_STATE; + } + } + + for (; ; ) { + if (exState != EX_NO_JS_STATE) { + bool onlyFinally = (exState != EX_CATCH_STATE); + indexReg = getExceptionHandler (frame, onlyFinally); + if (indexReg >= 0) { + // We caught an exception, restart the loop + // with exception pending the processing at the loop + // start + + goto StateLoop; + } + } + // No allowed execption handlers in this frame, unwind + // to parent and try to look there + + ExitFrame (cx, frame, throwable); + + frame = frame.parentFrame; + if (frame == null) { + break; + } + if (cjump2 != null && cjump2.branchFrame == frame) { + // Continuation branch point was hit, + // restart the state loop to reenter continuation + indexReg = -1; + + goto StateLoop; + } + } + + // No more frames, rethrow the exception or deal with continuation + if (cjump2 != null) { + if (cjump2.branchFrame != null) { + // The above loop should locate the top frame + Context.CodeBug (); + } + if (cjump2.capturedFrame != null) { + // Restarting detached continuation + indexReg = -1; + + goto StateLoop; + } + // Return continuation result to the caller + interpreterResult = cjump2.result; + interpreterResultDbl = cjump2.resultDbl; + throwable = null; + } + + goto StateLoop_brk; + + StateLoop: + ; + } + + StateLoop_brk: + ; + // end of StateLoop: for(;;) + + // Do cleanups/restorations before the final return or throw + + if (cx.previousInterpreterInvocations != null && cx.previousInterpreterInvocations.size () != 0) { + cx.lastInterpreterFrame = cx.previousInterpreterInvocations.pop (); + } + else { + // It was the last interpreter frame on the stack + cx.lastInterpreterFrame = null; + // Force GC of the value cx.previousInterpreterInvocations + cx.previousInterpreterInvocations = null; + } + + if (throwable != null) { + if (throwable is Helpers.StackOverflowVerifierException) { + throw Context.ReportRuntimeError ( + ScriptRuntime.GetMessage ("mag.too.deep.parser.recursion")); + } + throw (Exception)throwable; + } + + return (interpreterResult != DBL_MRK) ? interpreterResult : + interpreterResultDbl; + } + + static void initFrame (Context cx, IScriptable callerScope, IScriptable thisObj, object [] args, double [] argsDbl, int argShift, int argCount, InterpretedFunction fnOrScript, CallFrame parentFrame, CallFrame frame) + { + InterpreterData idata = fnOrScript.idata; + + bool useActivation = idata.itsNeedsActivation; + DebugFrame debuggerFrame = null; + if (cx.m_Debugger != null) { + debuggerFrame = cx.m_Debugger.GetFrame (cx, idata); + if (debuggerFrame != null) { + useActivation = true; + } + } + + if (useActivation) { + // Copy args to new array to pass to enterActivationFunction + // or debuggerFrame.onEnter + if (argsDbl != null) { + args = GetArgsArray (args, argsDbl, argShift, argCount); + } + argShift = 0; + argsDbl = null; + } + + IScriptable scope; + if (idata.itsFunctionType != 0) { + if (!idata.useDynamicScope) { + scope = fnOrScript.ParentScope; + } + else { + scope = callerScope; + } + + if (useActivation) { + scope = ScriptRuntime.createFunctionActivation (fnOrScript, scope, args); + } + } + else { + scope = callerScope; + ScriptRuntime.initScript (fnOrScript, thisObj, cx, scope, fnOrScript.idata.evalScriptFlag); + } + + if (idata.itsNestedFunctions != null) { + if (idata.itsFunctionType != 0 && !idata.itsNeedsActivation) + Context.CodeBug (); + for (int i = 0; i < idata.itsNestedFunctions.Length; i++) { + InterpreterData fdata = idata.itsNestedFunctions [i]; + if (fdata.itsFunctionType == FunctionNode.FUNCTION_STATEMENT) { + initFunction (cx, scope, fnOrScript, i); + } + } + } + + IScriptable [] scriptRegExps = null; + if (idata.itsRegExpLiterals != null) { + // Wrapped regexps for functions are stored in + // InterpretedFunction + // but for script which should not contain references to scope + // the regexps re-wrapped during each script execution + if (idata.itsFunctionType != 0) { + scriptRegExps = fnOrScript.functionRegExps; + } + else { + scriptRegExps = fnOrScript.createRegExpWraps (cx, scope); + } + } + + // Initialize args, vars, locals and stack + + int emptyStackTop = idata.itsMaxVars + idata.itsMaxLocals - 1; + int maxFrameArray = idata.itsMaxFrameArray; + if (maxFrameArray != emptyStackTop + idata.itsMaxStack + 1) + Context.CodeBug (); + + object [] stack; + double [] sDbl; + bool stackReuse; + if (frame.stack != null && maxFrameArray <= frame.stack.Length) { + // Reuse stacks from old frame + stackReuse = true; + stack = frame.stack; + sDbl = frame.sDbl; + } + else { + stackReuse = false; + stack = new object [maxFrameArray]; + sDbl = new double [maxFrameArray]; + } + + int definedArgs = idata.argCount; + if (definedArgs > argCount) { + definedArgs = argCount; + } + + // Fill the frame structure + + frame.parentFrame = parentFrame; + frame.frameIndex = (parentFrame == null) ? 0 : parentFrame.frameIndex + 1; + if (frame.frameIndex > cx.MaximumInterpreterStackDepth) + throw ScriptRuntime.TypeErrorById ("msg.stackoverflow"); + frame.frozen = false; + + frame.fnOrScript = fnOrScript; + frame.idata = idata; + + frame.stack = stack; + frame.sDbl = sDbl; + frame.varSource = frame; + frame.localShift = idata.itsMaxVars; + frame.emptyStackTop = emptyStackTop; + + frame.debuggerFrame = debuggerFrame; + frame.useActivation = useActivation; + + frame.thisObj = thisObj; + frame.scriptRegExps = scriptRegExps; + + // Initialize initial values of variables that change during + // interpretation. + frame.result = Undefined.Value; + frame.pc = 0; + frame.pcPrevBranch = 0; + frame.pcSourceLineStart = idata.firstLinePC; + frame.scope = scope; + + frame.savedStackTop = emptyStackTop; + frame.savedCallOp = 0; + + Array.Copy (args, argShift, stack, 0, definedArgs); + if (argsDbl != null) { + Array.Copy (argsDbl, argShift, sDbl, 0, definedArgs); + } + for (int i = definedArgs; i != idata.itsMaxVars; ++i) { + stack [i] = Undefined.Value; + } + if (stackReuse) { + // Clean the stack part and space beyond stack if any + // of the old array to allow to GC objects there + for (int i = emptyStackTop + 1; i != stack.Length; ++i) { + stack [i] = null; + } + } + + EnterFrame (cx, frame, args); + } + + static bool isFrameEnterExitRequired (CallFrame frame) + { + return frame.debuggerFrame != null || frame.idata.itsNeedsActivation; + } + + static void EnterFrame (Context cx, CallFrame frame, object [] args) + { + if (frame.debuggerFrame != null) { + frame.debuggerFrame.OnEnter (cx, frame.scope, frame.thisObj, args); + } + if (frame.idata.itsNeedsActivation) { + // Enter activation only when itsNeedsActivation true, not when + // useActivation holds since debugger should not interfere + // with activation chaining + ScriptRuntime.enterActivationFunction (cx, frame.scope); + } + } + + static void ExitFrame (Context cx, CallFrame frame, object throwable) + { + if (frame.idata.itsNeedsActivation) { + ScriptRuntime.exitActivationFunction (cx); + } + + if (frame.debuggerFrame != null) { + try { + if (throwable is Exception) { + frame.debuggerFrame.OnExit (cx, true, throwable); + } + else { + object result; + ContinuationJump cjump = (ContinuationJump)throwable; + if (cjump == null) { + result = frame.result; + } + else { + result = cjump.result; + } + if (result == UniqueTag.DoubleMark) { + double resultDbl; + if (cjump == null) { + resultDbl = frame.resultDbl; + } + else { + resultDbl = cjump.resultDbl; + } + result = resultDbl; + } + frame.debuggerFrame.OnExit (cx, false, result); + } + } + catch (Exception ex) { + Console.Error.WriteLine ("USAGE WARNING: onExit terminated with exception"); + Console.Error.WriteLine (ex.ToString ()); + } + } + } + + static void setCallResult (CallFrame frame, object callResult, double callResultDbl) + { + if (frame.savedCallOp == Token.CALL) { + frame.stack [frame.savedStackTop] = callResult; + frame.sDbl [frame.savedStackTop] = callResultDbl; + } + else if (frame.savedCallOp == Token.NEW) { + // If construct returns scriptable, + // then it replaces on stack top saved original instance + // of the object. + if (callResult is IScriptable) { + frame.stack [frame.savedStackTop] = callResult; + } + } + else { + Context.CodeBug (); + } + frame.savedCallOp = 0; + } + + static void captureContinuation (Context cx, CallFrame frame, int stackTop) + { + Continuation c = new Continuation (); + ScriptRuntime.setObjectProtoAndParent (c, ScriptRuntime.getTopCallScope (cx)); + + // Make sure that all frames upstack frames are frozen + CallFrame x = frame.parentFrame; + while (x != null && !x.frozen) { + x.frozen = true; + // Allow to GC unused stack space + for (int i = x.savedStackTop + 1; i != x.stack.Length; ++i) { + // Allow to GC unused stack space + x.stack [i] = null; + } + if (x.savedCallOp == Token.CALL) { + // the call will always overwrite the stack top with the result + x.stack [x.savedStackTop] = null; + } + else { + if (x.savedCallOp != Token.NEW) + Context.CodeBug (); + // the new operator uses stack top to store the constructed + // object so it shall not be cleared: see comments in + // setCallResult + } + x = x.parentFrame; + } + + c.initImplementation (frame.parentFrame); + frame.stack [stackTop] = c; + } + + static int stack_int32 (CallFrame frame, int i) + { + object x = frame.stack [i]; + double value; + if (x == UniqueTag.DoubleMark) { + value = frame.sDbl [i]; + } + else { + value = ScriptConvert.ToNumber (x); + } + return ScriptConvert.ToInt32 (value); + } + + static double stack_double (CallFrame frame, int i) + { + object x = frame.stack [i]; + if (x != UniqueTag.DoubleMark) { + return ScriptConvert.ToNumber (x); + } + else { + return frame.sDbl [i]; + } + } + + static bool stack_boolean (CallFrame frame, int i) + { + object x = frame.stack [i]; + if (x is bool) { + return (bool)x; + } + else if (x == UniqueTag.DoubleMark) { + double d = frame.sDbl [i]; + return !double.IsNaN (d) && d != 0.0; + } + else if (x == null || x == Undefined.Value) { + return false; + } + else if (CliHelper.IsNumber (x)) { + double d = Convert.ToDouble (x); + return (!double.IsNaN (d) && d != 0.0); + } + else { + return ScriptConvert.ToBoolean (x); + } + } + + static void DoAdd (object [] stack, double [] sDbl, int stackTop, Context cx) + { + object rhs = stack [stackTop + 1]; + object lhs = stack [stackTop]; + double d; + bool leftRightOrder; + if (rhs == UniqueTag.DoubleMark) { + d = sDbl [stackTop + 1]; + if (lhs == UniqueTag.DoubleMark) { + sDbl [stackTop] += d; + return; + } + leftRightOrder = true; + // fallthrough to object + number code + } + else if (lhs == UniqueTag.DoubleMark) { + d = sDbl [stackTop]; + lhs = rhs; + leftRightOrder = false; + // fallthrough to object + number code + } + else { + if (lhs is IScriptable || rhs is IScriptable) { + stack [stackTop] = ScriptRuntime.Add (lhs, rhs, cx); + } + else if (lhs is string) { + string lstr = (string)lhs; + string rstr = ScriptConvert.ToString (rhs); + stack [stackTop] = string.Concat (lstr, rstr); + } + else if (rhs is string) { + string lstr = ScriptConvert.ToString (lhs); + string rstr = (string)rhs; + stack [stackTop] = string.Concat (lstr, rstr); + } + else { + double lDbl = (CliHelper.IsNumber (lhs)) ? Convert.ToDouble (lhs) : ScriptConvert.ToNumber (lhs); + double rDbl = (CliHelper.IsNumber (rhs)) ? Convert.ToDouble (rhs) : ScriptConvert.ToNumber (rhs); + stack [stackTop] = UniqueTag.DoubleMark; + sDbl [stackTop] = lDbl + rDbl; + } + return; + } + + // handle object(lhs) + number(d) code + if (lhs is IScriptable) { + rhs = d; + if (!leftRightOrder) { + object tmp = lhs; + lhs = rhs; + rhs = tmp; + } + stack [stackTop] = ScriptRuntime.Add (lhs, rhs, cx); + } + else if (lhs is string) { + string lstr = (string)lhs; + string rstr = ScriptConvert.ToString (d); + if (leftRightOrder) { + stack [stackTop] = string.Concat (lstr, rstr); + } + else { + stack [stackTop] = string.Concat (rstr, lstr); + } + } + else { + double lDbl = (CliHelper.IsNumber (lhs)) ? Convert.ToDouble (lhs) : ScriptConvert.ToNumber (lhs); + stack [stackTop] = UniqueTag.DoubleMark; + sDbl [stackTop] = lDbl + d; + } + } + + void addGotoOp (int gotoOp) + { + sbyte [] array = itsData.itsICode; + int top = itsICodeTop; + if (top + 3 > array.Length) { + array = increaseICodeCapasity (3); + } + array [top] = (sbyte)gotoOp; + // Offset would written later + itsICodeTop = top + 1 + 2; + } + + + static object [] GetArgsArray (object [] stack, double [] sDbl, int shift, int count) + { + if (count == 0) { + return ScriptRuntime.EmptyArgs; + } + object [] args = new object [count]; + for (int i = 0; i != count; ++i, ++shift) { + object val = stack [shift]; + if (val == UniqueTag.DoubleMark) { + val = sDbl [shift]; + } + args [i] = val; + } + return args; + } + + static void addInstructionCount (Context cx, CallFrame frame, int extra) + { + cx.instructionCount += frame.pc - frame.pcPrevBranch + extra; + if (cx.instructionCount > cx.instructionThreshold) { + cx.ObserveInstructionCount (cx.instructionCount); + cx.instructionCount = 0; + } + } + + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/InterpreterData.cs b/src/EcmaScript.NET/InterpreterData.cs similarity index 96% rename from Code/EcmaScript.NET/InterpreterData.cs rename to src/EcmaScript.NET/InterpreterData.cs index c610843..d75dcb8 100644 --- a/Code/EcmaScript.NET/InterpreterData.cs +++ b/src/EcmaScript.NET/InterpreterData.cs @@ -1,186 +1,186 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -using EcmaScript.NET.Debugging; -using EcmaScript.NET.Collections; - -namespace EcmaScript.NET -{ - - internal sealed class InterpreterData : DebuggableScript - { - public bool TopLevel - { - get - { - return topLevel; - } - - } - public string FunctionName - { - get - { - return itsName; - } - - } - public int ParamCount - { - get - { - return argCount; - } - - } - public int ParamAndVarCount - { - get - { - return argNames.Length; - } - - } - public string SourceName - { - get - { - return itsSourceFile; - } - - } - public bool GeneratedScript - { - get - { - return ScriptRuntime.isGeneratedScript (itsSourceFile); - } - - } - public int [] LineNumbers - { - get - { - return Interpreter.getLineNumbers (this); - } - - } - public int FunctionCount - { - get - { - return (itsNestedFunctions == null) ? 0 : itsNestedFunctions.Length; - } - - } - public DebuggableScript Parent - { - get - { - return parentData; - } - - } - - internal const int INITIAL_MAX_ICODE_LENGTH = 1024; - internal const int INITIAL_STRINGTABLE_SIZE = 64; - internal const int INITIAL_NUMBERTABLE_SIZE = 64; - - internal InterpreterData (Context.Versions languageVersion, string sourceFile, string encodedSource) - { - this.languageVersion = languageVersion; - this.itsSourceFile = sourceFile; - this.encodedSource = encodedSource; - - Init (); - } - - internal InterpreterData (InterpreterData parent) - { - this.parentData = parent; - this.languageVersion = parent.languageVersion; - this.itsSourceFile = parent.itsSourceFile; - this.encodedSource = parent.encodedSource; - - Init (); - } - - private void Init () - { - itsICode = new sbyte [INITIAL_MAX_ICODE_LENGTH]; - itsStringTable = new string [INITIAL_STRINGTABLE_SIZE]; - } - - internal string itsName; - internal string itsSourceFile; - internal bool itsNeedsActivation; - internal int itsFunctionType; - - internal string [] itsStringTable; - internal double [] itsDoubleTable; - internal InterpreterData [] itsNestedFunctions; - internal object [] itsRegExpLiterals; - - internal sbyte [] itsICode; - - internal int [] itsExceptionTable; - - internal int itsMaxVars; - internal int itsMaxLocals; - internal int itsMaxStack; - internal int itsMaxFrameArray; - - // see comments in NativeFuncion for definition of argNames and argCount - internal string [] argNames; - internal int argCount; - - internal int itsMaxCalleeArgs; - - internal string encodedSource; - internal int encodedSourceStart; - internal int encodedSourceEnd; - - internal Context.Versions languageVersion; - - internal bool useDynamicScope; - - internal bool topLevel; - - internal object [] literalIds; - - internal UintMap longJumps; - - internal int firstLinePC = -1; // PC for the first LINE icode - - internal InterpreterData parentData; - - internal bool evalScriptFlag; // true if script corresponds to eval() code - - public bool IsFunction () - { - return itsFunctionType != 0; - } - - public string GetParamOrVarName (int index) - { - return argNames [index]; - } - - public DebuggableScript GetFunction (int index) - { - return itsNestedFunctions [index]; - } - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +using EcmaScript.NET.Debugging; +using EcmaScript.NET.Collections; + +namespace EcmaScript.NET +{ + + internal sealed class InterpreterData : DebuggableScript + { + public bool TopLevel + { + get + { + return topLevel; + } + + } + public string FunctionName + { + get + { + return itsName; + } + + } + public int ParamCount + { + get + { + return argCount; + } + + } + public int ParamAndVarCount + { + get + { + return argNames.Length; + } + + } + public string SourceName + { + get + { + return itsSourceFile; + } + + } + public bool GeneratedScript + { + get + { + return ScriptRuntime.isGeneratedScript (itsSourceFile); + } + + } + public int [] LineNumbers + { + get + { + return Interpreter.getLineNumbers (this); + } + + } + public int FunctionCount + { + get + { + return (itsNestedFunctions == null) ? 0 : itsNestedFunctions.Length; + } + + } + public DebuggableScript Parent + { + get + { + return parentData; + } + + } + + internal const int INITIAL_MAX_ICODE_LENGTH = 1024; + internal const int INITIAL_STRINGTABLE_SIZE = 64; + internal const int INITIAL_NUMBERTABLE_SIZE = 64; + + internal InterpreterData (Context.Versions languageVersion, string sourceFile, string encodedSource) + { + this.languageVersion = languageVersion; + this.itsSourceFile = sourceFile; + this.encodedSource = encodedSource; + + Init (); + } + + internal InterpreterData (InterpreterData parent) + { + this.parentData = parent; + this.languageVersion = parent.languageVersion; + this.itsSourceFile = parent.itsSourceFile; + this.encodedSource = parent.encodedSource; + + Init (); + } + + private void Init () + { + itsICode = new sbyte [INITIAL_MAX_ICODE_LENGTH]; + itsStringTable = new string [INITIAL_STRINGTABLE_SIZE]; + } + + internal string itsName; + internal string itsSourceFile; + internal bool itsNeedsActivation; + internal int itsFunctionType; + + internal string [] itsStringTable; + internal double [] itsDoubleTable; + internal InterpreterData [] itsNestedFunctions; + internal object [] itsRegExpLiterals; + + internal sbyte [] itsICode; + + internal int [] itsExceptionTable; + + internal int itsMaxVars; + internal int itsMaxLocals; + internal int itsMaxStack; + internal int itsMaxFrameArray; + + // see comments in NativeFuncion for definition of argNames and argCount + internal string [] argNames; + internal int argCount; + + internal int itsMaxCalleeArgs; + + internal string encodedSource; + internal int encodedSourceStart; + internal int encodedSourceEnd; + + internal Context.Versions languageVersion; + + internal bool useDynamicScope; + + internal bool topLevel; + + internal object [] literalIds; + + internal UintMap longJumps; + + internal int firstLinePC = -1; // PC for the first LINE icode + + internal InterpreterData parentData; + + internal bool evalScriptFlag; // true if script corresponds to eval() code + + public bool IsFunction () + { + return itsFunctionType != 0; + } + + public string GetParamOrVarName (int index) + { + return argNames [index]; + } + + public DebuggableScript GetFunction (int index) + { + return itsNestedFunctions [index]; + } + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/Node.cs b/src/EcmaScript.NET/Node.cs similarity index 96% rename from Code/EcmaScript.NET/Node.cs rename to src/EcmaScript.NET/Node.cs index 2dd2a3e..d803cae 100644 --- a/Code/EcmaScript.NET/Node.cs +++ b/src/EcmaScript.NET/Node.cs @@ -1,919 +1,919 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -using EcmaScript.NET.Collections; - -namespace EcmaScript.NET -{ - - /// This class implements the root of the intermediate representation. - /// - /// - public class Node - { - - internal class GetterPropertyLiteral - { - internal object Property; - - public GetterPropertyLiteral (object property) - { - Property = property; - } - } - - internal class SetterPropertyLiteral - { - internal object Property; - - public SetterPropertyLiteral (object property) - { - Property = property; - } - } - - public Node FirstChild - { - get - { - return first; - } - - } - public Node LastChild - { - get - { - return last; - } - - } - public Node Next - { - get - { - return next; - } - - } - public Node LastSibling - { - get - { - Node n = this; - while (n.next != null) { - n = n.next; - } - return n; - } - - } - public int Lineno - { - get - { - return lineno; - } - - } - /// Can only be called when getType() == Token.NUMBER - public double Double - { - get - { - return ((NumberNode)this).number; - } - - set - { - ((NumberNode)this).number = value; - } - - } - /// Can only be called when node has String context. - public string String - { - get - { - return ((StringNode)this).str; - } - - set - { - if (value == null) - Context.CodeBug (); - ((StringNode)this).str = value; - } - - } - - public const int FUNCTION_PROP = 1; - public const int LOCAL_PROP = 2; - public const int LOCAL_BLOCK_PROP = 3; - public const int REGEXP_PROP = 4; - public const int CASEARRAY_PROP = 5; - public const int TARGETBLOCK_PROP = 6; - public const int VARIABLE_PROP = 7; - public const int ISNUMBER_PROP = 8; - public const int DIRECTCALL_PROP = 9; - public const int SPECIALCALL_PROP = 10; - public const int SKIP_INDEXES_PROP = 11; - public const int OBJECT_IDS_PROP = 12; - public const int INCRDECR_PROP = 13; - public const int CATCH_SCOPE_PROP = 14; - public const int LABEL_ID_PROP = 15; - public const int MEMBER_TYPE_PROP = 16; - public const int NAME_PROP = 17; - public const int LAST_PROP = NAME_PROP; - - // values of ISNUMBER_PROP to specify - // which of the children are Number Types - public const int BOTH = 0; - public const int LEFT = 1; - public const int RIGHT = 2; - - public const int NON_SPECIALCALL = 0; - public const int SPECIALCALL_EVAL = 1; - public const int SPECIALCALL_WITH = 2; - - public const int DECR_FLAG = 0x1; - public const int POST_FLAG = 0x2; - - public const int PROPERTY_FLAG = 0x1; - public const int ATTRIBUTE_FLAG = 0x2; - public const int DESCENDANTS_FLAG = 0x4; // x..y or x..@i - - - private class NumberNode : Node - { - internal NumberNode (double number) - : base (Token.NUMBER) - { - this.number = number; - } - - internal double number; - } - - private class StringNode : Node - { - internal StringNode (int Type, string str) - : base (Type) - { - this.str = str; - } - - internal string str; - } - - public class Jump : Node - { - public Jump JumpStatement - { - get - { - if (!(Type == Token.BREAK || Type == Token.CONTINUE)) - Context.CodeBug (); - return jumpNode; - } - - set - { - if (!(Type == Token.BREAK || Type == Token.CONTINUE)) - Context.CodeBug (); - if (value == null) - Context.CodeBug (); - if (this.jumpNode != null) - Context.CodeBug (); //only once - this.jumpNode = value; - } - - } - public Node Default - { - get - { - if (!(Type == Token.SWITCH)) - Context.CodeBug (); - return target2; - } - - set - { - if (!(Type == Token.SWITCH)) - Context.CodeBug (); - if (value.Type != Token.TARGET) - Context.CodeBug (); - if (target2 != null) - Context.CodeBug (); //only once - target2 = value; - } - - } - public Node Finally - { - get - { - if (!(Type == Token.TRY)) - Context.CodeBug (); - return target2; - } - - set - { - if (!(Type == Token.TRY)) - Context.CodeBug (); - if (value.Type != Token.TARGET) - Context.CodeBug (); - if (target2 != null) - Context.CodeBug (); //only once - target2 = value; - } - - } - public Jump Loop - { - get - { - if (!(Type == Token.LABEL)) - Context.CodeBug (); - return jumpNode; - } - - set - { - if (!(Type == Token.LABEL)) - Context.CodeBug (); - if (value == null) - Context.CodeBug (); - if (jumpNode != null) - Context.CodeBug (); //only once - jumpNode = value; - } - - } - public Node Continue - { - get - { - if (Type != Token.LOOP) - Context.CodeBug (); - return target2; - } - - set - { - if (Type != Token.LOOP) - Context.CodeBug (); - if (value.Type != Token.TARGET) - Context.CodeBug (); - if (target2 != null) - Context.CodeBug (); //only once - target2 = value; - } - - } - public Jump (int Type) - : base (Type) - { - } - - internal Jump (int Type, int lineno) - : base (Type, lineno) - { - } - - internal Jump (int Type, Node child) - : base (Type, child) - { - } - - internal Jump (int Type, Node child, int lineno) - : base (Type, child, lineno) - { - } - - public Node target; - private Node target2; - private Jump jumpNode; - } - - private class PropListItem - { - internal PropListItem next; - internal int Type; - internal int intValue; - internal object objectValue; - } - - - public Node (int nodeType) - { - Type = nodeType; - } - - public Node (int nodeType, Node child) - { - Type = nodeType; - first = last = child; - child.next = null; - } - - public Node (int nodeType, Node left, Node right) - { - Type = nodeType; - first = left; - last = right; - left.next = right; - right.next = null; - } - - public Node (int nodeType, Node left, Node mid, Node right) - { - Type = nodeType; - first = left; - last = right; - left.next = mid; - mid.next = right; - right.next = null; - } - - public Node (int nodeType, int line) - { - Type = nodeType; - lineno = line; - } - - public Node (int nodeType, Node child, int line) - : this (nodeType, child) - { - lineno = line; - } - - public Node (int nodeType, Node left, Node right, int line) - : this (nodeType, left, right) - { - lineno = line; - } - - public Node (int nodeType, Node left, Node mid, Node right, int line) - : this (nodeType, left, mid, right) - { - lineno = line; - } - - public static Node newNumber (double number) - { - return new NumberNode (number); - } - - public static Node newString (string str) - { - return new StringNode (Token.STRING, str); - } - - public static Node newString (int Type, string str) - { - return new StringNode (Type, str); - } - - public bool hasChildren () - { - return first != null; - } - - public Node getChildBefore (Node child) - { - if (child == first) - return null; - Node n = first; - while (n.next != child) { - n = n.next; - if (n == null) - throw new ApplicationException ("node is not a child"); - } - return n; - } - - public void addChildToFront (Node child) - { - child.next = first; - first = child; - if (last == null) { - last = child; - } - } - - public void addChildToBack (Node child) - { - child.next = null; - if (last == null) { - first = last = child; - return; - } - last.next = child; - last = child; - } - - public void addChildrenToFront (Node children) - { - Node lastSib = children.LastSibling; - lastSib.next = first; - first = children; - if (last == null) { - last = lastSib; - } - } - - public void addChildrenToBack (Node children) - { - if (last != null) { - last.next = children; - } - last = children.LastSibling; - if (first == null) { - first = children; - } - } - - /// Add 'child' before 'node'. - public void addChildBefore (Node newChild, Node node) - { - if (newChild.next != null) - throw new ApplicationException ("newChild had siblings in addChildBefore"); - if (first == node) { - newChild.next = first; - first = newChild; - return; - } - Node prev = getChildBefore (node); - addChildAfter (newChild, prev); - } - - /// Add 'child' after 'node'. - public void addChildAfter (Node newChild, Node node) - { - if (newChild.next != null) - throw new ApplicationException ("newChild had siblings in addChildAfter"); - newChild.next = node.next; - node.next = newChild; - if (last == node) - last = newChild; - } - - public void removeChild (Node child) - { - Node prev = getChildBefore (child); - if (prev == null) - first = first.next; - else - prev.next = child.next; - if (child == last) - last = prev; - child.next = null; - } - - public void replaceChild (Node child, Node newChild) - { - newChild.next = child.next; - if (child == first) { - first = newChild; - } - else { - Node prev = getChildBefore (child); - prev.next = newChild; - } - if (child == last) - last = newChild; - child.next = null; - } - - public void replaceChildAfter (Node prevChild, Node newChild) - { - Node child = prevChild.next; - newChild.next = child.next; - prevChild.next = newChild; - if (child == last) - last = newChild; - child.next = null; - } - - private static string propToString (int propType) - { - if (Token.printTrees) { - // If Context.printTrees is false, the compiler - // can remove all these strings. - switch (propType) { - - case FUNCTION_PROP: - return "function"; - - case LOCAL_PROP: - return "local"; - - case LOCAL_BLOCK_PROP: - return "local_block"; - - case REGEXP_PROP: - return "regexp"; - - case CASEARRAY_PROP: - return "casearray"; - - - case TARGETBLOCK_PROP: - return "targetblock"; - - case VARIABLE_PROP: - return "variable"; - - case ISNUMBER_PROP: - return "isnumber"; - - case DIRECTCALL_PROP: - return "directcall"; - - - case SPECIALCALL_PROP: - return "specialcall"; - - case SKIP_INDEXES_PROP: - return "skip_indexes"; - - case OBJECT_IDS_PROP: - return "object_ids_prop"; - - case INCRDECR_PROP: - return "incrdecr_prop"; - - case CATCH_SCOPE_PROP: - return "catch_scope_prop"; - - case LABEL_ID_PROP: - return "label_id_prop"; - - case MEMBER_TYPE_PROP: - return "member_Type_prop"; - - case NAME_PROP: - return "name_prop"; - - - default: - Context.CodeBug (); - break; - - } - } - return null; - } - - private PropListItem lookupProperty (int propType) - { - PropListItem x = propListHead; - while (x != null && propType != x.Type) { - x = x.next; - } - return x; - } - - private PropListItem ensureProperty (int propType) - { - PropListItem item = lookupProperty (propType); - if (item == null) { - item = new PropListItem (); - item.Type = propType; - item.next = propListHead; - propListHead = item; - } - return item; - } - - public void removeProp (int propType) - { - PropListItem x = propListHead; - if (x != null) { - PropListItem prev = null; - while (x.Type != propType) { - prev = x; - x = x.next; - if (x == null) { - return; - } - } - if (prev == null) { - propListHead = x.next; - } - else { - prev.next = x.next; - } - } - } - - public object getProp (int propType) - { - PropListItem item = lookupProperty (propType); - if (item == null) { - return null; - } - return item.objectValue; - } - - public int getIntProp (int propType, int defaultValue) - { - PropListItem item = lookupProperty (propType); - if (item == null) { - return defaultValue; - } - return item.intValue; - } - - public int getExistingIntProp (int propType) - { - PropListItem item = lookupProperty (propType); - if (item == null) { - Context.CodeBug (); - } - return item.intValue; - } - - public void putProp (int propType, object prop) - { - if (prop == null) { - removeProp (propType); - } - else { - PropListItem item = ensureProperty (propType); - item.objectValue = prop; - } - } - - public void putIntProp (int propType, int prop) - { - PropListItem item = ensureProperty (propType); - item.intValue = prop; - } - - public static Node newTarget () - { - return new Node (Token.TARGET); - } - - public int labelId () - { - if (Type != Token.TARGET) - Context.CodeBug (); - return getIntProp (LABEL_ID_PROP, -1); - } - - public void labelId (int labelId) - { - if (Type != Token.TARGET) - Context.CodeBug (); - putIntProp (LABEL_ID_PROP, labelId); - } - - public override string ToString () - { - if (Token.printTrees) { - System.Text.StringBuilder sb = new System.Text.StringBuilder (); - toString (new ObjToIntMap (), sb); - return sb.ToString (); - } - return Convert.ToString (Type); - } - - private void toString (ObjToIntMap printIds, System.Text.StringBuilder sb) - { - if (Token.printTrees) { - sb.Append (Token.name (this.Type)); - if (this is StringNode) { - sb.Append (' '); - sb.Append (String); - } - else if (this is ScriptOrFnNode) { - ScriptOrFnNode sof = (ScriptOrFnNode)this; - if (this is FunctionNode) { - FunctionNode fn = (FunctionNode)this; - sb.Append (' '); - sb.Append (fn.FunctionName); - } - sb.Append (" [source name: "); - sb.Append (sof.SourceName); - sb.Append ("] [encoded source length: "); - sb.Append (sof.EncodedSourceEnd - sof.EncodedSourceStart); - sb.Append ("] [base line: "); - sb.Append (sof.BaseLineno); - sb.Append ("] [end line: "); - sb.Append (sof.EndLineno); - sb.Append (']'); - } - else if (this is Jump) { - Jump jump = (Jump)this; - if (this.Type == Token.BREAK || this.Type == Token.CONTINUE) { - sb.Append (" [label: "); - appendPrintId (jump.JumpStatement, printIds, sb); - sb.Append (']'); - } - else if (this.Type == Token.TRY) { - Node catchNode = jump.target; - Node finallyTarget = jump.Finally; - if (catchNode != null) { - sb.Append (" [catch: "); - appendPrintId (catchNode, printIds, sb); - sb.Append (']'); - } - if (finallyTarget != null) { - sb.Append (" [finally: "); - appendPrintId (finallyTarget, printIds, sb); - sb.Append (']'); - } - } - else if (this.Type == Token.LABEL || this.Type == Token.LOOP || this.Type == Token.SWITCH) { - sb.Append (" [break: "); - appendPrintId (jump.target, printIds, sb); - sb.Append (']'); - if (this.Type == Token.LOOP) { - sb.Append (" [continue: "); - appendPrintId (jump.Continue, printIds, sb); - sb.Append (']'); - } - } - else { - sb.Append (" [target: "); - appendPrintId (jump.target, printIds, sb); - sb.Append (']'); - } - } - else if (this.Type == Token.NUMBER) { - sb.Append (' '); - sb.Append (Double); - } - else if (this.Type == Token.TARGET) { - sb.Append (' '); - appendPrintId (this, printIds, sb); - } - if (lineno != -1) { - sb.Append (' '); - sb.Append (lineno); - } - - for (PropListItem x = propListHead; x != null; x = x.next) { - int Type = x.Type; - sb.Append (" ["); - sb.Append (propToString (Type)); - sb.Append (": "); - string value; - switch (Type) { - - case TARGETBLOCK_PROP: // can't add this as it recurses - value = "target block property"; - break; - - case LOCAL_BLOCK_PROP: // can't add this as it is dull - value = "last local block"; - break; - - case ISNUMBER_PROP: - switch (x.intValue) { - - case BOTH: - value = "both"; - break; - - case RIGHT: - value = "right"; - break; - - case LEFT: - value = "left"; - break; - - default: - throw Context.CodeBug (); - - } - break; - - case SPECIALCALL_PROP: - switch (x.intValue) { - - case SPECIALCALL_EVAL: - value = "eval"; - break; - - case SPECIALCALL_WITH: - value = "with"; - break; - - default: - // NON_SPECIALCALL should not be stored - throw Context.CodeBug (); - - } - break; - - default: - object obj = x.objectValue; - if (obj != null) { - value = obj.ToString (); - } - else { - value = Convert.ToString (x.intValue); - } - break; - - } - sb.Append (value); - sb.Append (']'); - } - } - } - - public string toStringTree (ScriptOrFnNode treeTop) - { - if (Token.printTrees) { - System.Text.StringBuilder sb = new System.Text.StringBuilder (); - toStringTreeHelper (treeTop, this, null, 0, sb); - return sb.ToString (); - } - return null; - } - - private static void toStringTreeHelper (ScriptOrFnNode treeTop, Node n, ObjToIntMap printIds, int level, System.Text.StringBuilder sb) - { - if (Token.printTrees) { - if (printIds == null) { - printIds = new ObjToIntMap (); - generatePrintIds (treeTop, printIds); - } - for (int i = 0; i != level; ++i) { - sb.Append (" "); - } - n.toString (printIds, sb); - sb.Append ('\n'); - for (Node cursor = n.FirstChild; cursor != null; cursor = cursor.Next) { - if (cursor.Type == Token.FUNCTION) { - int fnIndex = cursor.getExistingIntProp (Node.FUNCTION_PROP); - FunctionNode fn = treeTop.getFunctionNode (fnIndex); - toStringTreeHelper (fn, fn, null, level + 1, sb); - } - else { - toStringTreeHelper (treeTop, cursor, printIds, level + 1, sb); - } - } - } - } - - private static void generatePrintIds (Node n, ObjToIntMap map) - { - if (Token.printTrees) { - map.put (n, map.size ()); - for (Node cursor = n.FirstChild; cursor != null; cursor = cursor.Next) { - generatePrintIds (cursor, map); - } - } - } - - private static void appendPrintId (Node n, ObjToIntMap printIds, System.Text.StringBuilder sb) - { - if (Token.printTrees) { - if (n != null) { - int id = printIds.Get (n, -1); - sb.Append ('#'); - if (id != -1) { - sb.Append (id + 1); - } - else { - sb.Append (""); - } - } - } - } - - internal int Type; // Type of the node; Token.NAME for example - internal Node next; // next sibling - private Node first; // first element of a linked list of children - private Node last; // last element of a linked list of children - private int lineno = -1; // encapsulated int data; depends on Type - - /// Linked list of properties. Since vast majority of nodes would have - /// no more then 2 properties, linked list saves memory and provides - /// fast lookup. If this does not holds, propListHead can be replaced - /// by UintMap. - /// - private PropListItem propListHead; - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +using EcmaScript.NET.Collections; + +namespace EcmaScript.NET +{ + + /// This class implements the root of the intermediate representation. + /// + /// + public class Node + { + + internal class GetterPropertyLiteral + { + internal object Property; + + public GetterPropertyLiteral (object property) + { + Property = property; + } + } + + internal class SetterPropertyLiteral + { + internal object Property; + + public SetterPropertyLiteral (object property) + { + Property = property; + } + } + + public Node FirstChild + { + get + { + return first; + } + + } + public Node LastChild + { + get + { + return last; + } + + } + public Node Next + { + get + { + return next; + } + + } + public Node LastSibling + { + get + { + Node n = this; + while (n.next != null) { + n = n.next; + } + return n; + } + + } + public int Lineno + { + get + { + return lineno; + } + + } + /// Can only be called when getType() == Token.NUMBER + public double Double + { + get + { + return ((NumberNode)this).number; + } + + set + { + ((NumberNode)this).number = value; + } + + } + /// Can only be called when node has String context. + public string String + { + get + { + return ((StringNode)this).str; + } + + set + { + if (value == null) + Context.CodeBug (); + ((StringNode)this).str = value; + } + + } + + public const int FUNCTION_PROP = 1; + public const int LOCAL_PROP = 2; + public const int LOCAL_BLOCK_PROP = 3; + public const int REGEXP_PROP = 4; + public const int CASEARRAY_PROP = 5; + public const int TARGETBLOCK_PROP = 6; + public const int VARIABLE_PROP = 7; + public const int ISNUMBER_PROP = 8; + public const int DIRECTCALL_PROP = 9; + public const int SPECIALCALL_PROP = 10; + public const int SKIP_INDEXES_PROP = 11; + public const int OBJECT_IDS_PROP = 12; + public const int INCRDECR_PROP = 13; + public const int CATCH_SCOPE_PROP = 14; + public const int LABEL_ID_PROP = 15; + public const int MEMBER_TYPE_PROP = 16; + public const int NAME_PROP = 17; + public const int LAST_PROP = NAME_PROP; + + // values of ISNUMBER_PROP to specify + // which of the children are Number Types + public const int BOTH = 0; + public const int LEFT = 1; + public const int RIGHT = 2; + + public const int NON_SPECIALCALL = 0; + public const int SPECIALCALL_EVAL = 1; + public const int SPECIALCALL_WITH = 2; + + public const int DECR_FLAG = 0x1; + public const int POST_FLAG = 0x2; + + public const int PROPERTY_FLAG = 0x1; + public const int ATTRIBUTE_FLAG = 0x2; + public const int DESCENDANTS_FLAG = 0x4; // x..y or x..@i + + + private class NumberNode : Node + { + internal NumberNode (double number) + : base (Token.NUMBER) + { + this.number = number; + } + + internal double number; + } + + private class StringNode : Node + { + internal StringNode (int Type, string str) + : base (Type) + { + this.str = str; + } + + internal string str; + } + + public class Jump : Node + { + public Jump JumpStatement + { + get + { + if (!(Type == Token.BREAK || Type == Token.CONTINUE)) + Context.CodeBug (); + return jumpNode; + } + + set + { + if (!(Type == Token.BREAK || Type == Token.CONTINUE)) + Context.CodeBug (); + if (value == null) + Context.CodeBug (); + if (this.jumpNode != null) + Context.CodeBug (); //only once + this.jumpNode = value; + } + + } + public Node Default + { + get + { + if (!(Type == Token.SWITCH)) + Context.CodeBug (); + return target2; + } + + set + { + if (!(Type == Token.SWITCH)) + Context.CodeBug (); + if (value.Type != Token.TARGET) + Context.CodeBug (); + if (target2 != null) + Context.CodeBug (); //only once + target2 = value; + } + + } + public Node Finally + { + get + { + if (!(Type == Token.TRY)) + Context.CodeBug (); + return target2; + } + + set + { + if (!(Type == Token.TRY)) + Context.CodeBug (); + if (value.Type != Token.TARGET) + Context.CodeBug (); + if (target2 != null) + Context.CodeBug (); //only once + target2 = value; + } + + } + public Jump Loop + { + get + { + if (!(Type == Token.LABEL)) + Context.CodeBug (); + return jumpNode; + } + + set + { + if (!(Type == Token.LABEL)) + Context.CodeBug (); + if (value == null) + Context.CodeBug (); + if (jumpNode != null) + Context.CodeBug (); //only once + jumpNode = value; + } + + } + public Node Continue + { + get + { + if (Type != Token.LOOP) + Context.CodeBug (); + return target2; + } + + set + { + if (Type != Token.LOOP) + Context.CodeBug (); + if (value.Type != Token.TARGET) + Context.CodeBug (); + if (target2 != null) + Context.CodeBug (); //only once + target2 = value; + } + + } + public Jump (int Type) + : base (Type) + { + } + + internal Jump (int Type, int lineno) + : base (Type, lineno) + { + } + + internal Jump (int Type, Node child) + : base (Type, child) + { + } + + internal Jump (int Type, Node child, int lineno) + : base (Type, child, lineno) + { + } + + public Node target; + private Node target2; + private Jump jumpNode; + } + + private class PropListItem + { + internal PropListItem next; + internal int Type; + internal int intValue; + internal object objectValue; + } + + + public Node (int nodeType) + { + Type = nodeType; + } + + public Node (int nodeType, Node child) + { + Type = nodeType; + first = last = child; + child.next = null; + } + + public Node (int nodeType, Node left, Node right) + { + Type = nodeType; + first = left; + last = right; + left.next = right; + right.next = null; + } + + public Node (int nodeType, Node left, Node mid, Node right) + { + Type = nodeType; + first = left; + last = right; + left.next = mid; + mid.next = right; + right.next = null; + } + + public Node (int nodeType, int line) + { + Type = nodeType; + lineno = line; + } + + public Node (int nodeType, Node child, int line) + : this (nodeType, child) + { + lineno = line; + } + + public Node (int nodeType, Node left, Node right, int line) + : this (nodeType, left, right) + { + lineno = line; + } + + public Node (int nodeType, Node left, Node mid, Node right, int line) + : this (nodeType, left, mid, right) + { + lineno = line; + } + + public static Node newNumber (double number) + { + return new NumberNode (number); + } + + public static Node newString (string str) + { + return new StringNode (Token.STRING, str); + } + + public static Node newString (int Type, string str) + { + return new StringNode (Type, str); + } + + public bool hasChildren () + { + return first != null; + } + + public Node getChildBefore (Node child) + { + if (child == first) + return null; + Node n = first; + while (n.next != child) { + n = n.next; + if (n == null) + throw new Exception ("node is not a child"); + } + return n; + } + + public void addChildToFront (Node child) + { + child.next = first; + first = child; + if (last == null) { + last = child; + } + } + + public void addChildToBack (Node child) + { + child.next = null; + if (last == null) { + first = last = child; + return; + } + last.next = child; + last = child; + } + + public void addChildrenToFront (Node children) + { + Node lastSib = children.LastSibling; + lastSib.next = first; + first = children; + if (last == null) { + last = lastSib; + } + } + + public void addChildrenToBack (Node children) + { + if (last != null) { + last.next = children; + } + last = children.LastSibling; + if (first == null) { + first = children; + } + } + + /// Add 'child' before 'node'. + public void addChildBefore (Node newChild, Node node) + { + if (newChild.next != null) + throw new Exception ("newChild had siblings in addChildBefore"); + if (first == node) { + newChild.next = first; + first = newChild; + return; + } + Node prev = getChildBefore (node); + addChildAfter (newChild, prev); + } + + /// Add 'child' after 'node'. + public void addChildAfter (Node newChild, Node node) + { + if (newChild.next != null) + throw new Exception ("newChild had siblings in addChildAfter"); + newChild.next = node.next; + node.next = newChild; + if (last == node) + last = newChild; + } + + public void removeChild (Node child) + { + Node prev = getChildBefore (child); + if (prev == null) + first = first.next; + else + prev.next = child.next; + if (child == last) + last = prev; + child.next = null; + } + + public void replaceChild (Node child, Node newChild) + { + newChild.next = child.next; + if (child == first) { + first = newChild; + } + else { + Node prev = getChildBefore (child); + prev.next = newChild; + } + if (child == last) + last = newChild; + child.next = null; + } + + public void replaceChildAfter (Node prevChild, Node newChild) + { + Node child = prevChild.next; + newChild.next = child.next; + prevChild.next = newChild; + if (child == last) + last = newChild; + child.next = null; + } + + private static string propToString (int propType) + { + if (Token.printTrees) { + // If Context.printTrees is false, the compiler + // can remove all these strings. + switch (propType) { + + case FUNCTION_PROP: + return "function"; + + case LOCAL_PROP: + return "local"; + + case LOCAL_BLOCK_PROP: + return "local_block"; + + case REGEXP_PROP: + return "regexp"; + + case CASEARRAY_PROP: + return "casearray"; + + + case TARGETBLOCK_PROP: + return "targetblock"; + + case VARIABLE_PROP: + return "variable"; + + case ISNUMBER_PROP: + return "isnumber"; + + case DIRECTCALL_PROP: + return "directcall"; + + + case SPECIALCALL_PROP: + return "specialcall"; + + case SKIP_INDEXES_PROP: + return "skip_indexes"; + + case OBJECT_IDS_PROP: + return "object_ids_prop"; + + case INCRDECR_PROP: + return "incrdecr_prop"; + + case CATCH_SCOPE_PROP: + return "catch_scope_prop"; + + case LABEL_ID_PROP: + return "label_id_prop"; + + case MEMBER_TYPE_PROP: + return "member_Type_prop"; + + case NAME_PROP: + return "name_prop"; + + + default: + Context.CodeBug (); + break; + + } + } + return null; + } + + private PropListItem lookupProperty (int propType) + { + PropListItem x = propListHead; + while (x != null && propType != x.Type) { + x = x.next; + } + return x; + } + + private PropListItem ensureProperty (int propType) + { + PropListItem item = lookupProperty (propType); + if (item == null) { + item = new PropListItem (); + item.Type = propType; + item.next = propListHead; + propListHead = item; + } + return item; + } + + public void removeProp (int propType) + { + PropListItem x = propListHead; + if (x != null) { + PropListItem prev = null; + while (x.Type != propType) { + prev = x; + x = x.next; + if (x == null) { + return; + } + } + if (prev == null) { + propListHead = x.next; + } + else { + prev.next = x.next; + } + } + } + + public object getProp (int propType) + { + PropListItem item = lookupProperty (propType); + if (item == null) { + return null; + } + return item.objectValue; + } + + public int getIntProp (int propType, int defaultValue) + { + PropListItem item = lookupProperty (propType); + if (item == null) { + return defaultValue; + } + return item.intValue; + } + + public int getExistingIntProp (int propType) + { + PropListItem item = lookupProperty (propType); + if (item == null) { + Context.CodeBug (); + } + return item.intValue; + } + + public void putProp (int propType, object prop) + { + if (prop == null) { + removeProp (propType); + } + else { + PropListItem item = ensureProperty (propType); + item.objectValue = prop; + } + } + + public void putIntProp (int propType, int prop) + { + PropListItem item = ensureProperty (propType); + item.intValue = prop; + } + + public static Node newTarget () + { + return new Node (Token.TARGET); + } + + public int labelId () + { + if (Type != Token.TARGET) + Context.CodeBug (); + return getIntProp (LABEL_ID_PROP, -1); + } + + public void labelId (int labelId) + { + if (Type != Token.TARGET) + Context.CodeBug (); + putIntProp (LABEL_ID_PROP, labelId); + } + + public override string ToString () + { + if (Token.printTrees) { + System.Text.StringBuilder sb = new System.Text.StringBuilder (); + toString (new ObjToIntMap (), sb); + return sb.ToString (); + } + return Convert.ToString (Type); + } + + private void toString (ObjToIntMap printIds, System.Text.StringBuilder sb) + { + if (Token.printTrees) { + sb.Append (Token.name (this.Type)); + if (this is StringNode) { + sb.Append (' '); + sb.Append (String); + } + else if (this is ScriptOrFnNode) { + ScriptOrFnNode sof = (ScriptOrFnNode)this; + if (this is FunctionNode) { + FunctionNode fn = (FunctionNode)this; + sb.Append (' '); + sb.Append (fn.FunctionName); + } + sb.Append (" [source name: "); + sb.Append (sof.SourceName); + sb.Append ("] [encoded source length: "); + sb.Append (sof.EncodedSourceEnd - sof.EncodedSourceStart); + sb.Append ("] [base line: "); + sb.Append (sof.BaseLineno); + sb.Append ("] [end line: "); + sb.Append (sof.EndLineno); + sb.Append (']'); + } + else if (this is Jump) { + Jump jump = (Jump)this; + if (this.Type == Token.BREAK || this.Type == Token.CONTINUE) { + sb.Append (" [label: "); + appendPrintId (jump.JumpStatement, printIds, sb); + sb.Append (']'); + } + else if (this.Type == Token.TRY) { + Node catchNode = jump.target; + Node finallyTarget = jump.Finally; + if (catchNode != null) { + sb.Append (" [catch: "); + appendPrintId (catchNode, printIds, sb); + sb.Append (']'); + } + if (finallyTarget != null) { + sb.Append (" [finally: "); + appendPrintId (finallyTarget, printIds, sb); + sb.Append (']'); + } + } + else if (this.Type == Token.LABEL || this.Type == Token.LOOP || this.Type == Token.SWITCH) { + sb.Append (" [break: "); + appendPrintId (jump.target, printIds, sb); + sb.Append (']'); + if (this.Type == Token.LOOP) { + sb.Append (" [continue: "); + appendPrintId (jump.Continue, printIds, sb); + sb.Append (']'); + } + } + else { + sb.Append (" [target: "); + appendPrintId (jump.target, printIds, sb); + sb.Append (']'); + } + } + else if (this.Type == Token.NUMBER) { + sb.Append (' '); + sb.Append (Double); + } + else if (this.Type == Token.TARGET) { + sb.Append (' '); + appendPrintId (this, printIds, sb); + } + if (lineno != -1) { + sb.Append (' '); + sb.Append (lineno); + } + + for (PropListItem x = propListHead; x != null; x = x.next) { + int Type = x.Type; + sb.Append (" ["); + sb.Append (propToString (Type)); + sb.Append (": "); + string value; + switch (Type) { + + case TARGETBLOCK_PROP: // can't add this as it recurses + value = "target block property"; + break; + + case LOCAL_BLOCK_PROP: // can't add this as it is dull + value = "last local block"; + break; + + case ISNUMBER_PROP: + switch (x.intValue) { + + case BOTH: + value = "both"; + break; + + case RIGHT: + value = "right"; + break; + + case LEFT: + value = "left"; + break; + + default: + throw Context.CodeBug (); + + } + break; + + case SPECIALCALL_PROP: + switch (x.intValue) { + + case SPECIALCALL_EVAL: + value = "eval"; + break; + + case SPECIALCALL_WITH: + value = "with"; + break; + + default: + // NON_SPECIALCALL should not be stored + throw Context.CodeBug (); + + } + break; + + default: + object obj = x.objectValue; + if (obj != null) { + value = obj.ToString (); + } + else { + value = Convert.ToString (x.intValue); + } + break; + + } + sb.Append (value); + sb.Append (']'); + } + } + } + + public string toStringTree (ScriptOrFnNode treeTop) + { + if (Token.printTrees) { + System.Text.StringBuilder sb = new System.Text.StringBuilder (); + toStringTreeHelper (treeTop, this, null, 0, sb); + return sb.ToString (); + } + return null; + } + + private static void toStringTreeHelper (ScriptOrFnNode treeTop, Node n, ObjToIntMap printIds, int level, System.Text.StringBuilder sb) + { + if (Token.printTrees) { + if (printIds == null) { + printIds = new ObjToIntMap (); + generatePrintIds (treeTop, printIds); + } + for (int i = 0; i != level; ++i) { + sb.Append (" "); + } + n.toString (printIds, sb); + sb.Append ('\n'); + for (Node cursor = n.FirstChild; cursor != null; cursor = cursor.Next) { + if (cursor.Type == Token.FUNCTION) { + int fnIndex = cursor.getExistingIntProp (Node.FUNCTION_PROP); + FunctionNode fn = treeTop.getFunctionNode (fnIndex); + toStringTreeHelper (fn, fn, null, level + 1, sb); + } + else { + toStringTreeHelper (treeTop, cursor, printIds, level + 1, sb); + } + } + } + } + + private static void generatePrintIds (Node n, ObjToIntMap map) + { + if (Token.printTrees) { + map.put (n, map.size ()); + for (Node cursor = n.FirstChild; cursor != null; cursor = cursor.Next) { + generatePrintIds (cursor, map); + } + } + } + + private static void appendPrintId (Node n, ObjToIntMap printIds, System.Text.StringBuilder sb) + { + if (Token.printTrees) { + if (n != null) { + int id = printIds.Get (n, -1); + sb.Append ('#'); + if (id != -1) { + sb.Append (id + 1); + } + else { + sb.Append (""); + } + } + } + } + + internal int Type; // Type of the node; Token.NAME for example + internal Node next; // next sibling + private Node first; // first element of a linked list of children + private Node last; // last element of a linked list of children + private int lineno = -1; // encapsulated int data; depends on Type + + /// Linked list of properties. Since vast majority of nodes would have + /// no more then 2 properties, linked list saves memory and provides + /// fast lookup. If this does not holds, propListHead can be replaced + /// by UintMap. + /// + private PropListItem propListHead; + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/NodeFactory.cs b/src/EcmaScript.NET/NodeFactory.cs similarity index 97% rename from Code/EcmaScript.NET/NodeFactory.cs rename to src/EcmaScript.NET/NodeFactory.cs index e0efb67..0221f88 100644 --- a/Code/EcmaScript.NET/NodeFactory.cs +++ b/src/EcmaScript.NET/NodeFactory.cs @@ -1,1429 +1,1429 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -using EcmaScript.NET.Collections; - -namespace EcmaScript.NET -{ - - /// This class allows the creation of nodes, and follows the Factory pattern. - /// - /// - sealed class NodeFactory - { - internal NodeFactory (Parser parser) - { - this.parser = parser; - } - - internal ScriptOrFnNode CreateScript () - { - return new ScriptOrFnNode (Token.SCRIPT); - } - - /// Script (for associating file/url names with toplevel scripts.) - internal void initScript (ScriptOrFnNode scriptNode, Node body) - { - Node children = body.FirstChild; - if (children != null) { - scriptNode.addChildrenToBack (children); - } - } - - /// Leaf - internal Node CreateLeaf (int nodeType) - { - return new Node (nodeType); - } - - internal Node CreateLeaf (int nodeType, int nodeOp) - { - return new Node (nodeType, nodeOp); - } - - /// Statement leaf nodes. - - internal Node CreateSwitch (Node expr, int lineno) - { - // - // The switch will be rewritten from: - // - // switch (expr) { - // case test1: statements1; - // ... - // default: statementsDefault; - // ... - // case testN: statementsN; - // } - // - // to: - // - // { - // switch (expr) { - // case test1: goto label1; - // ... - // case testN: goto labelN; - // } - // goto labelDefault; - // label1: - // statements1; - // ... - // labelDefault: - // statementsDefault; - // ... - // labelN: - // statementsN; - // breakLabel: - // } - // - // where inside switch each "break;" without label will be replaced - // by "goto breakLabel". - // - // If the original switch does not have the default label, then - // the transformed code would contain after the switch instead of - // goto labelDefault; - // the following goto: - // goto breakLabel; - // - - Node.Jump switchNode = new Node.Jump (Token.SWITCH, expr, lineno); - Node block = new Node (Token.BLOCK, switchNode); - return block; - } - - /// If caseExpression argument is null it indicate default label. - internal void addSwitchCase (Node switchBlock, Node caseExpression, Node statements) - { - if (switchBlock.Type != Token.BLOCK) - throw Context.CodeBug (); - Node.Jump switchNode = (Node.Jump)switchBlock.FirstChild; - if (switchNode.Type != Token.SWITCH) - throw Context.CodeBug (); - - Node gotoTarget = Node.newTarget (); - if (caseExpression != null) { - Node.Jump caseNode = new Node.Jump (Token.CASE, caseExpression); - caseNode.target = gotoTarget; - switchNode.addChildToBack (caseNode); - } - else { - switchNode.Default = gotoTarget; - } - switchBlock.addChildToBack (gotoTarget); - switchBlock.addChildToBack (statements); - } - - internal void closeSwitch (Node switchBlock) - { - if (switchBlock.Type != Token.BLOCK) - throw Context.CodeBug (); - Node.Jump switchNode = (Node.Jump)switchBlock.FirstChild; - if (switchNode.Type != Token.SWITCH) - throw Context.CodeBug (); - - Node switchBreakTarget = Node.newTarget (); - // switchNode.target is only used by NodeTransformer - // to detect switch end - switchNode.target = switchBreakTarget; - - Node defaultTarget = switchNode.Default; - if (defaultTarget == null) { - defaultTarget = switchBreakTarget; - } - - switchBlock.addChildAfter (makeJump (Token.GOTO, defaultTarget), switchNode); - switchBlock.addChildToBack (switchBreakTarget); - } - - internal Node CreateVariables (int lineno) - { - return new Node (Token.VAR, lineno); - } - - internal Node CreateExprStatement (Node expr, int lineno) - { - int type; - if (parser.insideFunction ()) { - type = Token.EXPR_VOID; - } - else { - type = Token.EXPR_RESULT; - } - return new Node (type, expr, lineno); - } - - internal Node CreateExprStatementNoReturn (Node expr, int lineno) - { - return new Node (Token.EXPR_VOID, expr, lineno); - } - - internal Node CreateDefaultNamespace (Node expr, int lineno) - { - // default xml namespace requires activation - setRequiresActivation (); - Node n = CreateUnary (Token.DEFAULTNAMESPACE, expr); - Node result = CreateExprStatement (n, lineno); - return result; - } - - /// Name - internal Node CreateName (string name) - { - checkActivationName (name, Token.NAME); - return Node.newString (Token.NAME, name); - } - - /// String (for literals) - internal Node CreateString (string str) - { - return Node.newString (str); - } - - /// Number (for literals) - internal Node CreateNumber (double number) - { - return Node.newNumber (number); - } - - /// Catch clause of try/catch/finally - /// the name of the variable to bind to the exception - /// - /// the condition under which to catch the exception. - /// May be null if no condition is given. - /// - /// the statements in the catch clause - /// - /// the starting line number of the catch clause - /// - internal Node CreateCatch (string varName, Node catchCond, Node stmts, int lineno) - { - if (catchCond == null) { - catchCond = new Node (Token.EMPTY); - } - return new Node (Token.CATCH, CreateName (varName), catchCond, stmts, lineno); - } - - /// Throw - internal Node CreateThrow (Node expr, int lineno) - { - return new Node (Token.THROW, expr, lineno); - } - - /// Return - internal Node CreateReturn (Node expr, int lineno) - { - return expr == null ? new Node (Token.RETURN, lineno) : new Node (Token.RETURN, expr, lineno); - } - - /// Debugger - internal Node CreateDebugger(int lineno) - { - return new Node(Token.DEBUGGER, lineno); - } - - /// Label - internal Node CreateLabel (int lineno) - { - return new Node.Jump (Token.LABEL, lineno); - } - - internal Node getLabelLoop (Node label) - { - return ((Node.Jump)label).Loop; - } - - /// Label - internal Node CreateLabeledStatement (Node labelArg, Node statement) - { - Node.Jump label = (Node.Jump)labelArg; - - // Make a target and put it _after_ the statement - // node. And in the LABEL node, so breaks get the - // right target. - - Node breakTarget = Node.newTarget (); - Node block = new Node (Token.BLOCK, label, statement, breakTarget); - label.target = breakTarget; - - return block; - } - - /// Break (possibly labeled) - internal Node CreateBreak (Node breakStatement, int lineno) - { - Node.Jump n = new Node.Jump (Token.BREAK, lineno); - Node.Jump jumpStatement; - int t = breakStatement.Type; - if (t == Token.LOOP || t == Token.LABEL) { - jumpStatement = (Node.Jump)breakStatement; - } - else if (t == Token.BLOCK && breakStatement.FirstChild.Type == Token.SWITCH) { - jumpStatement = (Node.Jump)breakStatement.FirstChild; - } - else { - throw Context.CodeBug (); - } - n.JumpStatement = jumpStatement; - return n; - } - - /// Continue (possibly labeled) - internal Node CreateContinue (Node loop, int lineno) - { - if (loop.Type != Token.LOOP) - Context.CodeBug (); - Node.Jump n = new Node.Jump (Token.CONTINUE, lineno); - n.JumpStatement = (Node.Jump)loop; - return n; - } - - /// Statement block - /// Creates the empty statement block - /// Must make subsequent calls to add statements to the node - /// - internal Node CreateBlock (int lineno) - { - return new Node (Token.BLOCK, lineno); - } - - internal FunctionNode CreateFunction (string name) - { - return new FunctionNode (name); - } - - internal Node initFunction (FunctionNode fnNode, int functionIndex, Node statements, int functionType) - { - fnNode.itsFunctionType = functionType; - fnNode.addChildToBack (statements); - - int functionCount = fnNode.FunctionCount; - if (functionCount != 0) { - // Functions containing other functions require activation objects - fnNode.itsNeedsActivation = true; - for (int i = 0; i != functionCount; ++i) { - FunctionNode fn = fnNode.getFunctionNode (i); - // nested function expression statements overrides var - if (fn.FunctionType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) { - string name = fn.FunctionName; - if (name != null && name.Length != 0) { - fnNode.removeParamOrVar (name); - } - } - } - } - - if (functionType == FunctionNode.FUNCTION_EXPRESSION) { - string name = fnNode.FunctionName; - if (name != null && name.Length != 0 && !fnNode.hasParamOrVar (name)) { - // A function expression needs to have its name as a - // variable (if it isn't already allocated as a variable). - // See ECMA Ch. 13. We add code to the beginning of the - // function to initialize a local variable of the - // function's name to the function value. - fnNode.addVar (name); - Node setFn = new Node (Token.EXPR_VOID, new Node (Token.SETNAME, Node.newString (Token.BINDNAME, name), new Node (Token.THISFN))); - statements.addChildrenToFront (setFn); - } - } - - // Add return to end if needed. - Node lastStmt = statements.LastChild; - if (lastStmt == null || lastStmt.Type != Token.RETURN) { - statements.addChildToBack (new Node (Token.RETURN)); - } - - Node result = Node.newString (Token.FUNCTION, fnNode.FunctionName); - result.putIntProp (Node.FUNCTION_PROP, functionIndex); - return result; - } - - /// Add a child to the back of the given node. This function - /// breaks the Factory abstraction, but it removes a requirement - /// from implementors of Node. - /// - internal void addChildToBack (Node parent, Node child) - { - parent.addChildToBack (child); - } - - /// Create loop node. The parser will later call - /// CreateWhile|CreateDoWhile|CreateFor|CreateForIn - /// to finish loop generation. - /// - internal Node CreateLoopNode (Node loopLabel, int lineno) - { - Node.Jump result = new Node.Jump (Token.LOOP, lineno); - if (loopLabel != null) { - ((Node.Jump)loopLabel).Loop = result; - } - return result; - } - - /// While - internal Node CreateWhile (Node loop, Node cond, Node body) - { - return CreateLoop ((Node.Jump)loop, LOOP_WHILE, body, cond, null, null); - } - - /// DoWhile - internal Node CreateDoWhile (Node loop, Node body, Node cond) - { - return CreateLoop ((Node.Jump)loop, LOOP_DO_WHILE, body, cond, null, null); - } - - /// For - internal Node CreateFor (Node loop, Node init, Node test, Node incr, Node body) - { - return CreateLoop ((Node.Jump)loop, LOOP_FOR, body, test, init, incr); - } - - private Node CreateLoop (Node.Jump loop, int loopType, Node body, Node cond, Node init, Node incr) - { - Node bodyTarget = Node.newTarget (); - Node condTarget = Node.newTarget (); - if (loopType == LOOP_FOR && cond.Type == Token.EMPTY) { - cond = new Node (Token.TRUE); - } - Node.Jump IFEQ = new Node.Jump (Token.IFEQ, cond); - IFEQ.target = bodyTarget; - Node breakTarget = Node.newTarget (); - - loop.addChildToBack (bodyTarget); - loop.addChildrenToBack (body); - if (loopType == LOOP_WHILE || loopType == LOOP_FOR) { - // propagate lineno to condition - loop.addChildrenToBack (new Node (Token.EMPTY, loop.Lineno)); - } - loop.addChildToBack (condTarget); - loop.addChildToBack (IFEQ); - loop.addChildToBack (breakTarget); - - loop.target = breakTarget; - Node continueTarget = condTarget; - - if (loopType == LOOP_WHILE || loopType == LOOP_FOR) { - // Just add a GOTO to the condition in the do..while - loop.addChildToFront (makeJump (Token.GOTO, condTarget)); - - if (loopType == LOOP_FOR) { - if (init.Type != Token.EMPTY) { - if (init.Type != Token.VAR) { - init = new Node (Token.EXPR_VOID, init); - } - loop.addChildToFront (init); - } - Node incrTarget = Node.newTarget (); - loop.addChildAfter (incrTarget, body); - if (incr.Type != Token.EMPTY) { - incr = new Node (Token.EXPR_VOID, incr); - loop.addChildAfter (incr, incrTarget); - } - continueTarget = incrTarget; - } - } - - loop.Continue = continueTarget; - - return loop; - } - - /// For .. In - /// - /// - internal Node CreateForIn (Node loop, Node lhs, Node obj, Node body, bool isForEach) - { - int type = lhs.Type; - - Node lvalue; - if (type == Token.VAR) { - /* - * check that there was only one variable given. - * we can't do this in the parser, because then the - * parser would have to know something about the - * 'init' node of the for-in loop. - */ - Node lastChild = lhs.LastChild; - if (lhs.FirstChild != lastChild) { - parser.ReportError ("msg.mult.index"); - } - lvalue = Node.newString (Token.NAME, lastChild.String); - } - else { - lvalue = makeReference (lhs); - if (lvalue == null) { - parser.ReportError ("msg.bad.for.in.lhs"); - return obj; - } - } - - Node localBlock = new Node (Token.LOCAL_BLOCK); - - int initType = (isForEach) ? Token.ENUM_INIT_VALUES : Token.ENUM_INIT_KEYS; - Node init = new Node (initType, obj); - init.putProp (Node.LOCAL_BLOCK_PROP, localBlock); - Node cond = new Node (Token.ENUM_NEXT); - cond.putProp (Node.LOCAL_BLOCK_PROP, localBlock); - Node id = new Node (Token.ENUM_ID); - id.putProp (Node.LOCAL_BLOCK_PROP, localBlock); - - Node newBody = new Node (Token.BLOCK); - Node assign = simpleAssignment (lvalue, id); - newBody.addChildToBack (new Node (Token.EXPR_VOID, assign)); - newBody.addChildToBack (body); - - loop = CreateWhile (loop, cond, newBody); - loop.addChildToFront (init); - if (type == Token.VAR) - loop.addChildToFront (lhs); - localBlock.addChildToBack (loop); - - return localBlock; - } - - /// Try/Catch/Finally - /// - /// The IRFactory tries to express as much as possible in the tree; - /// the responsibilities remaining for Codegen are to add the Java - /// handlers: (Either (but not both) of TARGET and FINALLY might not - /// be defined) - /// - a catch handler for javascript exceptions that unwraps the - /// exception onto the stack and GOTOes to the catch target - /// - a finally handler - /// ... and a goto to GOTO around these handlers. - /// - internal Node CreateTryCatchFinally (Node tryBlock, Node catchBlocks, Node finallyBlock, int lineno) - { - bool hasFinally = (finallyBlock != null) && (finallyBlock.Type != Token.BLOCK || finallyBlock.hasChildren ()); - - // short circuit - if (tryBlock.Type == Token.BLOCK && !tryBlock.hasChildren () && !hasFinally) { - return tryBlock; - } - - bool hasCatch = catchBlocks.hasChildren (); - - // short circuit - if (!hasFinally && !hasCatch) { - // bc finally might be an empty block... - return tryBlock; - } - - - Node handlerBlock = new Node (Token.LOCAL_BLOCK); - Node.Jump pn = new Node.Jump (Token.TRY, tryBlock, lineno); - pn.putProp (Node.LOCAL_BLOCK_PROP, handlerBlock); - - if (hasCatch) { - // jump around catch code - Node endCatch = Node.newTarget (); - pn.addChildToBack (makeJump (Token.GOTO, endCatch)); - - // make a TARGET for the catch that the tcf node knows about - Node catchTarget = Node.newTarget (); - pn.target = catchTarget; - // mark it - pn.addChildToBack (catchTarget); - - // - // Given - // - // try { - // tryBlock; - // } catch (e if condition1) { - // something1; - // ... - // - // } catch (e if conditionN) { - // somethingN; - // } catch (e) { - // somethingDefault; - // } - // - // rewrite as - // - // try { - // tryBlock; - // goto after_catch: - // } catch (x) { - // with (newCatchScope(e, x)) { - // if (condition1) { - // something1; - // goto after_catch; - // } - // } - // ... - // with (newCatchScope(e, x)) { - // if (conditionN) { - // somethingN; - // goto after_catch; - // } - // } - // with (newCatchScope(e, x)) { - // somethingDefault; - // goto after_catch; - // } - // } - // after_catch: - // - // If there is no default catch, then the last with block - // arround "somethingDefault;" is replaced by "rethrow;" - - // It is assumed that catch handler generation will store - // exeception object in handlerBlock register - - // Block with local for exception scope objects - Node catchScopeBlock = new Node (Token.LOCAL_BLOCK); - - // expects catchblocks children to be (cond block) pairs. - Node cb = catchBlocks.FirstChild; - bool hasDefault = false; - int scopeIndex = 0; - while (cb != null) { - int catchLineNo = cb.Lineno; - - Node name = cb.FirstChild; - Node cond = name.Next; - Node catchStatement = cond.Next; - cb.removeChild (name); - cb.removeChild (cond); - cb.removeChild (catchStatement); - - // Add goto to the catch statement to jump out of catch - // but prefix it with LEAVEWITH since try..catch produces - // "with"code in order to limit the scope of the exception - // object. - catchStatement.addChildToBack (new Node (Token.LEAVEWITH)); - catchStatement.addChildToBack (makeJump (Token.GOTO, endCatch)); - - // Create condition "if" when present - Node condStmt; - if (cond.Type == Token.EMPTY) { - condStmt = catchStatement; - hasDefault = true; - } - else { - condStmt = CreateIf (cond, catchStatement, null, catchLineNo); - } - - // Generate code to Create the scope object and store - // it in catchScopeBlock register - Node catchScope = new Node (Token.CATCH_SCOPE, name, CreateUseLocal (handlerBlock)); - catchScope.putProp (Node.LOCAL_BLOCK_PROP, catchScopeBlock); - catchScope.putIntProp (Node.CATCH_SCOPE_PROP, scopeIndex); - catchScopeBlock.addChildToBack (catchScope); - - // Add with statement based on catch scope object - catchScopeBlock.addChildToBack (CreateWith (CreateUseLocal (catchScopeBlock), condStmt, catchLineNo)); - - // move to next cb - cb = cb.Next; - ++scopeIndex; - } - pn.addChildToBack (catchScopeBlock); - if (!hasDefault) { - // Generate code to rethrow if no catch clause was executed - Node rethrow = new Node (Token.RETHROW); - rethrow.putProp (Node.LOCAL_BLOCK_PROP, handlerBlock); - pn.addChildToBack (rethrow); - } - - pn.addChildToBack (endCatch); - } - - if (hasFinally) { - Node finallyTarget = Node.newTarget (); - pn.Finally = finallyTarget; - - // add jsr finally to the try block - pn.addChildToBack (makeJump (Token.JSR, finallyTarget)); - - // jump around finally code - Node finallyEnd = Node.newTarget (); - pn.addChildToBack (makeJump (Token.GOTO, finallyEnd)); - - pn.addChildToBack (finallyTarget); - Node fBlock = new Node (Token.FINALLY, finallyBlock); - fBlock.putProp (Node.LOCAL_BLOCK_PROP, handlerBlock); - pn.addChildToBack (fBlock); - - pn.addChildToBack (finallyEnd); - } - handlerBlock.addChildToBack (pn); - return handlerBlock; - } - - /// Throw, Return, Label, Break and Continue are defined in ASTFactory. - - /// With - internal Node CreateWith (Node obj, Node body, int lineno) - { - setRequiresActivation (); - Node result = new Node (Token.BLOCK, lineno); - result.addChildToBack (new Node (Token.ENTERWITH, obj)); - Node bodyNode = new Node (Token.WITH, body, lineno); - result.addChildrenToBack (bodyNode); - result.addChildToBack (new Node (Token.LEAVEWITH)); - return result; - } - - /// DOTQUERY - public Node CreateDotQuery (Node obj, Node body, int lineno) - { - setRequiresActivation (); - Node result = new Node (Token.DOTQUERY, obj, body, lineno); - return result; - } - - internal Node CreateArrayLiteral (ObjArray elems, int skipCount) - { - int length = elems.size (); - int [] skipIndexes = null; - if (skipCount != 0) { - skipIndexes = new int [skipCount]; - } - Node array = new Node (Token.ARRAYLIT); - for (int i = 0, j = 0; i != length; ++i) { - Node elem = (Node)elems.Get (i); - if (elem != null) { - array.addChildToBack (elem); - } - else { - skipIndexes [j] = i; - ++j; - } - } - if (skipCount != 0) { - array.putProp (Node.SKIP_INDEXES_PROP, skipIndexes); - } - return array; - } - - /// Object Literals - ///
CreateObjectLiteral rewrites its argument as object - /// creation plus object property entries, so later compiler - /// stages don't need to know about object literals. - ///
- internal Node CreateObjectLiteral (ObjArray elems) - { - int size = elems.size () / 2; - Node obj = new Node (Token.OBJECTLIT); - object [] properties; - if (size == 0) { - properties = ScriptRuntime.EmptyArgs; - } - else { - properties = new object [size]; - for (int i = 0; i != size; ++i) { - properties [i] = elems.Get (2 * i); - Node value = (Node)elems.Get (2 * i + 1); - obj.addChildToBack (value); - } - } - obj.putProp (Node.OBJECT_IDS_PROP, properties); - return obj; - } - - /// Regular expressions - internal Node CreateRegExp (int regexpIndex) - { - Node n = new Node (Token.REGEXP); - n.putIntProp (Node.REGEXP_PROP, regexpIndex); - return n; - } - - /// If statement - internal Node CreateIf (Node cond, Node ifTrue, Node ifFalse, int lineno) - { - int condStatus = isAlwaysDefinedBoolean (cond); - if (condStatus == ALWAYS_TRUE_BOOLEAN) { - return ifTrue; - } - else if (condStatus == ALWAYS_FALSE_BOOLEAN) { - if (ifFalse != null) { - return ifFalse; - } - return new Node (Token.BLOCK, lineno); - } - - Node result = new Node (Token.BLOCK, lineno); - Node ifNotTarget = Node.newTarget (); - Node.Jump IFNE = new Node.Jump (Token.IFNE, cond); - IFNE.target = ifNotTarget; - - result.addChildToBack (IFNE); - result.addChildrenToBack (ifTrue); - - if (ifFalse != null) { - Node endTarget = Node.newTarget (); - result.addChildToBack (makeJump (Token.GOTO, endTarget)); - result.addChildToBack (ifNotTarget); - result.addChildrenToBack (ifFalse); - result.addChildToBack (endTarget); - } - else { - result.addChildToBack (ifNotTarget); - } - - return result; - } - - internal Node CreateCondExpr (Node cond, Node ifTrue, Node ifFalse) - { - int condStatus = isAlwaysDefinedBoolean (cond); - if (condStatus == ALWAYS_TRUE_BOOLEAN) { - return ifTrue; - } - else if (condStatus == ALWAYS_FALSE_BOOLEAN) { - return ifFalse; - } - return new Node (Token.HOOK, cond, ifTrue, ifFalse); - } - - /// Unary - internal Node CreateUnary (int nodeType, Node child) - { - int childType = child.Type; - switch (nodeType) { - - case Token.DELPROP: { - Node n; - if (childType == Token.NAME) { - // Transform Delete(Name "a") - // to Delete(Bind("a"), String("a")) - child.Type = Token.BINDNAME; - Node left = child; - Node right = Node.newString (child.String); - n = new Node (nodeType, left, right); - } - else if (childType == Token.GETPROP || childType == Token.GETELEM) { - Node left = child.FirstChild; - Node right = child.LastChild; - child.removeChild (left); - child.removeChild (right); - n = new Node (nodeType, left, right); - } - else if (childType == Token.GET_REF) { - Node rf = child.FirstChild; - child.removeChild (rf); - n = new Node (Token.DEL_REF, rf); - } - else { - n = new Node (Token.TRUE); - } - return n; - } - - case Token.TYPEOF: - if (childType == Token.NAME) { - child.Type = Token.TYPEOFNAME; - return child; - } - break; - - case Token.BITNOT: - if (childType == Token.NUMBER) { - int value = ScriptConvert.ToInt32 (child.Double); - child.Double = ~value; - return child; - } - break; - - case Token.NEG: - if (childType == Token.NUMBER) { - child.Double = -child.Double; - return child; - } - break; - - case Token.NOT: { - int status = isAlwaysDefinedBoolean (child); - if (status != 0) { - int type; - if (status == ALWAYS_TRUE_BOOLEAN) { - type = Token.FALSE; - } - else { - type = Token.TRUE; - } - if (childType == Token.TRUE || childType == Token.FALSE) { - child.Type = type; - return child; - } - return new Node (type); - } - break; - } - } - return new Node (nodeType, child); - } - - internal Node CreateCallOrNew (int nodeType, Node child) - { - int type = Node.NON_SPECIALCALL; - if (child.Type == Token.NAME) { - string name = child.String; - if (name.Equals ("eval")) { - type = Node.SPECIALCALL_EVAL; - } - else if (name.Equals ("With")) { - type = Node.SPECIALCALL_WITH; - } - } - else if (child.Type == Token.GETPROP) { - string name = child.LastChild.String; - if (name.Equals ("eval")) { - type = Node.SPECIALCALL_EVAL; - } - } - Node node = new Node (nodeType, child); - if (type != Node.NON_SPECIALCALL) { - // Calls to these functions require activation objects. - setRequiresActivation (); - node.putIntProp (Node.SPECIALCALL_PROP, type); - } - return node; - } - - internal Node CreateIncDec (int nodeType, bool post, Node child) - { - child = makeReference (child); - if (child == null) { - string msg; - if (nodeType == Token.DEC) { - msg = "msg.bad.decr"; - } - else { - msg = "msg.bad.incr"; - } - parser.ReportError (msg); - return null; - } - - int childType = child.Type; - - switch (childType) { - - case Token.NAME: - case Token.GETPROP: - case Token.GETELEM: - case Token.GET_REF: { - Node n = new Node (nodeType, child); - int incrDecrMask = 0; - if (nodeType == Token.DEC) { - incrDecrMask |= Node.DECR_FLAG; - } - if (post) { - incrDecrMask |= Node.POST_FLAG; - } - n.putIntProp (Node.INCRDECR_PROP, incrDecrMask); - return n; - } - } - throw Context.CodeBug (); - } - - internal Node CreatePropertyGet (Node target, string ns, string name, int memberTypeFlags) - { - if (ns == null && memberTypeFlags == 0) { - if (target == null) { - return CreateName (name); - } - checkActivationName (name, Token.GETPROP); - if (ScriptRuntime.isSpecialProperty (name)) { - Node rf = new Node (Token.REF_SPECIAL, target); - rf.putProp (Node.NAME_PROP, name); - return new Node (Token.GET_REF, rf); - } - return new Node (Token.GETPROP, target, CreateString (name)); - } - Node elem = CreateString (name); - memberTypeFlags |= Node.PROPERTY_FLAG; - return CreateMemberRefGet (target, ns, elem, memberTypeFlags); - } - - internal Node CreateElementGet (Node target, string ns, Node elem, int memberTypeFlags) - { - // OPT: could optimize to CreatePropertyGet - // iff elem is string that can not be number - if (ns == null && memberTypeFlags == 0) { - // stand-alone [aaa] as primary expression is array literal - // declaration and should not come here! - if (target == null) - throw Context.CodeBug (); - return new Node (Token.GETELEM, target, elem); - } - return CreateMemberRefGet (target, ns, elem, memberTypeFlags); - } - - private Node CreateMemberRefGet (Node target, string ns, Node elem, int memberTypeFlags) - { - Node nsNode = null; - if (ns != null) { - // See 11.1.2 in ECMA 357 - if (ns.Equals ("*")) { - nsNode = new Node (Token.NULL); - } - else { - nsNode = CreateName (ns); - } - } - Node rf; - if (target == null) { - if (ns == null) { - rf = new Node (Token.REF_NAME, elem); - } - else { - rf = new Node (Token.REF_NS_NAME, nsNode, elem); - } - } - else { - if (ns == null) { - rf = new Node (Token.REF_MEMBER, target, elem); - } - else { - rf = new Node (Token.REF_NS_MEMBER, target, nsNode, elem); - } - } - if (memberTypeFlags != 0) { - rf.putIntProp (Node.MEMBER_TYPE_PROP, memberTypeFlags); - } - return new Node (Token.GET_REF, rf); - } - - /// Binary - internal Node CreateBinary (int nodeType, Node left, Node right) - { - switch (nodeType) { - - - case Token.ADD: - // numerical addition and string concatenation - if (left.Type == Token.STRING) { - string s2; - if (right.Type == Token.STRING) { - s2 = right.String; - } - else if (right.Type == Token.NUMBER) { - s2 = ScriptConvert.ToString (right.Double, 10); - } - else { - break; - } - string s1 = left.String; - left.String = string.Concat (s1, s2); - return left; - } - else if (left.Type == Token.NUMBER) { - if (right.Type == Token.NUMBER) { - left.Double = left.Double + right.Double; - return left; - } - else if (right.Type == Token.STRING) { - string s1, s2; - s1 = ScriptConvert.ToString (left.Double, 10); - s2 = right.String; - right.String = string.Concat (s1, s2); - return right; - } - } - // can't do anything if we don't know both types - since - // 0 + object is supposed to call toString on the object and do - // string concantenation rather than addition - break; - - - case Token.SUB: - // numerical subtraction - if (left.Type == Token.NUMBER) { - double ld = left.Double; - if (right.Type == Token.NUMBER) { - //both numbers - left.Double = ld - right.Double; - return left; - } - else if (ld == 0.0) { - // first 0: 0-x -> -x - return new Node (Token.NEG, right); - } - } - else if (right.Type == Token.NUMBER) { - if (right.Double == 0.0) { - //second 0: x - 0 -> +x - // can not make simply x because x - 0 must be number - return new Node (Token.POS, left); - } - } - break; - - - case Token.MUL: - // numerical multiplication - if (left.Type == Token.NUMBER) { - double ld = left.Double; - if (right.Type == Token.NUMBER) { - //both numbers - left.Double = ld * right.Double; - return left; - } - else if (ld == 1.0) { - // first 1: 1 * x -> +x - return new Node (Token.POS, right); - } - } - else if (right.Type == Token.NUMBER) { - if (right.Double == 1.0) { - //second 1: x * 1 -> +x - // can not make simply x because x - 0 must be number - return new Node (Token.POS, left); - } - } - // can't do x*0: Infinity * 0 gives NaN, not 0 - break; - - - case Token.DIV: - // number division - if (right.Type == Token.NUMBER) { - double rd = right.Double; - if (left.Type == Token.NUMBER) { - // both constants -- just divide, trust Java to handle x/0 - left.Double = left.Double / rd; - return left; - } - else if (rd == 1.0) { - // second 1: x/1 -> +x - // not simply x to force number convertion - return new Node (Token.POS, left); - } - } - break; - - - case Token.AND: { - int leftStatus = isAlwaysDefinedBoolean (left); - if (leftStatus == ALWAYS_FALSE_BOOLEAN) { - // if the first one is false, replace with FALSE - return new Node (Token.FALSE); - } - else if (leftStatus == ALWAYS_TRUE_BOOLEAN) { - // if first is true, set to second - return right; - } - int rightStatus = isAlwaysDefinedBoolean (right); - if (rightStatus == ALWAYS_FALSE_BOOLEAN) { - // if the second one is false, replace with FALSE - if (!hasSideEffects (left)) { - return new Node (Token.FALSE); - } - } - else if (rightStatus == ALWAYS_TRUE_BOOLEAN) { - // if second is true, set to first - return left; - } - break; - } - - - case Token.OR: { - int leftStatus = isAlwaysDefinedBoolean (left); - if (leftStatus == ALWAYS_TRUE_BOOLEAN) { - // if the first one is true, replace with TRUE - return new Node (Token.TRUE); - } - else if (leftStatus == ALWAYS_FALSE_BOOLEAN) { - // if first is false, set to second - return right; - } - int rightStatus = isAlwaysDefinedBoolean (right); - if (rightStatus == ALWAYS_TRUE_BOOLEAN) { - // if the second one is true, replace with TRUE - if (!hasSideEffects (left)) { - return new Node (Token.TRUE); - } - } - else if (rightStatus == ALWAYS_FALSE_BOOLEAN) { - // if second is false, set to first - return left; - } - break; - } - } - - return new Node (nodeType, left, right); - } - - private Node simpleAssignment (Node left, Node right) - { - int nodeType = left.Type; - switch (nodeType) { - - case Token.NAME: - left.Type = Token.BINDNAME; - return new Node (Token.SETNAME, left, right); - - - case Token.GETPROP: - case Token.GETELEM: { - Node obj = left.FirstChild; - Node id = left.LastChild; - int type; - if (nodeType == Token.GETPROP) { - type = Token.SETPROP; - } - else { - type = Token.SETELEM; - } - return new Node (type, obj, id, right); - } - - case Token.GET_REF: { - Node rf = left.FirstChild; - checkMutableReference (rf); - return new Node (Token.SET_REF, rf, right); - } - } - - throw Context.CodeBug (); - } - - private void checkMutableReference (Node n) - { - int memberTypeFlags = n.getIntProp (Node.MEMBER_TYPE_PROP, 0); - if ((memberTypeFlags & Node.DESCENDANTS_FLAG) != 0) { - parser.ReportError ("msg.bad.assign.left"); - } - } - - internal Node CreateAssignment (int assignType, Node left, Node right) - { - left = makeReference (left); - if (left == null) { - parser.ReportError ("msg.bad.assign.left"); - return right; - } - - int assignOp; - switch (assignType) { - - case Token.ASSIGN: - return simpleAssignment (left, right); - - case Token.ASSIGN_BITOR: - assignOp = Token.BITOR; - break; - - case Token.ASSIGN_BITXOR: - assignOp = Token.BITXOR; - break; - - case Token.ASSIGN_BITAND: - assignOp = Token.BITAND; - break; - - case Token.ASSIGN_LSH: - assignOp = Token.LSH; - break; - - case Token.ASSIGN_RSH: - assignOp = Token.RSH; - break; - - case Token.ASSIGN_URSH: - assignOp = Token.URSH; - break; - - case Token.ASSIGN_ADD: - assignOp = Token.ADD; - break; - - case Token.ASSIGN_SUB: - assignOp = Token.SUB; - break; - - case Token.ASSIGN_MUL: - assignOp = Token.MUL; - break; - - case Token.ASSIGN_DIV: - assignOp = Token.DIV; - break; - - case Token.ASSIGN_MOD: - assignOp = Token.MOD; - break; - - default: - throw Context.CodeBug (); - - } - - int nodeType = left.Type; - switch (nodeType) { - - case Token.NAME: { - string s = left.String; - - Node opLeft = Node.newString (Token.NAME, s); - Node op = new Node (assignOp, opLeft, right); - Node lvalueLeft = Node.newString (Token.BINDNAME, s); - return new Node (Token.SETNAME, lvalueLeft, op); - } - - case Token.GETPROP: - case Token.GETELEM: { - Node obj = left.FirstChild; - Node id = left.LastChild; - - int type = nodeType == Token.GETPROP ? Token.SETPROP_OP : Token.SETELEM_OP; - - Node opLeft = new Node (Token.USE_STACK); - Node op = new Node (assignOp, opLeft, right); - return new Node (type, obj, id, op); - } - - case Token.GET_REF: { - Node rf = left.FirstChild; - checkMutableReference (rf); - Node opLeft = new Node (Token.USE_STACK); - Node op = new Node (assignOp, opLeft, right); - return new Node (Token.SET_REF_OP, rf, op); - } - } - - throw Context.CodeBug (); - } - - internal Node CreateUseLocal (Node localBlock) - { - if (Token.LOCAL_BLOCK != localBlock.Type) - throw Context.CodeBug (); - Node result = new Node (Token.LOCAL_LOAD); - result.putProp (Node.LOCAL_BLOCK_PROP, localBlock); - return result; - } - - private Node.Jump makeJump (int type, Node target) - { - Node.Jump n = new Node.Jump (type); - n.target = target; - return n; - } - - private Node makeReference (Node node) - { - int type = node.Type; - switch (type) { - - case Token.NAME: - case Token.GETPROP: - case Token.GETELEM: - case Token.GET_REF: - return node; - - case Token.CALL: - node.Type = Token.REF_CALL; - return new Node (Token.GET_REF, node); - } - // Signal caller to report error - return null; - } - - // Check if Node always mean true or false in boolean context - private static int isAlwaysDefinedBoolean (Node node) - { - switch (node.Type) { - - case Token.FALSE: - case Token.NULL: - return ALWAYS_FALSE_BOOLEAN; - - case Token.TRUE: - return ALWAYS_TRUE_BOOLEAN; - - case Token.NUMBER: { - double num = node.Double; - if (!double.IsNaN (num) && num != 0.0) { - return ALWAYS_TRUE_BOOLEAN; - } - else { - return ALWAYS_FALSE_BOOLEAN; - } - } - } - return 0; - } - - private static bool hasSideEffects (Node exprTree) - { - switch (exprTree.Type) { - - case Token.INC: - case Token.DEC: - case Token.SETPROP: - case Token.SETELEM: - case Token.SETNAME: - case Token.CALL: - case Token.NEW: - return true; - - default: - Node child = exprTree.FirstChild; - while (child != null) { - if (hasSideEffects (child)) - return true; - child = child.Next; - } - break; - - } - return false; - } - - private void checkActivationName (string name, int token) - { - if (parser.insideFunction ()) { - bool activation = false; - if ("arguments".Equals (name) || (parser.compilerEnv.activationNames != null && parser.compilerEnv.activationNames.ContainsKey (name))) { - activation = true; - } - else if ("length".Equals (name)) { - if (token == Token.GETPROP && parser.compilerEnv.LanguageVersion == Context.Versions.JS1_2) { - // Use of "length" in 1.2 requires an activation object. - activation = true; - } - } - if (activation) { - setRequiresActivation (); - } - } - } - - private void setRequiresActivation () - { - if (parser.insideFunction ()) { - ((FunctionNode)parser.currentScriptOrFn).itsNeedsActivation = true; - } - } - - private Parser parser; - - private const int LOOP_DO_WHILE = 0; - private const int LOOP_WHILE = 1; - private const int LOOP_FOR = 2; - - private const int ALWAYS_TRUE_BOOLEAN = 1; - private const int ALWAYS_FALSE_BOOLEAN = -1; - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +using EcmaScript.NET.Collections; + +namespace EcmaScript.NET +{ + + /// This class allows the creation of nodes, and follows the Factory pattern. + /// + /// + sealed class NodeFactory + { + internal NodeFactory (Parser parser) + { + this.parser = parser; + } + + internal ScriptOrFnNode CreateScript () + { + return new ScriptOrFnNode (Token.SCRIPT); + } + + /// Script (for associating file/url names with toplevel scripts.) + internal void initScript (ScriptOrFnNode scriptNode, Node body) + { + Node children = body.FirstChild; + if (children != null) { + scriptNode.addChildrenToBack (children); + } + } + + /// Leaf + internal Node CreateLeaf (int nodeType) + { + return new Node (nodeType); + } + + internal Node CreateLeaf (int nodeType, int nodeOp) + { + return new Node (nodeType, nodeOp); + } + + /// Statement leaf nodes. + + internal Node CreateSwitch (Node expr, int lineno) + { + // + // The switch will be rewritten from: + // + // switch (expr) { + // case test1: statements1; + // ... + // default: statementsDefault; + // ... + // case testN: statementsN; + // } + // + // to: + // + // { + // switch (expr) { + // case test1: goto label1; + // ... + // case testN: goto labelN; + // } + // goto labelDefault; + // label1: + // statements1; + // ... + // labelDefault: + // statementsDefault; + // ... + // labelN: + // statementsN; + // breakLabel: + // } + // + // where inside switch each "break;" without label will be replaced + // by "goto breakLabel". + // + // If the original switch does not have the default label, then + // the transformed code would contain after the switch instead of + // goto labelDefault; + // the following goto: + // goto breakLabel; + // + + Node.Jump switchNode = new Node.Jump (Token.SWITCH, expr, lineno); + Node block = new Node (Token.BLOCK, switchNode); + return block; + } + + /// If caseExpression argument is null it indicate default label. + internal void addSwitchCase (Node switchBlock, Node caseExpression, Node statements) + { + if (switchBlock.Type != Token.BLOCK) + throw Context.CodeBug (); + Node.Jump switchNode = (Node.Jump)switchBlock.FirstChild; + if (switchNode.Type != Token.SWITCH) + throw Context.CodeBug (); + + Node gotoTarget = Node.newTarget (); + if (caseExpression != null) { + Node.Jump caseNode = new Node.Jump (Token.CASE, caseExpression); + caseNode.target = gotoTarget; + switchNode.addChildToBack (caseNode); + } + else { + switchNode.Default = gotoTarget; + } + switchBlock.addChildToBack (gotoTarget); + switchBlock.addChildToBack (statements); + } + + internal void closeSwitch (Node switchBlock) + { + if (switchBlock.Type != Token.BLOCK) + throw Context.CodeBug (); + Node.Jump switchNode = (Node.Jump)switchBlock.FirstChild; + if (switchNode.Type != Token.SWITCH) + throw Context.CodeBug (); + + Node switchBreakTarget = Node.newTarget (); + // switchNode.target is only used by NodeTransformer + // to detect switch end + switchNode.target = switchBreakTarget; + + Node defaultTarget = switchNode.Default; + if (defaultTarget == null) { + defaultTarget = switchBreakTarget; + } + + switchBlock.addChildAfter (makeJump (Token.GOTO, defaultTarget), switchNode); + switchBlock.addChildToBack (switchBreakTarget); + } + + internal Node CreateVariables (int lineno) + { + return new Node (Token.VAR, lineno); + } + + internal Node CreateExprStatement (Node expr, int lineno) + { + int type; + if (parser.insideFunction ()) { + type = Token.EXPR_VOID; + } + else { + type = Token.EXPR_RESULT; + } + return new Node (type, expr, lineno); + } + + internal Node CreateExprStatementNoReturn (Node expr, int lineno) + { + return new Node (Token.EXPR_VOID, expr, lineno); + } + + internal Node CreateDefaultNamespace (Node expr, int lineno) + { + // default xml namespace requires activation + setRequiresActivation (); + Node n = CreateUnary (Token.DEFAULTNAMESPACE, expr); + Node result = CreateExprStatement (n, lineno); + return result; + } + + /// Name + internal Node CreateName (string name) + { + checkActivationName (name, Token.NAME); + return Node.newString (Token.NAME, name); + } + + /// String (for literals) + internal Node CreateString (string str) + { + return Node.newString (str); + } + + /// Number (for literals) + internal Node CreateNumber (double number) + { + return Node.newNumber (number); + } + + /// Catch clause of try/catch/finally + /// the name of the variable to bind to the exception + /// + /// the condition under which to catch the exception. + /// May be null if no condition is given. + /// + /// the statements in the catch clause + /// + /// the starting line number of the catch clause + /// + internal Node CreateCatch (string varName, Node catchCond, Node stmts, int lineno) + { + if (catchCond == null) { + catchCond = new Node (Token.EMPTY); + } + return new Node (Token.CATCH, CreateName (varName), catchCond, stmts, lineno); + } + + /// Throw + internal Node CreateThrow (Node expr, int lineno) + { + return new Node (Token.THROW, expr, lineno); + } + + /// Return + internal Node CreateReturn (Node expr, int lineno) + { + return expr == null ? new Node (Token.RETURN, lineno) : new Node (Token.RETURN, expr, lineno); + } + + /// Debugger + internal Node CreateDebugger(int lineno) + { + return new Node(Token.DEBUGGER, lineno); + } + + /// Label + internal Node CreateLabel (int lineno) + { + return new Node.Jump (Token.LABEL, lineno); + } + + internal Node getLabelLoop (Node label) + { + return ((Node.Jump)label).Loop; + } + + /// Label + internal Node CreateLabeledStatement (Node labelArg, Node statement) + { + Node.Jump label = (Node.Jump)labelArg; + + // Make a target and put it _after_ the statement + // node. And in the LABEL node, so breaks get the + // right target. + + Node breakTarget = Node.newTarget (); + Node block = new Node (Token.BLOCK, label, statement, breakTarget); + label.target = breakTarget; + + return block; + } + + /// Break (possibly labeled) + internal Node CreateBreak (Node breakStatement, int lineno) + { + Node.Jump n = new Node.Jump (Token.BREAK, lineno); + Node.Jump jumpStatement; + int t = breakStatement.Type; + if (t == Token.LOOP || t == Token.LABEL) { + jumpStatement = (Node.Jump)breakStatement; + } + else if (t == Token.BLOCK && breakStatement.FirstChild.Type == Token.SWITCH) { + jumpStatement = (Node.Jump)breakStatement.FirstChild; + } + else { + throw Context.CodeBug (); + } + n.JumpStatement = jumpStatement; + return n; + } + + /// Continue (possibly labeled) + internal Node CreateContinue (Node loop, int lineno) + { + if (loop.Type != Token.LOOP) + Context.CodeBug (); + Node.Jump n = new Node.Jump (Token.CONTINUE, lineno); + n.JumpStatement = (Node.Jump)loop; + return n; + } + + /// Statement block + /// Creates the empty statement block + /// Must make subsequent calls to add statements to the node + /// + internal Node CreateBlock (int lineno) + { + return new Node (Token.BLOCK, lineno); + } + + internal FunctionNode CreateFunction (string name) + { + return new FunctionNode (name); + } + + internal Node initFunction (FunctionNode fnNode, int functionIndex, Node statements, int functionType) + { + fnNode.itsFunctionType = functionType; + fnNode.addChildToBack (statements); + + int functionCount = fnNode.FunctionCount; + if (functionCount != 0) { + // Functions containing other functions require activation objects + fnNode.itsNeedsActivation = true; + for (int i = 0; i != functionCount; ++i) { + FunctionNode fn = fnNode.getFunctionNode (i); + // nested function expression statements overrides var + if (fn.FunctionType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) { + string name = fn.FunctionName; + if (name != null && name.Length != 0) { + fnNode.removeParamOrVar (name); + } + } + } + } + + if (functionType == FunctionNode.FUNCTION_EXPRESSION) { + string name = fnNode.FunctionName; + if (name != null && name.Length != 0 && !fnNode.hasParamOrVar (name)) { + // A function expression needs to have its name as a + // variable (if it isn't already allocated as a variable). + // See ECMA Ch. 13. We add code to the beginning of the + // function to initialize a local variable of the + // function's name to the function value. + fnNode.addVar (name); + Node setFn = new Node (Token.EXPR_VOID, new Node (Token.SETNAME, Node.newString (Token.BINDNAME, name), new Node (Token.THISFN))); + statements.addChildrenToFront (setFn); + } + } + + // Add return to end if needed. + Node lastStmt = statements.LastChild; + if (lastStmt == null || lastStmt.Type != Token.RETURN) { + statements.addChildToBack (new Node (Token.RETURN)); + } + + Node result = Node.newString (Token.FUNCTION, fnNode.FunctionName); + result.putIntProp (Node.FUNCTION_PROP, functionIndex); + return result; + } + + /// Add a child to the back of the given node. This function + /// breaks the Factory abstraction, but it removes a requirement + /// from implementors of Node. + /// + internal void addChildToBack (Node parent, Node child) + { + parent.addChildToBack (child); + } + + /// Create loop node. The parser will later call + /// CreateWhile|CreateDoWhile|CreateFor|CreateForIn + /// to finish loop generation. + /// + internal Node CreateLoopNode (Node loopLabel, int lineno) + { + Node.Jump result = new Node.Jump (Token.LOOP, lineno); + if (loopLabel != null) { + ((Node.Jump)loopLabel).Loop = result; + } + return result; + } + + /// While + internal Node CreateWhile (Node loop, Node cond, Node body) + { + return CreateLoop ((Node.Jump)loop, LOOP_WHILE, body, cond, null, null); + } + + /// DoWhile + internal Node CreateDoWhile (Node loop, Node body, Node cond) + { + return CreateLoop ((Node.Jump)loop, LOOP_DO_WHILE, body, cond, null, null); + } + + /// For + internal Node CreateFor (Node loop, Node init, Node test, Node incr, Node body) + { + return CreateLoop ((Node.Jump)loop, LOOP_FOR, body, test, init, incr); + } + + private Node CreateLoop (Node.Jump loop, int loopType, Node body, Node cond, Node init, Node incr) + { + Node bodyTarget = Node.newTarget (); + Node condTarget = Node.newTarget (); + if (loopType == LOOP_FOR && cond.Type == Token.EMPTY) { + cond = new Node (Token.TRUE); + } + Node.Jump IFEQ = new Node.Jump (Token.IFEQ, cond); + IFEQ.target = bodyTarget; + Node breakTarget = Node.newTarget (); + + loop.addChildToBack (bodyTarget); + loop.addChildrenToBack (body); + if (loopType == LOOP_WHILE || loopType == LOOP_FOR) { + // propagate lineno to condition + loop.addChildrenToBack (new Node (Token.EMPTY, loop.Lineno)); + } + loop.addChildToBack (condTarget); + loop.addChildToBack (IFEQ); + loop.addChildToBack (breakTarget); + + loop.target = breakTarget; + Node continueTarget = condTarget; + + if (loopType == LOOP_WHILE || loopType == LOOP_FOR) { + // Just add a GOTO to the condition in the do..while + loop.addChildToFront (makeJump (Token.GOTO, condTarget)); + + if (loopType == LOOP_FOR) { + if (init.Type != Token.EMPTY) { + if (init.Type != Token.VAR) { + init = new Node (Token.EXPR_VOID, init); + } + loop.addChildToFront (init); + } + Node incrTarget = Node.newTarget (); + loop.addChildAfter (incrTarget, body); + if (incr.Type != Token.EMPTY) { + incr = new Node (Token.EXPR_VOID, incr); + loop.addChildAfter (incr, incrTarget); + } + continueTarget = incrTarget; + } + } + + loop.Continue = continueTarget; + + return loop; + } + + /// For .. In + /// + /// + internal Node CreateForIn (Node loop, Node lhs, Node obj, Node body, bool isForEach) + { + int type = lhs.Type; + + Node lvalue; + if (type == Token.VAR) { + /* + * check that there was only one variable given. + * we can't do this in the parser, because then the + * parser would have to know something about the + * 'init' node of the for-in loop. + */ + Node lastChild = lhs.LastChild; + if (lhs.FirstChild != lastChild) { + parser.ReportError ("msg.mult.index"); + } + lvalue = Node.newString (Token.NAME, lastChild.String); + } + else { + lvalue = makeReference (lhs); + if (lvalue == null) { + parser.ReportError ("msg.bad.for.in.lhs"); + return obj; + } + } + + Node localBlock = new Node (Token.LOCAL_BLOCK); + + int initType = (isForEach) ? Token.ENUM_INIT_VALUES : Token.ENUM_INIT_KEYS; + Node init = new Node (initType, obj); + init.putProp (Node.LOCAL_BLOCK_PROP, localBlock); + Node cond = new Node (Token.ENUM_NEXT); + cond.putProp (Node.LOCAL_BLOCK_PROP, localBlock); + Node id = new Node (Token.ENUM_ID); + id.putProp (Node.LOCAL_BLOCK_PROP, localBlock); + + Node newBody = new Node (Token.BLOCK); + Node assign = simpleAssignment (lvalue, id); + newBody.addChildToBack (new Node (Token.EXPR_VOID, assign)); + newBody.addChildToBack (body); + + loop = CreateWhile (loop, cond, newBody); + loop.addChildToFront (init); + if (type == Token.VAR) + loop.addChildToFront (lhs); + localBlock.addChildToBack (loop); + + return localBlock; + } + + /// Try/Catch/Finally + /// + /// The IRFactory tries to express as much as possible in the tree; + /// the responsibilities remaining for Codegen are to add the Java + /// handlers: (Either (but not both) of TARGET and FINALLY might not + /// be defined) + /// - a catch handler for javascript exceptions that unwraps the + /// exception onto the stack and GOTOes to the catch target + /// - a finally handler + /// ... and a goto to GOTO around these handlers. + /// + internal Node CreateTryCatchFinally (Node tryBlock, Node catchBlocks, Node finallyBlock, int lineno) + { + bool hasFinally = (finallyBlock != null) && (finallyBlock.Type != Token.BLOCK || finallyBlock.hasChildren ()); + + // short circuit + if (tryBlock.Type == Token.BLOCK && !tryBlock.hasChildren () && !hasFinally) { + return tryBlock; + } + + bool hasCatch = catchBlocks.hasChildren (); + + // short circuit + if (!hasFinally && !hasCatch) { + // bc finally might be an empty block... + return tryBlock; + } + + + Node handlerBlock = new Node (Token.LOCAL_BLOCK); + Node.Jump pn = new Node.Jump (Token.TRY, tryBlock, lineno); + pn.putProp (Node.LOCAL_BLOCK_PROP, handlerBlock); + + if (hasCatch) { + // jump around catch code + Node endCatch = Node.newTarget (); + pn.addChildToBack (makeJump (Token.GOTO, endCatch)); + + // make a TARGET for the catch that the tcf node knows about + Node catchTarget = Node.newTarget (); + pn.target = catchTarget; + // mark it + pn.addChildToBack (catchTarget); + + // + // Given + // + // try { + // tryBlock; + // } catch (e if condition1) { + // something1; + // ... + // + // } catch (e if conditionN) { + // somethingN; + // } catch (e) { + // somethingDefault; + // } + // + // rewrite as + // + // try { + // tryBlock; + // goto after_catch: + // } catch (x) { + // with (newCatchScope(e, x)) { + // if (condition1) { + // something1; + // goto after_catch; + // } + // } + // ... + // with (newCatchScope(e, x)) { + // if (conditionN) { + // somethingN; + // goto after_catch; + // } + // } + // with (newCatchScope(e, x)) { + // somethingDefault; + // goto after_catch; + // } + // } + // after_catch: + // + // If there is no default catch, then the last with block + // arround "somethingDefault;" is replaced by "rethrow;" + + // It is assumed that catch handler generation will store + // exeception object in handlerBlock register + + // Block with local for exception scope objects + Node catchScopeBlock = new Node (Token.LOCAL_BLOCK); + + // expects catchblocks children to be (cond block) pairs. + Node cb = catchBlocks.FirstChild; + bool hasDefault = false; + int scopeIndex = 0; + while (cb != null) { + int catchLineNo = cb.Lineno; + + Node name = cb.FirstChild; + Node cond = name.Next; + Node catchStatement = cond.Next; + cb.removeChild (name); + cb.removeChild (cond); + cb.removeChild (catchStatement); + + // Add goto to the catch statement to jump out of catch + // but prefix it with LEAVEWITH since try..catch produces + // "with"code in order to limit the scope of the exception + // object. + catchStatement.addChildToBack (new Node (Token.LEAVEWITH)); + catchStatement.addChildToBack (makeJump (Token.GOTO, endCatch)); + + // Create condition "if" when present + Node condStmt; + if (cond.Type == Token.EMPTY) { + condStmt = catchStatement; + hasDefault = true; + } + else { + condStmt = CreateIf (cond, catchStatement, null, catchLineNo); + } + + // Generate code to Create the scope object and store + // it in catchScopeBlock register + Node catchScope = new Node (Token.CATCH_SCOPE, name, CreateUseLocal (handlerBlock)); + catchScope.putProp (Node.LOCAL_BLOCK_PROP, catchScopeBlock); + catchScope.putIntProp (Node.CATCH_SCOPE_PROP, scopeIndex); + catchScopeBlock.addChildToBack (catchScope); + + // Add with statement based on catch scope object + catchScopeBlock.addChildToBack (CreateWith (CreateUseLocal (catchScopeBlock), condStmt, catchLineNo)); + + // move to next cb + cb = cb.Next; + ++scopeIndex; + } + pn.addChildToBack (catchScopeBlock); + if (!hasDefault) { + // Generate code to rethrow if no catch clause was executed + Node rethrow = new Node (Token.RETHROW); + rethrow.putProp (Node.LOCAL_BLOCK_PROP, handlerBlock); + pn.addChildToBack (rethrow); + } + + pn.addChildToBack (endCatch); + } + + if (hasFinally) { + Node finallyTarget = Node.newTarget (); + pn.Finally = finallyTarget; + + // add jsr finally to the try block + pn.addChildToBack (makeJump (Token.JSR, finallyTarget)); + + // jump around finally code + Node finallyEnd = Node.newTarget (); + pn.addChildToBack (makeJump (Token.GOTO, finallyEnd)); + + pn.addChildToBack (finallyTarget); + Node fBlock = new Node (Token.FINALLY, finallyBlock); + fBlock.putProp (Node.LOCAL_BLOCK_PROP, handlerBlock); + pn.addChildToBack (fBlock); + + pn.addChildToBack (finallyEnd); + } + handlerBlock.addChildToBack (pn); + return handlerBlock; + } + + /// Throw, Return, Label, Break and Continue are defined in ASTFactory. + + /// With + internal Node CreateWith (Node obj, Node body, int lineno) + { + setRequiresActivation (); + Node result = new Node (Token.BLOCK, lineno); + result.addChildToBack (new Node (Token.ENTERWITH, obj)); + Node bodyNode = new Node (Token.WITH, body, lineno); + result.addChildrenToBack (bodyNode); + result.addChildToBack (new Node (Token.LEAVEWITH)); + return result; + } + + /// DOTQUERY + public Node CreateDotQuery (Node obj, Node body, int lineno) + { + setRequiresActivation (); + Node result = new Node (Token.DOTQUERY, obj, body, lineno); + return result; + } + + internal Node CreateArrayLiteral (ObjArray elems, int skipCount) + { + int length = elems.size (); + int [] skipIndexes = null; + if (skipCount != 0) { + skipIndexes = new int [skipCount]; + } + Node array = new Node (Token.ARRAYLIT); + for (int i = 0, j = 0; i != length; ++i) { + Node elem = (Node)elems.Get (i); + if (elem != null) { + array.addChildToBack (elem); + } + else { + skipIndexes [j] = i; + ++j; + } + } + if (skipCount != 0) { + array.putProp (Node.SKIP_INDEXES_PROP, skipIndexes); + } + return array; + } + + /// Object Literals + ///
CreateObjectLiteral rewrites its argument as object + /// creation plus object property entries, so later compiler + /// stages don't need to know about object literals. + ///
+ internal Node CreateObjectLiteral (ObjArray elems) + { + int size = elems.size () / 2; + Node obj = new Node (Token.OBJECTLIT); + object [] properties; + if (size == 0) { + properties = ScriptRuntime.EmptyArgs; + } + else { + properties = new object [size]; + for (int i = 0; i != size; ++i) { + properties [i] = elems.Get (2 * i); + Node value = (Node)elems.Get (2 * i + 1); + obj.addChildToBack (value); + } + } + obj.putProp (Node.OBJECT_IDS_PROP, properties); + return obj; + } + + /// Regular expressions + internal Node CreateRegExp (int regexpIndex) + { + Node n = new Node (Token.REGEXP); + n.putIntProp (Node.REGEXP_PROP, regexpIndex); + return n; + } + + /// If statement + internal Node CreateIf (Node cond, Node ifTrue, Node ifFalse, int lineno) + { + int condStatus = isAlwaysDefinedBoolean (cond); + if (condStatus == ALWAYS_TRUE_BOOLEAN) { + return ifTrue; + } + else if (condStatus == ALWAYS_FALSE_BOOLEAN) { + if (ifFalse != null) { + return ifFalse; + } + return new Node (Token.BLOCK, lineno); + } + + Node result = new Node (Token.BLOCK, lineno); + Node ifNotTarget = Node.newTarget (); + Node.Jump IFNE = new Node.Jump (Token.IFNE, cond); + IFNE.target = ifNotTarget; + + result.addChildToBack (IFNE); + result.addChildrenToBack (ifTrue); + + if (ifFalse != null) { + Node endTarget = Node.newTarget (); + result.addChildToBack (makeJump (Token.GOTO, endTarget)); + result.addChildToBack (ifNotTarget); + result.addChildrenToBack (ifFalse); + result.addChildToBack (endTarget); + } + else { + result.addChildToBack (ifNotTarget); + } + + return result; + } + + internal Node CreateCondExpr (Node cond, Node ifTrue, Node ifFalse) + { + int condStatus = isAlwaysDefinedBoolean (cond); + if (condStatus == ALWAYS_TRUE_BOOLEAN) { + return ifTrue; + } + else if (condStatus == ALWAYS_FALSE_BOOLEAN) { + return ifFalse; + } + return new Node (Token.HOOK, cond, ifTrue, ifFalse); + } + + /// Unary + internal Node CreateUnary (int nodeType, Node child) + { + int childType = child.Type; + switch (nodeType) { + + case Token.DELPROP: { + Node n; + if (childType == Token.NAME) { + // Transform Delete(Name "a") + // to Delete(Bind("a"), String("a")) + child.Type = Token.BINDNAME; + Node left = child; + Node right = Node.newString (child.String); + n = new Node (nodeType, left, right); + } + else if (childType == Token.GETPROP || childType == Token.GETELEM) { + Node left = child.FirstChild; + Node right = child.LastChild; + child.removeChild (left); + child.removeChild (right); + n = new Node (nodeType, left, right); + } + else if (childType == Token.GET_REF) { + Node rf = child.FirstChild; + child.removeChild (rf); + n = new Node (Token.DEL_REF, rf); + } + else { + n = new Node (Token.TRUE); + } + return n; + } + + case Token.TYPEOF: + if (childType == Token.NAME) { + child.Type = Token.TYPEOFNAME; + return child; + } + break; + + case Token.BITNOT: + if (childType == Token.NUMBER) { + int value = ScriptConvert.ToInt32 (child.Double); + child.Double = ~value; + return child; + } + break; + + case Token.NEG: + if (childType == Token.NUMBER) { + child.Double = -child.Double; + return child; + } + break; + + case Token.NOT: { + int status = isAlwaysDefinedBoolean (child); + if (status != 0) { + int type; + if (status == ALWAYS_TRUE_BOOLEAN) { + type = Token.FALSE; + } + else { + type = Token.TRUE; + } + if (childType == Token.TRUE || childType == Token.FALSE) { + child.Type = type; + return child; + } + return new Node (type); + } + break; + } + } + return new Node (nodeType, child); + } + + internal Node CreateCallOrNew (int nodeType, Node child) + { + int type = Node.NON_SPECIALCALL; + if (child.Type == Token.NAME) { + string name = child.String; + if (name.Equals ("eval")) { + type = Node.SPECIALCALL_EVAL; + } + else if (name.Equals ("With")) { + type = Node.SPECIALCALL_WITH; + } + } + else if (child.Type == Token.GETPROP) { + string name = child.LastChild.String; + if (name.Equals ("eval")) { + type = Node.SPECIALCALL_EVAL; + } + } + Node node = new Node (nodeType, child); + if (type != Node.NON_SPECIALCALL) { + // Calls to these functions require activation objects. + setRequiresActivation (); + node.putIntProp (Node.SPECIALCALL_PROP, type); + } + return node; + } + + internal Node CreateIncDec (int nodeType, bool post, Node child) + { + child = makeReference (child); + if (child == null) { + string msg; + if (nodeType == Token.DEC) { + msg = "msg.bad.decr"; + } + else { + msg = "msg.bad.incr"; + } + parser.ReportError (msg); + return null; + } + + int childType = child.Type; + + switch (childType) { + + case Token.NAME: + case Token.GETPROP: + case Token.GETELEM: + case Token.GET_REF: { + Node n = new Node (nodeType, child); + int incrDecrMask = 0; + if (nodeType == Token.DEC) { + incrDecrMask |= Node.DECR_FLAG; + } + if (post) { + incrDecrMask |= Node.POST_FLAG; + } + n.putIntProp (Node.INCRDECR_PROP, incrDecrMask); + return n; + } + } + throw Context.CodeBug (); + } + + internal Node CreatePropertyGet (Node target, string ns, string name, int memberTypeFlags) + { + if (ns == null && memberTypeFlags == 0) { + if (target == null) { + return CreateName (name); + } + checkActivationName (name, Token.GETPROP); + if (ScriptRuntime.isSpecialProperty (name)) { + Node rf = new Node (Token.REF_SPECIAL, target); + rf.putProp (Node.NAME_PROP, name); + return new Node (Token.GET_REF, rf); + } + return new Node (Token.GETPROP, target, CreateString (name)); + } + Node elem = CreateString (name); + memberTypeFlags |= Node.PROPERTY_FLAG; + return CreateMemberRefGet (target, ns, elem, memberTypeFlags); + } + + internal Node CreateElementGet (Node target, string ns, Node elem, int memberTypeFlags) + { + // OPT: could optimize to CreatePropertyGet + // iff elem is string that can not be number + if (ns == null && memberTypeFlags == 0) { + // stand-alone [aaa] as primary expression is array literal + // declaration and should not come here! + if (target == null) + throw Context.CodeBug (); + return new Node (Token.GETELEM, target, elem); + } + return CreateMemberRefGet (target, ns, elem, memberTypeFlags); + } + + private Node CreateMemberRefGet (Node target, string ns, Node elem, int memberTypeFlags) + { + Node nsNode = null; + if (ns != null) { + // See 11.1.2 in ECMA 357 + if (ns.Equals ("*")) { + nsNode = new Node (Token.NULL); + } + else { + nsNode = CreateName (ns); + } + } + Node rf; + if (target == null) { + if (ns == null) { + rf = new Node (Token.REF_NAME, elem); + } + else { + rf = new Node (Token.REF_NS_NAME, nsNode, elem); + } + } + else { + if (ns == null) { + rf = new Node (Token.REF_MEMBER, target, elem); + } + else { + rf = new Node (Token.REF_NS_MEMBER, target, nsNode, elem); + } + } + if (memberTypeFlags != 0) { + rf.putIntProp (Node.MEMBER_TYPE_PROP, memberTypeFlags); + } + return new Node (Token.GET_REF, rf); + } + + /// Binary + internal Node CreateBinary (int nodeType, Node left, Node right) + { + switch (nodeType) { + + + case Token.ADD: + // numerical addition and string concatenation + if (left.Type == Token.STRING) { + string s2; + if (right.Type == Token.STRING) { + s2 = right.String; + } + else if (right.Type == Token.NUMBER) { + s2 = ScriptConvert.ToString (right.Double, 10); + } + else { + break; + } + string s1 = left.String; + left.String = string.Concat (s1, s2); + return left; + } + else if (left.Type == Token.NUMBER) { + if (right.Type == Token.NUMBER) { + left.Double = left.Double + right.Double; + return left; + } + else if (right.Type == Token.STRING) { + string s1, s2; + s1 = ScriptConvert.ToString (left.Double, 10); + s2 = right.String; + right.String = string.Concat (s1, s2); + return right; + } + } + // can't do anything if we don't know both types - since + // 0 + object is supposed to call toString on the object and do + // string concantenation rather than addition + break; + + + case Token.SUB: + // numerical subtraction + if (left.Type == Token.NUMBER) { + double ld = left.Double; + if (right.Type == Token.NUMBER) { + //both numbers + left.Double = ld - right.Double; + return left; + } + else if (ld == 0.0) { + // first 0: 0-x -> -x + return new Node (Token.NEG, right); + } + } + else if (right.Type == Token.NUMBER) { + if (right.Double == 0.0) { + //second 0: x - 0 -> +x + // can not make simply x because x - 0 must be number + return new Node (Token.POS, left); + } + } + break; + + + case Token.MUL: + // numerical multiplication + if (left.Type == Token.NUMBER) { + double ld = left.Double; + if (right.Type == Token.NUMBER) { + //both numbers + left.Double = ld * right.Double; + return left; + } + else if (ld == 1.0) { + // first 1: 1 * x -> +x + return new Node (Token.POS, right); + } + } + else if (right.Type == Token.NUMBER) { + if (right.Double == 1.0) { + //second 1: x * 1 -> +x + // can not make simply x because x - 0 must be number + return new Node (Token.POS, left); + } + } + // can't do x*0: Infinity * 0 gives NaN, not 0 + break; + + + case Token.DIV: + // number division + if (right.Type == Token.NUMBER) { + double rd = right.Double; + if (left.Type == Token.NUMBER) { + // both constants -- just divide, trust Java to handle x/0 + left.Double = left.Double / rd; + return left; + } + else if (rd == 1.0) { + // second 1: x/1 -> +x + // not simply x to force number convertion + return new Node (Token.POS, left); + } + } + break; + + + case Token.AND: { + int leftStatus = isAlwaysDefinedBoolean (left); + if (leftStatus == ALWAYS_FALSE_BOOLEAN) { + // if the first one is false, replace with FALSE + return new Node (Token.FALSE); + } + else if (leftStatus == ALWAYS_TRUE_BOOLEAN) { + // if first is true, set to second + return right; + } + int rightStatus = isAlwaysDefinedBoolean (right); + if (rightStatus == ALWAYS_FALSE_BOOLEAN) { + // if the second one is false, replace with FALSE + if (!hasSideEffects (left)) { + return new Node (Token.FALSE); + } + } + else if (rightStatus == ALWAYS_TRUE_BOOLEAN) { + // if second is true, set to first + return left; + } + break; + } + + + case Token.OR: { + int leftStatus = isAlwaysDefinedBoolean (left); + if (leftStatus == ALWAYS_TRUE_BOOLEAN) { + // if the first one is true, replace with TRUE + return new Node (Token.TRUE); + } + else if (leftStatus == ALWAYS_FALSE_BOOLEAN) { + // if first is false, set to second + return right; + } + int rightStatus = isAlwaysDefinedBoolean (right); + if (rightStatus == ALWAYS_TRUE_BOOLEAN) { + // if the second one is true, replace with TRUE + if (!hasSideEffects (left)) { + return new Node (Token.TRUE); + } + } + else if (rightStatus == ALWAYS_FALSE_BOOLEAN) { + // if second is false, set to first + return left; + } + break; + } + } + + return new Node (nodeType, left, right); + } + + private Node simpleAssignment (Node left, Node right) + { + int nodeType = left.Type; + switch (nodeType) { + + case Token.NAME: + left.Type = Token.BINDNAME; + return new Node (Token.SETNAME, left, right); + + + case Token.GETPROP: + case Token.GETELEM: { + Node obj = left.FirstChild; + Node id = left.LastChild; + int type; + if (nodeType == Token.GETPROP) { + type = Token.SETPROP; + } + else { + type = Token.SETELEM; + } + return new Node (type, obj, id, right); + } + + case Token.GET_REF: { + Node rf = left.FirstChild; + checkMutableReference (rf); + return new Node (Token.SET_REF, rf, right); + } + } + + throw Context.CodeBug (); + } + + private void checkMutableReference (Node n) + { + int memberTypeFlags = n.getIntProp (Node.MEMBER_TYPE_PROP, 0); + if ((memberTypeFlags & Node.DESCENDANTS_FLAG) != 0) { + parser.ReportError ("msg.bad.assign.left"); + } + } + + internal Node CreateAssignment (int assignType, Node left, Node right) + { + left = makeReference (left); + if (left == null) { + parser.ReportError ("msg.bad.assign.left"); + return right; + } + + int assignOp; + switch (assignType) { + + case Token.ASSIGN: + return simpleAssignment (left, right); + + case Token.ASSIGN_BITOR: + assignOp = Token.BITOR; + break; + + case Token.ASSIGN_BITXOR: + assignOp = Token.BITXOR; + break; + + case Token.ASSIGN_BITAND: + assignOp = Token.BITAND; + break; + + case Token.ASSIGN_LSH: + assignOp = Token.LSH; + break; + + case Token.ASSIGN_RSH: + assignOp = Token.RSH; + break; + + case Token.ASSIGN_URSH: + assignOp = Token.URSH; + break; + + case Token.ASSIGN_ADD: + assignOp = Token.ADD; + break; + + case Token.ASSIGN_SUB: + assignOp = Token.SUB; + break; + + case Token.ASSIGN_MUL: + assignOp = Token.MUL; + break; + + case Token.ASSIGN_DIV: + assignOp = Token.DIV; + break; + + case Token.ASSIGN_MOD: + assignOp = Token.MOD; + break; + + default: + throw Context.CodeBug (); + + } + + int nodeType = left.Type; + switch (nodeType) { + + case Token.NAME: { + string s = left.String; + + Node opLeft = Node.newString (Token.NAME, s); + Node op = new Node (assignOp, opLeft, right); + Node lvalueLeft = Node.newString (Token.BINDNAME, s); + return new Node (Token.SETNAME, lvalueLeft, op); + } + + case Token.GETPROP: + case Token.GETELEM: { + Node obj = left.FirstChild; + Node id = left.LastChild; + + int type = nodeType == Token.GETPROP ? Token.SETPROP_OP : Token.SETELEM_OP; + + Node opLeft = new Node (Token.USE_STACK); + Node op = new Node (assignOp, opLeft, right); + return new Node (type, obj, id, op); + } + + case Token.GET_REF: { + Node rf = left.FirstChild; + checkMutableReference (rf); + Node opLeft = new Node (Token.USE_STACK); + Node op = new Node (assignOp, opLeft, right); + return new Node (Token.SET_REF_OP, rf, op); + } + } + + throw Context.CodeBug (); + } + + internal Node CreateUseLocal (Node localBlock) + { + if (Token.LOCAL_BLOCK != localBlock.Type) + throw Context.CodeBug (); + Node result = new Node (Token.LOCAL_LOAD); + result.putProp (Node.LOCAL_BLOCK_PROP, localBlock); + return result; + } + + private Node.Jump makeJump (int type, Node target) + { + Node.Jump n = new Node.Jump (type); + n.target = target; + return n; + } + + private Node makeReference (Node node) + { + int type = node.Type; + switch (type) { + + case Token.NAME: + case Token.GETPROP: + case Token.GETELEM: + case Token.GET_REF: + return node; + + case Token.CALL: + node.Type = Token.REF_CALL; + return new Node (Token.GET_REF, node); + } + // Signal caller to report error + return null; + } + + // Check if Node always mean true or false in boolean context + private static int isAlwaysDefinedBoolean (Node node) + { + switch (node.Type) { + + case Token.FALSE: + case Token.NULL: + return ALWAYS_FALSE_BOOLEAN; + + case Token.TRUE: + return ALWAYS_TRUE_BOOLEAN; + + case Token.NUMBER: { + double num = node.Double; + if (!double.IsNaN (num) && num != 0.0) { + return ALWAYS_TRUE_BOOLEAN; + } + else { + return ALWAYS_FALSE_BOOLEAN; + } + } + } + return 0; + } + + private static bool hasSideEffects (Node exprTree) + { + switch (exprTree.Type) { + + case Token.INC: + case Token.DEC: + case Token.SETPROP: + case Token.SETELEM: + case Token.SETNAME: + case Token.CALL: + case Token.NEW: + return true; + + default: + Node child = exprTree.FirstChild; + while (child != null) { + if (hasSideEffects (child)) + return true; + child = child.Next; + } + break; + + } + return false; + } + + private void checkActivationName (string name, int token) + { + if (parser.insideFunction ()) { + bool activation = false; + if ("arguments".Equals (name) || (parser.compilerEnv.activationNames != null && parser.compilerEnv.activationNames.ContainsKey (name))) { + activation = true; + } + else if ("length".Equals (name)) { + if (token == Token.GETPROP && parser.compilerEnv.LanguageVersion == Context.Versions.JS1_2) { + // Use of "length" in 1.2 requires an activation object. + activation = true; + } + } + if (activation) { + setRequiresActivation (); + } + } + } + + private void setRequiresActivation () + { + if (parser.insideFunction ()) { + ((FunctionNode)parser.currentScriptOrFn).itsNeedsActivation = true; + } + } + + private Parser parser; + + private const int LOOP_DO_WHILE = 0; + private const int LOOP_WHILE = 1; + private const int LOOP_FOR = 2; + + private const int ALWAYS_TRUE_BOOLEAN = 1; + private const int ALWAYS_FALSE_BOOLEAN = -1; + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/NodeTransformer.cs b/src/EcmaScript.NET/NodeTransformer.cs similarity index 97% rename from Code/EcmaScript.NET/NodeTransformer.cs rename to src/EcmaScript.NET/NodeTransformer.cs index ef4d0b6..4ec7562 100644 --- a/Code/EcmaScript.NET/NodeTransformer.cs +++ b/src/EcmaScript.NET/NodeTransformer.cs @@ -1,345 +1,345 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -using EcmaScript.NET.Collections; - -namespace EcmaScript.NET -{ - - /// This class transforms a tree to a lower-level representation for codegen. - /// - /// - public class NodeTransformer - { - - public NodeTransformer () - { - } - - public void transform (ScriptOrFnNode tree) - { - transformCompilationUnit (tree); - for (int i = 0; i != tree.FunctionCount; ++i) { - FunctionNode fn = tree.getFunctionNode (i); - transform (fn); - } - } - - private void transformCompilationUnit (ScriptOrFnNode tree) - { - loops = new ObjArray (); - loopEnds = new ObjArray (); - // to save against upchecks if no finally blocks are used. - hasFinally = false; - - try { - transformCompilationUnit_r (tree, tree); - } catch (Helpers.StackOverflowVerifierException) { - throw Context.ReportRuntimeError ( - ScriptRuntime.GetMessage ("mag.too.deep.parser.recursion")); - } - } - - private void transformCompilationUnit_r (ScriptOrFnNode tree, Node parent) - { - Node node = null; - - using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier (1024)) { - for (; ; ) { - Node previous = null; - if (node == null) { - node = parent.FirstChild; - } - else { - previous = node; - node = node.Next; - } - if (node == null) { - break; - } - - int type = node.Type; - - switch (type) { - - - case Token.LABEL: - case Token.SWITCH: - case Token.LOOP: - loops.push (node); - loopEnds.push (((Node.Jump)node).target); - break; - - - case Token.WITH: { - loops.push (node); - Node leave = node.Next; - if (leave.Type != Token.LEAVEWITH) { - Context.CodeBug (); - } - loopEnds.push (leave); - break; - } - - - case Token.TRY: { - Node.Jump jump = (Node.Jump)node; - Node finallytarget = jump.Finally; - if (finallytarget != null) { - hasFinally = true; - loops.push (node); - loopEnds.push (finallytarget); - } - break; - } - - - case Token.TARGET: - case Token.LEAVEWITH: - if (!loopEnds.Empty && loopEnds.peek () == node) { - loopEnds.pop (); - loops.pop (); - } - break; - - - case Token.RETURN: { - /* If we didn't support try/finally, it wouldn't be - * necessary to put LEAVEWITH nodes here... but as - * we do need a series of JSR FINALLY nodes before - * each RETURN, we need to ensure that each finally - * block gets the correct scope... which could mean - * that some LEAVEWITH nodes are necessary. - */ - if (!hasFinally) - break; // skip the whole mess. - Node unwindBlock = null; - for (int i = loops.size () - 1; i >= 0; i--) { - Node n = (Node)loops.Get (i); - int elemtype = n.Type; - if (elemtype == Token.TRY || elemtype == Token.WITH) { - Node unwind; - if (elemtype == Token.TRY) { - Node.Jump jsrnode = new Node.Jump (Token.JSR); - Node jsrtarget = ((Node.Jump)n).Finally; - jsrnode.target = jsrtarget; - unwind = jsrnode; - } - else { - unwind = new Node (Token.LEAVEWITH); - } - if (unwindBlock == null) { - unwindBlock = new Node (Token.BLOCK, node.Lineno); - } - unwindBlock.addChildToBack (unwind); - } - } - if (unwindBlock != null) { - Node returnNode = node; - Node returnExpr = returnNode.FirstChild; - node = replaceCurrent (parent, previous, node, unwindBlock); - if (returnExpr == null) { - unwindBlock.addChildToBack (returnNode); - } - else { - Node store = new Node (Token.EXPR_RESULT, returnExpr); - unwindBlock.addChildToFront (store); - returnNode = new Node (Token.RETURN_RESULT); - unwindBlock.addChildToBack (returnNode); - // transform return expression - transformCompilationUnit_r (tree, store); - } - // skip transformCompilationUnit_r to avoid infinite loop - - goto siblingLoop; - } - break; - } - - - case Token.BREAK: - case Token.CONTINUE: { - Node.Jump jump = (Node.Jump)node; - Node.Jump jumpStatement = jump.JumpStatement; - if (jumpStatement == null) - Context.CodeBug (); - - for (int i = loops.size (); ; ) { - if (i == 0) { - // Parser/IRFactory ensure that break/continue - // always has a jump statement associated with it - // which should be found - throw Context.CodeBug (); - } - --i; - Node n = (Node)loops.Get (i); - if (n == jumpStatement) { - break; - } - - int elemtype = n.Type; - if (elemtype == Token.WITH) { - Node leave = new Node (Token.LEAVEWITH); - previous = addBeforeCurrent (parent, previous, node, leave); - } - else if (elemtype == Token.TRY) { - Node.Jump tryNode = (Node.Jump)n; - Node.Jump jsrFinally = new Node.Jump (Token.JSR); - jsrFinally.target = tryNode.Finally; - previous = addBeforeCurrent (parent, previous, node, jsrFinally); - } - } - - if (type == Token.BREAK) { - jump.target = jumpStatement.target; - } - else { - jump.target = jumpStatement.Continue; - } - jump.Type = Token.GOTO; - - break; - } - - - case Token.CALL: - visitCall (node, tree); - break; - - - case Token.NEW: - visitNew (node, tree); - break; - - - case Token.VAR: { - Node result = new Node (Token.BLOCK); - for (Node cursor = node.FirstChild; cursor != null; ) { - // Move cursor to next before createAssignment get chance - // to change n.next - Node n = cursor; - if (n.Type != Token.NAME) - Context.CodeBug (); - cursor = cursor.Next; - if (!n.hasChildren ()) - continue; - Node init = n.FirstChild; - n.removeChild (init); - n.Type = Token.BINDNAME; - n = new Node (Token.SETNAME, n, init); - Node pop = new Node (Token.EXPR_VOID, n, node.Lineno); - result.addChildToBack (pop); - } - node = replaceCurrent (parent, previous, node, result); - break; - } - - - case Token.NAME: - case Token.SETNAME: - case Token.DELPROP: { - // Turn name to var for faster access if possible - if (tree.Type != Token.FUNCTION || ((FunctionNode)tree).RequiresActivation) { - break; - } - Node nameSource; - if (type == Token.NAME) { - nameSource = node; - } - else { - nameSource = node.FirstChild; - if (nameSource.Type != Token.BINDNAME) { - if (type == Token.DELPROP) { - break; - } - throw Context.CodeBug (); - } - } - string name = nameSource.String; - if (tree.hasParamOrVar (name)) { - if (type == Token.NAME) { - node.Type = Token.GETVAR; - } - else if (type == Token.SETNAME) { - node.Type = Token.SETVAR; - nameSource.Type = Token.STRING; - } - else if (type == Token.DELPROP) { - // Local variables are by definition permanent - Node n = new Node (Token.FALSE); - node = replaceCurrent (parent, previous, node, n); - } - else { - throw Context.CodeBug (); - } - } - break; - } - } - - transformCompilationUnit_r (tree, node); - - siblingLoop: - ; - } - } - } - - protected internal virtual void visitNew (Node node, ScriptOrFnNode tree) - { - } - - protected internal virtual void visitCall (Node node, ScriptOrFnNode tree) - { - } - - private static Node addBeforeCurrent (Node parent, Node previous, Node current, Node toAdd) - { - if (previous == null) { - if (!(current == parent.FirstChild)) - Context.CodeBug (); - parent.addChildToFront (toAdd); - } - else { - if (!(current == previous.Next)) - Context.CodeBug (); - parent.addChildAfter (toAdd, previous); - } - return toAdd; - } - - private static Node replaceCurrent (Node parent, Node previous, Node current, Node replacement) - { - if (previous == null) { - if (!(current == parent.FirstChild)) - Context.CodeBug (); - parent.replaceChild (current, replacement); - } - else if (previous.next == current) { - // Check cachedPrev.next == current is necessary due to possible - // tree mutations - parent.replaceChildAfter (previous, replacement); - } - else { - parent.replaceChild (current, replacement); - } - return replacement; - } - - private ObjArray loops; - private ObjArray loopEnds; - private bool hasFinally; - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +using EcmaScript.NET.Collections; + +namespace EcmaScript.NET +{ + + /// This class transforms a tree to a lower-level representation for codegen. + /// + /// + public class NodeTransformer + { + + public NodeTransformer () + { + } + + public void transform (ScriptOrFnNode tree) + { + transformCompilationUnit (tree); + for (int i = 0; i != tree.FunctionCount; ++i) { + FunctionNode fn = tree.getFunctionNode (i); + transform (fn); + } + } + + private void transformCompilationUnit (ScriptOrFnNode tree) + { + loops = new ObjArray (); + loopEnds = new ObjArray (); + // to save against upchecks if no finally blocks are used. + hasFinally = false; + + try { + transformCompilationUnit_r (tree, tree); + } catch (Helpers.StackOverflowVerifierException) { + throw Context.ReportRuntimeError ( + ScriptRuntime.GetMessage ("mag.too.deep.parser.recursion")); + } + } + + private void transformCompilationUnit_r (ScriptOrFnNode tree, Node parent) + { + Node node = null; + + using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier (1024)) { + for (; ; ) { + Node previous = null; + if (node == null) { + node = parent.FirstChild; + } + else { + previous = node; + node = node.Next; + } + if (node == null) { + break; + } + + int type = node.Type; + + switch (type) { + + + case Token.LABEL: + case Token.SWITCH: + case Token.LOOP: + loops.push (node); + loopEnds.push (((Node.Jump)node).target); + break; + + + case Token.WITH: { + loops.push (node); + Node leave = node.Next; + if (leave.Type != Token.LEAVEWITH) { + Context.CodeBug (); + } + loopEnds.push (leave); + break; + } + + + case Token.TRY: { + Node.Jump jump = (Node.Jump)node; + Node finallytarget = jump.Finally; + if (finallytarget != null) { + hasFinally = true; + loops.push (node); + loopEnds.push (finallytarget); + } + break; + } + + + case Token.TARGET: + case Token.LEAVEWITH: + if (!loopEnds.Empty && loopEnds.peek () == node) { + loopEnds.pop (); + loops.pop (); + } + break; + + + case Token.RETURN: { + /* If we didn't support try/finally, it wouldn't be + * necessary to put LEAVEWITH nodes here... but as + * we do need a series of JSR FINALLY nodes before + * each RETURN, we need to ensure that each finally + * block gets the correct scope... which could mean + * that some LEAVEWITH nodes are necessary. + */ + if (!hasFinally) + break; // skip the whole mess. + Node unwindBlock = null; + for (int i = loops.size () - 1; i >= 0; i--) { + Node n = (Node)loops.Get (i); + int elemtype = n.Type; + if (elemtype == Token.TRY || elemtype == Token.WITH) { + Node unwind; + if (elemtype == Token.TRY) { + Node.Jump jsrnode = new Node.Jump (Token.JSR); + Node jsrtarget = ((Node.Jump)n).Finally; + jsrnode.target = jsrtarget; + unwind = jsrnode; + } + else { + unwind = new Node (Token.LEAVEWITH); + } + if (unwindBlock == null) { + unwindBlock = new Node (Token.BLOCK, node.Lineno); + } + unwindBlock.addChildToBack (unwind); + } + } + if (unwindBlock != null) { + Node returnNode = node; + Node returnExpr = returnNode.FirstChild; + node = replaceCurrent (parent, previous, node, unwindBlock); + if (returnExpr == null) { + unwindBlock.addChildToBack (returnNode); + } + else { + Node store = new Node (Token.EXPR_RESULT, returnExpr); + unwindBlock.addChildToFront (store); + returnNode = new Node (Token.RETURN_RESULT); + unwindBlock.addChildToBack (returnNode); + // transform return expression + transformCompilationUnit_r (tree, store); + } + // skip transformCompilationUnit_r to avoid infinite loop + + goto siblingLoop; + } + break; + } + + + case Token.BREAK: + case Token.CONTINUE: { + Node.Jump jump = (Node.Jump)node; + Node.Jump jumpStatement = jump.JumpStatement; + if (jumpStatement == null) + Context.CodeBug (); + + for (int i = loops.size (); ; ) { + if (i == 0) { + // Parser/IRFactory ensure that break/continue + // always has a jump statement associated with it + // which should be found + throw Context.CodeBug (); + } + --i; + Node n = (Node)loops.Get (i); + if (n == jumpStatement) { + break; + } + + int elemtype = n.Type; + if (elemtype == Token.WITH) { + Node leave = new Node (Token.LEAVEWITH); + previous = addBeforeCurrent (parent, previous, node, leave); + } + else if (elemtype == Token.TRY) { + Node.Jump tryNode = (Node.Jump)n; + Node.Jump jsrFinally = new Node.Jump (Token.JSR); + jsrFinally.target = tryNode.Finally; + previous = addBeforeCurrent (parent, previous, node, jsrFinally); + } + } + + if (type == Token.BREAK) { + jump.target = jumpStatement.target; + } + else { + jump.target = jumpStatement.Continue; + } + jump.Type = Token.GOTO; + + break; + } + + + case Token.CALL: + visitCall (node, tree); + break; + + + case Token.NEW: + visitNew (node, tree); + break; + + + case Token.VAR: { + Node result = new Node (Token.BLOCK); + for (Node cursor = node.FirstChild; cursor != null; ) { + // Move cursor to next before createAssignment get chance + // to change n.next + Node n = cursor; + if (n.Type != Token.NAME) + Context.CodeBug (); + cursor = cursor.Next; + if (!n.hasChildren ()) + continue; + Node init = n.FirstChild; + n.removeChild (init); + n.Type = Token.BINDNAME; + n = new Node (Token.SETNAME, n, init); + Node pop = new Node (Token.EXPR_VOID, n, node.Lineno); + result.addChildToBack (pop); + } + node = replaceCurrent (parent, previous, node, result); + break; + } + + + case Token.NAME: + case Token.SETNAME: + case Token.DELPROP: { + // Turn name to var for faster access if possible + if (tree.Type != Token.FUNCTION || ((FunctionNode)tree).RequiresActivation) { + break; + } + Node nameSource; + if (type == Token.NAME) { + nameSource = node; + } + else { + nameSource = node.FirstChild; + if (nameSource.Type != Token.BINDNAME) { + if (type == Token.DELPROP) { + break; + } + throw Context.CodeBug (); + } + } + string name = nameSource.String; + if (tree.hasParamOrVar (name)) { + if (type == Token.NAME) { + node.Type = Token.GETVAR; + } + else if (type == Token.SETNAME) { + node.Type = Token.SETVAR; + nameSource.Type = Token.STRING; + } + else if (type == Token.DELPROP) { + // Local variables are by definition permanent + Node n = new Node (Token.FALSE); + node = replaceCurrent (parent, previous, node, n); + } + else { + throw Context.CodeBug (); + } + } + break; + } + } + + transformCompilationUnit_r (tree, node); + + siblingLoop: + ; + } + } + } + + protected internal virtual void visitNew (Node node, ScriptOrFnNode tree) + { + } + + protected internal virtual void visitCall (Node node, ScriptOrFnNode tree) + { + } + + private static Node addBeforeCurrent (Node parent, Node previous, Node current, Node toAdd) + { + if (previous == null) { + if (!(current == parent.FirstChild)) + Context.CodeBug (); + parent.addChildToFront (toAdd); + } + else { + if (!(current == previous.Next)) + Context.CodeBug (); + parent.addChildAfter (toAdd, previous); + } + return toAdd; + } + + private static Node replaceCurrent (Node parent, Node previous, Node current, Node replacement) + { + if (previous == null) { + if (!(current == parent.FirstChild)) + Context.CodeBug (); + parent.replaceChild (current, replacement); + } + else if (previous.next == current) { + // Check cachedPrev.next == current is necessary due to possible + // tree mutations + parent.replaceChildAfter (previous, replacement); + } + else { + parent.replaceChild (current, replacement); + } + return replacement; + } + + private ObjArray loops; + private ObjArray loopEnds; + private bool hasFinally; + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/Parser.cs b/src/EcmaScript.NET/Parser.cs similarity index 97% rename from Code/EcmaScript.NET/Parser.cs rename to src/EcmaScript.NET/Parser.cs index ff25eaa..43ef227 100644 --- a/Code/EcmaScript.NET/Parser.cs +++ b/src/EcmaScript.NET/Parser.cs @@ -1,2464 +1,2464 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; -using System.Collections; - -using EcmaScript.NET.Collections; - -namespace EcmaScript.NET -{ - - /// This class implements the JavaScript parser. - /// - /// It is based on the C source files jsparse.c and jsparse.h - /// in the jsref package. - /// - /// - public class Parser - { - public string EncodedSource - { - get - { - return encodedSource; - } - - } - // TokenInformation flags : currentFlaggedToken stores them together - // with token type - internal const int CLEAR_TI_MASK = 0xFFFF; - internal const int TI_AFTER_EOL = 1 << 16; - internal const int TI_CHECK_LABEL = 1 << 17; // indicates to check for label - - internal CompilerEnvirons compilerEnv; - ErrorReporter errorReporter; - string sourceURI; - internal bool calledByCompileFunction; - - TokenStream ts; - int currentFlaggedToken; - int syntaxErrorCount; - - NodeFactory nf; - - int nestingOfFunction; - - Decompiler decompiler; - string encodedSource; - - // The following are per function variables and should be saved/restored - // during function parsing. - // TODO: Move to separated class? - internal ScriptOrFnNode currentScriptOrFn; - int nestingOfWith; - Hashtable labelSet; // map of label names into nodes - ObjArray loopSet; - ObjArray loopAndSwitchSet; - // end of per function variables - - // Exception to unwind - - class ParserException : ApplicationException - { - - } - - public Parser(CompilerEnvirons compilerEnv, ErrorReporter errorReporter) - { - this.compilerEnv = compilerEnv; - this.errorReporter = errorReporter; - } - - Decompiler CreateDecompiler(CompilerEnvirons compilerEnv) - { - return new Decompiler(); - } - - internal void AddWarning(string messageId, string messageArg) - { - string message = ScriptRuntime.GetMessage(messageId, messageArg); - errorReporter.Warning(message, sourceURI, ts.Lineno, ts.Line, ts.Offset); - } - - internal void AddError(string messageId) - { - ++syntaxErrorCount; - string message = ScriptRuntime.GetMessage(messageId); - errorReporter.Error(message, sourceURI, ts.Lineno, ts.Line, ts.Offset); - } - - internal Exception ReportError(string messageId) - { - AddError(messageId); - - // Throw a ParserException exception to unwind the recursive descent - // parse. - throw new ParserException(); - } - - int peekToken() - { - int tt = currentFlaggedToken; - if (tt == Token.EOF) - { - - while ((tt = ts.Token) == Token.CONDCOMMENT || tt == Token.KEEPCOMMENT) - { - if (tt == Token.CONDCOMMENT) - { - /* Support for JScript conditional comments */ - decompiler.AddJScriptConditionalComment(ts.String); - } - else - { - /* Support for preserved comments */ - decompiler.AddPreservedComment(ts.String); - } - } - - if (tt == Token.EOL) - { - do - { - tt = ts.Token; - - if (tt == Token.CONDCOMMENT) - { - /* Support for JScript conditional comments */ - decompiler.AddJScriptConditionalComment(ts.String); - } - else if (tt == Token.KEEPCOMMENT) - { - /* Support for preserved comments */ - decompiler.AddPreservedComment(ts.String); - } - - } - while (tt == Token.EOL || tt == Token.CONDCOMMENT || tt == Token.KEEPCOMMENT); - tt |= TI_AFTER_EOL; - } - currentFlaggedToken = tt; - } - return tt & CLEAR_TI_MASK; - } - - int peekFlaggedToken() - { - peekToken(); - return currentFlaggedToken; - } - - void consumeToken() - { - currentFlaggedToken = Token.EOF; - } - - int nextToken() - { - int tt = peekToken(); - consumeToken(); - return tt; - } - - int nextFlaggedToken() - { - peekToken(); - int ttFlagged = currentFlaggedToken; - consumeToken(); - return ttFlagged; - } - - bool matchToken(int toMatch) - { - int tt = peekToken(); - if (tt != toMatch) - { - return false; - } - consumeToken(); - return true; - } - - int peekTokenOrEOL() - { - int tt = peekToken(); - // Check for last peeked token flags - if ((currentFlaggedToken & TI_AFTER_EOL) != 0) - { - tt = Token.EOL; - } - return tt; - } - - void setCheckForLabel() - { - if ((currentFlaggedToken & CLEAR_TI_MASK) != Token.NAME) - throw Context.CodeBug(); - currentFlaggedToken |= TI_CHECK_LABEL; - } - - void mustMatchToken(int toMatch, string messageId) - { - if (!matchToken(toMatch)) - { - ReportError(messageId); - } - } - - void mustHaveXML() - { - if (!compilerEnv.isXmlAvailable()) - { - ReportError("msg.XML.not.available"); - } - } - - public bool Eof - { - get - { - return ts.eof(); - } - } - - internal bool insideFunction() - { - return nestingOfFunction != 0; - } - - Node enterLoop(Node loopLabel) - { - Node loop = nf.CreateLoopNode(loopLabel, ts.Lineno); - if (loopSet == null) - { - loopSet = new ObjArray(); - if (loopAndSwitchSet == null) - { - loopAndSwitchSet = new ObjArray(); - } - } - loopSet.push(loop); - loopAndSwitchSet.push(loop); - return loop; - } - - void exitLoop() - { - loopSet.pop(); - loopAndSwitchSet.pop(); - } - - Node enterSwitch(Node switchSelector, int lineno, Node switchLabel) - { - Node switchNode = nf.CreateSwitch(switchSelector, lineno); - if (loopAndSwitchSet == null) - { - loopAndSwitchSet = new ObjArray(); - } - loopAndSwitchSet.push(switchNode); - return switchNode; - } - - void exitSwitch() - { - loopAndSwitchSet.pop(); - } - - /* - * Build a parse tree from the given sourceString. - * - * @return an Object representing the parsed - * program. If the parse fails, null will be returned. (The - * parse failure will result in a call to the ErrorReporter from - * CompilerEnvirons.) - */ - public ScriptOrFnNode Parse(string sourceString, string sourceURI, int lineno) - { - this.sourceURI = sourceURI; - this.ts = new TokenStream(this, null, sourceString, lineno); - try - { - return Parse(); - } - catch (System.IO.IOException) - { - // Should never happen - throw new ApplicationException(); - } - } - - /* - * Build a parse tree from the given sourceString. - * - * @return an Object representing the parsed - * program. If the parse fails, null will be returned. (The - * parse failure will result in a call to the ErrorReporter from - * CompilerEnvirons.) - */ - public ScriptOrFnNode Parse(System.IO.StreamReader sourceReader, string sourceURI, int lineno) - { - this.sourceURI = sourceURI; - this.ts = new TokenStream(this, sourceReader, null, lineno); - return Parse(); - } - - ScriptOrFnNode Parse() - { - this.decompiler = CreateDecompiler(compilerEnv); - this.nf = new NodeFactory(this); - currentScriptOrFn = nf.CreateScript(); - int sourceStartOffset = decompiler.CurrentOffset; - this.encodedSource = null; - decompiler.AddToken(Token.SCRIPT); - - this.currentFlaggedToken = Token.EOF; - this.syntaxErrorCount = 0; - - int baseLineno = ts.Lineno; // line number where source starts - - /* so we have something to add nodes to until - * we've collected all the source */ - Node pn = nf.CreateLeaf(Token.BLOCK); - - for (; ; ) - { - int tt = peekToken(); - - if (tt <= Token.EOF) - { - break; - } - - Node n; - if (tt == Token.FUNCTION) - { - consumeToken(); - try - { - n = function(calledByCompileFunction ? FunctionNode.FUNCTION_EXPRESSION : FunctionNode.FUNCTION_STATEMENT); - } - catch (ParserException) - { - break; - } - } - else - { - n = statement(); - } - nf.addChildToBack(pn, n); - } - - if (this.syntaxErrorCount != 0) - { - string msg = Convert.ToString(this.syntaxErrorCount); - msg = ScriptRuntime.GetMessage("msg.got.syntax.errors", msg); - throw errorReporter.RuntimeError(msg, sourceURI, baseLineno, null, 0); - } - - currentScriptOrFn.SourceName = sourceURI; - currentScriptOrFn.BaseLineno = baseLineno; - currentScriptOrFn.EndLineno = ts.Lineno; - - int sourceEndOffset = decompiler.CurrentOffset; - currentScriptOrFn.setEncodedSourceBounds(sourceStartOffset, sourceEndOffset); - - nf.initScript(currentScriptOrFn, pn); - - if (compilerEnv.isGeneratingSource()) - { - encodedSource = decompiler.EncodedSource; - } - this.decompiler = null; // It helps GC - - return currentScriptOrFn; - } - - /* - * The C version of this function takes an argument list, - * which doesn't seem to be needed for tree generation... - * it'd only be useful for checking argument hiding, which - * I'm not doing anyway... - */ - Node parseFunctionBody() - { - ++nestingOfFunction; - Node pn = nf.CreateBlock(ts.Lineno); - try - { - for (; ; ) - { - Node n; - int tt = peekToken(); - switch (tt) - { - - case Token.ERROR: - case Token.EOF: - case Token.RC: - - goto bodyLoop_brk; - - - case Token.FUNCTION: - consumeToken(); - n = function(FunctionNode.FUNCTION_STATEMENT); - break; - - default: - n = statement(); - break; - - } - nf.addChildToBack(pn, n); - } - - bodyLoop_brk: - ; - - } - catch (ParserException) - { - // Ignore it - } - finally - { - --nestingOfFunction; - } - - return pn; - } - - Node function(int functionType) - { - using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier(1024)) - { - int syntheticType = functionType; - int baseLineno = ts.Lineno; // line number where source starts - - int functionSourceStart = decompiler.MarkFunctionStart(functionType); - string name; - Node memberExprNode = null; - if (matchToken(Token.NAME)) - { - name = ts.String; - decompiler.AddName(name); - if (!matchToken(Token.LP)) - { - if (compilerEnv.isAllowMemberExprAsFunctionName()) - { - // Extension to ECMA: if 'function ' does not follow - // by '(', assume starts memberExpr - Node memberExprHead = nf.CreateName(name); - name = ""; - memberExprNode = memberExprTail(false, memberExprHead); - } - mustMatchToken(Token.LP, "msg.no.paren.parms"); - } - } - else if (matchToken(Token.LP)) - { - // Anonymous function - name = ""; - } - else - { - name = ""; - if (compilerEnv.isAllowMemberExprAsFunctionName()) - { - // Note that memberExpr can not start with '(' like - // in function (1+2).toString(), because 'function (' already - // processed as anonymous function - memberExprNode = memberExpr(false); - } - mustMatchToken(Token.LP, "msg.no.paren.parms"); - } - - if (memberExprNode != null) - { - syntheticType = FunctionNode.FUNCTION_EXPRESSION; - } - - bool nested = insideFunction(); - - FunctionNode fnNode = nf.CreateFunction(name); - if (nested || nestingOfWith > 0) - { - // 1. Nested functions are not affected by the dynamic scope flag - // as dynamic scope is already a parent of their scope. - // 2. Functions defined under the with statement also immune to - // this setup, in which case dynamic scope is ignored in favor - // of with object. - fnNode.itsIgnoreDynamicScope = true; - } - - int functionIndex = currentScriptOrFn.addFunction(fnNode); - - int functionSourceEnd; - - ScriptOrFnNode savedScriptOrFn = currentScriptOrFn; - currentScriptOrFn = fnNode; - int savedNestingOfWith = nestingOfWith; - nestingOfWith = 0; - Hashtable savedLabelSet = labelSet; - labelSet = null; - ObjArray savedLoopSet = loopSet; - loopSet = null; - ObjArray savedLoopAndSwitchSet = loopAndSwitchSet; - loopAndSwitchSet = null; - - Node body; - try - { - decompiler.AddToken(Token.LP); - if (!matchToken(Token.RP)) - { - bool first = true; - do - { - if (!first) - decompiler.AddToken(Token.COMMA); - first = false; - mustMatchToken(Token.NAME, "msg.no.parm"); - string s = ts.String; - if (fnNode.hasParamOrVar(s)) - { - AddWarning("msg.dup.parms", s); - } - fnNode.addParam(s); - decompiler.AddName(s); - } - while (matchToken(Token.COMMA)); - - mustMatchToken(Token.RP, "msg.no.paren.after.parms"); - } - decompiler.AddToken(Token.RP); - - mustMatchToken(Token.LC, "msg.no.brace.body"); - decompiler.AddEol(Token.LC); - body = parseFunctionBody(); - mustMatchToken(Token.RC, "msg.no.brace.after.body"); - - decompiler.AddToken(Token.RC); - functionSourceEnd = decompiler.MarkFunctionEnd(functionSourceStart); - if (functionType != FunctionNode.FUNCTION_EXPRESSION) - { - if (compilerEnv.LanguageVersion >= Context.Versions.JS1_2) - { - // function f() {} function g() {} is not allowed in 1.2 - // or later but for compatibility with old scripts - // the check is done only if language is - // explicitly set. - // TODO: warning needed if version == VERSION_DEFAULT ? - int tt = peekTokenOrEOL(); - if (tt == Token.FUNCTION) - { - ReportError("msg.no.semi.stmt"); - } - } - // Add EOL only if function is not part of expression - // since it gets SEMI + EOL from Statement in that case - decompiler.AddToken(Token.EOL); - } - } - finally - { - loopAndSwitchSet = savedLoopAndSwitchSet; - loopSet = savedLoopSet; - labelSet = savedLabelSet; - nestingOfWith = savedNestingOfWith; - currentScriptOrFn = savedScriptOrFn; - } - - fnNode.setEncodedSourceBounds(functionSourceStart, functionSourceEnd); - fnNode.SourceName = sourceURI; - fnNode.BaseLineno = baseLineno; - fnNode.EndLineno = ts.Lineno; - - Node pn = nf.initFunction(fnNode, functionIndex, body, syntheticType); - if (memberExprNode != null) - { - pn = nf.CreateAssignment(Token.ASSIGN, memberExprNode, pn); - if (functionType != FunctionNode.FUNCTION_EXPRESSION) - { - // TOOD: check JScript behavior: should it be createExprStatement? - pn = nf.CreateExprStatementNoReturn(pn, baseLineno); - } - } - return pn; - } - } - - Node statements() - { - Node pn = nf.CreateBlock(ts.Lineno); - - int tt; - while ((tt = peekToken()) > Token.EOF && tt != Token.RC) - { - nf.addChildToBack(pn, statement()); - } - - return pn; - } - - Node condition() - { - Node pn; - mustMatchToken(Token.LP, "msg.no.paren.cond"); - decompiler.AddToken(Token.LP); - pn = expr(false); - mustMatchToken(Token.RP, "msg.no.paren.after.cond"); - decompiler.AddToken(Token.RP); - - // there's a check here in jsparse.c that corrects = to == - - return pn; - } - - // match a NAME; return null if no match. - Node matchJumpLabelName() - { - Node label = null; - - int tt = peekTokenOrEOL(); - if (tt == Token.NAME) - { - consumeToken(); - string name = ts.String; - decompiler.AddName(name); - if (labelSet != null) - { - label = (Node)labelSet[name]; - } - if (label == null) - { - ReportError("msg.undef.label"); - } - } - - return label; - } - - Node statement() - { - using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier(512)) - { - try - { - Node pn = statementHelper(null); - if (pn != null) - { - return pn; - } - } - catch (ParserException) - { - } - } - - // skip to end of statement - int lineno = ts.Lineno; - for (; ; ) - { - int tt = peekTokenOrEOL(); - consumeToken(); - switch (tt) - { - - case Token.ERROR: - case Token.EOF: - case Token.EOL: - case Token.SEMI: - - goto guessingStatementEnd_brk; - } - } - - guessingStatementEnd_brk: - ; - - return nf.CreateExprStatement(nf.CreateName("error"), lineno); - } - - /// Whether the "catch (e: e instanceof Exception) { ... }" syntax - /// is implemented. - /// - - Node statementHelper(Node statementLabel) - { - Node pn = null; - - int tt; - - tt = peekToken(); - - switch (tt) - { - - case Token.IF: - { - consumeToken(); - - decompiler.AddToken(Token.IF); - int lineno = ts.Lineno; - Node cond = condition(); - decompiler.AddEol(Token.LC); - Node ifTrue = statement(); - Node ifFalse = null; - if (matchToken(Token.ELSE)) - { - decompiler.AddToken(Token.RC); - decompiler.AddToken(Token.ELSE); - decompiler.AddEol(Token.LC); - ifFalse = statement(); - } - decompiler.AddEol(Token.RC); - pn = nf.CreateIf(cond, ifTrue, ifFalse, lineno); - return pn; - } - - - case Token.SWITCH: - { - consumeToken(); - - decompiler.AddToken(Token.SWITCH); - int lineno = ts.Lineno; - mustMatchToken(Token.LP, "msg.no.paren.switch"); - decompiler.AddToken(Token.LP); - pn = enterSwitch(expr(false), lineno, statementLabel); - try - { - mustMatchToken(Token.RP, "msg.no.paren.after.switch"); - decompiler.AddToken(Token.RP); - mustMatchToken(Token.LC, "msg.no.brace.switch"); - decompiler.AddEol(Token.LC); - - bool hasDefault = false; - for (; ; ) - { - tt = nextToken(); - Node caseExpression; - switch (tt) - { - - case Token.RC: - - goto switchLoop_brk; - - - case Token.CASE: - decompiler.AddToken(Token.CASE); - caseExpression = expr(false); - mustMatchToken(Token.COLON, "msg.no.colon.case"); - decompiler.AddEol(Token.COLON); - break; - - - case Token.DEFAULT: - if (hasDefault) - { - ReportError("msg.double.switch.default"); - } - decompiler.AddToken(Token.DEFAULT); - hasDefault = true; - caseExpression = null; - mustMatchToken(Token.COLON, "msg.no.colon.case"); - decompiler.AddEol(Token.COLON); - break; - - - default: - ReportError("msg.bad.switch"); - - goto switchLoop_brk; - - } - - Node block = nf.CreateLeaf(Token.BLOCK); - while ((tt = peekToken()) != Token.RC && tt != Token.CASE && tt != Token.DEFAULT && tt != Token.EOF) - { - nf.addChildToBack(block, statement()); - } - - // caseExpression == null => add default lable - nf.addSwitchCase(pn, caseExpression, block); - } - - switchLoop_brk: - ; - - decompiler.AddEol(Token.RC); - nf.closeSwitch(pn); - } - finally - { - exitSwitch(); - } - return pn; - } - - - case Token.WHILE: - { - consumeToken(); - decompiler.AddToken(Token.WHILE); - - Node loop = enterLoop(statementLabel); - try - { - Node cond = condition(); - decompiler.AddEol(Token.LC); - Node body = statement(); - decompiler.AddEol(Token.RC); - pn = nf.CreateWhile(loop, cond, body); - } - finally - { - exitLoop(); - } - return pn; - } - - - case Token.DO: - { - consumeToken(); - decompiler.AddToken(Token.DO); - decompiler.AddEol(Token.LC); - - Node loop = enterLoop(statementLabel); - try - { - Node body = statement(); - decompiler.AddToken(Token.RC); - mustMatchToken(Token.WHILE, "msg.no.while.do"); - decompiler.AddToken(Token.WHILE); - Node cond = condition(); - pn = nf.CreateDoWhile(loop, body, cond); - } - finally - { - exitLoop(); - } - // Always auto-insert semicon to follow SpiderMonkey: - // It is required by EMAScript but is ignored by the rest of - // world, see bug 238945 - matchToken(Token.SEMI); - decompiler.AddEol(Token.SEMI); - return pn; - } - - - case Token.FOR: - { - consumeToken(); - bool isForEach = false; - decompiler.AddToken(Token.FOR); - - Node loop = enterLoop(statementLabel); - try - { - - Node init; // Node init is also foo in 'foo in Object' - Node cond; // Node cond is also object in 'foo in Object' - Node incr = null; // to kill warning - Node body; - - // See if this is a for each () instead of just a for () - if (matchToken(Token.NAME)) - { - decompiler.AddName(ts.String); - if (ts.String.Equals("each")) - { - isForEach = true; - } - else - { - ReportError("msg.no.paren.for"); - } - } - - mustMatchToken(Token.LP, "msg.no.paren.for"); - decompiler.AddToken(Token.LP); - tt = peekToken(); - if (tt == Token.SEMI) - { - init = nf.CreateLeaf(Token.EMPTY); - } - else - { - if (tt == Token.VAR) - { - // set init to a var list or initial - consumeToken(); // consume the 'var' token - init = variables(true); - } - else - { - init = expr(true); - } - } - - if (matchToken(Token.IN)) - { - decompiler.AddToken(Token.IN); - // 'cond' is the object over which we're iterating - cond = expr(false); - } - else - { - // ordinary for loop - mustMatchToken(Token.SEMI, "msg.no.semi.for"); - decompiler.AddToken(Token.SEMI); - if (peekToken() == Token.SEMI) - { - // no loop condition - cond = nf.CreateLeaf(Token.EMPTY); - } - else - { - cond = expr(false); - } - - mustMatchToken(Token.SEMI, "msg.no.semi.for.cond"); - decompiler.AddToken(Token.SEMI); - if (peekToken() == Token.RP) - { - incr = nf.CreateLeaf(Token.EMPTY); - } - else - { - incr = expr(false); - } - } - - mustMatchToken(Token.RP, "msg.no.paren.for.ctrl"); - decompiler.AddToken(Token.RP); - decompiler.AddEol(Token.LC); - body = statement(); - decompiler.AddEol(Token.RC); - - if (incr == null) - { - // cond could be null if 'in obj' got eaten - // by the init node. - pn = nf.CreateForIn(loop, init, cond, body, isForEach); - } - else - { - pn = nf.CreateFor(loop, init, cond, incr, body); - } - } - finally - { - exitLoop(); - } - return pn; - } - - - case Token.TRY: - { - consumeToken(); - int lineno = ts.Lineno; - - Node tryblock; - Node catchblocks = null; - Node finallyblock = null; - - decompiler.AddToken(Token.TRY); - decompiler.AddEol(Token.LC); - tryblock = statement(); - decompiler.AddEol(Token.RC); - - catchblocks = nf.CreateLeaf(Token.BLOCK); - - bool sawDefaultCatch = false; - int peek = peekToken(); - if (peek == Token.CATCH) - { - while (matchToken(Token.CATCH)) - { - if (sawDefaultCatch) - { - ReportError("msg.catch.unreachable"); - } - decompiler.AddToken(Token.CATCH); - mustMatchToken(Token.LP, "msg.no.paren.catch"); - decompiler.AddToken(Token.LP); - - mustMatchToken(Token.NAME, "msg.bad.catchcond"); - string varName = ts.String; - decompiler.AddName(varName); - - Node catchCond = null; - if (matchToken(Token.IF)) - { - decompiler.AddToken(Token.IF); - catchCond = expr(false); - } - else - { - sawDefaultCatch = true; - } - - mustMatchToken(Token.RP, "msg.bad.catchcond"); - decompiler.AddToken(Token.RP); - mustMatchToken(Token.LC, "msg.no.brace.catchblock"); - decompiler.AddEol(Token.LC); - - nf.addChildToBack(catchblocks, nf.CreateCatch(varName, catchCond, statements(), ts.Lineno)); - - mustMatchToken(Token.RC, "msg.no.brace.after.body"); - decompiler.AddEol(Token.RC); - } - } - else if (peek != Token.FINALLY) - { - mustMatchToken(Token.FINALLY, "msg.try.no.catchfinally"); - } - - if (matchToken(Token.FINALLY)) - { - decompiler.AddToken(Token.FINALLY); - decompiler.AddEol(Token.LC); - finallyblock = statement(); - decompiler.AddEol(Token.RC); - } - - pn = nf.CreateTryCatchFinally(tryblock, catchblocks, finallyblock, lineno); - - return pn; - } - - - case Token.THROW: - { - consumeToken(); - if (peekTokenOrEOL() == Token.EOL) - { - // ECMAScript does not allow new lines before throw expression, - // see bug 256617 - ReportError("msg.bad.throw.eol"); - } - - int lineno = ts.Lineno; - decompiler.AddToken(Token.THROW); - pn = nf.CreateThrow(expr(false), lineno); - break; - } - - - case Token.BREAK: - { - consumeToken(); - int lineno = ts.Lineno; - - decompiler.AddToken(Token.BREAK); - - // matchJumpLabelName only matches if there is one - Node breakStatement = matchJumpLabelName(); - if (breakStatement == null) - { - if (loopAndSwitchSet == null || loopAndSwitchSet.size() == 0) - { - ReportError("msg.bad.break"); - return null; - } - breakStatement = (Node)loopAndSwitchSet.peek(); - } - pn = nf.CreateBreak(breakStatement, lineno); - break; - } - - - case Token.CONTINUE: - { - consumeToken(); - int lineno = ts.Lineno; - - decompiler.AddToken(Token.CONTINUE); - - Node loop; - // matchJumpLabelName only matches if there is one - Node label = matchJumpLabelName(); - if (label == null) - { - if (loopSet == null || loopSet.size() == 0) - { - ReportError("msg.continue.outside"); - return null; - } - loop = (Node)loopSet.peek(); - } - else - { - loop = nf.getLabelLoop(label); - if (loop == null) - { - ReportError("msg.continue.nonloop"); - return null; - } - } - pn = nf.CreateContinue(loop, lineno); - break; - } - - - case Token.WITH: - { - consumeToken(); - - decompiler.AddToken(Token.WITH); - int lineno = ts.Lineno; - mustMatchToken(Token.LP, "msg.no.paren.with"); - decompiler.AddToken(Token.LP); - Node obj = expr(false); - mustMatchToken(Token.RP, "msg.no.paren.after.with"); - decompiler.AddToken(Token.RP); - decompiler.AddEol(Token.LC); - - ++nestingOfWith; - Node body; - try - { - body = statement(); - } - finally - { - --nestingOfWith; - } - - decompiler.AddEol(Token.RC); - - pn = nf.CreateWith(obj, body, lineno); - return pn; - } - - - case Token.VAR: - { - consumeToken(); - pn = variables(false); - break; - } - - - case Token.RETURN: - { - if (!insideFunction()) - { - ReportError("msg.bad.return"); - } - consumeToken(); - decompiler.AddToken(Token.RETURN); - int lineno = ts.Lineno; - - Node retExpr; - /* This is ugly, but we don't want to require a semicolon. */ - tt = peekTokenOrEOL(); - switch (tt) - { - - case Token.SEMI: - case Token.RC: - case Token.EOF: - case Token.EOL: - case Token.ERROR: - retExpr = null; - break; - - default: - retExpr = expr(false); - break; - - } - pn = nf.CreateReturn(retExpr, lineno); - break; - } - - case Token.DEBUGGER: - consumeToken(); - decompiler.AddToken(Token.DEBUGGER); - pn = nf.CreateDebugger(ts.Lineno); - break; - - case Token.LC: - consumeToken(); - if (statementLabel != null) - { - decompiler.AddToken(Token.LC); - } - pn = statements(); - mustMatchToken(Token.RC, "msg.no.brace.block"); - if (statementLabel != null) - { - decompiler.AddEol(Token.RC); - } - return pn; - - - case Token.ERROR: - // Fall thru, to have a node for error recovery to work on - case Token.SEMI: - consumeToken(); - pn = nf.CreateLeaf(Token.EMPTY); - return pn; - - - case Token.FUNCTION: - { - consumeToken(); - pn = function(FunctionNode.FUNCTION_EXPRESSION_STATEMENT); - return pn; - } - - - case Token.DEFAULT: - consumeToken(); - mustHaveXML(); - - decompiler.AddToken(Token.DEFAULT); - int nsLine = ts.Lineno; - - if (!(matchToken(Token.NAME) && ts.String.Equals("xml"))) - { - ReportError("msg.bad.namespace"); - } - decompiler.AddName(ts.String); - - if (!(matchToken(Token.NAME) && ts.String.Equals("namespace"))) - { - ReportError("msg.bad.namespace"); - } - decompiler.AddName(ts.String); - - if (!matchToken(Token.ASSIGN)) - { - ReportError("msg.bad.namespace"); - } - decompiler.AddToken(Token.ASSIGN); - - Node e = expr(false); - pn = nf.CreateDefaultNamespace(e, nsLine); - break; - - - case Token.NAME: - { - int lineno = ts.Lineno; - string name = ts.String; - setCheckForLabel(); - pn = expr(false); - if (pn.Type != Token.LABEL) - { - - if (compilerEnv.getterAndSetterSupport) - { - tt = peekToken(); - if (tt == Token.NAME) - { - if (ts.String == "getter" || ts.String == "setter") - { - pn.Type = (ts.String[0] == 'g' ? Token.SETPROP_GETTER - : Token.SETPROP_SETTER); - decompiler.AddName(" " + ts.String); // HACK: Hack (whitespace) for decmpiler - consumeToken(); - matchToken(Token.ASSIGN); - decompiler.AddToken(Token.ASSIGN); - matchToken(Token.FUNCTION); - Node fn = function(FunctionNode.FUNCTION_EXPRESSION); - pn.addChildToBack(fn); - } - } - } - pn = nf.CreateExprStatement(pn, lineno); - } - else - { - // Parsed the label: push back token should be - // colon that primaryExpr left untouched. - if (peekToken() != Token.COLON) - Context.CodeBug(); - consumeToken(); - // depend on decompiling lookahead to guess that that - // last name was a label. - decompiler.AddName(name); - decompiler.AddEol(Token.COLON); - - if (labelSet == null) - { - labelSet = Hashtable.Synchronized(new Hashtable()); - } - else if (labelSet.ContainsKey(name)) - { - ReportError("msg.dup.label"); - } - - bool firstLabel; - if (statementLabel == null) - { - firstLabel = true; - statementLabel = pn; - } - else - { - // Discard multiple label nodes and use only - // the first: it allows to simplify IRFactory - firstLabel = false; - } - labelSet[name] = statementLabel; - try - { - pn = statementHelper(statementLabel); - } - finally - { - labelSet.Remove(name); - } - if (firstLabel) - { - pn = nf.CreateLabeledStatement(statementLabel, pn); - } - return pn; - } - break; - } - - - default: - { - int lineno = ts.Lineno; - pn = expr(false); - pn = nf.CreateExprStatement(pn, lineno); - break; - } - - } - - // FINDME - - int ttFlagged = peekFlaggedToken(); - switch (ttFlagged & CLEAR_TI_MASK) - { - - case Token.SEMI: - // Consume ';' as a part of expression - consumeToken(); - break; - - case Token.ERROR: - case Token.EOF: - case Token.RC: - // Autoinsert ; - break; - - default: - if ((ttFlagged & TI_AFTER_EOL) == 0) - { - // Report error if no EOL or autoinsert ; otherwise - ReportError("msg.no.semi.stmt"); - } - break; - - } - decompiler.AddEol(Token.SEMI); - - return pn; - } - - Node variables(bool inForInit) - { - Node pn = nf.CreateVariables(ts.Lineno); - bool first = true; - - decompiler.AddToken(Token.VAR); - - for (; ; ) - { - Node name; - Node init; - mustMatchToken(Token.NAME, "msg.bad.var"); - string s = ts.String; - - if (!first) - decompiler.AddToken(Token.COMMA); - first = false; - - decompiler.AddName(s); - currentScriptOrFn.addVar(s); - name = nf.CreateName(s); - - // omitted check for argument hiding - - if (matchToken(Token.ASSIGN)) - { - decompiler.AddToken(Token.ASSIGN); - - init = assignExpr(inForInit); - nf.addChildToBack(name, init); - } - nf.addChildToBack(pn, name); - if (!matchToken(Token.COMMA)) - break; - } - return pn; - } - - Node expr(bool inForInit) - { - Node pn = assignExpr(inForInit); - while (matchToken(Token.COMMA)) - { - decompiler.AddToken(Token.COMMA); - pn = nf.CreateBinary(Token.COMMA, pn, assignExpr(inForInit)); - } - return pn; - } - - Node assignExpr(bool inForInit) - { - Node pn = condExpr(inForInit); - - int tt = peekToken(); - if (Token.FIRST_ASSIGN <= tt && tt <= Token.LAST_ASSIGN) - { - consumeToken(); - decompiler.AddToken(tt); - pn = nf.CreateAssignment(tt, pn, assignExpr(inForInit)); - } - - return pn; - } - - Node condExpr(bool inForInit) - { - Node ifTrue; - Node ifFalse; - - Node pn = orExpr(inForInit); - - if (matchToken(Token.HOOK)) - { - decompiler.AddToken(Token.HOOK); - ifTrue = assignExpr(false); - mustMatchToken(Token.COLON, "msg.no.colon.cond"); - decompiler.AddToken(Token.COLON); - ifFalse = assignExpr(inForInit); - return nf.CreateCondExpr(pn, ifTrue, ifFalse); - } - - return pn; - } - - Node orExpr(bool inForInit) - { - Node pn = andExpr(inForInit); - if (matchToken(Token.OR)) - { - decompiler.AddToken(Token.OR); - pn = nf.CreateBinary(Token.OR, pn, orExpr(inForInit)); - } - - return pn; - } - - Node andExpr(bool inForInit) - { - Node pn = bitOrExpr(inForInit); - if (matchToken(Token.AND)) - { - decompiler.AddToken(Token.AND); - pn = nf.CreateBinary(Token.AND, pn, andExpr(inForInit)); - } - - return pn; - } - - Node bitOrExpr(bool inForInit) - { - Node pn = bitXorExpr(inForInit); - while (matchToken(Token.BITOR)) - { - decompiler.AddToken(Token.BITOR); - pn = nf.CreateBinary(Token.BITOR, pn, bitXorExpr(inForInit)); - } - return pn; - } - - Node bitXorExpr(bool inForInit) - { - Node pn = bitAndExpr(inForInit); - while (matchToken(Token.BITXOR)) - { - decompiler.AddToken(Token.BITXOR); - pn = nf.CreateBinary(Token.BITXOR, pn, bitAndExpr(inForInit)); - } - return pn; - } - - Node bitAndExpr(bool inForInit) - { - Node pn = eqExpr(inForInit); - while (matchToken(Token.BITAND)) - { - decompiler.AddToken(Token.BITAND); - pn = nf.CreateBinary(Token.BITAND, pn, eqExpr(inForInit)); - } - return pn; - } - - Node eqExpr(bool inForInit) - { - Node pn = relExpr(inForInit); - for (; ; ) - { - int tt = peekToken(); - switch (tt) - { - - case Token.EQ: - case Token.NE: - case Token.SHEQ: - case Token.SHNE: - consumeToken(); - int decompilerToken = tt; - int parseToken = tt; - if (compilerEnv.LanguageVersion == Context.Versions.JS1_2) - { - // JavaScript 1.2 uses shallow equality for == and != . - // In addition, convert === and !== for decompiler into - // == and != since the decompiler is supposed to show - // canonical source and in 1.2 ===, !== are allowed - // only as an alias to ==, !=. - switch (tt) - { - - case Token.EQ: - parseToken = Token.SHEQ; - break; - - case Token.NE: - parseToken = Token.SHNE; - break; - - case Token.SHEQ: - decompilerToken = Token.EQ; - break; - - case Token.SHNE: - decompilerToken = Token.NE; - break; - } - } - decompiler.AddToken(decompilerToken); - pn = nf.CreateBinary(parseToken, pn, relExpr(inForInit)); - continue; - } - break; - } - return pn; - } - - Node relExpr(bool inForInit) - { - Node pn = shiftExpr(); - for (; ; ) - { - int tt = peekToken(); - switch (tt) - { - - case Token.IN: - if (inForInit) - break; - // fall through - goto case Token.INSTANCEOF; - - case Token.INSTANCEOF: - case Token.LE: - case Token.LT: - case Token.GE: - case Token.GT: - consumeToken(); - decompiler.AddToken(tt); - pn = nf.CreateBinary(tt, pn, shiftExpr()); - continue; - } - break; - } - return pn; - } - - Node shiftExpr() - { - Node pn = addExpr(); - for (; ; ) - { - int tt = peekToken(); - switch (tt) - { - - case Token.LSH: - case Token.URSH: - case Token.RSH: - consumeToken(); - decompiler.AddToken(tt); - pn = nf.CreateBinary(tt, pn, addExpr()); - continue; - } - break; - } - return pn; - } - - Node addExpr() - { - Node pn = mulExpr(); - for (; ; ) - { - int tt = peekToken(); - if (tt == Token.ADD || tt == Token.SUB) - { - consumeToken(); - decompiler.AddToken(tt); - // flushNewLines - pn = nf.CreateBinary(tt, pn, mulExpr()); - continue; - } - break; - } - - return pn; - } - - Node mulExpr() - { - Node pn = unaryExpr(); - for (; ; ) - { - int tt = peekToken(); - switch (tt) - { - - case Token.MUL: - case Token.DIV: - case Token.MOD: - consumeToken(); - decompiler.AddToken(tt); - pn = nf.CreateBinary(tt, pn, unaryExpr()); - continue; - } - break; - } - - return pn; - } - - Node unaryExpr() - { - using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier(4096)) - { - int tt; - - tt = peekToken(); - - switch (tt) - { - - case Token.VOID: - case Token.NOT: - case Token.BITNOT: - case Token.TYPEOF: - consumeToken(); - decompiler.AddToken(tt); - return nf.CreateUnary(tt, unaryExpr()); - - - case Token.ADD: - consumeToken(); - // Convert to special POS token in decompiler and parse tree - decompiler.AddToken(Token.POS); - return nf.CreateUnary(Token.POS, unaryExpr()); - - - case Token.SUB: - consumeToken(); - // Convert to special NEG token in decompiler and parse tree - decompiler.AddToken(Token.NEG); - return nf.CreateUnary(Token.NEG, unaryExpr()); - - - case Token.INC: - case Token.DEC: - consumeToken(); - decompiler.AddToken(tt); - return nf.CreateIncDec(tt, false, memberExpr(true)); - - - case Token.DELPROP: - consumeToken(); - decompiler.AddToken(Token.DELPROP); - return nf.CreateUnary(Token.DELPROP, unaryExpr()); - - - case Token.ERROR: - consumeToken(); - break; - - // XML stream encountered in expression. - - case Token.LT: - if (compilerEnv.isXmlAvailable()) - { - consumeToken(); - Node pn = xmlInitializer(); - return memberExprTail(true, pn); - } - // Fall thru to the default handling of RELOP - goto default; - - - default: - { - Node pn = memberExpr(true); - - // Don't look across a newline boundary for a postfix incop. - tt = peekTokenOrEOL(); - if (tt == Token.INC || tt == Token.DEC) - { - consumeToken(); - decompiler.AddToken(tt); - return nf.CreateIncDec(tt, true, pn); - } - return pn; - } - - } - return nf.CreateName("err"); // Only reached on error. Try to continue. - } - } - - Node xmlInitializer() - { - int tt = ts.FirstXMLToken; - if (tt != Token.XML && tt != Token.XMLEND) - { - ReportError("msg.syntax"); - return null; - } - - /* Make a NEW node to append to. */ - Node pnXML = nf.CreateLeaf(Token.NEW); - decompiler.AddToken(Token.NEW); - decompiler.AddToken(Token.DOT); - - string xml = ts.String; - bool fAnonymous = xml.Trim().StartsWith("<>"); - - decompiler.AddName(fAnonymous ? "XMLList" : "XML"); - Node pn = nf.CreateName(fAnonymous ? "XMLList" : "XML"); - nf.addChildToBack(pnXML, pn); - - pn = null; - Node e; - for (; ; tt = ts.NextXMLToken) - { - switch (tt) - { - - case Token.XML: - xml = ts.String; - decompiler.AddString(xml); - mustMatchToken(Token.LC, "msg.syntax"); - decompiler.AddToken(Token.LC); - e = (peekToken() == Token.RC) ? nf.CreateString("") : expr(false); - mustMatchToken(Token.RC, "msg.syntax"); - decompiler.AddToken(Token.RC); - if (pn == null) - { - pn = nf.CreateString(xml); - } - else - { - pn = nf.CreateBinary(Token.ADD, pn, nf.CreateString(xml)); - } - int nodeType; - if (ts.XMLAttribute) - { - nodeType = Token.ESCXMLATTR; - } - else - { - nodeType = Token.ESCXMLTEXT; - } - e = nf.CreateUnary(nodeType, e); - pn = nf.CreateBinary(Token.ADD, pn, e); - break; - - case Token.XMLEND: - xml = ts.String; - decompiler.AddString(xml); - if (pn == null) - { - pn = nf.CreateString(xml); - } - else - { - pn = nf.CreateBinary(Token.ADD, pn, nf.CreateString(xml)); - } - - nf.addChildToBack(pnXML, pn); - return pnXML; - - default: - ReportError("msg.syntax"); - return null; - - } - } - } - - void argumentList(Node listNode) - { - bool matched; - matched = matchToken(Token.RP); - if (!matched) - { - bool first = true; - do - { - if (!first) - decompiler.AddToken(Token.COMMA); - first = false; - nf.addChildToBack(listNode, assignExpr(false)); - } - while (matchToken(Token.COMMA)); - - mustMatchToken(Token.RP, "msg.no.paren.arg"); - } - decompiler.AddToken(Token.RP); - } - - Node memberExpr(bool allowCallSyntax) - { - int tt; - - Node pn; - - /* Check for new expressions. */ - tt = peekToken(); - if (tt == Token.NEW) - { - /* Eat the NEW token. */ - consumeToken(); - decompiler.AddToken(Token.NEW); - - /* Make a NEW node to append to. */ - pn = nf.CreateCallOrNew(Token.NEW, memberExpr(false)); - - if (matchToken(Token.LP)) - { - decompiler.AddToken(Token.LP); - /* Add the arguments to pn, if any are supplied. */ - argumentList(pn); - } - - // TODO: there's a check in the C source against - // TODO: "too many constructor arguments" - how many - // TODO: do we claim to support? - - /* Experimental syntax: allow an object literal to follow a new expression, - * which will mean a kind of anonymous class built with the JavaAdapter. - * the object literal will be passed as an additional argument to the constructor. - */ - tt = peekToken(); - if (tt == Token.LC) - { - nf.addChildToBack(pn, primaryExpr()); - } - } - else - { - pn = primaryExpr(); - } - - return memberExprTail(allowCallSyntax, pn); - } - - Node memberExprTail(bool allowCallSyntax, Node pn) - { - for (; ; ) - { - int tt = peekToken(); - switch (tt) - { - - - case Token.DOT: - case Token.DOTDOT: - { - int memberTypeFlags; - string s; - - consumeToken(); - decompiler.AddToken(tt); - memberTypeFlags = 0; - if (tt == Token.DOTDOT) - { - mustHaveXML(); - memberTypeFlags = Node.DESCENDANTS_FLAG; - } - if (!compilerEnv.isXmlAvailable()) - { - mustMatchToken(Token.NAME, "msg.no.name.after.dot"); - s = ts.String; - decompiler.AddName(s); - pn = nf.CreatePropertyGet(pn, null, s, memberTypeFlags); - break; - } - - - tt = nextToken(); - - switch (tt) - { - - // handles: name, ns::name, ns::*, ns::[expr] - case Token.NAME: - s = ts.String; - decompiler.AddName(s); - pn = propertyName(pn, s, memberTypeFlags); - break; - - // handles: *, *::name, *::*, *::[expr] - - case Token.MUL: - decompiler.AddName("*"); - pn = propertyName(pn, "*", memberTypeFlags); - break; - - // handles: '@attr', '@ns::attr', '@ns::*', '@ns::*', - // '@::attr', '@::*', '@*', '@*::attr', '@*::*' - - case Token.XMLATTR: - decompiler.AddToken(Token.XMLATTR); - pn = attributeAccess(pn, memberTypeFlags); - break; - - - default: - ReportError("msg.no.name.after.dot"); - break; - - } - } - break; - - - case Token.DOTQUERY: - consumeToken(); - mustHaveXML(); - decompiler.AddToken(Token.DOTQUERY); - pn = nf.CreateDotQuery(pn, expr(false), ts.Lineno); - mustMatchToken(Token.RP, "msg.no.paren"); - decompiler.AddToken(Token.RP); - break; - - - case Token.LB: - consumeToken(); - decompiler.AddToken(Token.LB); - pn = nf.CreateElementGet(pn, null, expr(false), 0); - mustMatchToken(Token.RB, "msg.no.bracket.index"); - decompiler.AddToken(Token.RB); - break; - - - case Token.LP: - if (!allowCallSyntax) - { - - goto tailLoop_brk; - } - consumeToken(); - decompiler.AddToken(Token.LP); - pn = nf.CreateCallOrNew(Token.CALL, pn); - /* Add the arguments to pn, if any are supplied. */ - argumentList(pn); - break; - - - default: - - goto tailLoop_brk; - - } - } - - tailLoop_brk: - ; - - return pn; - } - - /* - * Xml attribute expression: - * '@attr', '@ns::attr', '@ns::*', '@ns::*', '@*', '@*::attr', '@*::*' - */ - Node attributeAccess(Node pn, int memberTypeFlags) - { - memberTypeFlags |= Node.ATTRIBUTE_FLAG; - int tt = nextToken(); - - switch (tt) - { - - // handles: @name, @ns::name, @ns::*, @ns::[expr] - case Token.NAME: - { - string s = ts.String; - decompiler.AddName(s); - pn = propertyName(pn, s, memberTypeFlags); - } - break; - - // handles: @*, @*::name, @*::*, @*::[expr] - - case Token.MUL: - decompiler.AddName("*"); - pn = propertyName(pn, "*", memberTypeFlags); - break; - - // handles @[expr] - - case Token.LB: - decompiler.AddToken(Token.LB); - pn = nf.CreateElementGet(pn, null, expr(false), memberTypeFlags); - mustMatchToken(Token.RB, "msg.no.bracket.index"); - decompiler.AddToken(Token.RB); - break; - - - default: - ReportError("msg.no.name.after.xmlAttr"); - pn = nf.CreatePropertyGet(pn, null, "?", memberTypeFlags); - break; - - } - - return pn; - } - - /// Check if :: follows name in which case it becomes qualified name - Node propertyName(Node pn, string name, int memberTypeFlags) - { - string ns = null; - if (matchToken(Token.COLONCOLON)) - { - decompiler.AddToken(Token.COLONCOLON); - ns = name; - - int tt = nextToken(); - switch (tt) - { - - // handles name::name - case Token.NAME: - name = ts.String; - decompiler.AddName(name); - break; - - // handles name::* - - case Token.MUL: - decompiler.AddName("*"); - name = "*"; - break; - - // handles name::[expr] - - case Token.LB: - decompiler.AddToken(Token.LB); - pn = nf.CreateElementGet(pn, ns, expr(false), memberTypeFlags); - mustMatchToken(Token.RB, "msg.no.bracket.index"); - decompiler.AddToken(Token.RB); - return pn; - - - default: - ReportError("msg.no.name.after.coloncolon"); - name = "?"; - break; - - } - } - - pn = nf.CreatePropertyGet(pn, ns, name, memberTypeFlags); - return pn; - } - - int currentStackIndex = 0; - - - Node primaryExpr() - { - try - { - if (currentStackIndex++ > ScriptRuntime.MAXSTACKSIZE) - { - currentStackIndex = 0; - throw Context.ReportRuntimeError( - ScriptRuntime.GetMessage("mag.too.deep.parser.recursion"), sourceURI, ts.Lineno, null, 0); - } - - Node pn; - - int ttFlagged = nextFlaggedToken(); - int tt = ttFlagged & CLEAR_TI_MASK; - - switch (tt) - { - - - case Token.FUNCTION: - return function(FunctionNode.FUNCTION_EXPRESSION); - - - case Token.LB: - { - ObjArray elems = new ObjArray(); - int skipCount = 0; - decompiler.AddToken(Token.LB); - bool after_lb_or_comma = true; - for (; ; ) - { - tt = peekToken(); - - if (tt == Token.COMMA) - { - consumeToken(); - decompiler.AddToken(Token.COMMA); - if (!after_lb_or_comma) - { - after_lb_or_comma = true; - } - else - { - elems.add((object)null); - ++skipCount; - } - } - else if (tt == Token.RB) - { - consumeToken(); - decompiler.AddToken(Token.RB); - break; - } - else - { - if (!after_lb_or_comma) - { - ReportError("msg.no.bracket.arg"); - } - elems.add(assignExpr(false)); - after_lb_or_comma = false; - } - } - return nf.CreateArrayLiteral(elems, skipCount); - } - - - case Token.LC: - { - ObjArray elems = new ObjArray(); - decompiler.AddToken(Token.LC); - if (!matchToken(Token.RC)) - { - - bool first = true; - do - { - object property; - - if (!first) - decompiler.AddToken(Token.COMMA); - else - first = false; - - tt = peekToken(); - switch (tt) - { - - case Token.NAME: - case Token.STRING: - consumeToken(); - if (compilerEnv.getterAndSetterSupport) - { - if (tt == Token.NAME) - if (CheckForGetOrSet(elems) || CheckForGetterOrSetter(elems)) - goto next_prop; - } - - - // map NAMEs to STRINGs in object literal context - // but tell the decompiler the proper type - string s = ts.String; - if (tt == Token.NAME) - { - decompiler.AddName(s); - } - else - { - decompiler.AddString(s); - } - property = ScriptRuntime.getIndexObject(s); - - break; - - - case Token.NUMBER: - consumeToken(); - double n = ts.Number; - decompiler.AddNumber(n); - property = ScriptRuntime.getIndexObject(n); - break; - - - case Token.RC: - // trailing comma is OK. - - goto commaloop_brk; - - default: - ReportError("msg.bad.prop"); - - goto commaloop_brk; - - } - mustMatchToken(Token.COLON, "msg.no.colon.prop"); - - // OBJLIT is used as ':' in object literal for - // decompilation to solve spacing ambiguity. - decompiler.AddToken(Token.OBJECTLIT); - elems.add(property); - elems.add(assignExpr(false)); - - next_prop: - ; - } - while (matchToken(Token.COMMA)); - - commaloop_brk: - ; - - - mustMatchToken(Token.RC, "msg.no.brace.prop"); - } - decompiler.AddToken(Token.RC); - return nf.CreateObjectLiteral(elems); - } - - - case Token.LP: - - /* Brendan's IR-jsparse.c makes a new node tagged with - * TOK_LP here... I'm not sure I understand why. Isn't - * the grouping already implicit in the structure of the - * parse tree? also TOK_LP is already overloaded (I - * think) in the C IR as 'function call.' */ - decompiler.AddToken(Token.LP); - pn = expr(false); - decompiler.AddToken(Token.RP); - mustMatchToken(Token.RP, "msg.no.paren"); - return pn; - - - case Token.XMLATTR: - mustHaveXML(); - decompiler.AddToken(Token.XMLATTR); - pn = attributeAccess(null, 0); - return pn; - - - case Token.NAME: - { - string name = ts.String; - if ((ttFlagged & TI_CHECK_LABEL) != 0) - { - if (peekToken() == Token.COLON) - { - // Do not consume colon, it is used as unwind indicator - // to return to statementHelper. - // TODO: Better way? - return nf.CreateLabel(ts.Lineno); - } - } - - decompiler.AddName(name); - if (compilerEnv.isXmlAvailable()) - { - pn = propertyName(null, name, 0); - } - else - { - pn = nf.CreateName(name); - } - return pn; - } - - - case Token.NUMBER: - { - double n = ts.Number; - decompiler.AddNumber(n); - return nf.CreateNumber(n); - } - - - case Token.STRING: - { - string s = ts.String; - decompiler.AddString(s); - return nf.CreateString(s); - } - - - case Token.DIV: - case Token.ASSIGN_DIV: - { - // Got / or /= which should be treated as regexp in fact - ts.readRegExp(tt); - string flags = ts.regExpFlags; - ts.regExpFlags = null; - string re = ts.String; - decompiler.AddRegexp(re, flags); - int index = currentScriptOrFn.addRegexp(re, flags); - return nf.CreateRegExp(index); - } - - - case Token.NULL: - case Token.THIS: - case Token.FALSE: - case Token.TRUE: - decompiler.AddToken(tt); - return nf.CreateLeaf(tt); - - - case Token.RESERVED: - ReportError("msg.reserved.id"); - break; - - - case Token.ERROR: - /* the scanner or one of its subroutines reported the error. */ - break; - - - case Token.EOF: - ReportError("msg.unexpected.eof"); - break; - - - default: - ReportError("msg.syntax"); - break; - - } - return null; // should never reach here - } - finally - { - currentStackIndex--; - } - } - - - /// - /// Support for non-ecma "get"/"set" spidermonkey extension. - /// - /// - /// get NAME () SCOPE - /// set NAME () SCOPE - /// - bool CheckForGetOrSet(ObjArray elems) - { - int tt; - - string type = ts.String; - if (type != "get" && type != "set") - { - return false; - } - tt = peekToken(); - if (tt != Token.NAME) - return false; - consumeToken(); - - string name = ts.String; - - decompiler.AddName(name); - - Node func = function(FunctionNode.FUNCTION_EXPRESSION); - object property = ScriptRuntime.getIndexObject(name); - - elems.add((type[0] == 'g') ? (object)new Node.GetterPropertyLiteral(property) - : (object)new Node.SetterPropertyLiteral(property)); - elems.add(func); - - return true; - } - - /// - /// Support for non-ecma "get"/"set" spidermonkey extension. - /// - /// - /// NAME getter: FUNCTION () SCOPE - /// NAME setter: FUNCTION () SCOPE - /// - bool CheckForGetterOrSetter(ObjArray elems) - { - int tt; - - string name = ts.String; - consumeToken(); - - tt = peekToken(); - if (tt != Token.NAME) - return false; - string type = ts.String; - if (type != "getter" && type != "setter") - { - return false; - } - consumeToken(); - - matchToken(Token.COLON); - matchToken(Token.FUNCTION); - - Node func = function(FunctionNode.FUNCTION_EXPRESSION); - object property = ScriptRuntime.getIndexObject(name); - - elems.add((type[0] == 'g') ? (object)new Node.GetterPropertyLiteral(property) - : (object)new Node.SetterPropertyLiteral(property)); - elems.add(func); - - return true; - } - - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; +using System.Collections; + +using EcmaScript.NET.Collections; + +namespace EcmaScript.NET +{ + + /// This class implements the JavaScript parser. + /// + /// It is based on the C source files jsparse.c and jsparse.h + /// in the jsref package. + /// + /// + public class Parser + { + public string EncodedSource + { + get + { + return encodedSource; + } + + } + // TokenInformation flags : currentFlaggedToken stores them together + // with token type + internal const int CLEAR_TI_MASK = 0xFFFF; + internal const int TI_AFTER_EOL = 1 << 16; + internal const int TI_CHECK_LABEL = 1 << 17; // indicates to check for label + + internal CompilerEnvirons compilerEnv; + ErrorReporter errorReporter; + string sourceURI; + internal bool calledByCompileFunction; + + TokenStream ts; + int currentFlaggedToken; + int syntaxErrorCount; + + NodeFactory nf; + + int nestingOfFunction; + + Decompiler decompiler; + string encodedSource; + + // The following are per function variables and should be saved/restored + // during function parsing. + // TODO: Move to separated class? + internal ScriptOrFnNode currentScriptOrFn; + int nestingOfWith; + Hashtable labelSet; // map of label names into nodes + ObjArray loopSet; + ObjArray loopAndSwitchSet; + // end of per function variables + + // Exception to unwind + + class ParserException : Exception + { + + } + + public Parser(CompilerEnvirons compilerEnv, ErrorReporter errorReporter) + { + this.compilerEnv = compilerEnv; + this.errorReporter = errorReporter; + } + + Decompiler CreateDecompiler(CompilerEnvirons compilerEnv) + { + return new Decompiler(); + } + + internal void AddWarning(string messageId, string messageArg) + { + string message = ScriptRuntime.GetMessage(messageId, messageArg); + errorReporter.Warning(message, sourceURI, ts.Lineno, ts.Line, ts.Offset); + } + + internal void AddError(string messageId) + { + ++syntaxErrorCount; + string message = ScriptRuntime.GetMessage(messageId); + errorReporter.Error(message, sourceURI, ts.Lineno, ts.Line, ts.Offset); + } + + internal Exception ReportError(string messageId) + { + AddError(messageId); + + // Throw a ParserException exception to unwind the recursive descent + // parse. + throw new ParserException(); + } + + int peekToken() + { + int tt = currentFlaggedToken; + if (tt == Token.EOF) + { + + while ((tt = ts.Token) == Token.CONDCOMMENT || tt == Token.KEEPCOMMENT) + { + if (tt == Token.CONDCOMMENT) + { + /* Support for JScript conditional comments */ + decompiler.AddJScriptConditionalComment(ts.String); + } + else + { + /* Support for preserved comments */ + decompiler.AddPreservedComment(ts.String); + } + } + + if (tt == Token.EOL) + { + do + { + tt = ts.Token; + + if (tt == Token.CONDCOMMENT) + { + /* Support for JScript conditional comments */ + decompiler.AddJScriptConditionalComment(ts.String); + } + else if (tt == Token.KEEPCOMMENT) + { + /* Support for preserved comments */ + decompiler.AddPreservedComment(ts.String); + } + + } + while (tt == Token.EOL || tt == Token.CONDCOMMENT || tt == Token.KEEPCOMMENT); + tt |= TI_AFTER_EOL; + } + currentFlaggedToken = tt; + } + return tt & CLEAR_TI_MASK; + } + + int peekFlaggedToken() + { + peekToken(); + return currentFlaggedToken; + } + + void consumeToken() + { + currentFlaggedToken = Token.EOF; + } + + int nextToken() + { + int tt = peekToken(); + consumeToken(); + return tt; + } + + int nextFlaggedToken() + { + peekToken(); + int ttFlagged = currentFlaggedToken; + consumeToken(); + return ttFlagged; + } + + bool matchToken(int toMatch) + { + int tt = peekToken(); + if (tt != toMatch) + { + return false; + } + consumeToken(); + return true; + } + + int peekTokenOrEOL() + { + int tt = peekToken(); + // Check for last peeked token flags + if ((currentFlaggedToken & TI_AFTER_EOL) != 0) + { + tt = Token.EOL; + } + return tt; + } + + void setCheckForLabel() + { + if ((currentFlaggedToken & CLEAR_TI_MASK) != Token.NAME) + throw Context.CodeBug(); + currentFlaggedToken |= TI_CHECK_LABEL; + } + + void mustMatchToken(int toMatch, string messageId) + { + if (!matchToken(toMatch)) + { + ReportError(messageId); + } + } + + void mustHaveXML() + { + if (!compilerEnv.isXmlAvailable()) + { + ReportError("msg.XML.not.available"); + } + } + + public bool Eof + { + get + { + return ts.eof(); + } + } + + internal bool insideFunction() + { + return nestingOfFunction != 0; + } + + Node enterLoop(Node loopLabel) + { + Node loop = nf.CreateLoopNode(loopLabel, ts.Lineno); + if (loopSet == null) + { + loopSet = new ObjArray(); + if (loopAndSwitchSet == null) + { + loopAndSwitchSet = new ObjArray(); + } + } + loopSet.push(loop); + loopAndSwitchSet.push(loop); + return loop; + } + + void exitLoop() + { + loopSet.pop(); + loopAndSwitchSet.pop(); + } + + Node enterSwitch(Node switchSelector, int lineno, Node switchLabel) + { + Node switchNode = nf.CreateSwitch(switchSelector, lineno); + if (loopAndSwitchSet == null) + { + loopAndSwitchSet = new ObjArray(); + } + loopAndSwitchSet.push(switchNode); + return switchNode; + } + + void exitSwitch() + { + loopAndSwitchSet.pop(); + } + + /* + * Build a parse tree from the given sourceString. + * + * @return an Object representing the parsed + * program. If the parse fails, null will be returned. (The + * parse failure will result in a call to the ErrorReporter from + * CompilerEnvirons.) + */ + public ScriptOrFnNode Parse(string sourceString, string sourceURI, int lineno) + { + this.sourceURI = sourceURI; + this.ts = new TokenStream(this, null, sourceString, lineno); + try + { + return Parse(); + } + catch (System.IO.IOException) + { + // Should never happen + throw new Exception(); + } + } + + /* + * Build a parse tree from the given sourceString. + * + * @return an Object representing the parsed + * program. If the parse fails, null will be returned. (The + * parse failure will result in a call to the ErrorReporter from + * CompilerEnvirons.) + */ + public ScriptOrFnNode Parse(System.IO.StreamReader sourceReader, string sourceURI, int lineno) + { + this.sourceURI = sourceURI; + this.ts = new TokenStream(this, sourceReader, null, lineno); + return Parse(); + } + + ScriptOrFnNode Parse() + { + this.decompiler = CreateDecompiler(compilerEnv); + this.nf = new NodeFactory(this); + currentScriptOrFn = nf.CreateScript(); + int sourceStartOffset = decompiler.CurrentOffset; + this.encodedSource = null; + decompiler.AddToken(Token.SCRIPT); + + this.currentFlaggedToken = Token.EOF; + this.syntaxErrorCount = 0; + + int baseLineno = ts.Lineno; // line number where source starts + + /* so we have something to add nodes to until + * we've collected all the source */ + Node pn = nf.CreateLeaf(Token.BLOCK); + + for (; ; ) + { + int tt = peekToken(); + + if (tt <= Token.EOF) + { + break; + } + + Node n; + if (tt == Token.FUNCTION) + { + consumeToken(); + try + { + n = function(calledByCompileFunction ? FunctionNode.FUNCTION_EXPRESSION : FunctionNode.FUNCTION_STATEMENT); + } + catch (ParserException) + { + break; + } + } + else + { + n = statement(); + } + nf.addChildToBack(pn, n); + } + + if (this.syntaxErrorCount != 0) + { + string msg = Convert.ToString(this.syntaxErrorCount); + msg = ScriptRuntime.GetMessage("msg.got.syntax.errors", msg); + throw errorReporter.RuntimeError(msg, sourceURI, baseLineno, null, 0); + } + + currentScriptOrFn.SourceName = sourceURI; + currentScriptOrFn.BaseLineno = baseLineno; + currentScriptOrFn.EndLineno = ts.Lineno; + + int sourceEndOffset = decompiler.CurrentOffset; + currentScriptOrFn.setEncodedSourceBounds(sourceStartOffset, sourceEndOffset); + + nf.initScript(currentScriptOrFn, pn); + + if (compilerEnv.isGeneratingSource()) + { + encodedSource = decompiler.EncodedSource; + } + this.decompiler = null; // It helps GC + + return currentScriptOrFn; + } + + /* + * The C version of this function takes an argument list, + * which doesn't seem to be needed for tree generation... + * it'd only be useful for checking argument hiding, which + * I'm not doing anyway... + */ + Node parseFunctionBody() + { + ++nestingOfFunction; + Node pn = nf.CreateBlock(ts.Lineno); + try + { + for (; ; ) + { + Node n; + int tt = peekToken(); + switch (tt) + { + + case Token.ERROR: + case Token.EOF: + case Token.RC: + + goto bodyLoop_brk; + + + case Token.FUNCTION: + consumeToken(); + n = function(FunctionNode.FUNCTION_STATEMENT); + break; + + default: + n = statement(); + break; + + } + nf.addChildToBack(pn, n); + } + + bodyLoop_brk: + ; + + } + catch (ParserException) + { + // Ignore it + } + finally + { + --nestingOfFunction; + } + + return pn; + } + + Node function(int functionType) + { + using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier(1024)) + { + int syntheticType = functionType; + int baseLineno = ts.Lineno; // line number where source starts + + int functionSourceStart = decompiler.MarkFunctionStart(functionType); + string name; + Node memberExprNode = null; + if (matchToken(Token.NAME)) + { + name = ts.String; + decompiler.AddName(name); + if (!matchToken(Token.LP)) + { + if (compilerEnv.isAllowMemberExprAsFunctionName()) + { + // Extension to ECMA: if 'function ' does not follow + // by '(', assume starts memberExpr + Node memberExprHead = nf.CreateName(name); + name = ""; + memberExprNode = memberExprTail(false, memberExprHead); + } + mustMatchToken(Token.LP, "msg.no.paren.parms"); + } + } + else if (matchToken(Token.LP)) + { + // Anonymous function + name = ""; + } + else + { + name = ""; + if (compilerEnv.isAllowMemberExprAsFunctionName()) + { + // Note that memberExpr can not start with '(' like + // in function (1+2).toString(), because 'function (' already + // processed as anonymous function + memberExprNode = memberExpr(false); + } + mustMatchToken(Token.LP, "msg.no.paren.parms"); + } + + if (memberExprNode != null) + { + syntheticType = FunctionNode.FUNCTION_EXPRESSION; + } + + bool nested = insideFunction(); + + FunctionNode fnNode = nf.CreateFunction(name); + if (nested || nestingOfWith > 0) + { + // 1. Nested functions are not affected by the dynamic scope flag + // as dynamic scope is already a parent of their scope. + // 2. Functions defined under the with statement also immune to + // this setup, in which case dynamic scope is ignored in favor + // of with object. + fnNode.itsIgnoreDynamicScope = true; + } + + int functionIndex = currentScriptOrFn.addFunction(fnNode); + + int functionSourceEnd; + + ScriptOrFnNode savedScriptOrFn = currentScriptOrFn; + currentScriptOrFn = fnNode; + int savedNestingOfWith = nestingOfWith; + nestingOfWith = 0; + Hashtable savedLabelSet = labelSet; + labelSet = null; + ObjArray savedLoopSet = loopSet; + loopSet = null; + ObjArray savedLoopAndSwitchSet = loopAndSwitchSet; + loopAndSwitchSet = null; + + Node body; + try + { + decompiler.AddToken(Token.LP); + if (!matchToken(Token.RP)) + { + bool first = true; + do + { + if (!first) + decompiler.AddToken(Token.COMMA); + first = false; + mustMatchToken(Token.NAME, "msg.no.parm"); + string s = ts.String; + if (fnNode.hasParamOrVar(s)) + { + AddWarning("msg.dup.parms", s); + } + fnNode.addParam(s); + decompiler.AddName(s); + } + while (matchToken(Token.COMMA)); + + mustMatchToken(Token.RP, "msg.no.paren.after.parms"); + } + decompiler.AddToken(Token.RP); + + mustMatchToken(Token.LC, "msg.no.brace.body"); + decompiler.AddEol(Token.LC); + body = parseFunctionBody(); + mustMatchToken(Token.RC, "msg.no.brace.after.body"); + + decompiler.AddToken(Token.RC); + functionSourceEnd = decompiler.MarkFunctionEnd(functionSourceStart); + if (functionType != FunctionNode.FUNCTION_EXPRESSION) + { + if (compilerEnv.LanguageVersion >= Context.Versions.JS1_2) + { + // function f() {} function g() {} is not allowed in 1.2 + // or later but for compatibility with old scripts + // the check is done only if language is + // explicitly set. + // TODO: warning needed if version == VERSION_DEFAULT ? + int tt = peekTokenOrEOL(); + if (tt == Token.FUNCTION) + { + ReportError("msg.no.semi.stmt"); + } + } + // Add EOL only if function is not part of expression + // since it gets SEMI + EOL from Statement in that case + decompiler.AddToken(Token.EOL); + } + } + finally + { + loopAndSwitchSet = savedLoopAndSwitchSet; + loopSet = savedLoopSet; + labelSet = savedLabelSet; + nestingOfWith = savedNestingOfWith; + currentScriptOrFn = savedScriptOrFn; + } + + fnNode.setEncodedSourceBounds(functionSourceStart, functionSourceEnd); + fnNode.SourceName = sourceURI; + fnNode.BaseLineno = baseLineno; + fnNode.EndLineno = ts.Lineno; + + Node pn = nf.initFunction(fnNode, functionIndex, body, syntheticType); + if (memberExprNode != null) + { + pn = nf.CreateAssignment(Token.ASSIGN, memberExprNode, pn); + if (functionType != FunctionNode.FUNCTION_EXPRESSION) + { + // TOOD: check JScript behavior: should it be createExprStatement? + pn = nf.CreateExprStatementNoReturn(pn, baseLineno); + } + } + return pn; + } + } + + Node statements() + { + Node pn = nf.CreateBlock(ts.Lineno); + + int tt; + while ((tt = peekToken()) > Token.EOF && tt != Token.RC) + { + nf.addChildToBack(pn, statement()); + } + + return pn; + } + + Node condition() + { + Node pn; + mustMatchToken(Token.LP, "msg.no.paren.cond"); + decompiler.AddToken(Token.LP); + pn = expr(false); + mustMatchToken(Token.RP, "msg.no.paren.after.cond"); + decompiler.AddToken(Token.RP); + + // there's a check here in jsparse.c that corrects = to == + + return pn; + } + + // match a NAME; return null if no match. + Node matchJumpLabelName() + { + Node label = null; + + int tt = peekTokenOrEOL(); + if (tt == Token.NAME) + { + consumeToken(); + string name = ts.String; + decompiler.AddName(name); + if (labelSet != null) + { + label = (Node)labelSet[name]; + } + if (label == null) + { + ReportError("msg.undef.label"); + } + } + + return label; + } + + Node statement() + { + using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier(512)) + { + try + { + Node pn = statementHelper(null); + if (pn != null) + { + return pn; + } + } + catch (ParserException) + { + } + } + + // skip to end of statement + int lineno = ts.Lineno; + for (; ; ) + { + int tt = peekTokenOrEOL(); + consumeToken(); + switch (tt) + { + + case Token.ERROR: + case Token.EOF: + case Token.EOL: + case Token.SEMI: + + goto guessingStatementEnd_brk; + } + } + + guessingStatementEnd_brk: + ; + + return nf.CreateExprStatement(nf.CreateName("error"), lineno); + } + + /// Whether the "catch (e: e instanceof Exception) { ... }" syntax + /// is implemented. + /// + + Node statementHelper(Node statementLabel) + { + Node pn = null; + + int tt; + + tt = peekToken(); + + switch (tt) + { + + case Token.IF: + { + consumeToken(); + + decompiler.AddToken(Token.IF); + int lineno = ts.Lineno; + Node cond = condition(); + decompiler.AddEol(Token.LC); + Node ifTrue = statement(); + Node ifFalse = null; + if (matchToken(Token.ELSE)) + { + decompiler.AddToken(Token.RC); + decompiler.AddToken(Token.ELSE); + decompiler.AddEol(Token.LC); + ifFalse = statement(); + } + decompiler.AddEol(Token.RC); + pn = nf.CreateIf(cond, ifTrue, ifFalse, lineno); + return pn; + } + + + case Token.SWITCH: + { + consumeToken(); + + decompiler.AddToken(Token.SWITCH); + int lineno = ts.Lineno; + mustMatchToken(Token.LP, "msg.no.paren.switch"); + decompiler.AddToken(Token.LP); + pn = enterSwitch(expr(false), lineno, statementLabel); + try + { + mustMatchToken(Token.RP, "msg.no.paren.after.switch"); + decompiler.AddToken(Token.RP); + mustMatchToken(Token.LC, "msg.no.brace.switch"); + decompiler.AddEol(Token.LC); + + bool hasDefault = false; + for (; ; ) + { + tt = nextToken(); + Node caseExpression; + switch (tt) + { + + case Token.RC: + + goto switchLoop_brk; + + + case Token.CASE: + decompiler.AddToken(Token.CASE); + caseExpression = expr(false); + mustMatchToken(Token.COLON, "msg.no.colon.case"); + decompiler.AddEol(Token.COLON); + break; + + + case Token.DEFAULT: + if (hasDefault) + { + ReportError("msg.double.switch.default"); + } + decompiler.AddToken(Token.DEFAULT); + hasDefault = true; + caseExpression = null; + mustMatchToken(Token.COLON, "msg.no.colon.case"); + decompiler.AddEol(Token.COLON); + break; + + + default: + ReportError("msg.bad.switch"); + + goto switchLoop_brk; + + } + + Node block = nf.CreateLeaf(Token.BLOCK); + while ((tt = peekToken()) != Token.RC && tt != Token.CASE && tt != Token.DEFAULT && tt != Token.EOF) + { + nf.addChildToBack(block, statement()); + } + + // caseExpression == null => add default lable + nf.addSwitchCase(pn, caseExpression, block); + } + + switchLoop_brk: + ; + + decompiler.AddEol(Token.RC); + nf.closeSwitch(pn); + } + finally + { + exitSwitch(); + } + return pn; + } + + + case Token.WHILE: + { + consumeToken(); + decompiler.AddToken(Token.WHILE); + + Node loop = enterLoop(statementLabel); + try + { + Node cond = condition(); + decompiler.AddEol(Token.LC); + Node body = statement(); + decompiler.AddEol(Token.RC); + pn = nf.CreateWhile(loop, cond, body); + } + finally + { + exitLoop(); + } + return pn; + } + + + case Token.DO: + { + consumeToken(); + decompiler.AddToken(Token.DO); + decompiler.AddEol(Token.LC); + + Node loop = enterLoop(statementLabel); + try + { + Node body = statement(); + decompiler.AddToken(Token.RC); + mustMatchToken(Token.WHILE, "msg.no.while.do"); + decompiler.AddToken(Token.WHILE); + Node cond = condition(); + pn = nf.CreateDoWhile(loop, body, cond); + } + finally + { + exitLoop(); + } + // Always auto-insert semicon to follow SpiderMonkey: + // It is required by EMAScript but is ignored by the rest of + // world, see bug 238945 + matchToken(Token.SEMI); + decompiler.AddEol(Token.SEMI); + return pn; + } + + + case Token.FOR: + { + consumeToken(); + bool isForEach = false; + decompiler.AddToken(Token.FOR); + + Node loop = enterLoop(statementLabel); + try + { + + Node init; // Node init is also foo in 'foo in Object' + Node cond; // Node cond is also object in 'foo in Object' + Node incr = null; // to kill warning + Node body; + + // See if this is a for each () instead of just a for () + if (matchToken(Token.NAME)) + { + decompiler.AddName(ts.String); + if (ts.String.Equals("each")) + { + isForEach = true; + } + else + { + ReportError("msg.no.paren.for"); + } + } + + mustMatchToken(Token.LP, "msg.no.paren.for"); + decompiler.AddToken(Token.LP); + tt = peekToken(); + if (tt == Token.SEMI) + { + init = nf.CreateLeaf(Token.EMPTY); + } + else + { + if (tt == Token.VAR) + { + // set init to a var list or initial + consumeToken(); // consume the 'var' token + init = variables(true); + } + else + { + init = expr(true); + } + } + + if (matchToken(Token.IN)) + { + decompiler.AddToken(Token.IN); + // 'cond' is the object over which we're iterating + cond = expr(false); + } + else + { + // ordinary for loop + mustMatchToken(Token.SEMI, "msg.no.semi.for"); + decompiler.AddToken(Token.SEMI); + if (peekToken() == Token.SEMI) + { + // no loop condition + cond = nf.CreateLeaf(Token.EMPTY); + } + else + { + cond = expr(false); + } + + mustMatchToken(Token.SEMI, "msg.no.semi.for.cond"); + decompiler.AddToken(Token.SEMI); + if (peekToken() == Token.RP) + { + incr = nf.CreateLeaf(Token.EMPTY); + } + else + { + incr = expr(false); + } + } + + mustMatchToken(Token.RP, "msg.no.paren.for.ctrl"); + decompiler.AddToken(Token.RP); + decompiler.AddEol(Token.LC); + body = statement(); + decompiler.AddEol(Token.RC); + + if (incr == null) + { + // cond could be null if 'in obj' got eaten + // by the init node. + pn = nf.CreateForIn(loop, init, cond, body, isForEach); + } + else + { + pn = nf.CreateFor(loop, init, cond, incr, body); + } + } + finally + { + exitLoop(); + } + return pn; + } + + + case Token.TRY: + { + consumeToken(); + int lineno = ts.Lineno; + + Node tryblock; + Node catchblocks = null; + Node finallyblock = null; + + decompiler.AddToken(Token.TRY); + decompiler.AddEol(Token.LC); + tryblock = statement(); + decompiler.AddEol(Token.RC); + + catchblocks = nf.CreateLeaf(Token.BLOCK); + + bool sawDefaultCatch = false; + int peek = peekToken(); + if (peek == Token.CATCH) + { + while (matchToken(Token.CATCH)) + { + if (sawDefaultCatch) + { + ReportError("msg.catch.unreachable"); + } + decompiler.AddToken(Token.CATCH); + mustMatchToken(Token.LP, "msg.no.paren.catch"); + decompiler.AddToken(Token.LP); + + mustMatchToken(Token.NAME, "msg.bad.catchcond"); + string varName = ts.String; + decompiler.AddName(varName); + + Node catchCond = null; + if (matchToken(Token.IF)) + { + decompiler.AddToken(Token.IF); + catchCond = expr(false); + } + else + { + sawDefaultCatch = true; + } + + mustMatchToken(Token.RP, "msg.bad.catchcond"); + decompiler.AddToken(Token.RP); + mustMatchToken(Token.LC, "msg.no.brace.catchblock"); + decompiler.AddEol(Token.LC); + + nf.addChildToBack(catchblocks, nf.CreateCatch(varName, catchCond, statements(), ts.Lineno)); + + mustMatchToken(Token.RC, "msg.no.brace.after.body"); + decompiler.AddEol(Token.RC); + } + } + else if (peek != Token.FINALLY) + { + mustMatchToken(Token.FINALLY, "msg.try.no.catchfinally"); + } + + if (matchToken(Token.FINALLY)) + { + decompiler.AddToken(Token.FINALLY); + decompiler.AddEol(Token.LC); + finallyblock = statement(); + decompiler.AddEol(Token.RC); + } + + pn = nf.CreateTryCatchFinally(tryblock, catchblocks, finallyblock, lineno); + + return pn; + } + + + case Token.THROW: + { + consumeToken(); + if (peekTokenOrEOL() == Token.EOL) + { + // ECMAScript does not allow new lines before throw expression, + // see bug 256617 + ReportError("msg.bad.throw.eol"); + } + + int lineno = ts.Lineno; + decompiler.AddToken(Token.THROW); + pn = nf.CreateThrow(expr(false), lineno); + break; + } + + + case Token.BREAK: + { + consumeToken(); + int lineno = ts.Lineno; + + decompiler.AddToken(Token.BREAK); + + // matchJumpLabelName only matches if there is one + Node breakStatement = matchJumpLabelName(); + if (breakStatement == null) + { + if (loopAndSwitchSet == null || loopAndSwitchSet.size() == 0) + { + ReportError("msg.bad.break"); + return null; + } + breakStatement = (Node)loopAndSwitchSet.peek(); + } + pn = nf.CreateBreak(breakStatement, lineno); + break; + } + + + case Token.CONTINUE: + { + consumeToken(); + int lineno = ts.Lineno; + + decompiler.AddToken(Token.CONTINUE); + + Node loop; + // matchJumpLabelName only matches if there is one + Node label = matchJumpLabelName(); + if (label == null) + { + if (loopSet == null || loopSet.size() == 0) + { + ReportError("msg.continue.outside"); + return null; + } + loop = (Node)loopSet.peek(); + } + else + { + loop = nf.getLabelLoop(label); + if (loop == null) + { + ReportError("msg.continue.nonloop"); + return null; + } + } + pn = nf.CreateContinue(loop, lineno); + break; + } + + + case Token.WITH: + { + consumeToken(); + + decompiler.AddToken(Token.WITH); + int lineno = ts.Lineno; + mustMatchToken(Token.LP, "msg.no.paren.with"); + decompiler.AddToken(Token.LP); + Node obj = expr(false); + mustMatchToken(Token.RP, "msg.no.paren.after.with"); + decompiler.AddToken(Token.RP); + decompiler.AddEol(Token.LC); + + ++nestingOfWith; + Node body; + try + { + body = statement(); + } + finally + { + --nestingOfWith; + } + + decompiler.AddEol(Token.RC); + + pn = nf.CreateWith(obj, body, lineno); + return pn; + } + + + case Token.VAR: + { + consumeToken(); + pn = variables(false); + break; + } + + + case Token.RETURN: + { + if (!insideFunction()) + { + ReportError("msg.bad.return"); + } + consumeToken(); + decompiler.AddToken(Token.RETURN); + int lineno = ts.Lineno; + + Node retExpr; + /* This is ugly, but we don't want to require a semicolon. */ + tt = peekTokenOrEOL(); + switch (tt) + { + + case Token.SEMI: + case Token.RC: + case Token.EOF: + case Token.EOL: + case Token.ERROR: + retExpr = null; + break; + + default: + retExpr = expr(false); + break; + + } + pn = nf.CreateReturn(retExpr, lineno); + break; + } + + case Token.DEBUGGER: + consumeToken(); + decompiler.AddToken(Token.DEBUGGER); + pn = nf.CreateDebugger(ts.Lineno); + break; + + case Token.LC: + consumeToken(); + if (statementLabel != null) + { + decompiler.AddToken(Token.LC); + } + pn = statements(); + mustMatchToken(Token.RC, "msg.no.brace.block"); + if (statementLabel != null) + { + decompiler.AddEol(Token.RC); + } + return pn; + + + case Token.ERROR: + // Fall thru, to have a node for error recovery to work on + case Token.SEMI: + consumeToken(); + pn = nf.CreateLeaf(Token.EMPTY); + return pn; + + + case Token.FUNCTION: + { + consumeToken(); + pn = function(FunctionNode.FUNCTION_EXPRESSION_STATEMENT); + return pn; + } + + + case Token.DEFAULT: + consumeToken(); + mustHaveXML(); + + decompiler.AddToken(Token.DEFAULT); + int nsLine = ts.Lineno; + + if (!(matchToken(Token.NAME) && ts.String.Equals("xml"))) + { + ReportError("msg.bad.namespace"); + } + decompiler.AddName(ts.String); + + if (!(matchToken(Token.NAME) && ts.String.Equals("namespace"))) + { + ReportError("msg.bad.namespace"); + } + decompiler.AddName(ts.String); + + if (!matchToken(Token.ASSIGN)) + { + ReportError("msg.bad.namespace"); + } + decompiler.AddToken(Token.ASSIGN); + + Node e = expr(false); + pn = nf.CreateDefaultNamespace(e, nsLine); + break; + + + case Token.NAME: + { + int lineno = ts.Lineno; + string name = ts.String; + setCheckForLabel(); + pn = expr(false); + if (pn.Type != Token.LABEL) + { + + if (compilerEnv.getterAndSetterSupport) + { + tt = peekToken(); + if (tt == Token.NAME) + { + if (ts.String == "getter" || ts.String == "setter") + { + pn.Type = (ts.String[0] == 'g' ? Token.SETPROP_GETTER + : Token.SETPROP_SETTER); + decompiler.AddName(" " + ts.String); // HACK: Hack (whitespace) for decmpiler + consumeToken(); + matchToken(Token.ASSIGN); + decompiler.AddToken(Token.ASSIGN); + matchToken(Token.FUNCTION); + Node fn = function(FunctionNode.FUNCTION_EXPRESSION); + pn.addChildToBack(fn); + } + } + } + pn = nf.CreateExprStatement(pn, lineno); + } + else + { + // Parsed the label: push back token should be + // colon that primaryExpr left untouched. + if (peekToken() != Token.COLON) + Context.CodeBug(); + consumeToken(); + // depend on decompiling lookahead to guess that that + // last name was a label. + decompiler.AddName(name); + decompiler.AddEol(Token.COLON); + + if (labelSet == null) + { + labelSet = Hashtable.Synchronized(new Hashtable()); + } + else if (labelSet.ContainsKey(name)) + { + ReportError("msg.dup.label"); + } + + bool firstLabel; + if (statementLabel == null) + { + firstLabel = true; + statementLabel = pn; + } + else + { + // Discard multiple label nodes and use only + // the first: it allows to simplify IRFactory + firstLabel = false; + } + labelSet[name] = statementLabel; + try + { + pn = statementHelper(statementLabel); + } + finally + { + labelSet.Remove(name); + } + if (firstLabel) + { + pn = nf.CreateLabeledStatement(statementLabel, pn); + } + return pn; + } + break; + } + + + default: + { + int lineno = ts.Lineno; + pn = expr(false); + pn = nf.CreateExprStatement(pn, lineno); + break; + } + + } + + // FINDME + + int ttFlagged = peekFlaggedToken(); + switch (ttFlagged & CLEAR_TI_MASK) + { + + case Token.SEMI: + // Consume ';' as a part of expression + consumeToken(); + break; + + case Token.ERROR: + case Token.EOF: + case Token.RC: + // Autoinsert ; + break; + + default: + if ((ttFlagged & TI_AFTER_EOL) == 0) + { + // Report error if no EOL or autoinsert ; otherwise + ReportError("msg.no.semi.stmt"); + } + break; + + } + decompiler.AddEol(Token.SEMI); + + return pn; + } + + Node variables(bool inForInit) + { + Node pn = nf.CreateVariables(ts.Lineno); + bool first = true; + + decompiler.AddToken(Token.VAR); + + for (; ; ) + { + Node name; + Node init; + mustMatchToken(Token.NAME, "msg.bad.var"); + string s = ts.String; + + if (!first) + decompiler.AddToken(Token.COMMA); + first = false; + + decompiler.AddName(s); + currentScriptOrFn.addVar(s); + name = nf.CreateName(s); + + // omitted check for argument hiding + + if (matchToken(Token.ASSIGN)) + { + decompiler.AddToken(Token.ASSIGN); + + init = assignExpr(inForInit); + nf.addChildToBack(name, init); + } + nf.addChildToBack(pn, name); + if (!matchToken(Token.COMMA)) + break; + } + return pn; + } + + Node expr(bool inForInit) + { + Node pn = assignExpr(inForInit); + while (matchToken(Token.COMMA)) + { + decompiler.AddToken(Token.COMMA); + pn = nf.CreateBinary(Token.COMMA, pn, assignExpr(inForInit)); + } + return pn; + } + + Node assignExpr(bool inForInit) + { + Node pn = condExpr(inForInit); + + int tt = peekToken(); + if (Token.FIRST_ASSIGN <= tt && tt <= Token.LAST_ASSIGN) + { + consumeToken(); + decompiler.AddToken(tt); + pn = nf.CreateAssignment(tt, pn, assignExpr(inForInit)); + } + + return pn; + } + + Node condExpr(bool inForInit) + { + Node ifTrue; + Node ifFalse; + + Node pn = orExpr(inForInit); + + if (matchToken(Token.HOOK)) + { + decompiler.AddToken(Token.HOOK); + ifTrue = assignExpr(false); + mustMatchToken(Token.COLON, "msg.no.colon.cond"); + decompiler.AddToken(Token.COLON); + ifFalse = assignExpr(inForInit); + return nf.CreateCondExpr(pn, ifTrue, ifFalse); + } + + return pn; + } + + Node orExpr(bool inForInit) + { + Node pn = andExpr(inForInit); + if (matchToken(Token.OR)) + { + decompiler.AddToken(Token.OR); + pn = nf.CreateBinary(Token.OR, pn, orExpr(inForInit)); + } + + return pn; + } + + Node andExpr(bool inForInit) + { + Node pn = bitOrExpr(inForInit); + if (matchToken(Token.AND)) + { + decompiler.AddToken(Token.AND); + pn = nf.CreateBinary(Token.AND, pn, andExpr(inForInit)); + } + + return pn; + } + + Node bitOrExpr(bool inForInit) + { + Node pn = bitXorExpr(inForInit); + while (matchToken(Token.BITOR)) + { + decompiler.AddToken(Token.BITOR); + pn = nf.CreateBinary(Token.BITOR, pn, bitXorExpr(inForInit)); + } + return pn; + } + + Node bitXorExpr(bool inForInit) + { + Node pn = bitAndExpr(inForInit); + while (matchToken(Token.BITXOR)) + { + decompiler.AddToken(Token.BITXOR); + pn = nf.CreateBinary(Token.BITXOR, pn, bitAndExpr(inForInit)); + } + return pn; + } + + Node bitAndExpr(bool inForInit) + { + Node pn = eqExpr(inForInit); + while (matchToken(Token.BITAND)) + { + decompiler.AddToken(Token.BITAND); + pn = nf.CreateBinary(Token.BITAND, pn, eqExpr(inForInit)); + } + return pn; + } + + Node eqExpr(bool inForInit) + { + Node pn = relExpr(inForInit); + for (; ; ) + { + int tt = peekToken(); + switch (tt) + { + + case Token.EQ: + case Token.NE: + case Token.SHEQ: + case Token.SHNE: + consumeToken(); + int decompilerToken = tt; + int parseToken = tt; + if (compilerEnv.LanguageVersion == Context.Versions.JS1_2) + { + // JavaScript 1.2 uses shallow equality for == and != . + // In addition, convert === and !== for decompiler into + // == and != since the decompiler is supposed to show + // canonical source and in 1.2 ===, !== are allowed + // only as an alias to ==, !=. + switch (tt) + { + + case Token.EQ: + parseToken = Token.SHEQ; + break; + + case Token.NE: + parseToken = Token.SHNE; + break; + + case Token.SHEQ: + decompilerToken = Token.EQ; + break; + + case Token.SHNE: + decompilerToken = Token.NE; + break; + } + } + decompiler.AddToken(decompilerToken); + pn = nf.CreateBinary(parseToken, pn, relExpr(inForInit)); + continue; + } + break; + } + return pn; + } + + Node relExpr(bool inForInit) + { + Node pn = shiftExpr(); + for (; ; ) + { + int tt = peekToken(); + switch (tt) + { + + case Token.IN: + if (inForInit) + break; + // fall through + goto case Token.INSTANCEOF; + + case Token.INSTANCEOF: + case Token.LE: + case Token.LT: + case Token.GE: + case Token.GT: + consumeToken(); + decompiler.AddToken(tt); + pn = nf.CreateBinary(tt, pn, shiftExpr()); + continue; + } + break; + } + return pn; + } + + Node shiftExpr() + { + Node pn = addExpr(); + for (; ; ) + { + int tt = peekToken(); + switch (tt) + { + + case Token.LSH: + case Token.URSH: + case Token.RSH: + consumeToken(); + decompiler.AddToken(tt); + pn = nf.CreateBinary(tt, pn, addExpr()); + continue; + } + break; + } + return pn; + } + + Node addExpr() + { + Node pn = mulExpr(); + for (; ; ) + { + int tt = peekToken(); + if (tt == Token.ADD || tt == Token.SUB) + { + consumeToken(); + decompiler.AddToken(tt); + // flushNewLines + pn = nf.CreateBinary(tt, pn, mulExpr()); + continue; + } + break; + } + + return pn; + } + + Node mulExpr() + { + Node pn = unaryExpr(); + for (; ; ) + { + int tt = peekToken(); + switch (tt) + { + + case Token.MUL: + case Token.DIV: + case Token.MOD: + consumeToken(); + decompiler.AddToken(tt); + pn = nf.CreateBinary(tt, pn, unaryExpr()); + continue; + } + break; + } + + return pn; + } + + Node unaryExpr() + { + using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier(4096)) + { + int tt; + + tt = peekToken(); + + switch (tt) + { + + case Token.VOID: + case Token.NOT: + case Token.BITNOT: + case Token.TYPEOF: + consumeToken(); + decompiler.AddToken(tt); + return nf.CreateUnary(tt, unaryExpr()); + + + case Token.ADD: + consumeToken(); + // Convert to special POS token in decompiler and parse tree + decompiler.AddToken(Token.POS); + return nf.CreateUnary(Token.POS, unaryExpr()); + + + case Token.SUB: + consumeToken(); + // Convert to special NEG token in decompiler and parse tree + decompiler.AddToken(Token.NEG); + return nf.CreateUnary(Token.NEG, unaryExpr()); + + + case Token.INC: + case Token.DEC: + consumeToken(); + decompiler.AddToken(tt); + return nf.CreateIncDec(tt, false, memberExpr(true)); + + + case Token.DELPROP: + consumeToken(); + decompiler.AddToken(Token.DELPROP); + return nf.CreateUnary(Token.DELPROP, unaryExpr()); + + + case Token.ERROR: + consumeToken(); + break; + + // XML stream encountered in expression. + + case Token.LT: + if (compilerEnv.isXmlAvailable()) + { + consumeToken(); + Node pn = xmlInitializer(); + return memberExprTail(true, pn); + } + // Fall thru to the default handling of RELOP + goto default; + + + default: + { + Node pn = memberExpr(true); + + // Don't look across a newline boundary for a postfix incop. + tt = peekTokenOrEOL(); + if (tt == Token.INC || tt == Token.DEC) + { + consumeToken(); + decompiler.AddToken(tt); + return nf.CreateIncDec(tt, true, pn); + } + return pn; + } + + } + return nf.CreateName("err"); // Only reached on error. Try to continue. + } + } + + Node xmlInitializer() + { + int tt = ts.FirstXMLToken; + if (tt != Token.XML && tt != Token.XMLEND) + { + ReportError("msg.syntax"); + return null; + } + + /* Make a NEW node to append to. */ + Node pnXML = nf.CreateLeaf(Token.NEW); + decompiler.AddToken(Token.NEW); + decompiler.AddToken(Token.DOT); + + string xml = ts.String; + bool fAnonymous = xml.Trim().StartsWith("<>"); + + decompiler.AddName(fAnonymous ? "XMLList" : "XML"); + Node pn = nf.CreateName(fAnonymous ? "XMLList" : "XML"); + nf.addChildToBack(pnXML, pn); + + pn = null; + Node e; + for (; ; tt = ts.NextXMLToken) + { + switch (tt) + { + + case Token.XML: + xml = ts.String; + decompiler.AddString(xml); + mustMatchToken(Token.LC, "msg.syntax"); + decompiler.AddToken(Token.LC); + e = (peekToken() == Token.RC) ? nf.CreateString("") : expr(false); + mustMatchToken(Token.RC, "msg.syntax"); + decompiler.AddToken(Token.RC); + if (pn == null) + { + pn = nf.CreateString(xml); + } + else + { + pn = nf.CreateBinary(Token.ADD, pn, nf.CreateString(xml)); + } + int nodeType; + if (ts.XMLAttribute) + { + nodeType = Token.ESCXMLATTR; + } + else + { + nodeType = Token.ESCXMLTEXT; + } + e = nf.CreateUnary(nodeType, e); + pn = nf.CreateBinary(Token.ADD, pn, e); + break; + + case Token.XMLEND: + xml = ts.String; + decompiler.AddString(xml); + if (pn == null) + { + pn = nf.CreateString(xml); + } + else + { + pn = nf.CreateBinary(Token.ADD, pn, nf.CreateString(xml)); + } + + nf.addChildToBack(pnXML, pn); + return pnXML; + + default: + ReportError("msg.syntax"); + return null; + + } + } + } + + void argumentList(Node listNode) + { + bool matched; + matched = matchToken(Token.RP); + if (!matched) + { + bool first = true; + do + { + if (!first) + decompiler.AddToken(Token.COMMA); + first = false; + nf.addChildToBack(listNode, assignExpr(false)); + } + while (matchToken(Token.COMMA)); + + mustMatchToken(Token.RP, "msg.no.paren.arg"); + } + decompiler.AddToken(Token.RP); + } + + Node memberExpr(bool allowCallSyntax) + { + int tt; + + Node pn; + + /* Check for new expressions. */ + tt = peekToken(); + if (tt == Token.NEW) + { + /* Eat the NEW token. */ + consumeToken(); + decompiler.AddToken(Token.NEW); + + /* Make a NEW node to append to. */ + pn = nf.CreateCallOrNew(Token.NEW, memberExpr(false)); + + if (matchToken(Token.LP)) + { + decompiler.AddToken(Token.LP); + /* Add the arguments to pn, if any are supplied. */ + argumentList(pn); + } + + // TODO: there's a check in the C source against + // TODO: "too many constructor arguments" - how many + // TODO: do we claim to support? + + /* Experimental syntax: allow an object literal to follow a new expression, + * which will mean a kind of anonymous class built with the JavaAdapter. + * the object literal will be passed as an additional argument to the constructor. + */ + tt = peekToken(); + if (tt == Token.LC) + { + nf.addChildToBack(pn, primaryExpr()); + } + } + else + { + pn = primaryExpr(); + } + + return memberExprTail(allowCallSyntax, pn); + } + + Node memberExprTail(bool allowCallSyntax, Node pn) + { + for (; ; ) + { + int tt = peekToken(); + switch (tt) + { + + + case Token.DOT: + case Token.DOTDOT: + { + int memberTypeFlags; + string s; + + consumeToken(); + decompiler.AddToken(tt); + memberTypeFlags = 0; + if (tt == Token.DOTDOT) + { + mustHaveXML(); + memberTypeFlags = Node.DESCENDANTS_FLAG; + } + if (!compilerEnv.isXmlAvailable()) + { + mustMatchToken(Token.NAME, "msg.no.name.after.dot"); + s = ts.String; + decompiler.AddName(s); + pn = nf.CreatePropertyGet(pn, null, s, memberTypeFlags); + break; + } + + + tt = nextToken(); + + switch (tt) + { + + // handles: name, ns::name, ns::*, ns::[expr] + case Token.NAME: + s = ts.String; + decompiler.AddName(s); + pn = propertyName(pn, s, memberTypeFlags); + break; + + // handles: *, *::name, *::*, *::[expr] + + case Token.MUL: + decompiler.AddName("*"); + pn = propertyName(pn, "*", memberTypeFlags); + break; + + // handles: '@attr', '@ns::attr', '@ns::*', '@ns::*', + // '@::attr', '@::*', '@*', '@*::attr', '@*::*' + + case Token.XMLATTR: + decompiler.AddToken(Token.XMLATTR); + pn = attributeAccess(pn, memberTypeFlags); + break; + + + default: + ReportError("msg.no.name.after.dot"); + break; + + } + } + break; + + + case Token.DOTQUERY: + consumeToken(); + mustHaveXML(); + decompiler.AddToken(Token.DOTQUERY); + pn = nf.CreateDotQuery(pn, expr(false), ts.Lineno); + mustMatchToken(Token.RP, "msg.no.paren"); + decompiler.AddToken(Token.RP); + break; + + + case Token.LB: + consumeToken(); + decompiler.AddToken(Token.LB); + pn = nf.CreateElementGet(pn, null, expr(false), 0); + mustMatchToken(Token.RB, "msg.no.bracket.index"); + decompiler.AddToken(Token.RB); + break; + + + case Token.LP: + if (!allowCallSyntax) + { + + goto tailLoop_brk; + } + consumeToken(); + decompiler.AddToken(Token.LP); + pn = nf.CreateCallOrNew(Token.CALL, pn); + /* Add the arguments to pn, if any are supplied. */ + argumentList(pn); + break; + + + default: + + goto tailLoop_brk; + + } + } + + tailLoop_brk: + ; + + return pn; + } + + /* + * Xml attribute expression: + * '@attr', '@ns::attr', '@ns::*', '@ns::*', '@*', '@*::attr', '@*::*' + */ + Node attributeAccess(Node pn, int memberTypeFlags) + { + memberTypeFlags |= Node.ATTRIBUTE_FLAG; + int tt = nextToken(); + + switch (tt) + { + + // handles: @name, @ns::name, @ns::*, @ns::[expr] + case Token.NAME: + { + string s = ts.String; + decompiler.AddName(s); + pn = propertyName(pn, s, memberTypeFlags); + } + break; + + // handles: @*, @*::name, @*::*, @*::[expr] + + case Token.MUL: + decompiler.AddName("*"); + pn = propertyName(pn, "*", memberTypeFlags); + break; + + // handles @[expr] + + case Token.LB: + decompiler.AddToken(Token.LB); + pn = nf.CreateElementGet(pn, null, expr(false), memberTypeFlags); + mustMatchToken(Token.RB, "msg.no.bracket.index"); + decompiler.AddToken(Token.RB); + break; + + + default: + ReportError("msg.no.name.after.xmlAttr"); + pn = nf.CreatePropertyGet(pn, null, "?", memberTypeFlags); + break; + + } + + return pn; + } + + /// Check if :: follows name in which case it becomes qualified name + Node propertyName(Node pn, string name, int memberTypeFlags) + { + string ns = null; + if (matchToken(Token.COLONCOLON)) + { + decompiler.AddToken(Token.COLONCOLON); + ns = name; + + int tt = nextToken(); + switch (tt) + { + + // handles name::name + case Token.NAME: + name = ts.String; + decompiler.AddName(name); + break; + + // handles name::* + + case Token.MUL: + decompiler.AddName("*"); + name = "*"; + break; + + // handles name::[expr] + + case Token.LB: + decompiler.AddToken(Token.LB); + pn = nf.CreateElementGet(pn, ns, expr(false), memberTypeFlags); + mustMatchToken(Token.RB, "msg.no.bracket.index"); + decompiler.AddToken(Token.RB); + return pn; + + + default: + ReportError("msg.no.name.after.coloncolon"); + name = "?"; + break; + + } + } + + pn = nf.CreatePropertyGet(pn, ns, name, memberTypeFlags); + return pn; + } + + int currentStackIndex = 0; + + + Node primaryExpr() + { + try + { + if (currentStackIndex++ > ScriptRuntime.MAXSTACKSIZE) + { + currentStackIndex = 0; + throw Context.ReportRuntimeError( + ScriptRuntime.GetMessage("mag.too.deep.parser.recursion"), sourceURI, ts.Lineno, null, 0); + } + + Node pn; + + int ttFlagged = nextFlaggedToken(); + int tt = ttFlagged & CLEAR_TI_MASK; + + switch (tt) + { + + + case Token.FUNCTION: + return function(FunctionNode.FUNCTION_EXPRESSION); + + + case Token.LB: + { + ObjArray elems = new ObjArray(); + int skipCount = 0; + decompiler.AddToken(Token.LB); + bool after_lb_or_comma = true; + for (; ; ) + { + tt = peekToken(); + + if (tt == Token.COMMA) + { + consumeToken(); + decompiler.AddToken(Token.COMMA); + if (!after_lb_or_comma) + { + after_lb_or_comma = true; + } + else + { + elems.add((object)null); + ++skipCount; + } + } + else if (tt == Token.RB) + { + consumeToken(); + decompiler.AddToken(Token.RB); + break; + } + else + { + if (!after_lb_or_comma) + { + ReportError("msg.no.bracket.arg"); + } + elems.add(assignExpr(false)); + after_lb_or_comma = false; + } + } + return nf.CreateArrayLiteral(elems, skipCount); + } + + + case Token.LC: + { + ObjArray elems = new ObjArray(); + decompiler.AddToken(Token.LC); + if (!matchToken(Token.RC)) + { + + bool first = true; + do + { + object property; + + if (!first) + decompiler.AddToken(Token.COMMA); + else + first = false; + + tt = peekToken(); + switch (tt) + { + + case Token.NAME: + case Token.STRING: + consumeToken(); + if (compilerEnv.getterAndSetterSupport) + { + if (tt == Token.NAME) + if (CheckForGetOrSet(elems) || CheckForGetterOrSetter(elems)) + goto next_prop; + } + + + // map NAMEs to STRINGs in object literal context + // but tell the decompiler the proper type + string s = ts.String; + if (tt == Token.NAME) + { + decompiler.AddName(s); + } + else + { + decompiler.AddString(s); + } + property = ScriptRuntime.getIndexObject(s); + + break; + + + case Token.NUMBER: + consumeToken(); + double n = ts.Number; + decompiler.AddNumber(n); + property = ScriptRuntime.getIndexObject(n); + break; + + + case Token.RC: + // trailing comma is OK. + + goto commaloop_brk; + + default: + ReportError("msg.bad.prop"); + + goto commaloop_brk; + + } + mustMatchToken(Token.COLON, "msg.no.colon.prop"); + + // OBJLIT is used as ':' in object literal for + // decompilation to solve spacing ambiguity. + decompiler.AddToken(Token.OBJECTLIT); + elems.add(property); + elems.add(assignExpr(false)); + + next_prop: + ; + } + while (matchToken(Token.COMMA)); + + commaloop_brk: + ; + + + mustMatchToken(Token.RC, "msg.no.brace.prop"); + } + decompiler.AddToken(Token.RC); + return nf.CreateObjectLiteral(elems); + } + + + case Token.LP: + + /* Brendan's IR-jsparse.c makes a new node tagged with + * TOK_LP here... I'm not sure I understand why. Isn't + * the grouping already implicit in the structure of the + * parse tree? also TOK_LP is already overloaded (I + * think) in the C IR as 'function call.' */ + decompiler.AddToken(Token.LP); + pn = expr(false); + decompiler.AddToken(Token.RP); + mustMatchToken(Token.RP, "msg.no.paren"); + return pn; + + + case Token.XMLATTR: + mustHaveXML(); + decompiler.AddToken(Token.XMLATTR); + pn = attributeAccess(null, 0); + return pn; + + + case Token.NAME: + { + string name = ts.String; + if ((ttFlagged & TI_CHECK_LABEL) != 0) + { + if (peekToken() == Token.COLON) + { + // Do not consume colon, it is used as unwind indicator + // to return to statementHelper. + // TODO: Better way? + return nf.CreateLabel(ts.Lineno); + } + } + + decompiler.AddName(name); + if (compilerEnv.isXmlAvailable()) + { + pn = propertyName(null, name, 0); + } + else + { + pn = nf.CreateName(name); + } + return pn; + } + + + case Token.NUMBER: + { + double n = ts.Number; + decompiler.AddNumber(n); + return nf.CreateNumber(n); + } + + + case Token.STRING: + { + string s = ts.String; + decompiler.AddString(s); + return nf.CreateString(s); + } + + + case Token.DIV: + case Token.ASSIGN_DIV: + { + // Got / or /= which should be treated as regexp in fact + ts.readRegExp(tt); + string flags = ts.regExpFlags; + ts.regExpFlags = null; + string re = ts.String; + decompiler.AddRegexp(re, flags); + int index = currentScriptOrFn.addRegexp(re, flags); + return nf.CreateRegExp(index); + } + + + case Token.NULL: + case Token.THIS: + case Token.FALSE: + case Token.TRUE: + decompiler.AddToken(tt); + return nf.CreateLeaf(tt); + + + case Token.RESERVED: + ReportError("msg.reserved.id"); + break; + + + case Token.ERROR: + /* the scanner or one of its subroutines reported the error. */ + break; + + + case Token.EOF: + ReportError("msg.unexpected.eof"); + break; + + + default: + ReportError("msg.syntax"); + break; + + } + return null; // should never reach here + } + finally + { + currentStackIndex--; + } + } + + + /// + /// Support for non-ecma "get"/"set" spidermonkey extension. + /// + /// + /// get NAME () SCOPE + /// set NAME () SCOPE + /// + bool CheckForGetOrSet(ObjArray elems) + { + int tt; + + string type = ts.String; + if (type != "get" && type != "set") + { + return false; + } + tt = peekToken(); + if (tt != Token.NAME) + return false; + consumeToken(); + + string name = ts.String; + + decompiler.AddName(name); + + Node func = function(FunctionNode.FUNCTION_EXPRESSION); + object property = ScriptRuntime.getIndexObject(name); + + elems.add((type[0] == 'g') ? (object)new Node.GetterPropertyLiteral(property) + : (object)new Node.SetterPropertyLiteral(property)); + elems.add(func); + + return true; + } + + /// + /// Support for non-ecma "get"/"set" spidermonkey extension. + /// + /// + /// NAME getter: FUNCTION () SCOPE + /// NAME setter: FUNCTION () SCOPE + /// + bool CheckForGetterOrSetter(ObjArray elems) + { + int tt; + + string name = ts.String; + consumeToken(); + + tt = peekToken(); + if (tt != Token.NAME) + return false; + string type = ts.String; + if (type != "getter" && type != "setter") + { + return false; + } + consumeToken(); + + matchToken(Token.COLON); + matchToken(Token.FUNCTION); + + Node func = function(FunctionNode.FUNCTION_EXPRESSION); + object property = ScriptRuntime.getIndexObject(name); + + elems.add((type[0] == 'g') ? (object)new Node.GetterPropertyLiteral(property) + : (object)new Node.SetterPropertyLiteral(property)); + elems.add(func); + + return true; + } + + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/RegExpProxy.cs b/src/EcmaScript.NET/RegExpProxy.cs similarity index 96% rename from Code/EcmaScript.NET/RegExpProxy.cs rename to src/EcmaScript.NET/RegExpProxy.cs index 9769fbf..c9b9b7a 100644 --- a/Code/EcmaScript.NET/RegExpProxy.cs +++ b/src/EcmaScript.NET/RegExpProxy.cs @@ -1,46 +1,46 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -namespace EcmaScript.NET -{ - - - public enum RegExpActions - { - None = 0, - Match = 1, - Replace = 2, - Search = 3 - } - - /// - /// A proxy for the regexp package, so that the regexp package can be - /// loaded optionally. - /// - public interface RegExpProxy - { - - bool IsRegExp (IScriptable obj); - - object Compile (Context cx, string source, string flags); - - IScriptable Wrap (Context cx, IScriptable scope, object compiled); - - object Perform (Context cx, IScriptable scope, IScriptable thisObj, object [] args, RegExpActions actionType); - - int FindSplit (Context cx, IScriptable scope, string target, string separator, IScriptable re, int [] ip, int [] matchlen, bool [] matched, string [] [] parensp); - - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +namespace EcmaScript.NET +{ + + + public enum RegExpActions + { + None = 0, + Match = 1, + Replace = 2, + Search = 3 + } + + /// + /// A proxy for the regexp package, so that the regexp package can be + /// loaded optionally. + /// + public interface RegExpProxy + { + + bool IsRegExp (IScriptable obj); + + object Compile (Context cx, string source, string flags); + + IScriptable Wrap (Context cx, IScriptable scope, object compiled); + + object Perform (Context cx, IScriptable scope, IScriptable thisObj, object [] args, RegExpActions actionType); + + int FindSplit (Context cx, IScriptable scope, string target, string separator, IScriptable re, int [] ip, int [] matchlen, bool [] matched, string [] [] parensp); + + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/Resources/ChangeLog b/src/EcmaScript.NET/Resources/ChangeLog similarity index 97% rename from Code/EcmaScript.NET/Resources/ChangeLog rename to src/EcmaScript.NET/Resources/ChangeLog index def77fd..58da71b 100644 --- a/Code/EcmaScript.NET/Resources/ChangeLog +++ b/src/EcmaScript.NET/Resources/ChangeLog @@ -1,35 +1,35 @@ -2007-01-01 Christian Birkl - - * Added 'it' object - * typeof /x/ must return object, not function - -2006-12-30 Christian Birkl - - * Added Helpers.StackOverflowVerifier to prevent StackOverflowExceptions - which aren't cachable in .NET 2.0 - -2006-12-30 Christian Birkl - - * Added "gc" function to NativeGlobalObject - - * Duplicate regexp quantifiers now raise a SyntaxError (e.g. /x{1}{1}/) - - * Ported bugfix for https://bugzilla.mozilla.org/show_bug.cgi?id=289628 - - * Fixed some OutOfMemoryExceptions in Array.concat/push/... - by adding OutOfRange checks. - -2006-12-29 Christian Birkl - - * First public release (based partly on Rhino 1.6R5) - - * Major Changes are: - - - Removed support for compiling javascript sources - - Removed LiveConnect and replaced it with a new .NET layer - (See EcmaScript.NET.Types.Cli) - - Rewrote E4X Support completely since it was based on - javax.beans.* framework which has no counterpart in .NET. - - Added support JavaScript 1.5 getter and setter - - .NET'ished some bits here and there (e.g. refactoring methods +2007-01-01 Christian Birkl + + * Added 'it' object + * typeof /x/ must return object, not function + +2006-12-30 Christian Birkl + + * Added Helpers.StackOverflowVerifier to prevent StackOverflowExceptions + which aren't cachable in .NET 2.0 + +2006-12-30 Christian Birkl + + * Added "gc" function to NativeGlobalObject + + * Duplicate regexp quantifiers now raise a SyntaxError (e.g. /x{1}{1}/) + + * Ported bugfix for https://bugzilla.mozilla.org/show_bug.cgi?id=289628 + + * Fixed some OutOfMemoryExceptions in Array.concat/push/... + by adding OutOfRange checks. + +2006-12-29 Christian Birkl + + * First public release (based partly on Rhino 1.6R5) + + * Major Changes are: + + - Removed support for compiling javascript sources + - Removed LiveConnect and replaced it with a new .NET layer + (See EcmaScript.NET.Types.Cli) + - Rewrote E4X Support completely since it was based on + javax.beans.* framework which has no counterpart in .NET. + - Added support JavaScript 1.5 getter and setter + - .NET'ished some bits here and there (e.g. refactoring methods into properties and events) \ No newline at end of file diff --git a/Code/EcmaScript.NET/Resources/LICENSE b/src/EcmaScript.NET/Resources/LICENSE similarity index 97% rename from Code/EcmaScript.NET/Resources/LICENSE rename to src/EcmaScript.NET/Resources/LICENSE index 9b53555..b2b3b0a 100644 --- a/Code/EcmaScript.NET/Resources/LICENSE +++ b/src/EcmaScript.NET/Resources/LICENSE @@ -1,34 +1,34 @@ -/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Rhino code, released - * May 6, 1999. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1997-1999 - * the Initial Developer. All Rights Reserved. - * - * Alternatively, the contents of this file may be used under the terms of - * the GNU General Public License Version 2 or later (the "GPL"), in which - * case the provisions of the GPL are applicable instead of those above. If - * you wish to allow use of your version of this file only under the terms of - * the GPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replacing - * them with the notice and other provisions required by the GPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the GPL. - * +/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Rhino code, released + * May 6, 1999. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1997-1999 + * the Initial Developer. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU General Public License Version 2 or later (the "GPL"), in which + * case the provisions of the GPL are applicable instead of those above. If + * you wish to allow use of your version of this file only under the terms of + * the GPL and not to allow others to use your version of this file under the + * MPL, indicate your decision by deleting the provisions above and replacing + * them with the notice and other provisions required by the GPL. If you do + * not delete the provisions above, a recipient may use your version of this + * file under either the MPL or the GPL. + * * ***** END LICENSE BLOCK ***** */ \ No newline at end of file diff --git a/Code/EcmaScript.NET/Resources/Messages.resx b/src/EcmaScript.NET/Resources/Messages.resx similarity index 97% rename from Code/EcmaScript.NET/Resources/Messages.resx rename to src/EcmaScript.NET/Resources/Messages.resx index b8b8d4c..02a6c08 100644 --- a/Code/EcmaScript.NET/Resources/Messages.resx +++ b/src/EcmaScript.NET/Resources/Messages.resx @@ -1,675 +1,675 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - missing name after . operator - - - missing ( before function parameters. - - - no source found to decompile function reference {0} - - - missing } in compound statement - - - missing ) after formal parameters - - - missing name after .. operator - - - Program too complex: too big jump offset. - - - invalid property id - - - illegal character - - - Invalid increment operand. - - - Function {0} can not be used as the left-hand side of assignment or as an operand of ++ or -- operator. - - - unterminated string literal - - - Construction of objects of type "{0}" is not supported. - - - Internal error: type conversion of {0} to assign to {1} on {2} failed. - - - XML runtime not available - - - @IMPLEMENTATION.VERSION@ - - - missing ] in index expression - - - Java method "{0}" was invoked with {1} as "this" value that can not be converted to Java type {2}. - - - Method "{0}" must be static with the signature "(Context cx, Scriptable thisObj, Object[] args, Function funObj)" to define a variable arguments function. - - - Unterminated character class {0} - - - {0} must extend ScriptableObject in order to define property {1}. - - - missing ) after for-loop control - - - {0} is not a function, it is {1}. - - - invalid return - - - unmatched ) in regular expression. - - - In order to define a property, getter {0} must have zero parameters or a single ScriptableObject parameter. - - - Calling eval() with anything other than a primitive string value will simply return the value. Is this what you intended? - - - Function "{0}" must be called directly, and not by way of a function of another name. - - - missing ) after with-statement object - - - invalid Unicode escape sequence - - - Invalid assignment left-hand side. - - - missing '{' before catch-block body - - - no input for {0} - - - Cannot apply "with" to {0} - - - Calling eval() with anything other than a primitive string value is not allowed in the strict mode. - - - undefined labe - - - Only one argument may be specified if the first argument to RegExp.prototype.compile is a RegExp object. - - - Cannot import "{0}" since a property by that name is already defined. - - - Cyclic {0} value not allowed. - - - missing ; before statement - - - Two-parameter setter must take a ScriptableObject as its first parameter. - - - Java package names may not be numbers. - - - missing } after property list - - - Too deep recursion while parsing - - - Unterminated quantifier {0} - - - Program too complex: internal index exceeds 64K limit. - - - Unterminated parenthetical {0} - - - Attempt to assign non-existing name "{0}" in the strict mode. It could indicate a missing variable statement. - - - invalid switch statement - - - illegal octal literal digit {0}; interpreting it as a decimal digit - - - missing name after :: operator - - - missing ( after for - - - error instantiating ({0}): class {1} is interface or abstract - - - Cannot convert {0} to interface {1} with no methods - - - Function importPackage must be called with a package; had "{0}" instead. - - - Can''t find converter method "{0}" on class {1}. - - - Script objects are not constructors. - - - "{0}" may only be invoked from a "new" expression. - - - Maximum {0} less than minimum - - - "{0}" is not a constructor. - - - Array length {0} exceeds supported capacity limit. - - - Method "{0}" called on incompatible object. - - - missing : in conditional expression - - - Cannot convert undefined to an object. - - - missing ( before condition - - - Object''s getDefaultValue() method returned an object. - - - Invalid quantifier {0} - - - Regular expressions are not available. - - - Compilation produced {0} syntax errors. - - - illegally formed XML syntax - - - Overly large back reference {0} - - - Argument {0} is not Java class: {1}. - - - Cannot modify a property of a sealed object: {0}. - - - The "{0}" constructor is deprecated. - - - duplicatet label - - - missing } after function body - - - not a valid default namespace statement. Syntax is: default xml namespace = EXPRESSION; - - - Trailing \ in regular expression. - - - missing formal parameter - - - missing ) after switch expression - - - Primitive type expected (had {0} instead) - - - "{0}" is not defined. - - - missing '{' before switch body - - - invalid catch block condition - - - ''prototype'' property of {0} is not an object. - - - missing ) after condition - - - Can''t find method {0}. - - - The undefined value has no properties. - - - {0} is not a reference to read reference value. - - - Unsupported return type "{0}" in method "{1}". - - - Invalid JavaScript value of type {0} - - - missing ( before catch-block condition - - - Can''t define constructor or class {0} since more than one constructor has multiple parameters. - - - Cannot add a property to a sealed object: {0}. - - - Expected static or delegated setter {0} to take two parameters. - - - Malformed URI sequence. - - - continue can only use labeles of iteration statements - - - Namespace object expected to left of :: (found {0} instead) - - - Cannot set property "{1}" of {0} to "{2}" - - - Unsupported parameter type "{0}" in setter "{1}". - - - back-reference exceeds number of capturing parentheses. - - - Cannot convert {0} to {1} - - - Cannot remove a property from a sealed object: {0}. - - - Invalid left-hand side of for..in loop. - - - Unsupported parameter type "{0}" in method "{1}". - - - Invalid range in character class. - - - Ambiguous import: "{0}" and and "{1}". - - - Method or constructor "{0}" must be static with the signature "(Context cx, Object[] args, Function ctorObj, boolean inNewExpr)" to define a variable arguments constructor. - - - missing ; after for-loop condition - - - Expected either one or two parameters for setter. - - - Cannot delete property "{1}" of {0} - - - Function importClass must be called with a class; had "{0}" instead. - - - missing : after property id - - - Cannot find default value for object. - - - Cannot convert null to an object. - - - invalid label - - - missing variable name - - - Can''t convert to type "{0}". - - - Cannot read property "{1}" from {0} - - - Cannot convert function {0} to interface since it contains methods with different signatures - - - Method "{0}" occurs multiple times in class "{1}". - - - Cannot call method "{1}" of {0} - - - unlabelled break must be inside loop or switch - - - Getter and setter must both be static or neither be static. - - - missing ( before with-statement object - - - Only one variable allowed in for..in loop. - - - missing ; after for-loop initializer - - - identifier is a reserved word - - - Only one class may be extended by a JavaAdapter. Had {0} and {1}. - - - invalid variable initialization - - - JavaAdapter requires at least one argument. - - - illegal usage of future reserved keyword {0}; interpreting it as ordinary identifier - - - Unexpected end of file - - - missing name after .@ - - - Can''t use instanceof on a non-object. - - - missing ) after argument list - - - missing ) in parenthetical - - - missing exponent - - - Invalid decerement operand. - - - missing ( before switch expression - - - unterminated comment - - - Zero quantifier {0} - - - illegal radix {0}. - - - invalid string escape mask - - - Duplicate parameter name "{0}". - - - Java class "{0}" has no public instance field or method named "{1}". - - - Expected static or delegated getter {0} to take a ScriptableObject parameter. - - - Line terminator is not allowed between the throw keyword and throw expression. - - - Method "{0}" not found in "{1}". - - - The choice of Java constructor {0} matching JavaScript argument types ({1}) is ambiguous; candidate constructors are: {2} - - - Internal error: attempt to access private/protected field "{0}". - - - Cannot load class "{0}" which has no zero-parameter constructor. - - - invalid flag after regular expression - - - Property {0} not found. - - - Expected argument to getClass() to be a Java object. - - - number format error - - - second argument to Function.prototype.apply must be an array - - - {0} is not an xml object. - - - The choice of Java method {0}.{1} matching JavaScript argument types ({2}) is ambiguous; candidate methods are: {3} - - - Constructor for "Packages" expects argument of type java.lang.Classloader - - - missing : after case expression - - - any catch clauses following an unqualified catch are unreachable - - - double default label in the switch statement - - - unterminated regular expression literal - - - continue must be inside loop - - - function "{0}" redeclared; prior definition will be ignored - - - Expected single parameter setter for {0} - - - Constructor for "{0}" not found. - - - syntax error - - - Overly large minimum {0} - - - missing '{' before function body - - - missing ] after element list - - - Found constructor with wrong signature: {0} calling {1} with signature {2} - - - Inappropriate array length. - - - missing while after do-loop body - - - Java constructor for "{0}" with arguments "{1}" not found. - - - ''try'' without ''catch'' or ''finally'' - - - Precision {0} out of range. - - - Java method "{0}" cannot be assigned to. - - - Cannot find function {0}. - - - Overly large maximum {0} - - - {0} is not a reference to set reference value tpo {1}. - - - Exceeded maximum stack depth - - - invalid instanceof usage - - - {0} is read-only - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + missing name after . operator + + + missing ( before function parameters. + + + no source found to decompile function reference {0} + + + missing } in compound statement + + + missing ) after formal parameters + + + missing name after .. operator + + + Program too complex: too big jump offset. + + + invalid property id + + + illegal character + + + Invalid increment operand. + + + Function {0} can not be used as the left-hand side of assignment or as an operand of ++ or -- operator. + + + unterminated string literal + + + Construction of objects of type "{0}" is not supported. + + + Internal error: type conversion of {0} to assign to {1} on {2} failed. + + + XML runtime not available + + + @IMPLEMENTATION.VERSION@ + + + missing ] in index expression + + + Java method "{0}" was invoked with {1} as "this" value that can not be converted to Java type {2}. + + + Method "{0}" must be static with the signature "(Context cx, Scriptable thisObj, Object[] args, Function funObj)" to define a variable arguments function. + + + Unterminated character class {0} + + + {0} must extend ScriptableObject in order to define property {1}. + + + missing ) after for-loop control + + + {0} is not a function, it is {1}. + + + invalid return + + + unmatched ) in regular expression. + + + In order to define a property, getter {0} must have zero parameters or a single ScriptableObject parameter. + + + Calling eval() with anything other than a primitive string value will simply return the value. Is this what you intended? + + + Function "{0}" must be called directly, and not by way of a function of another name. + + + missing ) after with-statement object + + + invalid Unicode escape sequence + + + Invalid assignment left-hand side. + + + missing '{' before catch-block body + + + no input for {0} + + + Cannot apply "with" to {0} + + + Calling eval() with anything other than a primitive string value is not allowed in the strict mode. + + + undefined labe + + + Only one argument may be specified if the first argument to RegExp.prototype.compile is a RegExp object. + + + Cannot import "{0}" since a property by that name is already defined. + + + Cyclic {0} value not allowed. + + + missing ; before statement + + + Two-parameter setter must take a ScriptableObject as its first parameter. + + + Java package names may not be numbers. + + + missing } after property list + + + Too deep recursion while parsing + + + Unterminated quantifier {0} + + + Program too complex: internal index exceeds 64K limit. + + + Unterminated parenthetical {0} + + + Attempt to assign non-existing name "{0}" in the strict mode. It could indicate a missing variable statement. + + + invalid switch statement + + + illegal octal literal digit {0}; interpreting it as a decimal digit + + + missing name after :: operator + + + missing ( after for + + + error instantiating ({0}): class {1} is interface or abstract + + + Cannot convert {0} to interface {1} with no methods + + + Function importPackage must be called with a package; had "{0}" instead. + + + Can''t find converter method "{0}" on class {1}. + + + Script objects are not constructors. + + + "{0}" may only be invoked from a "new" expression. + + + Maximum {0} less than minimum + + + "{0}" is not a constructor. + + + Array length {0} exceeds supported capacity limit. + + + Method "{0}" called on incompatible object. + + + missing : in conditional expression + + + Cannot convert undefined to an object. + + + missing ( before condition + + + Object''s getDefaultValue() method returned an object. + + + Invalid quantifier {0} + + + Regular expressions are not available. + + + Compilation produced {0} syntax errors. + + + illegally formed XML syntax + + + Overly large back reference {0} + + + Argument {0} is not Java class: {1}. + + + Cannot modify a property of a sealed object: {0}. + + + The "{0}" constructor is deprecated. + + + duplicatet label + + + missing } after function body + + + not a valid default namespace statement. Syntax is: default xml namespace = EXPRESSION; + + + Trailing \ in regular expression. + + + missing formal parameter + + + missing ) after switch expression + + + Primitive type expected (had {0} instead) + + + "{0}" is not defined. + + + missing '{' before switch body + + + invalid catch block condition + + + ''prototype'' property of {0} is not an object. + + + missing ) after condition + + + Can''t find method {0}. + + + The undefined value has no properties. + + + {0} is not a reference to read reference value. + + + Unsupported return type "{0}" in method "{1}". + + + Invalid JavaScript value of type {0} + + + missing ( before catch-block condition + + + Can''t define constructor or class {0} since more than one constructor has multiple parameters. + + + Cannot add a property to a sealed object: {0}. + + + Expected static or delegated setter {0} to take two parameters. + + + Malformed URI sequence. + + + continue can only use labeles of iteration statements + + + Namespace object expected to left of :: (found {0} instead) + + + Cannot set property "{1}" of {0} to "{2}" + + + Unsupported parameter type "{0}" in setter "{1}". + + + back-reference exceeds number of capturing parentheses. + + + Cannot convert {0} to {1} + + + Cannot remove a property from a sealed object: {0}. + + + Invalid left-hand side of for..in loop. + + + Unsupported parameter type "{0}" in method "{1}". + + + Invalid range in character class. + + + Ambiguous import: "{0}" and and "{1}". + + + Method or constructor "{0}" must be static with the signature "(Context cx, Object[] args, Function ctorObj, boolean inNewExpr)" to define a variable arguments constructor. + + + missing ; after for-loop condition + + + Expected either one or two parameters for setter. + + + Cannot delete property "{1}" of {0} + + + Function importClass must be called with a class; had "{0}" instead. + + + missing : after property id + + + Cannot find default value for object. + + + Cannot convert null to an object. + + + invalid label + + + missing variable name + + + Can''t convert to type "{0}". + + + Cannot read property "{1}" from {0} + + + Cannot convert function {0} to interface since it contains methods with different signatures + + + Method "{0}" occurs multiple times in class "{1}". + + + Cannot call method "{1}" of {0} + + + unlabelled break must be inside loop or switch + + + Getter and setter must both be static or neither be static. + + + missing ( before with-statement object + + + Only one variable allowed in for..in loop. + + + missing ; after for-loop initializer + + + identifier is a reserved word + + + Only one class may be extended by a JavaAdapter. Had {0} and {1}. + + + invalid variable initialization + + + JavaAdapter requires at least one argument. + + + illegal usage of future reserved keyword {0}; interpreting it as ordinary identifier + + + Unexpected end of file + + + missing name after .@ + + + Can''t use instanceof on a non-object. + + + missing ) after argument list + + + missing ) in parenthetical + + + missing exponent + + + Invalid decerement operand. + + + missing ( before switch expression + + + unterminated comment + + + Zero quantifier {0} + + + illegal radix {0}. + + + invalid string escape mask + + + Duplicate parameter name "{0}". + + + Java class "{0}" has no public instance field or method named "{1}". + + + Expected static or delegated getter {0} to take a ScriptableObject parameter. + + + Line terminator is not allowed between the throw keyword and throw expression. + + + Method "{0}" not found in "{1}". + + + The choice of Java constructor {0} matching JavaScript argument types ({1}) is ambiguous; candidate constructors are: {2} + + + Internal error: attempt to access private/protected field "{0}". + + + Cannot load class "{0}" which has no zero-parameter constructor. + + + invalid flag after regular expression + + + Property {0} not found. + + + Expected argument to getClass() to be a Java object. + + + number format error + + + second argument to Function.prototype.apply must be an array + + + {0} is not an xml object. + + + The choice of Java method {0}.{1} matching JavaScript argument types ({2}) is ambiguous; candidate methods are: {3} + + + Constructor for "Packages" expects argument of type java.lang.Classloader + + + missing : after case expression + + + any catch clauses following an unqualified catch are unreachable + + + double default label in the switch statement + + + unterminated regular expression literal + + + continue must be inside loop + + + function "{0}" redeclared; prior definition will be ignored + + + Expected single parameter setter for {0} + + + Constructor for "{0}" not found. + + + syntax error + + + Overly large minimum {0} + + + missing '{' before function body + + + missing ] after element list + + + Found constructor with wrong signature: {0} calling {1} with signature {2} + + + Inappropriate array length. + + + missing while after do-loop body + + + Java constructor for "{0}" with arguments "{1}" not found. + + + ''try'' without ''catch'' or ''finally'' + + + Precision {0} out of range. + + + Java method "{0}" cannot be assigned to. + + + Cannot find function {0}. + + + Overly large maximum {0} + + + {0} is not a reference to set reference value tpo {1}. + + + Exceeded maximum stack depth + + + invalid instanceof usage + + + {0} is read-only + \ No newline at end of file diff --git a/Code/EcmaScript.NET/Resources/TODO b/src/EcmaScript.NET/Resources/TODO similarity index 96% rename from Code/EcmaScript.NET/Resources/TODO rename to src/EcmaScript.NET/Resources/TODO index c273548..ac550d4 100644 --- a/Code/EcmaScript.NET/Resources/TODO +++ b/src/EcmaScript.NET/Resources/TODO @@ -1,36 +1,36 @@ -* Fix "NumberToString" Conversions (my math knowledge is too basic to figure out - how to write an algorithm which generates correct toString () representation of double) - -* DateTime tests fails with wrong (?) timezone (daylight saving time). - -* Remove ErrorReporter and make events (OnError, OnWarning) - -* Way too much public methods/classes - -* Way too much virtual methods - -* Fix Date Tests - -* Fix E4X part - -* .NET'ish lower case named methods - -* .NET'ish getXXX and setXXX methods - -* Tell Rhino guys about bugfixes made (e.g. /x{1}{1}/, RangeChecks in Array, ...) - -* Implement full JS 1.6 and JS 1.7 - -* Find a better solution for handling StackOverflowExceptions than using StackOverflowVerifier. - -* Fix Interpreter.InterpreterLoop throw (Excpetion)throwable which screwes up StackTrace - -* I've broken Array.toString () (reverted to original state - see #if FALSE in BuiltinArray.cs) - -* Merge NativeGlobal and NativeGlobalObject - -* Implement __noSucheMethod__ handler (see bug #196097) - -* Implement "LongRunningScript" Handler - -* Implement "const" keyword (http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Statements:const) +* Fix "NumberToString" Conversions (my math knowledge is too basic to figure out + how to write an algorithm which generates correct toString () representation of double) + +* DateTime tests fails with wrong (?) timezone (daylight saving time). + +* Remove ErrorReporter and make events (OnError, OnWarning) + +* Way too much public methods/classes + +* Way too much virtual methods + +* Fix Date Tests + +* Fix E4X part + +* .NET'ish lower case named methods + +* .NET'ish getXXX and setXXX methods + +* Tell Rhino guys about bugfixes made (e.g. /x{1}{1}/, RangeChecks in Array, ...) + +* Implement full JS 1.6 and JS 1.7 + +* Find a better solution for handling StackOverflowExceptions than using StackOverflowVerifier. + +* Fix Interpreter.InterpreterLoop throw (Excpetion)throwable which screwes up StackTrace + +* I've broken Array.toString () (reverted to original state - see #if FALSE in BuiltinArray.cs) + +* Merge NativeGlobal and NativeGlobalObject + +* Implement __noSucheMethod__ handler (see bug #196097) + +* Implement "LongRunningScript" Handler + +* Implement "const" keyword (http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Statements:const) diff --git a/Code/EcmaScript.NET/ScriptConvert.cs b/src/EcmaScript.NET/ScriptConvert.cs similarity index 97% rename from Code/EcmaScript.NET/ScriptConvert.cs rename to src/EcmaScript.NET/ScriptConvert.cs index 642f84f..f4071a0 100644 --- a/Code/EcmaScript.NET/ScriptConvert.cs +++ b/src/EcmaScript.NET/ScriptConvert.cs @@ -1,660 +1,660 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; -using System.Text; -using System.Globalization; - -namespace EcmaScript.NET -{ - - public sealed class ScriptConvert - { - - - /// - /// If character c is a hexadecimal digit, return - /// accumulator * 16 plus corresponding - /// number. Otherise return -1. - /// - internal static int XDigitToInt (int c, int accumulator) - { - { - // Use 0..9 < A..Z < a..z - if (c <= '9') { - c -= '0'; - if (0 <= c) { - - goto check_brk; - } - } - else if (c <= 'F') { - if ('A' <= c) { - c -= ('A' - 10); - - goto check_brk; - } - } - else if (c <= 'f') { - if ('a' <= c) { - c -= ('a' - 10); - - goto check_brk; - } - } - return -1; - } - - check_brk: - ; - - return (accumulator << 4) | c; - } - - - public static IScriptable ToObject (IScriptable scope, object val) - { - if (val is IScriptable) { - return (IScriptable)val; - } - return ToObject (null, scope, val); - } - - public static IScriptable ToObjectOrNull (Context cx, object obj) - { - if (obj is IScriptable) { - return (IScriptable)obj; - } - else if (obj != null && obj != Undefined.Value) { - return ToObject (cx, ScriptRuntime.getTopCallScope (cx), obj); - } - return null; - } - - /// Convert the value to an object. - /// - /// See ECMA 9.9. - /// - public static IScriptable ToObject (Context cx, IScriptable scope, object val) - { - if (val is IScriptable) { - return (IScriptable)val; - } - if (val == null) { - throw ScriptRuntime.TypeErrorById ("msg.null.to.object"); - } - if (val == Undefined.Value) { - throw ScriptRuntime.TypeErrorById ("msg.undef.to.object"); - } - string className = val is string ? "String" : (CliHelper.IsNumber (val) ? "Number" : (val is bool ? "Boolean" : null)); - if (className != null) { - object [] args = new object [] { val }; - scope = ScriptableObject.GetTopLevelScope (scope); - return ScriptRuntime.NewObject (cx == null ? Context.CurrentContext : cx, scope, className, args); - } - - // Extension: Wrap as a LiveConnect object. - object wrapped = cx.Wrap (scope, val, null); - if (wrapped is IScriptable) - return (IScriptable)wrapped; - throw ScriptRuntime.errorWithClassName ("msg.invalid.type", val); - } - - - /// - /// See ECMA 9.4. - /// - public static double ToInteger (object val) - { - return ToInteger (ToNumber (val)); - } - - // convenience method - public static double ToInteger (double d) - { - // if it's double.NaN - if (double.IsNaN (d)) - return +0.0; - - if (d == 0.0 || d == System.Double.PositiveInfinity || d == System.Double.NegativeInfinity) - return d; - - if (d > 0.0) - return Math.Floor (d); - else - return Math.Ceiling (d); - } - - public static double ToInteger (object [] args, int index) - { - return (index < args.Length) ? ToInteger (args [index]) : +0.0; - } - - /// - /// See ECMA 9.5. - /// - public static int ToInt32 (object val) - { - // short circuit for common integer values - if (val is int) - return ((int)val); - - return ToInt32 (ToNumber (val)); - } - - public static int ToInt32 (object [] args, int index) - { - return (index < args.Length) ? ToInt32 (args [index]) : 0; - } - - public static int ToInt32 (double d) - { - int id = (int)d; - if (id == d) { - // This covers -0.0 as well - return id; - } - - if (double.IsNaN (d) || d == System.Double.PositiveInfinity || d == System.Double.NegativeInfinity) { - return 0; - } - - d = (d >= 0) ? Math.Floor (d) : Math.Ceiling (d); - - double two32 = 4294967296.0; - d = Math.IEEERemainder (d, two32); - // (double)(long)d == d should hold here - - long l = (long)d; - // returning (int)d does not work as d can be outside int range - // but the result must always be 32 lower bits of l - return (int)l; - } - - /// See ECMA 9.6. - /// long value representing 32 bits unsigned integer - /// - public static long ToUint32 (double d) - { - long l = (long)d; - if (l == d) { - // This covers -0.0 as well - return l & 0xffffffffL; - } - - if (double.IsNaN (d) || d == System.Double.PositiveInfinity || d == System.Double.NegativeInfinity) { - return 0; - } - - d = (d >= 0) ? Math.Floor (d) : Math.Ceiling (d); - - double two32 = 4294967296.0; - l = (long)Math.IEEERemainder (d, two32); - unchecked { - return l & (int)0xffffffffL; - } - } - - public static long ToUint32 (object val) - { - return ToUint32 (ToNumber (val)); - } - - - /// Convert the value to a boolean. - /// - /// See ECMA 9.2. - /// - public static bool ToBoolean (object val) - { - for (; ; ) { - if (val is bool) - return ((bool)val); - if (val == null || val == Undefined.Value) - return false; - if (val is string) - return ((string)val).Length != 0; - if (CliHelper.IsNumber (val)) { - double d = Convert.ToDouble (val); - return (!double.IsNaN (d) && d != 0.0); - } - if (val is IScriptable) { - if (Context.CurrentContext.VersionECMA1) { - // pure ECMA - return true; - } - // ECMA extension - val = ((IScriptable)val).GetDefaultValue (typeof (bool)); - if (val is IScriptable) - throw ScriptRuntime.errorWithClassName ("msg.primitive.expected", val); - continue; - } - ScriptRuntime.WarnAboutNonJSObject (val); - return true; - } - } - - public static bool ToBoolean (object [] args, int index) - { - return (index < args.Length) ? ToBoolean (args [index]) : false; - } - - /// Convert the value to a number. - /// - /// See ECMA 9.3. - /// - public static double ToNumber (object val) - { - for (; ; ) { - if (val is double) - return (double)val; - if (CliHelper.IsNumber (val)) - return Convert.ToDouble (val); - if (val == null) - return +0.0; - if (val == Undefined.Value) - return double.NaN; - if (val is string) - return ToNumber ((string)val); - if (val is bool) - return ((bool)val) ? 1 : +0.0; - if (val is IScriptable) { - val = ((IScriptable)val).GetDefaultValue (typeof (long)); - if (val is IScriptable) - throw ScriptRuntime.errorWithClassName ("msg.primitive.expected", val); - continue; - } - ScriptRuntime.WarnAboutNonJSObject (val); - return double.NaN; - } - } - - public static double ToNumber (object [] args, int index) - { - return (index < args.Length) ? ToNumber (args [index]) : double.NaN; - } - - internal static double ToNumber (string s, int start, int radix) - { - char digitMax = '9'; - char lowerCaseBound = 'a'; - char upperCaseBound = 'A'; - int len = s.Length; - if (radix < 10) { - digitMax = (char)('0' + radix - 1); - } - if (radix > 10) { - lowerCaseBound = (char)('a' + radix - 10); - upperCaseBound = (char)('A' + radix - 10); - } - int end; - double sum = 0.0; - for (end = start; end < len; end++) { - char c = s [end]; - int newDigit; - if ('0' <= c && c <= digitMax) - newDigit = c - '0'; - else if ('a' <= c && c < lowerCaseBound) - newDigit = c - 'a' + 10; - else if ('A' <= c && c < upperCaseBound) - newDigit = c - 'A' + 10; - else - break; - sum = sum * radix + newDigit; - } - if (start == end) { - return double.NaN; - } - if (sum >= 9007199254740992.0) { - if (radix == 10) { - /* If we're accumulating a decimal number and the number - * is >= 2^53, then the result from the repeated multiply-add - * above may be inaccurate. Call Java to get the correct - * answer. - */ - try { - return System.Double.Parse (s.Substring (start, (end) - (start))); - } - catch (System.FormatException) { - return double.NaN; - } - } - else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32) { - /* The number may also be inaccurate for one of these bases. - * This happens if the addition in value*radix + digit causes - * a round-down to an even least significant mantissa bit - * when the first dropped bit is a one. If any of the - * following digits in the number (which haven't been added - * in yet) are nonzero then the correct action would have - * been to round up instead of down. An example of this - * occurs when reading the number 0x1000000000000081, which - * rounds to 0x1000000000000000 instead of 0x1000000000000100. - */ - int bitShiftInChar = 1; - int digit = 0; - - const int SKIP_LEADING_ZEROS = 0; - const int FIRST_EXACT_53_BITS = 1; - const int AFTER_BIT_53 = 2; - const int ZEROS_AFTER_54 = 3; - const int MIXED_AFTER_54 = 4; - - int state = SKIP_LEADING_ZEROS; - int exactBitsLimit = 53; - double factor = 0.0; - bool bit53 = false; - // bit54 is the 54th bit (the first dropped from the mantissa) - bool bit54 = false; - - for (; ; ) { - if (bitShiftInChar == 1) { - if (start == end) - break; - digit = s [start++]; - if ('0' <= digit && digit <= '9') - digit -= '0'; - else if ('a' <= digit && digit <= 'z') - digit -= ('a' - 10); - else - digit -= ('A' - 10); - bitShiftInChar = radix; - } - bitShiftInChar >>= 1; - bool bit = (digit & bitShiftInChar) != 0; - - switch (state) { - - case SKIP_LEADING_ZEROS: - if (bit) { - --exactBitsLimit; - sum = 1.0; - state = FIRST_EXACT_53_BITS; - } - break; - - case FIRST_EXACT_53_BITS: - sum *= 2.0; - if (bit) - sum += 1.0; - --exactBitsLimit; - if (exactBitsLimit == 0) { - bit53 = bit; - state = AFTER_BIT_53; - } - break; - - case AFTER_BIT_53: - bit54 = bit; - factor = 2.0; - state = ZEROS_AFTER_54; - break; - - case ZEROS_AFTER_54: - if (bit) { - state = MIXED_AFTER_54; - } - // fallthrough - goto case MIXED_AFTER_54; - - case MIXED_AFTER_54: - factor *= 2; - break; - } - } - switch (state) { - - case SKIP_LEADING_ZEROS: - sum = 0.0; - break; - - case FIRST_EXACT_53_BITS: - case AFTER_BIT_53: - // do nothing - break; - - case ZEROS_AFTER_54: - // x1.1 -> x1 + 1 (round up) - // x0.1 -> x0 (round down) - if (bit54 & bit53) - sum += 1.0; - sum *= factor; - break; - - case MIXED_AFTER_54: - // x.100...1.. -> x + 1 (round up) - // x.0anything -> x (round down) - if (bit54) - sum += 1.0; - sum *= factor; - break; - } - } - /* We don't worry about inaccurate numbers for any other base. */ - } - return sum; - } - - - public static string ToString (object [] args, int index) - { - return (index < args.Length) ? ToString (args [index]) : "undefined"; - } - - internal static object ToPrimitive (object val) - { - if (!(val is IScriptable)) { - return val; - } - IScriptable s = (IScriptable)val; - object result = s.GetDefaultValue (null); - if (result is IScriptable) - throw ScriptRuntime.TypeErrorById ("msg.bad.default.value"); - return result; - } - - /// Convert the value to a string. - /// - /// See ECMA 9.8. - /// - public static string ToString (object val) - { - for (; ; ) { - if (val == null) { - return "null"; - } - if (val == Undefined.Value) { - return "undefined"; - } - if (val is string) { - return (string)val; - } - if (val is Boolean) - return ((bool)val) ? "true" : "false"; - if (CliHelper.IsNumber (val)) { - // TODO: should we just teach NativeNumber.stringValue() - // TODO: about Numbers? - return ToString (Convert.ToDouble (val), 10); - } - if (val is IScriptable) { - val = ((IScriptable)val).GetDefaultValue (typeof (string)); - if (val is IScriptable) { - throw ScriptRuntime.errorWithClassName ("msg.primitive.expected", val); - } - continue; - } - return val.ToString (); - } - } - - - - /// ToNumber applied to the String type - /// - /// See ECMA 9.3.1 - /// - public static double ToNumber (string input) - { - int len = input.Length; - int start = 0; - char [] chars = input.ToCharArray (); - char startChar; - for (; ; ) { - if (start == len) { - // Empty or contains only whitespace - return +0.0; - } - startChar = chars [start]; - if (!char.IsWhiteSpace (startChar)) - break; - start++; - } - - if (startChar == '0') { - if (start + 2 < len) { - int c1 = chars [start + 1]; - if (c1 == 'x' || c1 == 'X') { - // A hexadecimal number - return ToNumber (input, start + 2, 16); - } - } - } - else if (startChar == '+' || startChar == '-') { - if (start + 3 < len && chars [start + 1] == '0') { - int c2 = chars [start + 2]; - if (c2 == 'x' || c2 == 'X') { - // A hexadecimal number with sign - double val = ToNumber (input, start + 3, 16); - return startChar == '-' ? -val : val; - } - } - } - - int end = len - 1; - char endChar; - while (char.IsWhiteSpace (endChar = chars [end])) - end--; - if (endChar == 'y') { - // check for "Infinity" - if (startChar == '+' || startChar == '-') - start++; - if (start + 7 == end && String.Compare (input, start, "Infinity", 0, 8) == 0) - return startChar == '-' ? System.Double.NegativeInfinity : System.Double.PositiveInfinity; - return double.NaN; - } - // A non-hexadecimal, non-infinity number: - // just try a normal floating point conversion - string sub = input.Substring (start, (end + 1) - (start)); - - // MS.NET will accept non-conformant strings - // rather than throwing a NumberFormatException - // as it should (like with \0). - for (int i = sub.Length - 1; i >= 0; i--) { - char c = sub [i]; - if (('0' <= c && c <= '9') || c == '.' || - c == 'e' || c == 'E' || - c == '+' || c == '-') - continue; - return double.NaN; - } - - try { - double ret = double.Parse (sub); - if (ret == 0) { - // IMHO a bug in MS.NET: double.Parse("-0.0") == 0.0 so we retard the "-" sign here - if (sub [0] == '-') - ret = -ret; - } - return ret; - } - catch (OverflowException) { - // HACK - if (sub [0] == '-') - return double.NegativeInfinity; - else - return double.PositiveInfinity; - } - catch (Exception) { - return double.NaN; - } - } - - /// - /// See ECMA 9.7. - /// - public static char ToUint16 (object val) - { - double d = ToNumber (val); - - int i = (int)d; - if (i == d) { - return (char)i; - } - - if (double.IsNaN (d) || d == System.Double.PositiveInfinity || d == System.Double.NegativeInfinity) { - return (char)(0); - } - - d = (d >= 0) ? Math.Floor (d) : Math.Ceiling (d); - - int int16 = 0x10000; - i = (int)Math.IEEERemainder (d, int16); - return (char)i; - } - - /// Optimized version of toString(Object) for numbers. - public static string ToString (double val) - { - return ToString (val, 10); - } - - /// - /// See ECMA 9.8.1 - /// - /// - /// - /// - public static string ToString (double d, int toBase) - { - if (double.IsNaN (d)) - return "NaN"; - if (d == System.Double.PositiveInfinity) - return "Infinity"; - if (d == System.Double.NegativeInfinity) - return "-Infinity"; - if (d == 0.0) - return "0"; - - if ((toBase < 2) || (toBase > 36)) { - throw Context.ReportRuntimeErrorById ("msg.bad.radix", Convert.ToString (toBase)); - } - - if (double.IsNaN (d)) - return "NaN"; - else if (Double.IsPositiveInfinity (d)) - return "Infinity"; - else if (Double.IsNegativeInfinity (d)) - return "-Infinity"; - else { - // BugFix: Item 9856 - g16 yields better results than "g". Not perfect, but better - string ret = d.ToString ("g16"); - // TODO: This is plain wrong, but as close as we can get - // without converting DtoA to C#. - return ret; - } - } - - - - } - -} +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; +using System.Text; +using System.Globalization; + +namespace EcmaScript.NET +{ + + public sealed class ScriptConvert + { + + + /// + /// If character c is a hexadecimal digit, return + /// accumulator * 16 plus corresponding + /// number. Otherise return -1. + /// + internal static int XDigitToInt (int c, int accumulator) + { + { + // Use 0..9 < A..Z < a..z + if (c <= '9') { + c -= '0'; + if (0 <= c) { + + goto check_brk; + } + } + else if (c <= 'F') { + if ('A' <= c) { + c -= ('A' - 10); + + goto check_brk; + } + } + else if (c <= 'f') { + if ('a' <= c) { + c -= ('a' - 10); + + goto check_brk; + } + } + return -1; + } + + check_brk: + ; + + return (accumulator << 4) | c; + } + + + public static IScriptable ToObject (IScriptable scope, object val) + { + if (val is IScriptable) { + return (IScriptable)val; + } + return ToObject (null, scope, val); + } + + public static IScriptable ToObjectOrNull (Context cx, object obj) + { + if (obj is IScriptable) { + return (IScriptable)obj; + } + else if (obj != null && obj != Undefined.Value) { + return ToObject (cx, ScriptRuntime.getTopCallScope (cx), obj); + } + return null; + } + + /// Convert the value to an object. + /// + /// See ECMA 9.9. + /// + public static IScriptable ToObject (Context cx, IScriptable scope, object val) + { + if (val is IScriptable) { + return (IScriptable)val; + } + if (val == null) { + throw ScriptRuntime.TypeErrorById ("msg.null.to.object"); + } + if (val == Undefined.Value) { + throw ScriptRuntime.TypeErrorById ("msg.undef.to.object"); + } + string className = val is string ? "String" : (CliHelper.IsNumber (val) ? "Number" : (val is bool ? "Boolean" : null)); + if (className != null) { + object [] args = new object [] { val }; + scope = ScriptableObject.GetTopLevelScope (scope); + return ScriptRuntime.NewObject (cx == null ? Context.CurrentContext : cx, scope, className, args); + } + + // Extension: Wrap as a LiveConnect object. + object wrapped = cx.Wrap (scope, val, null); + if (wrapped is IScriptable) + return (IScriptable)wrapped; + throw ScriptRuntime.errorWithClassName ("msg.invalid.type", val); + } + + + /// + /// See ECMA 9.4. + /// + public static double ToInteger (object val) + { + return ToInteger (ToNumber (val)); + } + + // convenience method + public static double ToInteger (double d) + { + // if it's double.NaN + if (double.IsNaN (d)) + return +0.0; + + if (d == 0.0 || d == System.Double.PositiveInfinity || d == System.Double.NegativeInfinity) + return d; + + if (d > 0.0) + return Math.Floor (d); + else + return Math.Ceiling (d); + } + + public static double ToInteger (object [] args, int index) + { + return (index < args.Length) ? ToInteger (args [index]) : +0.0; + } + + /// + /// See ECMA 9.5. + /// + public static int ToInt32 (object val) + { + // short circuit for common integer values + if (val is int) + return ((int)val); + + return ToInt32 (ToNumber (val)); + } + + public static int ToInt32 (object [] args, int index) + { + return (index < args.Length) ? ToInt32 (args [index]) : 0; + } + + public static int ToInt32 (double d) + { + int id = (int)d; + if (id == d) { + // This covers -0.0 as well + return id; + } + + if (double.IsNaN (d) || d == System.Double.PositiveInfinity || d == System.Double.NegativeInfinity) { + return 0; + } + + d = (d >= 0) ? Math.Floor (d) : Math.Ceiling (d); + + double two32 = 4294967296.0; + d = Math.IEEERemainder (d, two32); + // (double)(long)d == d should hold here + + long l = (long)d; + // returning (int)d does not work as d can be outside int range + // but the result must always be 32 lower bits of l + return (int)l; + } + + /// See ECMA 9.6. + /// long value representing 32 bits unsigned integer + /// + public static long ToUint32 (double d) + { + long l = (long)d; + if (l == d) { + // This covers -0.0 as well + return l & 0xffffffffL; + } + + if (double.IsNaN (d) || d == System.Double.PositiveInfinity || d == System.Double.NegativeInfinity) { + return 0; + } + + d = (d >= 0) ? Math.Floor (d) : Math.Ceiling (d); + + double two32 = 4294967296.0; + l = (long)Math.IEEERemainder (d, two32); + unchecked { + return l & (int)0xffffffffL; + } + } + + public static long ToUint32 (object val) + { + return ToUint32 (ToNumber (val)); + } + + + /// Convert the value to a boolean. + /// + /// See ECMA 9.2. + /// + public static bool ToBoolean (object val) + { + for (; ; ) { + if (val is bool) + return ((bool)val); + if (val == null || val == Undefined.Value) + return false; + if (val is string) + return ((string)val).Length != 0; + if (CliHelper.IsNumber (val)) { + double d = Convert.ToDouble (val); + return (!double.IsNaN (d) && d != 0.0); + } + if (val is IScriptable) { + if (Context.CurrentContext.VersionECMA1) { + // pure ECMA + return true; + } + // ECMA extension + val = ((IScriptable)val).GetDefaultValue (typeof (bool)); + if (val is IScriptable) + throw ScriptRuntime.errorWithClassName ("msg.primitive.expected", val); + continue; + } + ScriptRuntime.WarnAboutNonJSObject (val); + return true; + } + } + + public static bool ToBoolean (object [] args, int index) + { + return (index < args.Length) ? ToBoolean (args [index]) : false; + } + + /// Convert the value to a number. + /// + /// See ECMA 9.3. + /// + public static double ToNumber (object val) + { + for (; ; ) { + if (val is double) + return (double)val; + if (CliHelper.IsNumber (val)) + return Convert.ToDouble (val); + if (val == null) + return +0.0; + if (val == Undefined.Value) + return double.NaN; + if (val is string) + return ToNumber ((string)val); + if (val is bool) + return ((bool)val) ? 1 : +0.0; + if (val is IScriptable) { + val = ((IScriptable)val).GetDefaultValue (typeof (long)); + if (val is IScriptable) + throw ScriptRuntime.errorWithClassName ("msg.primitive.expected", val); + continue; + } + ScriptRuntime.WarnAboutNonJSObject (val); + return double.NaN; + } + } + + public static double ToNumber (object [] args, int index) + { + return (index < args.Length) ? ToNumber (args [index]) : double.NaN; + } + + internal static double ToNumber (string s, int start, int radix) + { + char digitMax = '9'; + char lowerCaseBound = 'a'; + char upperCaseBound = 'A'; + int len = s.Length; + if (radix < 10) { + digitMax = (char)('0' + radix - 1); + } + if (radix > 10) { + lowerCaseBound = (char)('a' + radix - 10); + upperCaseBound = (char)('A' + radix - 10); + } + int end; + double sum = 0.0; + for (end = start; end < len; end++) { + char c = s [end]; + int newDigit; + if ('0' <= c && c <= digitMax) + newDigit = c - '0'; + else if ('a' <= c && c < lowerCaseBound) + newDigit = c - 'a' + 10; + else if ('A' <= c && c < upperCaseBound) + newDigit = c - 'A' + 10; + else + break; + sum = sum * radix + newDigit; + } + if (start == end) { + return double.NaN; + } + if (sum >= 9007199254740992.0) { + if (radix == 10) { + /* If we're accumulating a decimal number and the number + * is >= 2^53, then the result from the repeated multiply-add + * above may be inaccurate. Call Java to get the correct + * answer. + */ + try { + return System.Double.Parse (s.Substring (start, (end) - (start))); + } + catch (System.FormatException) { + return double.NaN; + } + } + else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32) { + /* The number may also be inaccurate for one of these bases. + * This happens if the addition in value*radix + digit causes + * a round-down to an even least significant mantissa bit + * when the first dropped bit is a one. If any of the + * following digits in the number (which haven't been added + * in yet) are nonzero then the correct action would have + * been to round up instead of down. An example of this + * occurs when reading the number 0x1000000000000081, which + * rounds to 0x1000000000000000 instead of 0x1000000000000100. + */ + int bitShiftInChar = 1; + int digit = 0; + + const int SKIP_LEADING_ZEROS = 0; + const int FIRST_EXACT_53_BITS = 1; + const int AFTER_BIT_53 = 2; + const int ZEROS_AFTER_54 = 3; + const int MIXED_AFTER_54 = 4; + + int state = SKIP_LEADING_ZEROS; + int exactBitsLimit = 53; + double factor = 0.0; + bool bit53 = false; + // bit54 is the 54th bit (the first dropped from the mantissa) + bool bit54 = false; + + for (; ; ) { + if (bitShiftInChar == 1) { + if (start == end) + break; + digit = s [start++]; + if ('0' <= digit && digit <= '9') + digit -= '0'; + else if ('a' <= digit && digit <= 'z') + digit -= ('a' - 10); + else + digit -= ('A' - 10); + bitShiftInChar = radix; + } + bitShiftInChar >>= 1; + bool bit = (digit & bitShiftInChar) != 0; + + switch (state) { + + case SKIP_LEADING_ZEROS: + if (bit) { + --exactBitsLimit; + sum = 1.0; + state = FIRST_EXACT_53_BITS; + } + break; + + case FIRST_EXACT_53_BITS: + sum *= 2.0; + if (bit) + sum += 1.0; + --exactBitsLimit; + if (exactBitsLimit == 0) { + bit53 = bit; + state = AFTER_BIT_53; + } + break; + + case AFTER_BIT_53: + bit54 = bit; + factor = 2.0; + state = ZEROS_AFTER_54; + break; + + case ZEROS_AFTER_54: + if (bit) { + state = MIXED_AFTER_54; + } + // fallthrough + goto case MIXED_AFTER_54; + + case MIXED_AFTER_54: + factor *= 2; + break; + } + } + switch (state) { + + case SKIP_LEADING_ZEROS: + sum = 0.0; + break; + + case FIRST_EXACT_53_BITS: + case AFTER_BIT_53: + // do nothing + break; + + case ZEROS_AFTER_54: + // x1.1 -> x1 + 1 (round up) + // x0.1 -> x0 (round down) + if (bit54 & bit53) + sum += 1.0; + sum *= factor; + break; + + case MIXED_AFTER_54: + // x.100...1.. -> x + 1 (round up) + // x.0anything -> x (round down) + if (bit54) + sum += 1.0; + sum *= factor; + break; + } + } + /* We don't worry about inaccurate numbers for any other base. */ + } + return sum; + } + + + public static string ToString (object [] args, int index) + { + return (index < args.Length) ? ToString (args [index]) : "undefined"; + } + + internal static object ToPrimitive (object val) + { + if (!(val is IScriptable)) { + return val; + } + IScriptable s = (IScriptable)val; + object result = s.GetDefaultValue (null); + if (result is IScriptable) + throw ScriptRuntime.TypeErrorById ("msg.bad.default.value"); + return result; + } + + /// Convert the value to a string. + /// + /// See ECMA 9.8. + /// + public static string ToString (object val) + { + for (; ; ) { + if (val == null) { + return "null"; + } + if (val == Undefined.Value) { + return "undefined"; + } + if (val is string) { + return (string)val; + } + if (val is Boolean) + return ((bool)val) ? "true" : "false"; + if (CliHelper.IsNumber (val)) { + // TODO: should we just teach NativeNumber.stringValue() + // TODO: about Numbers? + return ToString (Convert.ToDouble (val), 10); + } + if (val is IScriptable) { + val = ((IScriptable)val).GetDefaultValue (typeof (string)); + if (val is IScriptable) { + throw ScriptRuntime.errorWithClassName ("msg.primitive.expected", val); + } + continue; + } + return val.ToString (); + } + } + + + + /// ToNumber applied to the String type + /// + /// See ECMA 9.3.1 + /// + public static double ToNumber (string input) + { + int len = input.Length; + int start = 0; + char [] chars = input.ToCharArray (); + char startChar; + for (; ; ) { + if (start == len) { + // Empty or contains only whitespace + return +0.0; + } + startChar = chars [start]; + if (!char.IsWhiteSpace (startChar)) + break; + start++; + } + + if (startChar == '0') { + if (start + 2 < len) { + int c1 = chars [start + 1]; + if (c1 == 'x' || c1 == 'X') { + // A hexadecimal number + return ToNumber (input, start + 2, 16); + } + } + } + else if (startChar == '+' || startChar == '-') { + if (start + 3 < len && chars [start + 1] == '0') { + int c2 = chars [start + 2]; + if (c2 == 'x' || c2 == 'X') { + // A hexadecimal number with sign + double val = ToNumber (input, start + 3, 16); + return startChar == '-' ? -val : val; + } + } + } + + int end = len - 1; + char endChar; + while (char.IsWhiteSpace (endChar = chars [end])) + end--; + if (endChar == 'y') { + // check for "Infinity" + if (startChar == '+' || startChar == '-') + start++; + if (start + 7 == end && String.Compare (input, start, "Infinity", 0, 8) == 0) + return startChar == '-' ? System.Double.NegativeInfinity : System.Double.PositiveInfinity; + return double.NaN; + } + // A non-hexadecimal, non-infinity number: + // just try a normal floating point conversion + string sub = input.Substring (start, (end + 1) - (start)); + + // MS.NET will accept non-conformant strings + // rather than throwing a NumberFormatException + // as it should (like with \0). + for (int i = sub.Length - 1; i >= 0; i--) { + char c = sub [i]; + if (('0' <= c && c <= '9') || c == '.' || + c == 'e' || c == 'E' || + c == '+' || c == '-') + continue; + return double.NaN; + } + + try { + double ret = double.Parse (sub); + if (ret == 0) { + // IMHO a bug in MS.NET: double.Parse("-0.0") == 0.0 so we retard the "-" sign here + if (sub [0] == '-') + ret = -ret; + } + return ret; + } + catch (OverflowException) { + // HACK + if (sub [0] == '-') + return double.NegativeInfinity; + else + return double.PositiveInfinity; + } + catch (Exception) { + return double.NaN; + } + } + + /// + /// See ECMA 9.7. + /// + public static char ToUint16 (object val) + { + double d = ToNumber (val); + + int i = (int)d; + if (i == d) { + return (char)i; + } + + if (double.IsNaN (d) || d == System.Double.PositiveInfinity || d == System.Double.NegativeInfinity) { + return (char)(0); + } + + d = (d >= 0) ? Math.Floor (d) : Math.Ceiling (d); + + int int16 = 0x10000; + i = (int)Math.IEEERemainder (d, int16); + return (char)i; + } + + /// Optimized version of toString(Object) for numbers. + public static string ToString (double val) + { + return ToString (val, 10); + } + + /// + /// See ECMA 9.8.1 + /// + /// + /// + /// + public static string ToString (double d, int toBase) + { + if (double.IsNaN (d)) + return "NaN"; + if (d == System.Double.PositiveInfinity) + return "Infinity"; + if (d == System.Double.NegativeInfinity) + return "-Infinity"; + if (d == 0.0) + return "0"; + + if ((toBase < 2) || (toBase > 36)) { + throw Context.ReportRuntimeErrorById ("msg.bad.radix", Convert.ToString (toBase)); + } + + if (double.IsNaN (d)) + return "NaN"; + else if (Double.IsPositiveInfinity (d)) + return "Infinity"; + else if (Double.IsNegativeInfinity (d)) + return "-Infinity"; + else { + // BugFix: Item 9856 - g16 yields better results than "g". Not perfect, but better + string ret = d.ToString ("g16"); + // TODO: This is plain wrong, but as close as we can get + // without converting DtoA to C#. + return ret; + } + } + + + + } + +} diff --git a/Code/EcmaScript.NET/ScriptOrFnNode.cs b/src/EcmaScript.NET/ScriptOrFnNode.cs similarity index 95% rename from Code/EcmaScript.NET/ScriptOrFnNode.cs rename to src/EcmaScript.NET/ScriptOrFnNode.cs index 6e4e45c..323616b 100644 --- a/Code/EcmaScript.NET/ScriptOrFnNode.cs +++ b/src/EcmaScript.NET/ScriptOrFnNode.cs @@ -1,278 +1,278 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -using EcmaScript.NET.Collections; - -namespace EcmaScript.NET -{ - - public class ScriptOrFnNode : Node - { - virtual public string SourceName - { - get - { - return sourceName; - } - - set - { - this.sourceName = value; - } - - } - virtual public int EncodedSourceStart - { - get - { - return encodedSourceStart; - } - - } - virtual public int EncodedSourceEnd - { - get - { - return encodedSourceEnd; - } - - } - virtual public int BaseLineno - { - get - { - return baseLineno; - } - - set - { - // One time action - if (value < 0 || baseLineno >= 0) - Context.CodeBug (); - baseLineno = value; - } - - } - virtual public int EndLineno - { - get - { - return baseLineno; - } - - set - { - // One time action - if (value < 0 || endLineno >= 0) - Context.CodeBug (); - endLineno = value; - } - - } - virtual public int FunctionCount - { - get - { - if (functions == null) { - return 0; - } - return functions.size (); - } - - } - virtual public int RegexpCount - { - get - { - if (regexps == null) { - return 0; - } - return regexps.size () / 2; - } - - } - virtual public int ParamCount - { - get - { - return varStart; - } - - } - virtual public int ParamAndVarCount - { - get - { - return itsVariables.size (); - } - - } - virtual public string [] ParamAndVarNames - { - get - { - int N = itsVariables.size (); - if (N == 0) { - return ScriptRuntime.EmptyStrings; - } - string [] array = new string [N]; - itsVariables.ToArray (array); - return array; - } - - } - virtual public object CompilerData - { - get - { - return compilerData; - } - - set - { - if (value == null) - throw new ArgumentException (); - // Can only call once - if (compilerData != null) - throw new ApplicationException (); - compilerData = value; - } - - } - - public ScriptOrFnNode (int nodeType) - : base (nodeType) - { - } - - public void setEncodedSourceBounds (int start, int end) - { - this.encodedSourceStart = start; - this.encodedSourceEnd = end; - } - - public FunctionNode getFunctionNode (int i) - { - return (FunctionNode)functions.Get (i); - } - - public int addFunction (FunctionNode fnNode) - { - if (fnNode == null) - Context.CodeBug (); - if (functions == null) { - functions = new ObjArray (); - } - functions.add (fnNode); - return functions.size () - 1; - } - - public string getRegexpString (int index) - { - return (string)regexps.Get (index * 2); - } - - public string getRegexpFlags (int index) - { - return (string)regexps.Get (index * 2 + 1); - } - - public int addRegexp (string str, string flags) - { - if (str == null) - Context.CodeBug (); - if (regexps == null) { - regexps = new ObjArray (); - } - regexps.add (str); - regexps.add (flags); - return regexps.size () / 2 - 1; - } - - public bool hasParamOrVar (string name) - { - return itsVariableNames.has (name); - } - - public int getParamOrVarIndex (string name) - { - return itsVariableNames.Get (name, -1); - } - - public string getParamOrVarName (int index) - { - return (string)itsVariables.Get (index); - } - - public void addParam (string name) - { - // Check addparam is not called after addLocal - if (varStart != itsVariables.size ()) - Context.CodeBug (); - // Allow non-unique parameter names: use the last occurrence - int index = varStart++; - itsVariables.add (name); - itsVariableNames.put (name, index); - } - - public void addVar (string name) - { - int vIndex = itsVariableNames.Get (name, -1); - if (vIndex != -1) { - // There's already a variable or parameter with this name. - return; - } - int index = itsVariables.size (); - itsVariables.add (name); - itsVariableNames.put (name, index); - } - - public void removeParamOrVar (string name) - { - int i = itsVariableNames.Get (name, -1); - if (i != -1) { - itsVariables.remove (i); - itsVariableNames.remove (name); - ObjToIntMap.Iterator iter = itsVariableNames.newIterator (); - for (iter.start (); !iter.done (); iter.next ()) { - int v = iter.Value; - if (v > i) { - iter.Value = v - 1; - } - } - } - } - - private int encodedSourceStart; - private int encodedSourceEnd; - private string sourceName; - private int baseLineno = -1; - private int endLineno = -1; - - private ObjArray functions; - - private ObjArray regexps; - - // a list of the formal parameters and local variables - private ObjArray itsVariables = new ObjArray (); - - // mapping from name to index in list - private ObjToIntMap itsVariableNames = new ObjToIntMap (11); - - private int varStart; // index in list of first variable - - private object compilerData; - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +using EcmaScript.NET.Collections; + +namespace EcmaScript.NET +{ + + public class ScriptOrFnNode : Node + { + virtual public string SourceName + { + get + { + return sourceName; + } + + set + { + this.sourceName = value; + } + + } + virtual public int EncodedSourceStart + { + get + { + return encodedSourceStart; + } + + } + virtual public int EncodedSourceEnd + { + get + { + return encodedSourceEnd; + } + + } + virtual public int BaseLineno + { + get + { + return baseLineno; + } + + set + { + // One time action + if (value < 0 || baseLineno >= 0) + Context.CodeBug (); + baseLineno = value; + } + + } + virtual public int EndLineno + { + get + { + return baseLineno; + } + + set + { + // One time action + if (value < 0 || endLineno >= 0) + Context.CodeBug (); + endLineno = value; + } + + } + virtual public int FunctionCount + { + get + { + if (functions == null) { + return 0; + } + return functions.size (); + } + + } + virtual public int RegexpCount + { + get + { + if (regexps == null) { + return 0; + } + return regexps.size () / 2; + } + + } + virtual public int ParamCount + { + get + { + return varStart; + } + + } + virtual public int ParamAndVarCount + { + get + { + return itsVariables.size (); + } + + } + virtual public string [] ParamAndVarNames + { + get + { + int N = itsVariables.size (); + if (N == 0) { + return ScriptRuntime.EmptyStrings; + } + string [] array = new string [N]; + itsVariables.ToArray (array); + return array; + } + + } + virtual public object CompilerData + { + get + { + return compilerData; + } + + set + { + if (value == null) + throw new ArgumentException (); + // Can only call once + if (compilerData != null) + throw new Exception (); + compilerData = value; + } + + } + + public ScriptOrFnNode (int nodeType) + : base (nodeType) + { + } + + public void setEncodedSourceBounds (int start, int end) + { + this.encodedSourceStart = start; + this.encodedSourceEnd = end; + } + + public FunctionNode getFunctionNode (int i) + { + return (FunctionNode)functions.Get (i); + } + + public int addFunction (FunctionNode fnNode) + { + if (fnNode == null) + Context.CodeBug (); + if (functions == null) { + functions = new ObjArray (); + } + functions.add (fnNode); + return functions.size () - 1; + } + + public string getRegexpString (int index) + { + return (string)regexps.Get (index * 2); + } + + public string getRegexpFlags (int index) + { + return (string)regexps.Get (index * 2 + 1); + } + + public int addRegexp (string str, string flags) + { + if (str == null) + Context.CodeBug (); + if (regexps == null) { + regexps = new ObjArray (); + } + regexps.add (str); + regexps.add (flags); + return regexps.size () / 2 - 1; + } + + public bool hasParamOrVar (string name) + { + return itsVariableNames.has (name); + } + + public int getParamOrVarIndex (string name) + { + return itsVariableNames.Get (name, -1); + } + + public string getParamOrVarName (int index) + { + return (string)itsVariables.Get (index); + } + + public void addParam (string name) + { + // Check addparam is not called after addLocal + if (varStart != itsVariables.size ()) + Context.CodeBug (); + // Allow non-unique parameter names: use the last occurrence + int index = varStart++; + itsVariables.add (name); + itsVariableNames.put (name, index); + } + + public void addVar (string name) + { + int vIndex = itsVariableNames.Get (name, -1); + if (vIndex != -1) { + // There's already a variable or parameter with this name. + return; + } + int index = itsVariables.size (); + itsVariables.add (name); + itsVariableNames.put (name, index); + } + + public void removeParamOrVar (string name) + { + int i = itsVariableNames.Get (name, -1); + if (i != -1) { + itsVariables.remove (i); + itsVariableNames.remove (name); + ObjToIntMap.Iterator iter = itsVariableNames.newIterator (); + for (iter.start (); !iter.done (); iter.next ()) { + int v = iter.Value; + if (v > i) { + iter.Value = v - 1; + } + } + } + } + + private int encodedSourceStart; + private int encodedSourceEnd; + private string sourceName; + private int baseLineno = -1; + private int endLineno = -1; + + private ObjArray functions; + + private ObjArray regexps; + + // a list of the formal parameters and local variables + private ObjArray itsVariables = new ObjArray (); + + // mapping from name to index in list + private ObjToIntMap itsVariableNames = new ObjToIntMap (11); + + private int varStart; // index in list of first variable + + private object compilerData; + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/ScriptRuntime.cs b/src/EcmaScript.NET/ScriptRuntime.cs similarity index 96% rename from Code/EcmaScript.NET/ScriptRuntime.cs rename to src/EcmaScript.NET/ScriptRuntime.cs index 8b581be..7ef35fe 100644 --- a/Code/EcmaScript.NET/ScriptRuntime.cs +++ b/src/EcmaScript.NET/ScriptRuntime.cs @@ -1,2610 +1,2610 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; -using System.Resources; -using System.Globalization; -using System.Text; -using System.Threading; - -using EcmaScript.NET; -using EcmaScript.NET.Types; -using EcmaScript.NET.Types.RegExp; -using EcmaScript.NET.Types.E4X; -using EcmaScript.NET.Collections; - -namespace EcmaScript.NET -{ - - /// This is the class that implements the runtime. - /// - /// - public class ScriptRuntime - { - - /// No instances should be created. - protected internal ScriptRuntime () - { - } - - public const int MAXSTACKSIZE = 1000; - - private const string XML_INIT_CLASS = "EcmaScript.NET.Xml.Impl.XMLLib"; - - private static readonly object LIBRARY_SCOPE_KEY = new object (); - - public static bool IsNativeRuntimeType (Type cl) - { - if (cl.IsPrimitive) { - return (cl != typeof (char)); - } - else { - return (cl == typeof (string) || cl == typeof (bool) - || CliHelper.IsNumberType (cl) - || typeof (IScriptable).IsAssignableFrom (cl)); - } - } - - public static ScriptableObject InitStandardObjects (Context cx, ScriptableObject scope, bool zealed) - { - if (scope == null) { - scope = new BuiltinObject (); - } - scope.AssociateValue (LIBRARY_SCOPE_KEY, scope); - - BaseFunction.Init (scope, zealed); - BuiltinObject.Init (scope, zealed); - - IScriptable objectProto = ScriptableObject.GetObjectPrototype (scope); - - // Function.prototype.__proto__ should be Object.prototype - IScriptable functionProto = ScriptableObject.GetFunctionPrototype (scope); - functionProto.SetPrototype (objectProto); - - // Set the prototype of the object passed in if need be - if (scope.GetPrototype () == null) - scope.SetPrototype (objectProto); - - // must precede NativeGlobal since it's needed therein - BuiltinError.Init (scope, zealed); - BuiltinGlobal.Init (cx, scope, zealed); - - if (scope is BuiltinGlobalObject) { - ((BuiltinGlobalObject)scope).Init (scope, zealed); - } - - BuiltinArray.Init (scope, zealed); - BuiltinString.Init (scope, zealed); - BuiltinBoolean.Init (scope, zealed); - BuiltinNumber.Init (scope, zealed); - BuiltinDate.Init (scope, zealed); - BuiltinMath.Init (scope, zealed); - - BuiltinWith.Init (scope, zealed); - BuiltinCall.Init (scope, zealed); - BuiltinScript.Init (scope, zealed); - - BuiltinRegExp.Init (scope, zealed); - - if (cx.HasFeature (Context.Features.E4x)) { - Types.E4X.XMLLib.Init (scope, zealed); - } - - Continuation.Init (scope, zealed); - - if (cx.HasFeature (Context.Features.NonEcmaItObject)) { - InitItObject (cx, scope); - } - - return scope; - } - - static void InitItObject (Context cx, ScriptableObject scope) { - BuiltinObject itObj = new BuiltinObject (); - itObj.SetPrototype (scope); - itObj.DefineProperty ("color", Undefined.Value, ScriptableObject.PERMANENT); - itObj.DefineProperty ("height", Undefined.Value, ScriptableObject.PERMANENT); - itObj.DefineProperty ("width", Undefined.Value, ScriptableObject.PERMANENT); - itObj.DefineProperty ("funny", Undefined.Value, ScriptableObject.PERMANENT); - itObj.DefineProperty ("array", Undefined.Value, ScriptableObject.PERMANENT); - itObj.DefineProperty ("rdonly", Undefined.Value, ScriptableObject.READONLY); - scope.DefineProperty ("it", itObj, ScriptableObject.PERMANENT); - } - - public static ScriptableObject getLibraryScopeOrNull (IScriptable scope) - { - ScriptableObject libScope; - libScope = (ScriptableObject)ScriptableObject.GetTopScopeValue (scope, LIBRARY_SCOPE_KEY); - return libScope; - } - - // It is public so NativeRegExp can access it . - public static bool isJSLineTerminator (int c) - { - // Optimization for faster check for eol character: - // they do not have 0xDFD0 bits set - if ((c & 0xDFD0) != 0) { - return false; - } - return c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029; - } - - - /// Helper function for builtin objects that use the varargs form. - /// ECMA function formal arguments are undefined if not supplied; - /// this function pads the argument array out to the expected - /// length, if necessary. - /// - public static object [] padArguments (object [] args, int count) - { - if (count < args.Length) - return args; - - int i; - object [] result = new object [count]; - for (i = 0; i < args.Length; i++) { - result [i] = args [i]; - } - - for (; i < count; i++) { - result [i] = Undefined.Value; - } - - return result; - } - - - public static string escapeString (string s) - { - return escapeString (s, '"'); - } - - /// For escaping strings printed by object and array literals; not quite - /// the same as 'escape.' - /// - public static string escapeString (string s, char escapeQuote) - { - if (!(escapeQuote == '"' || escapeQuote == '\'')) - Context.CodeBug (); - System.Text.StringBuilder sb = null; - - for (int i = 0, L = s.Length; i != L; ++i) { - int c = s [i]; - - if (' ' <= c && c <= '~' && c != escapeQuote && c != '\\') { - // an ordinary print character (like C isprint()) and not " - // or \ . - if (sb != null) { - sb.Append ((char)c); - } - continue; - } - if (sb == null) { - sb = new System.Text.StringBuilder (L + 3); - sb.Append (s); - sb.Length = i; - } - - int escape = -1; - switch (c) { - - case '\b': - escape = 'b'; - break; - - case '\f': - escape = 'f'; - break; - - case '\n': - escape = 'n'; - break; - - case '\r': - escape = 'r'; - break; - - case '\t': - escape = 't'; - break; - - case 0xb: - escape = 'v'; - break; // Java lacks \v. - - case ' ': - escape = ' '; - break; - - case '\\': - escape = '\\'; - break; - } - if (escape >= 0) { - // an \escaped sort of character - sb.Append ('\\'); - sb.Append ((char)escape); - } - else if (c == escapeQuote) { - sb.Append ('\\'); - sb.Append (escapeQuote); - } - else { - int hexSize; - if (c < 256) { - // 2-digit hex - sb.Append ("\\x"); - hexSize = 2; - } - else { - // Unicode. - sb.Append ("\\u"); - hexSize = 4; - } - // append hexadecimal form of c left-padded with 0 - for (int shift = (hexSize - 1) * 4; shift >= 0; shift -= 4) { - int digit = 0xf & (c >> shift); - int hc = (digit < 10) ? '0' + digit : 'a' - 10 + digit; - sb.Append ((char)hc); - } - } - } - return (sb == null) ? s : sb.ToString (); - } - - internal static bool isValidIdentifierName (string s) - { - int L = s.Length; - if (L == 0) - return false; - if (!(char.IsLetter (s [0]) || s [0].CompareTo ('$') == 0 || s [0].CompareTo ('_') == 0)) - return false; - for (int i = 1; i != L; ++i) { - if (!TokenStream.IsJavaIdentifierPart (s [i])) - return false; - } - return !TokenStream.isKeyword (s); - } - - - - internal static string DefaultObjectToString (IScriptable obj) - { - return "[object " + obj.ClassName + ']'; - } - - internal static string uneval (Context cx, IScriptable scope, object value) - { - if (value == null) { - return "null"; - } - if (value == Undefined.Value) { - return "undefined"; - } - if (value is string) { - string escaped = escapeString ((string)value); - System.Text.StringBuilder sb = new System.Text.StringBuilder (escaped.Length + 2); - sb.Append ('\"'); - sb.Append (escaped); - sb.Append ('\"'); - return sb.ToString (); - } - if (CliHelper.IsNumber (value)) { - double d = Convert.ToDouble (value); - if (d == 0 && 1 / d < 0) { - return "-0"; - } - return ScriptConvert.ToString (d); - } - if (value is bool) { - return ScriptConvert.ToString (value); - } - if (value is IScriptable) { - IScriptable obj = (IScriptable)value; - object v = ScriptableObject.GetProperty (obj, "toSource"); - if (v is IFunction) { - IFunction f = (IFunction)v; - return ScriptConvert.ToString (f.Call (cx, scope, obj, EmptyArgs)); - } - return ScriptConvert.ToString (value); - } - WarnAboutNonJSObject (value); - return value.ToString (); - } - - internal static string defaultObjectToSource (Context cx, IScriptable scope, IScriptable thisObj, object [] args) - { - using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier (1024)) { - bool toplevel, iterating; - if (cx.iterating == null) { - toplevel = true; - iterating = false; - cx.iterating = new ObjToIntMap (31); - } - else { - toplevel = false; - iterating = cx.iterating.has (thisObj); - } - - System.Text.StringBuilder result = new System.Text.StringBuilder (128); - if (toplevel) { - result.Append ("("); - } - result.Append ('{'); - - // Make sure cx.iterating is set to null when done - // so we don't leak memory - try { - if (!iterating) { - cx.iterating.intern (thisObj); // stop recursion. - object [] ids = thisObj.GetIds (); - for (int i = 0; i < ids.Length; i++) { - if (i > 0) - result.Append (", "); - object id = ids [i]; - object value; - if (id is int) { - int intId = ((int)id); - value = thisObj.Get (intId, thisObj); - result.Append (intId); - } - else { - string strId = (string)id; - value = thisObj.Get (strId, thisObj); - if (ScriptRuntime.isValidIdentifierName (strId)) { - result.Append (strId); - } - else { - result.Append ('\''); - result.Append (ScriptRuntime.escapeString (strId, '\'')); - result.Append ('\''); - } - } - result.Append (':'); - result.Append (ScriptRuntime.uneval (cx, scope, value)); - } - } - } - finally { - if (toplevel) { - cx.iterating = null; - } - } - - result.Append ('}'); - if (toplevel) { - result.Append (')'); - } - return result.ToString (); - } - } - - - - - public static IScriptable NewObject (Context cx, IScriptable scope, string constructorName, object [] args) - { - scope = ScriptableObject.GetTopLevelScope (scope); - IFunction ctor = getExistingCtor (cx, scope, constructorName); - if (args == null) { - args = ScriptRuntime.EmptyArgs; - } - return ctor.Construct (cx, scope, args); - } - - - // TODO: this is until setDefaultNamespace will learn how to store NS - // TODO: properly and separates namespace form Scriptable.get etc. - private const string DEFAULT_NS_TAG = "__default_namespace__"; - - public static object setDefaultNamespace (object ns, Context cx) - { - IScriptable scope = cx.currentActivationCall; - if (scope == null) { - scope = getTopCallScope (cx); - } - - XMLLib xmlLib = CurrentXMLLib (cx); - object obj = xmlLib.ToDefaultXmlNamespace (cx, ns); - - // TODO: this should be in separated namesapce from Scriptable.get/put - if (!scope.Has (DEFAULT_NS_TAG, scope)) { - // TODO: this is racy of cause - ScriptableObject.DefineProperty (scope, DEFAULT_NS_TAG, obj, ScriptableObject.PERMANENT | ScriptableObject.DONTENUM); - } - else { - scope.Put (DEFAULT_NS_TAG, scope, obj); - } - - return Undefined.Value; - } - - public static object searchDefaultNamespace (Context cx) - { - IScriptable scope = cx.currentActivationCall; - if (scope == null) { - scope = getTopCallScope (cx); - } - object nsObject; - for (; ; ) { - IScriptable parent = scope.ParentScope; - if (parent == null) { - nsObject = ScriptableObject.GetProperty (scope, DEFAULT_NS_TAG); - if (nsObject == UniqueTag.NotFound) { - return null; - } - break; - } - nsObject = scope.Get (DEFAULT_NS_TAG, scope); - if (nsObject != UniqueTag.NotFound) { - break; - } - scope = parent; - } - return nsObject; - } - - public static object getTopLevelProp (IScriptable scope, string id) - { - scope = ScriptableObject.GetTopLevelScope (scope); - return ScriptableObject.GetProperty (scope, id); - } - - internal static IFunction getExistingCtor (Context cx, IScriptable scope, string constructorName) - { - object ctorVal = ScriptableObject.GetProperty (scope, constructorName); - if (ctorVal is IFunction) { - return (IFunction)ctorVal; - } - if (ctorVal == UniqueTag.NotFound) { - throw Context.ReportRuntimeErrorById ("msg.ctor.not.found", constructorName); - } - else { - throw Context.ReportRuntimeErrorById ("msg.not.ctor", constructorName); - } - } - - /// Return -1L if str is not an index or the index value as lower 32 - /// bits of the result. - /// - private static long indexFromString (string str) - { - // The length of the decimal string representation of - // Integer.MAX_VALUE, 2147483647 - const int MAX_VALUE_LENGTH = 10; - - int len = str.Length; - if (len > 0) { - int i = 0; - bool negate = false; - int c = str [0]; - if (c == '-') { - if (len > 1) { - c = str [1]; - i = 1; - negate = true; - } - } - c -= '0'; - if (0 <= c && c <= 9 && len <= (negate ? MAX_VALUE_LENGTH + 1 : MAX_VALUE_LENGTH)) { - // Use negative numbers to accumulate index to handle - // Integer.MIN_VALUE that is greater by 1 in absolute value - // then Integer.MAX_VALUE - int index = -c; - int oldIndex = 0; - i++; - if (index != 0) { - // Note that 00, 01, 000 etc. are not indexes - while (i != len && 0 <= (c = str [i] - '0') && c <= 9) { - oldIndex = index; - index = 10 * index - c; - i++; - } - } - // Make sure all characters were consumed and that it couldn't - // have overflowed. - if (i == len && (oldIndex > (int.MinValue / 10) || (oldIndex == (int.MinValue / 10) && c <= (negate ? -(int.MinValue % 10) : (int.MaxValue % 10))))) { - return unchecked ((int)0xFFFFFFFFL) & (negate ? index : -index); - } - } - } - return -1L; - } - - /// If str is a decimal presentation of Uint32 value, return it as long. - /// Othewise return -1L; - /// - public static long testUint32String (string str) - { - // The length of the decimal string representation of - // UINT32_MAX_VALUE, 4294967296 - const int MAX_VALUE_LENGTH = 10; - - int len = str.Length; - if (1 <= len && len <= MAX_VALUE_LENGTH) { - int c = str [0]; - c -= '0'; - if (c == 0) { - // Note that 00,01 etc. are not valid Uint32 presentations - return (len == 1) ? 0L : -1L; - } - if (1 <= c && c <= 9) { - long v = c; - for (int i = 1; i != len; ++i) { - c = str [i] - '0'; - if (!(0 <= c && c <= 9)) { - return -1; - } - v = 10 * v + c; - } - // Check for overflow - if ((ulong)v >> 32 == 0) { - return v; - } - } - } - return -1; - } - - /// If s represents index, then return index value wrapped as Integer - /// and othewise return s. - /// - internal static object getIndexObject (string s) - { - long indexTest = indexFromString (s); - if (indexTest >= 0) { - return (int)indexTest; - } - return s; - } - - /// If d is exact int value, return its value wrapped as Integer - /// and othewise return d converted to String. - /// - internal static object getIndexObject (double d) - { - int i = (int)d; - if ((double)i == d) { - return (int)i; - } - return ScriptConvert.ToString (d); - } - - /// If ScriptConvert.ToString(id) is a decimal presentation of int32 value, then id - /// is index. In this case return null and make the index available - /// as ScriptRuntime.lastIndexResult(cx). Otherwise return ScriptConvert.ToString(id). - /// - internal static string ToStringIdOrIndex (Context cx, object id) - { - if (CliHelper.IsNumber (id)) { - double d = Convert.ToDouble (id); - int index = (int)d; - if (((double)index) == d) { - storeIndexResult (cx, index); - return null; - } - return ScriptConvert.ToString (id); - } - else { - string s; - if (id is string) { - s = ((string)id); - } - else { - s = ScriptConvert.ToString (id); - } - long indexTest = indexFromString (s); - if (indexTest >= 0) { - storeIndexResult (cx, (int)indexTest); - return null; - } - return s; - } - } - - /// Call obj.[[Get]](id) - public static object getObjectElem (object obj, object elem, Context cx) - { - IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj); - if (sobj == null) { - throw UndefReadError (obj, elem); - } - return getObjectElem (sobj, elem, cx); - } - - public static object getObjectElem (IScriptable obj, object elem, Context cx) - { - if (obj is XMLObject) { - XMLObject xmlObject = (XMLObject)obj; - return xmlObject.EcmaGet (cx, elem); - } - - object result; - - string s = ScriptRuntime.ToStringIdOrIndex (cx, elem); - if (s == null) { - int index = lastIndexResult (cx); - result = ScriptableObject.GetProperty (obj, index); - } - else { - result = ScriptableObject.GetProperty (obj, s); - } - - if (result == UniqueTag.NotFound) { - result = Undefined.Value; - } - - return result; - } - - /// Version of getObjectElem when elem is a valid JS identifier name. - public static object getObjectProp (object obj, string property, Context cx) - { - IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj); - if (sobj == null) { - throw UndefReadError (obj, property); - } - return getObjectProp (sobj, property, cx); - } - - public static object getObjectProp (IScriptable obj, string property, Context cx) - { - if (obj is XMLObject) { - XMLObject xmlObject = (XMLObject)obj; - return xmlObject.EcmaGet (cx, property); - } - - object result = ScriptableObject.GetProperty (obj, property); - if (result == UniqueTag.NotFound) { - result = Undefined.Value; - } - - return result; - } - - /* - * A cheaper and less general version of the above for well-known argument - * types. - */ - public static object getObjectIndex (object obj, double dblIndex, Context cx) - { - IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj); - if (sobj == null) { - throw UndefReadError (obj, ScriptConvert.ToString (dblIndex)); - } - int index = (int)dblIndex; - if ((double)index == dblIndex) { - return getObjectIndex (sobj, index, cx); - } - else { - string s = ScriptConvert.ToString (dblIndex); - return getObjectProp (sobj, s, cx); - } - } - - public static object getObjectIndex (IScriptable obj, int index, Context cx) - { - if (obj is XMLObject) { - XMLObject xmlObject = (XMLObject)obj; - return xmlObject.EcmaGet (cx, (object)index); - } - - object result = ScriptableObject.GetProperty (obj, index); - if (result == UniqueTag.NotFound) { - result = Undefined.Value; - } - - return result; - } - - /* - * Call obj.[[Put]](id, value) - */ - public static object setObjectElem (object obj, object elem, object value, Context cx) - { - IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj); - if (sobj == null) { - throw UndefWriteError (obj, elem, value); - } - return setObjectElem (sobj, elem, value, cx); - } - - public static object setObjectElem (IScriptable obj, object elem, object value, Context cx) - { - if (obj is XMLObject) { - XMLObject xmlObject = (XMLObject)obj; - xmlObject.EcmaPut (cx, elem, value); - return value; - } - - string s = ScriptRuntime.ToStringIdOrIndex (cx, elem); - if (s == null) { - int index = lastIndexResult (cx); - ScriptableObject.PutProperty (obj, index, value); - } - else { - ScriptableObject.PutProperty (obj, s, value); - } - - return value; - } - - /// Version of setObjectElem when elem is a valid JS identifier name. - public static object setObjectProp (object obj, string property, object value, Context cx) - { - IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj); - if (sobj == null) { - throw UndefWriteError (obj, property, value); - } - return setObjectProp (sobj, property, value, cx); - } - - public static object setObjectProp (IScriptable obj, string property, object value, Context cx) - { - if (obj is XMLObject) { - XMLObject xmlObject = (XMLObject)obj; - xmlObject.EcmaPut (cx, property, value); - } - else { - return ScriptableObject.PutProperty (obj, property, value); - } - return value; - } - - /* - * A cheaper and less general version of the above for well-known argument - * types. - */ - public static object setObjectIndex (object obj, double dblIndex, object value, Context cx) - { - IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj); - if (sobj == null) { - throw UndefWriteError (obj, Convert.ToString (dblIndex), value); - } - int index = (int)dblIndex; - if ((double)index == dblIndex) { - return setObjectIndex (sobj, index, value, cx); - } - else { - string s = ScriptConvert.ToString (dblIndex); - return setObjectProp (sobj, s, value, cx); - } - } - - public static object setObjectIndex (IScriptable obj, int index, object value, Context cx) - { - if (obj is XMLObject) { - XMLObject xmlObject = (XMLObject)obj; - xmlObject.EcmaPut (cx, (object)index, value); - } - else { - return ScriptableObject.PutProperty (obj, index, value); - } - return value; - } - - public static bool deleteObjectElem (IScriptable target, object elem, Context cx) - { - bool result; - if (target is XMLObject) { - XMLObject xmlObject = (XMLObject)target; - result = xmlObject.EcmaDelete (cx, elem); - } - else { - string s = ScriptRuntime.ToStringIdOrIndex (cx, elem); - if (s == null) { - int index = lastIndexResult (cx); - result = ScriptableObject.DeleteProperty (target, index); - } - else { - result = ScriptableObject.DeleteProperty (target, s); - } - } - return result; - } - - public static bool hasObjectElem (IScriptable target, object elem, Context cx) - { - bool result; - - if (target is XMLObject) { - XMLObject xmlObject = (XMLObject)target; - result = xmlObject.EcmaHas (cx, elem); - } - else { - string s = ScriptRuntime.ToStringIdOrIndex (cx, elem); - if (s == null) { - int index = lastIndexResult (cx); - result = ScriptableObject.HasProperty (target, index); - } - else { - result = ScriptableObject.HasProperty (target, s); - } - } - - return result; - } - - public static object refGet (IRef rf, Context cx) - { - return rf.Get (cx); - } - - public static object refSet (IRef rf, object value, Context cx) - { - return rf.Set (cx, value); - } - - public static object refDel (IRef rf, Context cx) - { - return rf.Delete (cx); - } - - internal static bool isSpecialProperty (string s) - { - return s.Equals ("__proto__") || s.Equals ("__parent__"); - } - - public static IRef specialRef (object obj, string specialProperty, Context cx) - { - return SpecialRef.createSpecial (cx, obj, specialProperty); - } - - /// The delete operator - /// - /// See ECMA 11.4.1 - /// - /// In ECMA 0.19, the description of the delete operator (11.4.1) - /// assumes that the [[Delete]] method returns a value. However, - /// the definition of the [[Delete]] operator (8.6.2.5) does not - /// define a return value. Here we assume that the [[Delete]] - /// method doesn't return a value. - /// - public static object delete (object obj, object id, Context cx) - { - IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj); - if (sobj == null) { - string idStr = (id == null) ? "null" : id.ToString (); - throw TypeErrorById ("msg.undef.prop.delete", ScriptConvert.ToString (obj), idStr); - } - bool result = deleteObjectElem (sobj, id, cx); - return result; - } - - /// Looks up a name in the scope chain and returns its value. - public static object name (Context cx, IScriptable scope, string name) - { - IScriptable parent = scope.ParentScope; - if (parent == null) { - object result = topScopeName (cx, scope, name); - if (result == UniqueTag.NotFound) { - throw NotFoundError (scope, name); - } - return result; - } - - return nameOrFunction (cx, scope, parent, name, false); - } - - private static object nameOrFunction (Context cx, IScriptable scope, IScriptable parentScope, string name, bool asFunctionCall) - { - object result; - IScriptable thisObj = scope; // It is used only if asFunctionCall==true. - - XMLObject firstXMLObject = null; - for (; ; ) { - if (scope is BuiltinWith) { - IScriptable withObj = scope.GetPrototype (); - if (withObj is XMLObject) { - XMLObject xmlObj = (XMLObject)withObj; - if (xmlObj.EcmaHas (cx, name)) { - // function this should be the target object of with - thisObj = xmlObj; - result = xmlObj.EcmaGet (cx, name); - break; - } - if (firstXMLObject == null) { - firstXMLObject = xmlObj; - } - } - else { - result = ScriptableObject.GetProperty (withObj, name); - if (result != UniqueTag.NotFound) { - // function this should be the target object of with - thisObj = withObj; - break; - } - } - } - else if (scope is BuiltinCall) { - // NativeCall does not prototype chain and Scriptable.get - // can be called directly. - result = scope.Get (name, scope); - if (result != UniqueTag.NotFound) { - if (asFunctionCall) { - // ECMA 262 requires that this for nested funtions - // should be top scope - thisObj = ScriptableObject.GetTopLevelScope (parentScope); - } - break; - } - } - else { - // Can happen if embedding decided that nested - // scopes are useful for what ever reasons. - result = ScriptableObject.GetProperty (scope, name); - if (result != UniqueTag.NotFound) { - thisObj = scope; - break; - } - } - scope = parentScope; - parentScope = parentScope.ParentScope; - if (parentScope == null) { - result = topScopeName (cx, scope, name); - if (result == UniqueTag.NotFound) { - if (firstXMLObject == null || asFunctionCall) { - throw NotFoundError (scope, name); - } - // The name was not found, but we did find an XML - // object in the scope chain and we are looking for name, - // not function. The result should be an empty XMLList - // in name context. - result = firstXMLObject.EcmaGet (cx, name); - } - // For top scope thisObj for functions is always scope itself. - thisObj = scope; - break; - } - } - - if (asFunctionCall) { - if (!(result is ICallable)) { - throw NotFunctionError (result, name); - } - storeScriptable (cx, thisObj); - } - - return result; - } - - private static object topScopeName (Context cx, IScriptable scope, string name) - { - if (cx.useDynamicScope) { - scope = checkDynamicScope (cx.topCallScope, scope); - } - return ScriptableObject.GetProperty (scope, name); - } - - - /// Returns the object in the scope chain that has a given property. - /// - /// The order of evaluation of an assignment expression involves - /// evaluating the lhs to a reference, evaluating the rhs, and then - /// modifying the reference with the rhs value. This method is used - /// to 'bind' the given name to an object containing that property - /// so that the side effects of evaluating the rhs do not affect - /// which property is modified. - /// Typically used in conjunction with setName. - /// - /// See ECMA 10.1.4 - /// - public static IScriptable bind (Context cx, IScriptable scope, string id) - { - IScriptable firstXMLObject = null; - IScriptable parent = scope.ParentScope; - if (parent != null) { - // Check for possibly nested "with" scopes first - while (scope is BuiltinWith) { - IScriptable withObj = scope.GetPrototype (); - if (withObj is XMLObject) { - XMLObject xmlObject = (XMLObject)withObj; - if (xmlObject.EcmaHas (cx, id)) { - return xmlObject; - } - if (firstXMLObject == null) { - firstXMLObject = xmlObject; - } - } - else { - if (ScriptableObject.HasProperty (withObj, id)) { - return withObj; - } - } - scope = parent; - parent = parent.ParentScope; - if (parent == null) { - - goto childScopesChecks_brk; - } - } - for (; ; ) { - if (ScriptableObject.HasProperty (scope, id)) { - return scope; - } - scope = parent; - parent = parent.ParentScope; - if (parent == null) { - - goto childScopesChecks_brk; - } - } - } - - childScopesChecks_brk: - ; - - // scope here is top scope - if (cx.useDynamicScope) { - scope = checkDynamicScope (cx.topCallScope, scope); - } - if (ScriptableObject.HasProperty (scope, id)) { - return scope; - } - // Nothing was found, but since XML objects always bind - // return one if found - return firstXMLObject; - } - - public static object setName (IScriptable bound, object value, Context cx, IScriptable scope, string id) - { - if (bound != null) { - if (bound is XMLObject) { - XMLObject xmlObject = (XMLObject)bound; - xmlObject.EcmaPut (cx, id, value); - } - else { - ScriptableObject.PutProperty (bound, id, value); - } - } - else { - // "newname = 7;", where 'newname' has not yet - // been defined, creates a new property in the - // top scope unless strict mode is specified. - if (cx.HasFeature (Context.Features.StrictVars)) { - throw Context.ReportRuntimeErrorById ("msg.assn.create.strict", id); - } - // Find the top scope by walking up the scope chain. - bound = ScriptableObject.GetTopLevelScope (scope); - if (cx.useDynamicScope) { - bound = checkDynamicScope (cx.topCallScope, bound); - } - bound.Put (id, bound, value); - } - return value; - } - - - - - - - /// Prepare for calling name(...): return function corresponding to - /// name and make current top scope available - /// as ScriptRuntime.lastStoredScriptable() for consumption as thisObj. - /// The caller must call ScriptRuntime.lastStoredScriptable() immediately - /// after calling this method. - /// - public static ICallable getNameFunctionAndThis (string name, Context cx, IScriptable scope) - { - IScriptable parent = scope.ParentScope; - if (parent == null) { - object result = topScopeName (cx, scope, name); - if (!(result is ICallable)) { - if (result == UniqueTag.NotFound) { - throw NotFoundError (scope, name); - } - else { - throw NotFunctionError (result, name); - } - } - // Top scope is not NativeWith or NativeCall => thisObj == scope - IScriptable thisObj = scope; - storeScriptable (cx, thisObj); - return (ICallable)result; - } - - // name will call storeScriptable(cx, thisObj); - return (ICallable)nameOrFunction (cx, scope, parent, name, true); - } - - /// Prepare for calling obj[id](...): return function corresponding to - /// obj[id] and make obj properly converted to Scriptable available - /// as ScriptRuntime.lastStoredScriptable() for consumption as thisObj. - /// The caller must call ScriptRuntime.lastStoredScriptable() immediately - /// after calling this method. - /// - public static ICallable GetElemFunctionAndThis (object obj, object elem, Context cx) - { - string s = ScriptRuntime.ToStringIdOrIndex (cx, elem); - if (s != null) { - return getPropFunctionAndThis (obj, s, cx); - } - int index = lastIndexResult (cx); - - IScriptable thisObj = ScriptConvert.ToObjectOrNull (cx, obj); - if (thisObj == null) { - throw UndefCallError (obj, Convert.ToString (index)); - } - - object value; - for (; ; ) { - // Ignore XML lookup as requred by ECMA 357, 11.2.2.1 - value = ScriptableObject.GetProperty (thisObj, index); - if (value != UniqueTag.NotFound) { - break; - } - if (!(thisObj is XMLObject)) { - break; - } - XMLObject xmlObject = (XMLObject)thisObj; - IScriptable extra = xmlObject.GetExtraMethodSource (cx); - if (extra == null) { - break; - } - thisObj = extra; - } - if (!(value is ICallable)) { - throw NotFunctionError (value, elem); - } - - storeScriptable (cx, thisObj); - return (ICallable)value; - } - - /// Prepare for calling obj.property(...): return function corresponding to - /// obj.property and make obj properly converted to Scriptable available - /// as ScriptRuntime.lastStoredScriptable() for consumption as thisObj. - /// The caller must call ScriptRuntime.lastStoredScriptable() immediately - /// after calling this method. - /// - public static ICallable getPropFunctionAndThis (object obj, string property, Context cx) - { - IScriptable thisObj = ScriptConvert.ToObjectOrNull (cx, obj); - if (thisObj == null) { - throw UndefCallError (obj, property); - } - - object value; - for (; ; ) { - // Ignore XML lookup as requred by ECMA 357, 11.2.2.1 - value = ScriptableObject.GetProperty (thisObj, property); - if (value != UniqueTag.NotFound) { - break; - } - if (!(thisObj is XMLObject)) { - break; - } - XMLObject xmlObject = (XMLObject)thisObj; - IScriptable extra = xmlObject.GetExtraMethodSource (cx); - if (extra == null) { - break; - } - thisObj = extra; - } - - if (value == UniqueTag.NotFound) { - //if (thisObj.Get ("__noSuchMethod__", thisObj) as ICallable != null) { - // return UniqueTag.NoSuchMethodMark; - //} - } - - if (!(value is ICallable)) { - throw NotFunctionError (value, property); - } - - storeScriptable (cx, thisObj); - return (ICallable)value; - } - - /// Prepare for calling (...): return function corresponding to - /// and make parent scope of the function available - /// as ScriptRuntime.lastStoredScriptable() for consumption as thisObj. - /// The caller must call ScriptRuntime.lastStoredScriptable() immediately - /// after calling this method. - /// - public static ICallable getValueFunctionAndThis (object value, Context cx) - { - if (!(value is ICallable)) { - throw NotFunctionError (value); - } - - ICallable f = (ICallable)value; - IScriptable thisObj; - if (f is IScriptable) { - thisObj = ((IScriptable)f).ParentScope; - } - else { - if (cx.topCallScope == null) - throw new Exception (); - thisObj = cx.topCallScope; - } - if (thisObj.ParentScope != null) { - if (thisObj is BuiltinWith) { - // functions defined inside with should have with target - // as their thisObj - } - else if (thisObj is BuiltinCall) { - // nested functions should have top scope as their thisObj - thisObj = ScriptableObject.GetTopLevelScope (thisObj); - } - } - storeScriptable (cx, thisObj); - return f; - } - - /// Perform function call in reference context. Should always - /// return value that can be passed to - /// {@link #refGet(Object)} or @link #refSet(Object, Object)} - /// arbitrary number of times. - /// The args array reference should not be stored in any object that is - /// can be GC-reachable after this method returns. If this is necessary, - /// store args.clone(), not args array itself. - /// - public static IRef callRef (ICallable function, IScriptable thisObj, object [] args, Context cx) - { - if (function is IRefCallable) { - IRefCallable rfunction = (IRefCallable)function; - IRef rf = rfunction.RefCall (cx, thisObj, args); - if (rf == null) { - throw new ApplicationException (rfunction.GetType ().FullName + ".refCall() returned null"); - } - return rf; - } - // No runtime support for now - string msg = GetMessage ("msg.no.ref.from.function", ScriptConvert.ToString (function)); - throw ConstructError ("ReferenceError", msg); - } - - /// Operator new. - /// - /// See ECMA 11.2.2 - /// - public static IScriptable NewObject (object fun, Context cx, IScriptable scope, object [] args) - { - if (!(fun is IFunction)) { - throw NotFunctionError (fun); - } - IFunction function = (IFunction)fun; - return function.Construct (cx, scope, args); - } - - public static object callSpecial (Context cx, ICallable fun, IScriptable thisObj, object [] args, IScriptable scope, IScriptable callerThis, int callType, string filename, int lineNumber) - { - if (callType == Node.SPECIALCALL_EVAL) { - if (BuiltinGlobal.isEvalFunction (fun)) { - return evalSpecial (cx, scope, callerThis, args, filename, lineNumber); - } - } - else if (callType == Node.SPECIALCALL_WITH) { - if (BuiltinWith.IsWithFunction (fun)) { - throw Context.ReportRuntimeErrorById ("msg.only.from.new", "With"); - } - } - else { - throw Context.CodeBug (); - } - - return fun.Call (cx, scope, thisObj, args); - } - - public static object newSpecial (Context cx, object fun, object [] args, IScriptable scope, int callType) - { - if (callType == Node.SPECIALCALL_EVAL) { - if (BuiltinGlobal.isEvalFunction (fun)) { - throw TypeErrorById ("msg.not.ctor", "eval"); - } - } - else if (callType == Node.SPECIALCALL_WITH) { - if (BuiltinWith.IsWithFunction (fun)) { - return BuiltinWith.NewWithSpecial (cx, scope, args); - } - } - else { - throw Context.CodeBug (); - } - - return NewObject (fun, cx, scope, args); - } - - /// Function.prototype.apply and Function.prototype.call - /// - /// See Ecma 15.3.4.[34] - /// - public static object applyOrCall (bool isApply, Context cx, IScriptable scope, IScriptable thisObj, object [] args) - { - int L = args.Length; - ICallable function; - if (thisObj is ICallable) { - function = (ICallable)thisObj; - } - else { - object value = thisObj.GetDefaultValue (typeof (IFunction)); - if (!(value is ICallable)) { - throw ScriptRuntime.NotFunctionError (value, thisObj); - } - function = (ICallable)value; - } - - IScriptable callThis = null; - if (L != 0) { - callThis = ScriptConvert.ToObjectOrNull (cx, args [0]); - } - if (callThis == null) { - // This covers the case of args[0] == (null|undefined) as well. - callThis = getTopCallScope (cx); - } - - object [] callArgs; - if (isApply) { - // Follow Ecma 15.3.4.3 - if (L <= 1) { - callArgs = ScriptRuntime.EmptyArgs; - } - else { - object arg1 = args [1]; - if (arg1 == null || arg1 == Undefined.Value) { - callArgs = ScriptRuntime.EmptyArgs; - } - else if (arg1 is BuiltinArray || arg1 is Arguments) { - callArgs = cx.GetElements ((IScriptable)arg1); - } - else { - throw ScriptRuntime.TypeErrorById ("msg.arg.isnt.array"); - } - } - } - else { - // Follow Ecma 15.3.4.4 - if (L <= 1) { - callArgs = ScriptRuntime.EmptyArgs; - } - else { - callArgs = new object [L - 1]; - Array.Copy (args, 1, callArgs, 0, L - 1); - } - } - - return function.Call (cx, scope, callThis, callArgs); - } - - /// The eval function property of the global object. - /// - /// See ECMA 15.1.2.1 - /// - public static object evalSpecial (Context cx, IScriptable scope, object thisArg, object [] args, string filename, int lineNumber) - { - if (args.Length < 1) - return Undefined.Value; - object x = args [0]; - if (!(x is string)) { - if (cx.HasFeature (Context.Features.StrictEval)) { - throw Context.ReportRuntimeErrorById ("msg.eval.nonstring.strict"); - } - string message = ScriptRuntime.GetMessage ("msg.eval.nonstring"); - Context.ReportWarning (message); - return x; - } - if (filename == null) { - int [] linep = new int [1]; - filename = Context.GetSourcePositionFromStack (linep); - if (filename != null) { - lineNumber = linep [0]; - } - else { - filename = ""; - } - } - string sourceName = ScriptRuntime.makeUrlForGeneratedScript (true, filename, lineNumber); - - ErrorReporter reporter; - reporter = DefaultErrorReporter.ForEval (cx.ErrorReporter); - - // Compile with explicit interpreter instance to force interpreter - // mode. - IScript script = cx.CompileString ((string)x, new Interpreter (), reporter, sourceName, 1, (object)null); - ((InterpretedFunction)script).idata.evalScriptFlag = true; - ICallable c = (ICallable)script; - return c.Call (cx, scope, (IScriptable)thisArg, ScriptRuntime.EmptyArgs); - } - - /// The typeof operator - public static string Typeof (object value) - { - if (value == null) - return "object"; - if (value == Undefined.Value) - return "undefined"; - if (value is IScriptable) { - if (value is XMLObject) - return "xml"; - - return (value is ICallable && !(value is BuiltinRegExp)) ? "function" : "object"; - } - if (value is string) - return "string"; - if (value is char || CliHelper.IsNumber (value)) - return "number"; - if (value is bool) - return "boolean"; - throw errorWithClassName ("msg.invalid.type", value); - } - - - internal static ApplicationException errorWithClassName (string msg, object val) - { - return Context.ReportRuntimeErrorById (msg, val.GetType ().FullName); - } - - /// The typeof operator that correctly handles the undefined case - public static string TypeofName (IScriptable scope, string id) - { - Context cx = Context.CurrentContext; - IScriptable val = bind (cx, scope, id); - if (val == null) - return "undefined"; - return Typeof (getObjectProp (val, id, cx)); - } - - // neg: - // implement the '-' operator inline in the caller - // as "-ScriptConvert.ToNumber(val)" - - // not: - // implement the '!' operator inline in the caller - // as "!toBoolean(val)" - - // bitnot: - // implement the '~' operator inline in the caller - // as "~toInt32(val)" - - public static object Add (object val1, object val2, Context cx) - { - if (CliHelper.IsNumber (val1) && CliHelper.IsNumber (val2)) { - return (double)val1 + (double)val2; - } - if (val1 is XMLObject) { - object test = ((XMLObject)val1).AddValues (cx, true, val2); - if (test != UniqueTag.NotFound) { - return test; - } - } - if (val2 is XMLObject) { - object test = ((XMLObject)val2).AddValues (cx, false, val1); - if (test != UniqueTag.NotFound) { - return test; - } - } - if (val1 is EcmaScript.NET.Types.Cli.CliEventInfo) { - return ((EcmaScript.NET.Types.Cli.CliEventInfo)val1).Add (val2, cx); - } - if (val1 is IScriptable) - val1 = ((IScriptable)val1).GetDefaultValue (null); - if (val2 is IScriptable) - val2 = ((IScriptable)val2).GetDefaultValue (null); - if (!(val1 is string) && !(val2 is string)) - if ((CliHelper.IsNumber (val1)) && (CliHelper.IsNumber (val2))) - return (double)val1 + (double)val2; - else - return ScriptConvert.ToNumber (val1) + ScriptConvert.ToNumber (val2); - return string.Concat (ScriptConvert.ToString (val1), ScriptConvert.ToString (val2)); - } - - public static object nameIncrDecr (IScriptable scopeChain, string id, int incrDecrMask) - { - IScriptable target; - object value; - { - do { - target = scopeChain; - do { - value = target.Get (id, scopeChain); - if (value != UniqueTag.NotFound) { - - goto search_brk; - } - target = target.GetPrototype (); - } - while (target != null); - scopeChain = scopeChain.ParentScope; - } - while (scopeChain != null); - throw NotFoundError (scopeChain, id); - } - - search_brk: - ; - - return doScriptableIncrDecr (target, id, scopeChain, value, incrDecrMask); - } - - public static object propIncrDecr (object obj, string id, Context cx, int incrDecrMask) - { - IScriptable start = ScriptConvert.ToObjectOrNull (cx, obj); - if (start == null) { - throw UndefReadError (obj, id); - } - - IScriptable target = start; - object value; - { - do { - value = target.Get (id, start); - if (value != UniqueTag.NotFound) { - - goto search1_brk; - } - target = target.GetPrototype (); - } - while (target != null); - start.Put (id, start, double.NaN); - return double.NaN; - } - - search1_brk: - ; - - return doScriptableIncrDecr (target, id, start, value, incrDecrMask); - } - - private static object doScriptableIncrDecr (IScriptable target, string id, IScriptable protoChainStart, object value, int incrDecrMask) - { - bool post = ((incrDecrMask & Node.POST_FLAG) != 0); - double number; - if (CliHelper.IsNumber (value)) { - number = Convert.ToDouble (value); - } - else { - number = ScriptConvert.ToNumber (value); - if (post) { - // convert result to number - value = number; - } - } - if ((incrDecrMask & Node.DECR_FLAG) == 0) { - ++number; - } - else { - --number; - } - object result = number; - target.Put (id, protoChainStart, result); - if (post) { - return value; - } - else { - return result; - } - } - - public static object elemIncrDecr (object obj, object index, Context cx, int incrDecrMask) - { - object value = getObjectElem (obj, index, cx); - bool post = ((incrDecrMask & Node.POST_FLAG) != 0); - double number; - if (CliHelper.IsNumber (value)) { - number = Convert.ToDouble (value); - } - else { - number = ScriptConvert.ToNumber (value); - if (post) { - // convert result to number - value = number; - } - } - if ((incrDecrMask & Node.DECR_FLAG) == 0) { - ++number; - } - else { - --number; - } - object result = number; - setObjectElem (obj, index, result, cx); - if (post) { - return value; - } - else { - return result; - } - } - - public static object refIncrDecr (IRef rf, Context cx, int incrDecrMask) - { - object value = rf.Get (cx); - bool post = ((incrDecrMask & Node.POST_FLAG) != 0); - double number; - if (CliHelper.IsNumber (value)) { - number = Convert.ToDouble (value); - } - else { - number = ScriptConvert.ToNumber (value); - if (post) { - // convert result to number - value = number; - } - } - if ((incrDecrMask & Node.DECR_FLAG) == 0) { - ++number; - } - else { - --number; - } - rf.Set (cx, number); - if (post) { - return value; - } - else { - return number; - } - } - - - /// Equality - /// - /// See ECMA 11.9 - /// - public static bool eq (object x, object y) - { - if (x == null || x == Undefined.Value) { - if (y == null || y == Undefined.Value) { - return true; - } - if (y is ScriptableObject) { - object test = ((ScriptableObject)y).EquivalentValues (x); - if (test != UniqueTag.NotFound) { - return ((bool)test); - } - } - return false; - } - else if (CliHelper.IsNumber (x)) { - return eqNumber (Convert.ToDouble (x), y); - } - else if (x is string) { - return eqString ((string)x, y); - } - else if (x is bool) { - bool b = ((bool)x); - if (y is bool) { - return b == ((bool)y); - } - if (y is ScriptableObject) { - object test = ((ScriptableObject)y).EquivalentValues (x); - if (test != UniqueTag.NotFound) { - return ((bool)test); - } - } - return eqNumber (b ? 1.0 : 0.0, y); - } - else if (x is IScriptable) { - if (y is IScriptable) { - if (x == y) { - return true; - } - if (x is ScriptableObject) { - object test = ((ScriptableObject)x).EquivalentValues (y); - if (test != UniqueTag.NotFound) { - return ((bool)test); - } - } - if (y is ScriptableObject) { - object test = ((ScriptableObject)y).EquivalentValues (x); - if (test != UniqueTag.NotFound) { - return ((bool)test); - } - } - if (x is Wrapper && y is Wrapper) { - return ((Wrapper)x).Unwrap () == ((Wrapper)y).Unwrap (); - } - return false; - } - else if (y is bool) { - if (x is ScriptableObject) { - object test = ((ScriptableObject)x).EquivalentValues (y); - if (test != UniqueTag.NotFound) { - return ((bool)test); - } - } - double d = ((bool)y) ? 1.0 : 0.0; - return eqNumber (d, x); - } - else if (CliHelper.IsNumber (y)) { - return eqNumber (Convert.ToDouble (y), x); - } - else if (y is string) { - return eqString ((string)y, x); - } - // covers the case when y == Undefined.instance as well - return false; - } - else { - WarnAboutNonJSObject (x); - return x == y; - } - } - - internal static bool eqNumber (double x, object y) - { - for (; ; ) { - if (y == null || y == Undefined.Value) { - return false; - } - else if (CliHelper.IsNumber (y)) { - return x == Convert.ToDouble (y); - } - else if (y is string) { - return x == ScriptConvert.ToNumber (y); - } - else if (y is bool) { - return x == (((bool)y) ? 1.0 : +0.0); - } - else if (y is IScriptable) { - if (y is ScriptableObject) { - object xval = x; - object test = ((ScriptableObject)y).EquivalentValues (xval); - if (test != UniqueTag.NotFound) { - return ((bool)test); - } - } - y = ScriptConvert.ToPrimitive (y); - } - else { - WarnAboutNonJSObject (y); - return false; - } - } - } - - private static bool eqString (string x, object y) - { - for (; ; ) { - if (y == null || y == Undefined.Value) { - return false; - } - else if (y is string) { - return x.Equals (y); - } - else if (CliHelper.IsNumber (y)) { - return ScriptConvert.ToNumber (x) == Convert.ToDouble (y); - } - else if (y is bool) { - return ScriptConvert.ToNumber (x) == (((bool)y) ? 1.0 : 0.0); - } - else if (y is IScriptable) { - if (y is ScriptableObject) { - object test = ((ScriptableObject)y).EquivalentValues (x); - if (test != UniqueTag.NotFound) { - return ((bool)test); - } - } - y = ScriptConvert.ToPrimitive (y); - continue; - } - else { - WarnAboutNonJSObject (y); - return false; - } - } - } - public static bool shallowEq (object x, object y) - { - if (x == y) { - if (!(CliHelper.IsNumber (x))) { - return true; - } - // double.NaN check - double d = Convert.ToDouble (x); - return !double.IsNaN (d); - } - if (x == null || x == Undefined.Value) { - return false; - } - else if (CliHelper.IsNumber (x)) { - if (CliHelper.IsNumber (y)) { - return Convert.ToDouble (x) == Convert.ToDouble (y); - } - } - else if (x is string) { - if (y is string) { - return x.Equals (y); - } - } - else if (x is bool) { - if (y is bool) { - return x.Equals (y); - } - } - else if (x is IScriptable) { - if (x is Wrapper && y is Wrapper) { - return ((Wrapper)x).Unwrap () == ((Wrapper)y).Unwrap (); - } - } - else { - WarnAboutNonJSObject (x); - return x == y; - } - return false; - } - - /// The instanceof operator. - /// - /// - /// a instanceof b - /// - public static bool InstanceOf (object a, object b, Context cx) - { - IScriptable sB = (b as IScriptable); - - // Check RHS is an object - if (sB == null) { - throw TypeErrorById ("msg.instanceof.not.object"); - } - - IScriptable sA = (a as IScriptable); - - // for primitive values on LHS, return false - // TODO we may want to change this so that 5 instanceof Number == true - if (sA == null) { - return false; - } - - - return sB.HasInstance (sA); - } - - /// Delegates to - /// - /// - /// true iff rhs appears in lhs' proto chain - /// - protected internal static bool jsDelegatesTo (IScriptable lhs, IScriptable rhs) - { - IScriptable proto = lhs.GetPrototype (); - - while (proto != null) { - if (proto.Equals (rhs)) - return true; - proto = proto.GetPrototype (); - } - - return false; - } - - /// The in operator. - /// - /// This is a new JS 1.3 language feature. The in operator mirrors - /// the operation of the for .. in construct, and tests whether the - /// rhs has the property given by the lhs. It is different from the - /// for .. in construct in that: - ///
- it doesn't perform ToObject on the right hand side - ///
- it returns true for DontEnum properties. - ///
- /// the left hand operand - /// - /// the right hand operand - /// - /// - /// true if property name or element number a is a property of b - /// - public static bool In (object a, object b, Context cx) - { - if (!(b is IScriptable)) { - throw TypeErrorById ("msg.instanceof.not.object"); - } - - return hasObjectElem ((IScriptable)b, a, cx); - } - - public static bool cmp_LT (object val1, object val2) - { - double d1, d2; - if (CliHelper.IsNumber (val1) && CliHelper.IsNumber (val2)) { - d1 = Convert.ToDouble (val1); - d2 = Convert.ToDouble (val2); - } - else { - if (val1 is IScriptable) - val1 = ((IScriptable)val1).GetDefaultValue (typeof (long)); - if (val2 is IScriptable) - val2 = ((IScriptable)val2).GetDefaultValue (typeof (long)); - if (val1 is string && val2 is string) { - return String.CompareOrdinal (((string)val1), (string)val2) < 0; - } - d1 = ScriptConvert.ToNumber (val1); - d2 = ScriptConvert.ToNumber (val2); - } - return d1 < d2; - } - - public static bool cmp_LE (object val1, object val2) - { - double d1, d2; - if (CliHelper.IsNumber (val1) && CliHelper.IsNumber (val2)) { - d1 = Convert.ToDouble (val1); - d2 = Convert.ToDouble (val2); - } - else { - if (val1 is IScriptable) - val1 = ((IScriptable)val1).GetDefaultValue (typeof (long)); - if (val2 is IScriptable) - val2 = ((IScriptable)val2).GetDefaultValue (typeof (long)); - if (val1 is string && val2 is string) { - return String.CompareOrdinal (((string)val1), (string)val2) <= 0; - } - d1 = ScriptConvert.ToNumber (val1); - d2 = ScriptConvert.ToNumber (val2); - } - return d1 <= d2; - } - - - public static bool hasTopCall (Context cx) - { - return (cx.topCallScope != null); - } - - public static IScriptable getTopCallScope (Context cx) - { - IScriptable scope = cx.topCallScope; - if (scope == null) { - throw new ApplicationException (); - } - return scope; - } - - public static object DoTopCall (ICallable callable, Context cx, IScriptable scope, IScriptable thisObj, object [] args) - { - if (scope == null) - throw new ArgumentException (); - if (cx.topCallScope != null) - throw new ApplicationException (); - - object result; - cx.topCallScope = ScriptableObject.GetTopLevelScope (scope); - cx.useDynamicScope = cx.HasFeature (Context.Features.DynamicScope); - ContextFactory f = cx.Factory; - try { - result = f.DoTopCall (callable, cx, scope, thisObj, args); - } - finally { - cx.topCallScope = null; - // Cleanup cached references - cx.cachedXMLLib = null; - - if (cx.currentActivationCall != null) { - // Function should always call exitActivationFunction - // if it creates activation record - throw new ApplicationException ( - "ActivationCall without exitActivationFunction() invokation." - ); - } - } - return result; - } - - /// Return possibleDynamicScope if staticTopScope - /// is present on its prototype chain and return staticTopScope - /// otherwise. - /// Should only be called when staticTopScope is top scope. - /// - internal static IScriptable checkDynamicScope (IScriptable possibleDynamicScope, IScriptable staticTopScope) - { - // Return cx.topCallScope if scope - if (possibleDynamicScope == staticTopScope) { - return possibleDynamicScope; - } - IScriptable proto = possibleDynamicScope; - for (; ; ) { - proto = proto.GetPrototype (); - if (proto == staticTopScope) { - return possibleDynamicScope; - } - if (proto == null) { - return staticTopScope; - } - } - } - - public static void initScript (BuiltinFunction funObj, IScriptable thisObj, Context cx, IScriptable scope, bool evalScript) - { - if (cx.topCallScope == null) - throw new ApplicationException (); - - int varCount = funObj.ParamAndVarCount; - if (varCount != 0) { - - IScriptable varScope = scope; - // Never define any variables from var statements inside with - // object. See bug 38590. - while (varScope is BuiltinWith) { - varScope = varScope.ParentScope; - } - - for (int i = varCount; i-- != 0; ) { - string name = funObj.getParamOrVarName (i); - // Don't overwrite existing def if already defined in object - // or prototypes of object. - if (!ScriptableObject.HasProperty (scope, name)) { - if (!evalScript) { - // Global var definitions are supposed to be DONTDELETE - ScriptableObject.DefineProperty (varScope, name, Undefined.Value, ScriptableObject.PERMANENT); - } - else { - varScope.Put (name, varScope, Undefined.Value); - } - } - } - } - } - - public static IScriptable createFunctionActivation (BuiltinFunction funObj, IScriptable scope, object [] args) - { - return new BuiltinCall (funObj, scope, args); - } - - - public static void enterActivationFunction (Context cx, IScriptable activation) - { - if (cx.topCallScope == null) - throw new ApplicationException (); - - BuiltinCall call = (BuiltinCall)activation; - call.parentActivationCall = cx.currentActivationCall; - cx.currentActivationCall = call; - } - - public static void exitActivationFunction (Context cx) - { - BuiltinCall call = cx.currentActivationCall; - cx.currentActivationCall = call.parentActivationCall; - call.parentActivationCall = null; - } - - internal static BuiltinCall findFunctionActivation (Context cx, IFunction f) - { - BuiltinCall call = cx.currentActivationCall; - while (call != null) { - if (call.function == f) - return call; - call = call.parentActivationCall; - } - return null; - } - - public static IScriptable NewCatchScope (Exception t, IScriptable lastCatchScope, string exceptionName, Context cx, IScriptable scope) - { - object obj; - bool cacheObj; - - if (t is EcmaScriptThrow) { - cacheObj = false; - obj = ((EcmaScriptThrow)t).Value; - } - else { - cacheObj = true; - - // Create wrapper object unless it was associated with - // the previous scope object - - if (lastCatchScope != null) { - BuiltinObject last = (BuiltinObject)lastCatchScope; - obj = last.GetAssociatedValue (t); - if (obj == null) - Context.CodeBug (); - - goto getObj_brk; - } - - EcmaScriptException re; - string errorName; - string errorMsg; - - Exception javaException = null; - - if (t is EcmaScriptError) { - EcmaScriptError ee = (EcmaScriptError)t; - re = ee; - errorName = ee.Name; - errorMsg = ee.ErrorMessage; - } - else if (t is EcmaScriptRuntimeException) { - re = (EcmaScriptRuntimeException)t; - if (t.InnerException != null) { - javaException = t.InnerException; - errorName = "JavaException"; - errorMsg = javaException.GetType ().FullName + ": " + javaException.Message; - } - else { - errorName = "InternalError"; - errorMsg = re.Message; - } - } - else { - // Script can catch only instances of JavaScriptException, - // EcmaError and EvaluatorException - throw Context.CodeBug (); - } - - string sourceUri = re.SourceName; - if (sourceUri == null) { - sourceUri = ""; - } - int line = re.LineNumber; - object [] args; - if (line > 0) { - args = new object [] { errorMsg, sourceUri, (int)line }; - } - else { - args = new object [] { errorMsg, sourceUri }; - } - - IScriptable errorObject = cx.NewObject (scope, errorName, args); - ScriptableObject.PutProperty (errorObject, "name", errorName); - - if (javaException != null) { - object wrap = cx.Wrap (scope, javaException, null); - ScriptableObject.DefineProperty (errorObject, "javaException", wrap, ScriptableObject.PERMANENT | ScriptableObject.READONLY); - } - if (re != null) { - object wrap = cx.Wrap (scope, re, null); - ScriptableObject.DefineProperty (errorObject, "rhinoException", wrap, ScriptableObject.PERMANENT | ScriptableObject.READONLY); - } - - obj = errorObject; - } - - getObj_brk: - ; - - - - BuiltinObject catchScopeObject = new BuiltinObject (); - // See ECMA 12.4 - catchScopeObject.DefineProperty (exceptionName, obj, ScriptableObject.PERMANENT); - if (cacheObj) { - catchScopeObject.AssociateValue (t, obj); - } - return catchScopeObject; - } - - public static IScriptable enterWith (object obj, Context cx, IScriptable scope) - { - IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj); - if (sobj == null) { - throw TypeErrorById ("msg.undef.with", ScriptConvert.ToString (obj)); - } - if (sobj is XMLObject) { - XMLObject xmlObject = (XMLObject)sobj; - return xmlObject.EnterWith (scope); - } - return new BuiltinWith (scope, sobj); - } - - public static IScriptable leaveWith (IScriptable scope) - { - BuiltinWith nw = (BuiltinWith)scope; - return nw.ParentScope; - } - - public static IScriptable enterDotQuery (object value, IScriptable scope) - { - if (!(value is XMLObject)) { - throw NotXmlError (value); - } - XMLObject obj = (XMLObject)value; - return obj.EnterDotQuery (scope); - } - - public static object updateDotQuery (bool value, IScriptable scope) - { - // Return null to continue looping - BuiltinWith nw = (BuiltinWith)scope; - return nw.UpdateDotQuery (value); - } - - public static IScriptable leaveDotQuery (IScriptable scope) - { - BuiltinWith nw = (BuiltinWith)scope; - return nw.ParentScope; - } - - public static void setFunctionProtoAndParent (BaseFunction fn, IScriptable scope) - { - fn.ParentScope = scope; - fn.SetPrototype (ScriptableObject.GetFunctionPrototype (scope)); - } - - public static void setObjectProtoAndParent (ScriptableObject obj, IScriptable scope) - { - // Compared with function it always sets the scope to top scope - scope = ScriptableObject.GetTopLevelScope (scope); - obj.ParentScope = scope; - IScriptable proto = ScriptableObject.getClassPrototype (scope, obj.ClassName); - obj.SetPrototype (proto); - } - - public static void initFunction (Context cx, IScriptable scope, BuiltinFunction function, int type, bool fromEvalCode) - { - if (type == FunctionNode.FUNCTION_STATEMENT) { - string name = function.FunctionName; - if (name != null && name.Length != 0) { - if (!fromEvalCode) { - // ECMA specifies that functions defined in global and - // function scope outside eval should have DONTDELETE set. - ScriptableObject.DefineProperty (scope, name, function, ScriptableObject.PERMANENT); - } - else { - scope.Put (name, scope, function); - } - } - } - else if (type == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) { - string name = function.FunctionName; - if (name != null && name.Length != 0) { - // Always put function expression statements into initial - // activation object ignoring the with statement to follow - // SpiderMonkey - while (scope is BuiltinWith) { - scope = scope.ParentScope; - } - scope.Put (name, scope, function); - } - } - else { - throw Context.CodeBug (); - } - } - - public static IScriptable newArrayLiteral (object [] objects, int [] skipIndexces, Context cx, IScriptable scope) - { - int count = objects.Length; - int skipCount = 0; - if (skipIndexces != null) { - skipCount = skipIndexces.Length; - } - int length = count + skipCount; - int lengthObj = (int)length; - IScriptable arrayObj; - /* - * If the version is 120, then new Array(4) means create a new - * array with 4 as the first element. In this case, we have to - * set length property manually. - */ - if (cx.Version == Context.Versions.JS1_2) { - arrayObj = cx.NewObject (scope, "Array", ScriptRuntime.EmptyArgs); - ScriptableObject.PutProperty (arrayObj, "length", (object)lengthObj); - } - else { - arrayObj = cx.NewObject (scope, "Array", new object [] { lengthObj }); - } - int skip = 0; - for (int i = 0, j = 0; i != length; ++i) { - if (skip != skipCount && skipIndexces [skip] == i) { - ++skip; - continue; - } - ScriptableObject.PutProperty (arrayObj, i, objects [j]); - ++j; - } - return arrayObj; - } - - public static IScriptable newObjectLiteral (object [] propertyIds, object [] propertyValues, Context cx, IScriptable scope) - { - IScriptable obj = cx.NewObject (scope); - for (int i = 0, end = propertyIds.Length; i != end; ++i) { - object id = propertyIds [i]; - object value = propertyValues [i]; - - if (id is Node.GetterPropertyLiteral) { - BuiltinObject nativeObj = (BuiltinObject)obj; - InterpretedFunction fun = (InterpretedFunction)value; - nativeObj.DefineGetter ((string)((Node.GetterPropertyLiteral)id).Property, fun); - } - else if (id is Node.SetterPropertyLiteral) { - BuiltinObject nativeObj = (BuiltinObject)obj; - InterpretedFunction fun = (InterpretedFunction)value; - nativeObj.DefineSetter ((string)((Node.SetterPropertyLiteral)id).Property, fun); - } - else if (id is string) { - ScriptableObject.PutProperty (obj, (string)id, value); - } - else { - ScriptableObject.PutProperty (obj, (int)id, value); - } - } - return obj; - } - - public static bool isArrayObject (object obj) - { - return obj is BuiltinArray || obj is Arguments; - } - - public static object [] getArrayElements (IScriptable obj) - { - Context cx = Context.CurrentContext; - long longLen = BuiltinArray.getLengthProperty (cx, obj); - if (longLen > int.MaxValue) { - // arrays beyond MAX_INT is not in Java in any case - throw new ArgumentException (); - } - int len = (int)longLen; - if (len == 0) { - return ScriptRuntime.EmptyArgs; - } - else { - object [] result = new object [len]; - for (int i = 0; i < len; i++) { - object elem = ScriptableObject.GetProperty (obj, i); - result [i] = (elem == UniqueTag.NotFound) ? Undefined.Value : elem; - } - return result; - } - } - - internal static void checkDeprecated (Context cx, string name) - { - Context.Versions version = cx.Version; - if (version >= Context.Versions.JS1_4 || version == Context.Versions.Default) { - string msg = GetMessage ("msg.deprec.ctor", name); - if (version == Context.Versions.Default) - Context.ReportWarning (msg); - else - throw Context.ReportRuntimeError (msg); - } - } - - - private static ResourceManager m_ResourceManager = null; - - public static string GetMessage (string messageId, params object [] arguments) - { - Context cx = Context.CurrentContext; - - // Get current culture - CultureInfo culture = null; - if (cx != null) - culture = cx.CurrentCulture; - - if (m_ResourceManager == null) { - m_ResourceManager = new ResourceManager ( - "EcmaScript.NET.Resources.Messages", typeof (ScriptRuntime).Assembly); - } - - string formatString = m_ResourceManager.GetString (messageId, culture); - if (formatString == null) - throw new ApplicationException ("Missing no message resource found for message property " + messageId); - - if (arguments == null) - arguments = new object [0]; - if (arguments.Length == 0) - return formatString; - return string.Format (formatString, arguments); - } - - public static EcmaScriptError ConstructError (string error, string message) - { - int [] linep = new int [1]; - string filename = Context.GetSourcePositionFromStack (linep); - return ConstructError (error, message, filename, linep [0], null, 0); - } - - public static EcmaScriptError ConstructError (string error, string message, string sourceName, int lineNumber, string lineSource, int columnNumber) - { - return new EcmaScriptError (error, message, sourceName, lineNumber, lineSource, columnNumber); - } - - public static EcmaScriptError TypeError (string message) - { - return ConstructError ("TypeError", message); - } - - public static EcmaScriptError TypeErrorById (string messageId, params string [] args) - { - return TypeError (GetMessage (messageId, args)); - } - - public static ApplicationException UndefReadError (object obj, object id) - { - string idStr = (id == null) ? "null" : id.ToString (); - return TypeErrorById ("msg.undef.prop.read", ScriptConvert.ToString (obj), idStr); - } - - public static ApplicationException UndefCallError (object obj, object id) - { - string idStr = (id == null) ? "null" : id.ToString (); - return TypeErrorById ("msg.undef.method.call", ScriptConvert.ToString (obj), idStr); - } - - public static ApplicationException UndefWriteError (object obj, object id, object value) - { - string idStr = (id == null) ? "null" : id.ToString (); - string valueStr = (value is IScriptable) ? value.ToString () : ScriptConvert.ToString (value); - return TypeErrorById ("msg.undef.prop.write", ScriptConvert.ToString (obj), idStr, valueStr); - } - - public static ApplicationException NotFoundError (IScriptable obj, string property) - { - // TODO: use object to improve the error message - string msg = GetMessage ("msg.is.not.defined", property); - throw ConstructError ("ReferenceError", msg); - } - - public static ApplicationException NotFunctionError (object value) - { - return NotFunctionError (value, value); - } - - public static ApplicationException NotFunctionError (object value, object messageHelper) - { - // TODO: Use value for better error reporting - string msg = (messageHelper == null) ? "null" : messageHelper.ToString (); - if (value == UniqueTag.NotFound) { - return TypeErrorById ("msg.function.not.found", msg); - } - return TypeErrorById ("msg.isnt.function", msg, value == null ? "null" : value.GetType ().FullName); - } - - private static ApplicationException NotXmlError (object value) - { - throw TypeErrorById ("msg.isnt.xml.object", ScriptConvert.ToString (value)); - } - - internal static void WarnAboutNonJSObject (object nonJSObject) - { - string message = "+++ USAGE WARNING: Missed Context.Wrap() conversion:\n" - + "Runtime detected object " + nonJSObject + " of class " + nonJSObject.GetType ().FullName + " where it expected String, Number, Boolean or Scriptable instance. " - + "Please check your code for missig Context.Wrap() call."; - - Context.ReportWarning (message); - Console.Error.WriteLine (message); - } - - - private static XMLLib CurrentXMLLib (Context cx) - { - // Scripts should be running to access this - if (cx.topCallScope == null) - throw new ApplicationException (); - - XMLLib xmlLib = cx.cachedXMLLib; - if (xmlLib == null) { - xmlLib = XMLLib.ExtractFromScope (cx.topCallScope); - if (xmlLib == null) - throw new ApplicationException (); - cx.cachedXMLLib = xmlLib; - } - - return xmlLib; - } - - /// Escapes the reserved characters in a value of an attribute - /// - /// - /// Unescaped text - /// - /// The escaped text - /// - public static string escapeAttributeValue (object value, Context cx) - { - XMLLib xmlLib = CurrentXMLLib (cx); - return xmlLib.EscapeAttributeValue (value); - } - - /// Escapes the reserved characters in a value of a text node - /// - /// - /// Unescaped text - /// - /// The escaped text - /// - public static string escapeTextValue (object value, Context cx) - { - XMLLib xmlLib = CurrentXMLLib (cx); - return xmlLib.EscapeTextValue (value); - } - - public static IRef memberRef (object obj, object elem, Context cx, int memberTypeFlags) - { - if (!(obj is XMLObject)) { - throw NotXmlError (obj); - } - XMLObject xmlObject = (XMLObject)obj; - return xmlObject.MemberRef (cx, elem, memberTypeFlags); - } - - public static IRef memberRef (object obj, object ns, object elem, Context cx, int memberTypeFlags) - { - if (!(obj is XMLObject)) { - throw NotXmlError (obj); - } - XMLObject xmlObject = (XMLObject)obj; - return xmlObject.MemberRef (cx, ns, elem, memberTypeFlags); - } - - public static IRef nameRef (object name, Context cx, IScriptable scope, int memberTypeFlags) - { - XMLLib xmlLib = CurrentXMLLib (cx); - return xmlLib.NameRef (cx, name, scope, memberTypeFlags); - } - - public static IRef nameRef (object ns, object name, Context cx, IScriptable scope, int memberTypeFlags) - { - XMLLib xmlLib = CurrentXMLLib (cx); - return xmlLib.NameRef (cx, ns, name, scope, memberTypeFlags); - } - - private static void storeIndexResult (Context cx, int index) - { - cx.scratchIndex = index; - } - - internal static int lastIndexResult (Context cx) - { - return cx.scratchIndex; - } - - public static void storeUint32Result (Context cx, long value) - { - if (((ulong)value >> 32) != 0) - throw new ArgumentException (); - cx.scratchUint32 = value; - } - - public static long lastUint32Result (Context cx) - { - long value = cx.scratchUint32; - if ((ulong)value >> 32 != 0) - throw new ApplicationException (); - return value; - } - - private static void storeScriptable (Context cx, IScriptable value) - { - // The previosly stored scratchScriptable should be consumed - if (cx.scratchScriptable != null) - throw new ApplicationException (); - cx.scratchScriptable = value; - } - - public static IScriptable lastStoredScriptable (Context cx) - { - IScriptable result = cx.scratchScriptable; - cx.scratchScriptable = null; - return result; - } - - internal static string makeUrlForGeneratedScript (bool isEval, string masterScriptUrl, int masterScriptLine) - { - if (isEval) { - return masterScriptUrl + '#' + masterScriptLine + "(eval)"; - } - else { - return masterScriptUrl + '#' + masterScriptLine + "(Function)"; - } - } - - internal static bool isGeneratedScript (string sourceUrl) - { - // ALERT: this may clash with a valid URL containing (eval) or - // (Function) - return sourceUrl.IndexOf ("(eval)") >= 0 || sourceUrl.IndexOf ("(Function)") >= 0; - } - - - public static readonly object [] EmptyArgs = new object [0]; - public static readonly string [] EmptyStrings = new string [0]; - - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; +using System.Resources; +using System.Globalization; +using System.Text; +using System.Threading; + +using EcmaScript.NET; +using EcmaScript.NET.Types; +using EcmaScript.NET.Types.RegExp; +using EcmaScript.NET.Types.E4X; +using EcmaScript.NET.Collections; + +namespace EcmaScript.NET +{ + + /// This is the class that implements the runtime. + /// + /// + public class ScriptRuntime + { + + /// No instances should be created. + protected internal ScriptRuntime () + { + } + + public const int MAXSTACKSIZE = 1000; + + private const string XML_INIT_CLASS = "EcmaScript.NET.Xml.Impl.XMLLib"; + + private static readonly object LIBRARY_SCOPE_KEY = new object (); + + public static bool IsNativeRuntimeType (Type cl) + { + if (cl.IsPrimitive) { + return (cl != typeof (char)); + } + else { + return (cl == typeof (string) || cl == typeof (bool) + || CliHelper.IsNumberType (cl) + || typeof (IScriptable).IsAssignableFrom (cl)); + } + } + + public static ScriptableObject InitStandardObjects (Context cx, ScriptableObject scope, bool zealed) + { + if (scope == null) { + scope = new BuiltinObject (); + } + scope.AssociateValue (LIBRARY_SCOPE_KEY, scope); + + BaseFunction.Init (scope, zealed); + BuiltinObject.Init (scope, zealed); + + IScriptable objectProto = ScriptableObject.GetObjectPrototype (scope); + + // Function.prototype.__proto__ should be Object.prototype + IScriptable functionProto = ScriptableObject.GetFunctionPrototype (scope); + functionProto.SetPrototype (objectProto); + + // Set the prototype of the object passed in if need be + if (scope.GetPrototype () == null) + scope.SetPrototype (objectProto); + + // must precede NativeGlobal since it's needed therein + BuiltinError.Init (scope, zealed); + BuiltinGlobal.Init (cx, scope, zealed); + + if (scope is BuiltinGlobalObject) { + ((BuiltinGlobalObject)scope).Init (scope, zealed); + } + + BuiltinArray.Init (scope, zealed); + BuiltinString.Init (scope, zealed); + BuiltinBoolean.Init (scope, zealed); + BuiltinNumber.Init (scope, zealed); + BuiltinDate.Init (scope, zealed); + BuiltinMath.Init (scope, zealed); + + BuiltinWith.Init (scope, zealed); + BuiltinCall.Init (scope, zealed); + BuiltinScript.Init (scope, zealed); + + BuiltinRegExp.Init (scope, zealed); + + if (cx.HasFeature (Context.Features.E4x)) { + Types.E4X.XMLLib.Init (scope, zealed); + } + + Continuation.Init (scope, zealed); + + if (cx.HasFeature (Context.Features.NonEcmaItObject)) { + InitItObject (cx, scope); + } + + return scope; + } + + static void InitItObject (Context cx, ScriptableObject scope) { + BuiltinObject itObj = new BuiltinObject (); + itObj.SetPrototype (scope); + itObj.DefineProperty ("color", Undefined.Value, ScriptableObject.PERMANENT); + itObj.DefineProperty ("height", Undefined.Value, ScriptableObject.PERMANENT); + itObj.DefineProperty ("width", Undefined.Value, ScriptableObject.PERMANENT); + itObj.DefineProperty ("funny", Undefined.Value, ScriptableObject.PERMANENT); + itObj.DefineProperty ("array", Undefined.Value, ScriptableObject.PERMANENT); + itObj.DefineProperty ("rdonly", Undefined.Value, ScriptableObject.READONLY); + scope.DefineProperty ("it", itObj, ScriptableObject.PERMANENT); + } + + public static ScriptableObject getLibraryScopeOrNull (IScriptable scope) + { + ScriptableObject libScope; + libScope = (ScriptableObject)ScriptableObject.GetTopScopeValue (scope, LIBRARY_SCOPE_KEY); + return libScope; + } + + // It is public so NativeRegExp can access it . + public static bool isJSLineTerminator (int c) + { + // Optimization for faster check for eol character: + // they do not have 0xDFD0 bits set + if ((c & 0xDFD0) != 0) { + return false; + } + return c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029; + } + + + /// Helper function for builtin objects that use the varargs form. + /// ECMA function formal arguments are undefined if not supplied; + /// this function pads the argument array out to the expected + /// length, if necessary. + /// + public static object [] padArguments (object [] args, int count) + { + if (count < args.Length) + return args; + + int i; + object [] result = new object [count]; + for (i = 0; i < args.Length; i++) { + result [i] = args [i]; + } + + for (; i < count; i++) { + result [i] = Undefined.Value; + } + + return result; + } + + + public static string escapeString (string s) + { + return escapeString (s, '"'); + } + + /// For escaping strings printed by object and array literals; not quite + /// the same as 'escape.' + /// + public static string escapeString (string s, char escapeQuote) + { + if (!(escapeQuote == '"' || escapeQuote == '\'')) + Context.CodeBug (); + System.Text.StringBuilder sb = null; + + for (int i = 0, L = s.Length; i != L; ++i) { + int c = s [i]; + + if (' ' <= c && c <= '~' && c != escapeQuote && c != '\\') { + // an ordinary print character (like C isprint()) and not " + // or \ . + if (sb != null) { + sb.Append ((char)c); + } + continue; + } + if (sb == null) { + sb = new System.Text.StringBuilder (L + 3); + sb.Append (s); + sb.Length = i; + } + + int escape = -1; + switch (c) { + + case '\b': + escape = 'b'; + break; + + case '\f': + escape = 'f'; + break; + + case '\n': + escape = 'n'; + break; + + case '\r': + escape = 'r'; + break; + + case '\t': + escape = 't'; + break; + + case 0xb: + escape = 'v'; + break; // Java lacks \v. + + case ' ': + escape = ' '; + break; + + case '\\': + escape = '\\'; + break; + } + if (escape >= 0) { + // an \escaped sort of character + sb.Append ('\\'); + sb.Append ((char)escape); + } + else if (c == escapeQuote) { + sb.Append ('\\'); + sb.Append (escapeQuote); + } + else { + int hexSize; + if (c < 256) { + // 2-digit hex + sb.Append ("\\x"); + hexSize = 2; + } + else { + // Unicode. + sb.Append ("\\u"); + hexSize = 4; + } + // append hexadecimal form of c left-padded with 0 + for (int shift = (hexSize - 1) * 4; shift >= 0; shift -= 4) { + int digit = 0xf & (c >> shift); + int hc = (digit < 10) ? '0' + digit : 'a' - 10 + digit; + sb.Append ((char)hc); + } + } + } + return (sb == null) ? s : sb.ToString (); + } + + internal static bool isValidIdentifierName (string s) + { + int L = s.Length; + if (L == 0) + return false; + if (!(char.IsLetter (s [0]) || s [0].CompareTo ('$') == 0 || s [0].CompareTo ('_') == 0)) + return false; + for (int i = 1; i != L; ++i) { + if (!TokenStream.IsJavaIdentifierPart (s [i])) + return false; + } + return !TokenStream.isKeyword (s); + } + + + + internal static string DefaultObjectToString (IScriptable obj) + { + return "[object " + obj.ClassName + ']'; + } + + internal static string uneval (Context cx, IScriptable scope, object value) + { + if (value == null) { + return "null"; + } + if (value == Undefined.Value) { + return "undefined"; + } + if (value is string) { + string escaped = escapeString ((string)value); + System.Text.StringBuilder sb = new System.Text.StringBuilder (escaped.Length + 2); + sb.Append ('\"'); + sb.Append (escaped); + sb.Append ('\"'); + return sb.ToString (); + } + if (CliHelper.IsNumber (value)) { + double d = Convert.ToDouble (value); + if (d == 0 && 1 / d < 0) { + return "-0"; + } + return ScriptConvert.ToString (d); + } + if (value is bool) { + return ScriptConvert.ToString (value); + } + if (value is IScriptable) { + IScriptable obj = (IScriptable)value; + object v = ScriptableObject.GetProperty (obj, "toSource"); + if (v is IFunction) { + IFunction f = (IFunction)v; + return ScriptConvert.ToString (f.Call (cx, scope, obj, EmptyArgs)); + } + return ScriptConvert.ToString (value); + } + WarnAboutNonJSObject (value); + return value.ToString (); + } + + internal static string defaultObjectToSource (Context cx, IScriptable scope, IScriptable thisObj, object [] args) + { + using (Helpers.StackOverflowVerifier sov = new Helpers.StackOverflowVerifier (1024)) { + bool toplevel, iterating; + if (cx.iterating == null) { + toplevel = true; + iterating = false; + cx.iterating = new ObjToIntMap (31); + } + else { + toplevel = false; + iterating = cx.iterating.has (thisObj); + } + + System.Text.StringBuilder result = new System.Text.StringBuilder (128); + if (toplevel) { + result.Append ("("); + } + result.Append ('{'); + + // Make sure cx.iterating is set to null when done + // so we don't leak memory + try { + if (!iterating) { + cx.iterating.intern (thisObj); // stop recursion. + object [] ids = thisObj.GetIds (); + for (int i = 0; i < ids.Length; i++) { + if (i > 0) + result.Append (", "); + object id = ids [i]; + object value; + if (id is int) { + int intId = ((int)id); + value = thisObj.Get (intId, thisObj); + result.Append (intId); + } + else { + string strId = (string)id; + value = thisObj.Get (strId, thisObj); + if (ScriptRuntime.isValidIdentifierName (strId)) { + result.Append (strId); + } + else { + result.Append ('\''); + result.Append (ScriptRuntime.escapeString (strId, '\'')); + result.Append ('\''); + } + } + result.Append (':'); + result.Append (ScriptRuntime.uneval (cx, scope, value)); + } + } + } + finally { + if (toplevel) { + cx.iterating = null; + } + } + + result.Append ('}'); + if (toplevel) { + result.Append (')'); + } + return result.ToString (); + } + } + + + + + public static IScriptable NewObject (Context cx, IScriptable scope, string constructorName, object [] args) + { + scope = ScriptableObject.GetTopLevelScope (scope); + IFunction ctor = getExistingCtor (cx, scope, constructorName); + if (args == null) { + args = ScriptRuntime.EmptyArgs; + } + return ctor.Construct (cx, scope, args); + } + + + // TODO: this is until setDefaultNamespace will learn how to store NS + // TODO: properly and separates namespace form Scriptable.get etc. + private const string DEFAULT_NS_TAG = "__default_namespace__"; + + public static object setDefaultNamespace (object ns, Context cx) + { + IScriptable scope = cx.currentActivationCall; + if (scope == null) { + scope = getTopCallScope (cx); + } + + XMLLib xmlLib = CurrentXMLLib (cx); + object obj = xmlLib.ToDefaultXmlNamespace (cx, ns); + + // TODO: this should be in separated namesapce from Scriptable.get/put + if (!scope.Has (DEFAULT_NS_TAG, scope)) { + // TODO: this is racy of cause + ScriptableObject.DefineProperty (scope, DEFAULT_NS_TAG, obj, ScriptableObject.PERMANENT | ScriptableObject.DONTENUM); + } + else { + scope.Put (DEFAULT_NS_TAG, scope, obj); + } + + return Undefined.Value; + } + + public static object searchDefaultNamespace (Context cx) + { + IScriptable scope = cx.currentActivationCall; + if (scope == null) { + scope = getTopCallScope (cx); + } + object nsObject; + for (; ; ) { + IScriptable parent = scope.ParentScope; + if (parent == null) { + nsObject = ScriptableObject.GetProperty (scope, DEFAULT_NS_TAG); + if (nsObject == UniqueTag.NotFound) { + return null; + } + break; + } + nsObject = scope.Get (DEFAULT_NS_TAG, scope); + if (nsObject != UniqueTag.NotFound) { + break; + } + scope = parent; + } + return nsObject; + } + + public static object getTopLevelProp (IScriptable scope, string id) + { + scope = ScriptableObject.GetTopLevelScope (scope); + return ScriptableObject.GetProperty (scope, id); + } + + internal static IFunction getExistingCtor (Context cx, IScriptable scope, string constructorName) + { + object ctorVal = ScriptableObject.GetProperty (scope, constructorName); + if (ctorVal is IFunction) { + return (IFunction)ctorVal; + } + if (ctorVal == UniqueTag.NotFound) { + throw Context.ReportRuntimeErrorById ("msg.ctor.not.found", constructorName); + } + else { + throw Context.ReportRuntimeErrorById ("msg.not.ctor", constructorName); + } + } + + /// Return -1L if str is not an index or the index value as lower 32 + /// bits of the result. + /// + private static long indexFromString (string str) + { + // The length of the decimal string representation of + // Integer.MAX_VALUE, 2147483647 + const int MAX_VALUE_LENGTH = 10; + + int len = str.Length; + if (len > 0) { + int i = 0; + bool negate = false; + int c = str [0]; + if (c == '-') { + if (len > 1) { + c = str [1]; + i = 1; + negate = true; + } + } + c -= '0'; + if (0 <= c && c <= 9 && len <= (negate ? MAX_VALUE_LENGTH + 1 : MAX_VALUE_LENGTH)) { + // Use negative numbers to accumulate index to handle + // Integer.MIN_VALUE that is greater by 1 in absolute value + // then Integer.MAX_VALUE + int index = -c; + int oldIndex = 0; + i++; + if (index != 0) { + // Note that 00, 01, 000 etc. are not indexes + while (i != len && 0 <= (c = str [i] - '0') && c <= 9) { + oldIndex = index; + index = 10 * index - c; + i++; + } + } + // Make sure all characters were consumed and that it couldn't + // have overflowed. + if (i == len && (oldIndex > (int.MinValue / 10) || (oldIndex == (int.MinValue / 10) && c <= (negate ? -(int.MinValue % 10) : (int.MaxValue % 10))))) { + return unchecked ((int)0xFFFFFFFFL) & (negate ? index : -index); + } + } + } + return -1L; + } + + /// If str is a decimal presentation of Uint32 value, return it as long. + /// Othewise return -1L; + /// + public static long testUint32String (string str) + { + // The length of the decimal string representation of + // UINT32_MAX_VALUE, 4294967296 + const int MAX_VALUE_LENGTH = 10; + + int len = str.Length; + if (1 <= len && len <= MAX_VALUE_LENGTH) { + int c = str [0]; + c -= '0'; + if (c == 0) { + // Note that 00,01 etc. are not valid Uint32 presentations + return (len == 1) ? 0L : -1L; + } + if (1 <= c && c <= 9) { + long v = c; + for (int i = 1; i != len; ++i) { + c = str [i] - '0'; + if (!(0 <= c && c <= 9)) { + return -1; + } + v = 10 * v + c; + } + // Check for overflow + if ((ulong)v >> 32 == 0) { + return v; + } + } + } + return -1; + } + + /// If s represents index, then return index value wrapped as Integer + /// and othewise return s. + /// + internal static object getIndexObject (string s) + { + long indexTest = indexFromString (s); + if (indexTest >= 0) { + return (int)indexTest; + } + return s; + } + + /// If d is exact int value, return its value wrapped as Integer + /// and othewise return d converted to String. + /// + internal static object getIndexObject (double d) + { + int i = (int)d; + if ((double)i == d) { + return (int)i; + } + return ScriptConvert.ToString (d); + } + + /// If ScriptConvert.ToString(id) is a decimal presentation of int32 value, then id + /// is index. In this case return null and make the index available + /// as ScriptRuntime.lastIndexResult(cx). Otherwise return ScriptConvert.ToString(id). + /// + internal static string ToStringIdOrIndex (Context cx, object id) + { + if (CliHelper.IsNumber (id)) { + double d = Convert.ToDouble (id); + int index = (int)d; + if (((double)index) == d) { + storeIndexResult (cx, index); + return null; + } + return ScriptConvert.ToString (id); + } + else { + string s; + if (id is string) { + s = ((string)id); + } + else { + s = ScriptConvert.ToString (id); + } + long indexTest = indexFromString (s); + if (indexTest >= 0) { + storeIndexResult (cx, (int)indexTest); + return null; + } + return s; + } + } + + /// Call obj.[[Get]](id) + public static object getObjectElem (object obj, object elem, Context cx) + { + IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj); + if (sobj == null) { + throw UndefReadError (obj, elem); + } + return getObjectElem (sobj, elem, cx); + } + + public static object getObjectElem (IScriptable obj, object elem, Context cx) + { + if (obj is XMLObject) { + XMLObject xmlObject = (XMLObject)obj; + return xmlObject.EcmaGet (cx, elem); + } + + object result; + + string s = ScriptRuntime.ToStringIdOrIndex (cx, elem); + if (s == null) { + int index = lastIndexResult (cx); + result = ScriptableObject.GetProperty (obj, index); + } + else { + result = ScriptableObject.GetProperty (obj, s); + } + + if (result == UniqueTag.NotFound) { + result = Undefined.Value; + } + + return result; + } + + /// Version of getObjectElem when elem is a valid JS identifier name. + public static object getObjectProp (object obj, string property, Context cx) + { + IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj); + if (sobj == null) { + throw UndefReadError (obj, property); + } + return getObjectProp (sobj, property, cx); + } + + public static object getObjectProp (IScriptable obj, string property, Context cx) + { + if (obj is XMLObject) { + XMLObject xmlObject = (XMLObject)obj; + return xmlObject.EcmaGet (cx, property); + } + + object result = ScriptableObject.GetProperty (obj, property); + if (result == UniqueTag.NotFound) { + result = Undefined.Value; + } + + return result; + } + + /* + * A cheaper and less general version of the above for well-known argument + * types. + */ + public static object getObjectIndex (object obj, double dblIndex, Context cx) + { + IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj); + if (sobj == null) { + throw UndefReadError (obj, ScriptConvert.ToString (dblIndex)); + } + int index = (int)dblIndex; + if ((double)index == dblIndex) { + return getObjectIndex (sobj, index, cx); + } + else { + string s = ScriptConvert.ToString (dblIndex); + return getObjectProp (sobj, s, cx); + } + } + + public static object getObjectIndex (IScriptable obj, int index, Context cx) + { + if (obj is XMLObject) { + XMLObject xmlObject = (XMLObject)obj; + return xmlObject.EcmaGet (cx, (object)index); + } + + object result = ScriptableObject.GetProperty (obj, index); + if (result == UniqueTag.NotFound) { + result = Undefined.Value; + } + + return result; + } + + /* + * Call obj.[[Put]](id, value) + */ + public static object setObjectElem (object obj, object elem, object value, Context cx) + { + IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj); + if (sobj == null) { + throw UndefWriteError (obj, elem, value); + } + return setObjectElem (sobj, elem, value, cx); + } + + public static object setObjectElem (IScriptable obj, object elem, object value, Context cx) + { + if (obj is XMLObject) { + XMLObject xmlObject = (XMLObject)obj; + xmlObject.EcmaPut (cx, elem, value); + return value; + } + + string s = ScriptRuntime.ToStringIdOrIndex (cx, elem); + if (s == null) { + int index = lastIndexResult (cx); + ScriptableObject.PutProperty (obj, index, value); + } + else { + ScriptableObject.PutProperty (obj, s, value); + } + + return value; + } + + /// Version of setObjectElem when elem is a valid JS identifier name. + public static object setObjectProp (object obj, string property, object value, Context cx) + { + IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj); + if (sobj == null) { + throw UndefWriteError (obj, property, value); + } + return setObjectProp (sobj, property, value, cx); + } + + public static object setObjectProp (IScriptable obj, string property, object value, Context cx) + { + if (obj is XMLObject) { + XMLObject xmlObject = (XMLObject)obj; + xmlObject.EcmaPut (cx, property, value); + } + else { + return ScriptableObject.PutProperty (obj, property, value); + } + return value; + } + + /* + * A cheaper and less general version of the above for well-known argument + * types. + */ + public static object setObjectIndex (object obj, double dblIndex, object value, Context cx) + { + IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj); + if (sobj == null) { + throw UndefWriteError (obj, Convert.ToString (dblIndex), value); + } + int index = (int)dblIndex; + if ((double)index == dblIndex) { + return setObjectIndex (sobj, index, value, cx); + } + else { + string s = ScriptConvert.ToString (dblIndex); + return setObjectProp (sobj, s, value, cx); + } + } + + public static object setObjectIndex (IScriptable obj, int index, object value, Context cx) + { + if (obj is XMLObject) { + XMLObject xmlObject = (XMLObject)obj; + xmlObject.EcmaPut (cx, (object)index, value); + } + else { + return ScriptableObject.PutProperty (obj, index, value); + } + return value; + } + + public static bool deleteObjectElem (IScriptable target, object elem, Context cx) + { + bool result; + if (target is XMLObject) { + XMLObject xmlObject = (XMLObject)target; + result = xmlObject.EcmaDelete (cx, elem); + } + else { + string s = ScriptRuntime.ToStringIdOrIndex (cx, elem); + if (s == null) { + int index = lastIndexResult (cx); + result = ScriptableObject.DeleteProperty (target, index); + } + else { + result = ScriptableObject.DeleteProperty (target, s); + } + } + return result; + } + + public static bool hasObjectElem (IScriptable target, object elem, Context cx) + { + bool result; + + if (target is XMLObject) { + XMLObject xmlObject = (XMLObject)target; + result = xmlObject.EcmaHas (cx, elem); + } + else { + string s = ScriptRuntime.ToStringIdOrIndex (cx, elem); + if (s == null) { + int index = lastIndexResult (cx); + result = ScriptableObject.HasProperty (target, index); + } + else { + result = ScriptableObject.HasProperty (target, s); + } + } + + return result; + } + + public static object refGet (IRef rf, Context cx) + { + return rf.Get (cx); + } + + public static object refSet (IRef rf, object value, Context cx) + { + return rf.Set (cx, value); + } + + public static object refDel (IRef rf, Context cx) + { + return rf.Delete (cx); + } + + internal static bool isSpecialProperty (string s) + { + return s.Equals ("__proto__") || s.Equals ("__parent__"); + } + + public static IRef specialRef (object obj, string specialProperty, Context cx) + { + return SpecialRef.createSpecial (cx, obj, specialProperty); + } + + /// The delete operator + /// + /// See ECMA 11.4.1 + /// + /// In ECMA 0.19, the description of the delete operator (11.4.1) + /// assumes that the [[Delete]] method returns a value. However, + /// the definition of the [[Delete]] operator (8.6.2.5) does not + /// define a return value. Here we assume that the [[Delete]] + /// method doesn't return a value. + /// + public static object delete (object obj, object id, Context cx) + { + IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj); + if (sobj == null) { + string idStr = (id == null) ? "null" : id.ToString (); + throw TypeErrorById ("msg.undef.prop.delete", ScriptConvert.ToString (obj), idStr); + } + bool result = deleteObjectElem (sobj, id, cx); + return result; + } + + /// Looks up a name in the scope chain and returns its value. + public static object name (Context cx, IScriptable scope, string name) + { + IScriptable parent = scope.ParentScope; + if (parent == null) { + object result = topScopeName (cx, scope, name); + if (result == UniqueTag.NotFound) { + throw NotFoundError (scope, name); + } + return result; + } + + return nameOrFunction (cx, scope, parent, name, false); + } + + private static object nameOrFunction (Context cx, IScriptable scope, IScriptable parentScope, string name, bool asFunctionCall) + { + object result; + IScriptable thisObj = scope; // It is used only if asFunctionCall==true. + + XMLObject firstXMLObject = null; + for (; ; ) { + if (scope is BuiltinWith) { + IScriptable withObj = scope.GetPrototype (); + if (withObj is XMLObject) { + XMLObject xmlObj = (XMLObject)withObj; + if (xmlObj.EcmaHas (cx, name)) { + // function this should be the target object of with + thisObj = xmlObj; + result = xmlObj.EcmaGet (cx, name); + break; + } + if (firstXMLObject == null) { + firstXMLObject = xmlObj; + } + } + else { + result = ScriptableObject.GetProperty (withObj, name); + if (result != UniqueTag.NotFound) { + // function this should be the target object of with + thisObj = withObj; + break; + } + } + } + else if (scope is BuiltinCall) { + // NativeCall does not prototype chain and Scriptable.get + // can be called directly. + result = scope.Get (name, scope); + if (result != UniqueTag.NotFound) { + if (asFunctionCall) { + // ECMA 262 requires that this for nested funtions + // should be top scope + thisObj = ScriptableObject.GetTopLevelScope (parentScope); + } + break; + } + } + else { + // Can happen if embedding decided that nested + // scopes are useful for what ever reasons. + result = ScriptableObject.GetProperty (scope, name); + if (result != UniqueTag.NotFound) { + thisObj = scope; + break; + } + } + scope = parentScope; + parentScope = parentScope.ParentScope; + if (parentScope == null) { + result = topScopeName (cx, scope, name); + if (result == UniqueTag.NotFound) { + if (firstXMLObject == null || asFunctionCall) { + throw NotFoundError (scope, name); + } + // The name was not found, but we did find an XML + // object in the scope chain and we are looking for name, + // not function. The result should be an empty XMLList + // in name context. + result = firstXMLObject.EcmaGet (cx, name); + } + // For top scope thisObj for functions is always scope itself. + thisObj = scope; + break; + } + } + + if (asFunctionCall) { + if (!(result is ICallable)) { + throw NotFunctionError (result, name); + } + storeScriptable (cx, thisObj); + } + + return result; + } + + private static object topScopeName (Context cx, IScriptable scope, string name) + { + if (cx.useDynamicScope) { + scope = checkDynamicScope (cx.topCallScope, scope); + } + return ScriptableObject.GetProperty (scope, name); + } + + + /// Returns the object in the scope chain that has a given property. + /// + /// The order of evaluation of an assignment expression involves + /// evaluating the lhs to a reference, evaluating the rhs, and then + /// modifying the reference with the rhs value. This method is used + /// to 'bind' the given name to an object containing that property + /// so that the side effects of evaluating the rhs do not affect + /// which property is modified. + /// Typically used in conjunction with setName. + /// + /// See ECMA 10.1.4 + /// + public static IScriptable bind (Context cx, IScriptable scope, string id) + { + IScriptable firstXMLObject = null; + IScriptable parent = scope.ParentScope; + if (parent != null) { + // Check for possibly nested "with" scopes first + while (scope is BuiltinWith) { + IScriptable withObj = scope.GetPrototype (); + if (withObj is XMLObject) { + XMLObject xmlObject = (XMLObject)withObj; + if (xmlObject.EcmaHas (cx, id)) { + return xmlObject; + } + if (firstXMLObject == null) { + firstXMLObject = xmlObject; + } + } + else { + if (ScriptableObject.HasProperty (withObj, id)) { + return withObj; + } + } + scope = parent; + parent = parent.ParentScope; + if (parent == null) { + + goto childScopesChecks_brk; + } + } + for (; ; ) { + if (ScriptableObject.HasProperty (scope, id)) { + return scope; + } + scope = parent; + parent = parent.ParentScope; + if (parent == null) { + + goto childScopesChecks_brk; + } + } + } + + childScopesChecks_brk: + ; + + // scope here is top scope + if (cx.useDynamicScope) { + scope = checkDynamicScope (cx.topCallScope, scope); + } + if (ScriptableObject.HasProperty (scope, id)) { + return scope; + } + // Nothing was found, but since XML objects always bind + // return one if found + return firstXMLObject; + } + + public static object setName (IScriptable bound, object value, Context cx, IScriptable scope, string id) + { + if (bound != null) { + if (bound is XMLObject) { + XMLObject xmlObject = (XMLObject)bound; + xmlObject.EcmaPut (cx, id, value); + } + else { + ScriptableObject.PutProperty (bound, id, value); + } + } + else { + // "newname = 7;", where 'newname' has not yet + // been defined, creates a new property in the + // top scope unless strict mode is specified. + if (cx.HasFeature (Context.Features.StrictVars)) { + throw Context.ReportRuntimeErrorById ("msg.assn.create.strict", id); + } + // Find the top scope by walking up the scope chain. + bound = ScriptableObject.GetTopLevelScope (scope); + if (cx.useDynamicScope) { + bound = checkDynamicScope (cx.topCallScope, bound); + } + bound.Put (id, bound, value); + } + return value; + } + + + + + + + /// Prepare for calling name(...): return function corresponding to + /// name and make current top scope available + /// as ScriptRuntime.lastStoredScriptable() for consumption as thisObj. + /// The caller must call ScriptRuntime.lastStoredScriptable() immediately + /// after calling this method. + /// + public static ICallable getNameFunctionAndThis (string name, Context cx, IScriptable scope) + { + IScriptable parent = scope.ParentScope; + if (parent == null) { + object result = topScopeName (cx, scope, name); + if (!(result is ICallable)) { + if (result == UniqueTag.NotFound) { + throw NotFoundError (scope, name); + } + else { + throw NotFunctionError (result, name); + } + } + // Top scope is not NativeWith or NativeCall => thisObj == scope + IScriptable thisObj = scope; + storeScriptable (cx, thisObj); + return (ICallable)result; + } + + // name will call storeScriptable(cx, thisObj); + return (ICallable)nameOrFunction (cx, scope, parent, name, true); + } + + /// Prepare for calling obj[id](...): return function corresponding to + /// obj[id] and make obj properly converted to Scriptable available + /// as ScriptRuntime.lastStoredScriptable() for consumption as thisObj. + /// The caller must call ScriptRuntime.lastStoredScriptable() immediately + /// after calling this method. + /// + public static ICallable GetElemFunctionAndThis (object obj, object elem, Context cx) + { + string s = ScriptRuntime.ToStringIdOrIndex (cx, elem); + if (s != null) { + return getPropFunctionAndThis (obj, s, cx); + } + int index = lastIndexResult (cx); + + IScriptable thisObj = ScriptConvert.ToObjectOrNull (cx, obj); + if (thisObj == null) { + throw UndefCallError (obj, Convert.ToString (index)); + } + + object value; + for (; ; ) { + // Ignore XML lookup as requred by ECMA 357, 11.2.2.1 + value = ScriptableObject.GetProperty (thisObj, index); + if (value != UniqueTag.NotFound) { + break; + } + if (!(thisObj is XMLObject)) { + break; + } + XMLObject xmlObject = (XMLObject)thisObj; + IScriptable extra = xmlObject.GetExtraMethodSource (cx); + if (extra == null) { + break; + } + thisObj = extra; + } + if (!(value is ICallable)) { + throw NotFunctionError (value, elem); + } + + storeScriptable (cx, thisObj); + return (ICallable)value; + } + + /// Prepare for calling obj.property(...): return function corresponding to + /// obj.property and make obj properly converted to Scriptable available + /// as ScriptRuntime.lastStoredScriptable() for consumption as thisObj. + /// The caller must call ScriptRuntime.lastStoredScriptable() immediately + /// after calling this method. + /// + public static ICallable getPropFunctionAndThis (object obj, string property, Context cx) + { + IScriptable thisObj = ScriptConvert.ToObjectOrNull (cx, obj); + if (thisObj == null) { + throw UndefCallError (obj, property); + } + + object value; + for (; ; ) { + // Ignore XML lookup as requred by ECMA 357, 11.2.2.1 + value = ScriptableObject.GetProperty (thisObj, property); + if (value != UniqueTag.NotFound) { + break; + } + if (!(thisObj is XMLObject)) { + break; + } + XMLObject xmlObject = (XMLObject)thisObj; + IScriptable extra = xmlObject.GetExtraMethodSource (cx); + if (extra == null) { + break; + } + thisObj = extra; + } + + if (value == UniqueTag.NotFound) { + //if (thisObj.Get ("__noSuchMethod__", thisObj) as ICallable != null) { + // return UniqueTag.NoSuchMethodMark; + //} + } + + if (!(value is ICallable)) { + throw NotFunctionError (value, property); + } + + storeScriptable (cx, thisObj); + return (ICallable)value; + } + + /// Prepare for calling (...): return function corresponding to + /// and make parent scope of the function available + /// as ScriptRuntime.lastStoredScriptable() for consumption as thisObj. + /// The caller must call ScriptRuntime.lastStoredScriptable() immediately + /// after calling this method. + /// + public static ICallable getValueFunctionAndThis (object value, Context cx) + { + if (!(value is ICallable)) { + throw NotFunctionError (value); + } + + ICallable f = (ICallable)value; + IScriptable thisObj; + if (f is IScriptable) { + thisObj = ((IScriptable)f).ParentScope; + } + else { + if (cx.topCallScope == null) + throw new Exception (); + thisObj = cx.topCallScope; + } + if (thisObj.ParentScope != null) { + if (thisObj is BuiltinWith) { + // functions defined inside with should have with target + // as their thisObj + } + else if (thisObj is BuiltinCall) { + // nested functions should have top scope as their thisObj + thisObj = ScriptableObject.GetTopLevelScope (thisObj); + } + } + storeScriptable (cx, thisObj); + return f; + } + + /// Perform function call in reference context. Should always + /// return value that can be passed to + /// {@link #refGet(Object)} or @link #refSet(Object, Object)} + /// arbitrary number of times. + /// The args array reference should not be stored in any object that is + /// can be GC-reachable after this method returns. If this is necessary, + /// store args.clone(), not args array itself. + /// + public static IRef callRef (ICallable function, IScriptable thisObj, object [] args, Context cx) + { + if (function is IRefCallable) { + IRefCallable rfunction = (IRefCallable)function; + IRef rf = rfunction.RefCall (cx, thisObj, args); + if (rf == null) { + throw new Exception (rfunction.GetType ().FullName + ".refCall() returned null"); + } + return rf; + } + // No runtime support for now + string msg = GetMessage ("msg.no.ref.from.function", ScriptConvert.ToString (function)); + throw ConstructError ("ReferenceError", msg); + } + + /// Operator new. + /// + /// See ECMA 11.2.2 + /// + public static IScriptable NewObject (object fun, Context cx, IScriptable scope, object [] args) + { + if (!(fun is IFunction)) { + throw NotFunctionError (fun); + } + IFunction function = (IFunction)fun; + return function.Construct (cx, scope, args); + } + + public static object callSpecial (Context cx, ICallable fun, IScriptable thisObj, object [] args, IScriptable scope, IScriptable callerThis, int callType, string filename, int lineNumber) + { + if (callType == Node.SPECIALCALL_EVAL) { + if (BuiltinGlobal.isEvalFunction (fun)) { + return evalSpecial (cx, scope, callerThis, args, filename, lineNumber); + } + } + else if (callType == Node.SPECIALCALL_WITH) { + if (BuiltinWith.IsWithFunction (fun)) { + throw Context.ReportRuntimeErrorById ("msg.only.from.new", "With"); + } + } + else { + throw Context.CodeBug (); + } + + return fun.Call (cx, scope, thisObj, args); + } + + public static object newSpecial (Context cx, object fun, object [] args, IScriptable scope, int callType) + { + if (callType == Node.SPECIALCALL_EVAL) { + if (BuiltinGlobal.isEvalFunction (fun)) { + throw TypeErrorById ("msg.not.ctor", "eval"); + } + } + else if (callType == Node.SPECIALCALL_WITH) { + if (BuiltinWith.IsWithFunction (fun)) { + return BuiltinWith.NewWithSpecial (cx, scope, args); + } + } + else { + throw Context.CodeBug (); + } + + return NewObject (fun, cx, scope, args); + } + + /// Function.prototype.apply and Function.prototype.call + /// + /// See Ecma 15.3.4.[34] + /// + public static object applyOrCall (bool isApply, Context cx, IScriptable scope, IScriptable thisObj, object [] args) + { + int L = args.Length; + ICallable function; + if (thisObj is ICallable) { + function = (ICallable)thisObj; + } + else { + object value = thisObj.GetDefaultValue (typeof (IFunction)); + if (!(value is ICallable)) { + throw ScriptRuntime.NotFunctionError (value, thisObj); + } + function = (ICallable)value; + } + + IScriptable callThis = null; + if (L != 0) { + callThis = ScriptConvert.ToObjectOrNull (cx, args [0]); + } + if (callThis == null) { + // This covers the case of args[0] == (null|undefined) as well. + callThis = getTopCallScope (cx); + } + + object [] callArgs; + if (isApply) { + // Follow Ecma 15.3.4.3 + if (L <= 1) { + callArgs = ScriptRuntime.EmptyArgs; + } + else { + object arg1 = args [1]; + if (arg1 == null || arg1 == Undefined.Value) { + callArgs = ScriptRuntime.EmptyArgs; + } + else if (arg1 is BuiltinArray || arg1 is Arguments) { + callArgs = cx.GetElements ((IScriptable)arg1); + } + else { + throw ScriptRuntime.TypeErrorById ("msg.arg.isnt.array"); + } + } + } + else { + // Follow Ecma 15.3.4.4 + if (L <= 1) { + callArgs = ScriptRuntime.EmptyArgs; + } + else { + callArgs = new object [L - 1]; + Array.Copy (args, 1, callArgs, 0, L - 1); + } + } + + return function.Call (cx, scope, callThis, callArgs); + } + + /// The eval function property of the global object. + /// + /// See ECMA 15.1.2.1 + /// + public static object evalSpecial (Context cx, IScriptable scope, object thisArg, object [] args, string filename, int lineNumber) + { + if (args.Length < 1) + return Undefined.Value; + object x = args [0]; + if (!(x is string)) { + if (cx.HasFeature (Context.Features.StrictEval)) { + throw Context.ReportRuntimeErrorById ("msg.eval.nonstring.strict"); + } + string message = ScriptRuntime.GetMessage ("msg.eval.nonstring"); + Context.ReportWarning (message); + return x; + } + if (filename == null) { + int [] linep = new int [1]; + filename = Context.GetSourcePositionFromStack (linep); + if (filename != null) { + lineNumber = linep [0]; + } + else { + filename = ""; + } + } + string sourceName = ScriptRuntime.makeUrlForGeneratedScript (true, filename, lineNumber); + + ErrorReporter reporter; + reporter = DefaultErrorReporter.ForEval (cx.ErrorReporter); + + // Compile with explicit interpreter instance to force interpreter + // mode. + IScript script = cx.CompileString ((string)x, new Interpreter (), reporter, sourceName, 1, (object)null); + ((InterpretedFunction)script).idata.evalScriptFlag = true; + ICallable c = (ICallable)script; + return c.Call (cx, scope, (IScriptable)thisArg, ScriptRuntime.EmptyArgs); + } + + /// The typeof operator + public static string Typeof (object value) + { + if (value == null) + return "object"; + if (value == Undefined.Value) + return "undefined"; + if (value is IScriptable) { + if (value is XMLObject) + return "xml"; + + return (value is ICallable && !(value is BuiltinRegExp)) ? "function" : "object"; + } + if (value is string) + return "string"; + if (value is char || CliHelper.IsNumber (value)) + return "number"; + if (value is bool) + return "boolean"; + throw errorWithClassName ("msg.invalid.type", value); + } + + + internal static Exception errorWithClassName (string msg, object val) + { + return Context.ReportRuntimeErrorById (msg, val.GetType ().FullName); + } + + /// The typeof operator that correctly handles the undefined case + public static string TypeofName (IScriptable scope, string id) + { + Context cx = Context.CurrentContext; + IScriptable val = bind (cx, scope, id); + if (val == null) + return "undefined"; + return Typeof (getObjectProp (val, id, cx)); + } + + // neg: + // implement the '-' operator inline in the caller + // as "-ScriptConvert.ToNumber(val)" + + // not: + // implement the '!' operator inline in the caller + // as "!toBoolean(val)" + + // bitnot: + // implement the '~' operator inline in the caller + // as "~toInt32(val)" + + public static object Add (object val1, object val2, Context cx) + { + if (CliHelper.IsNumber (val1) && CliHelper.IsNumber (val2)) { + return (double)val1 + (double)val2; + } + if (val1 is XMLObject) { + object test = ((XMLObject)val1).AddValues (cx, true, val2); + if (test != UniqueTag.NotFound) { + return test; + } + } + if (val2 is XMLObject) { + object test = ((XMLObject)val2).AddValues (cx, false, val1); + if (test != UniqueTag.NotFound) { + return test; + } + } + if (val1 is EcmaScript.NET.Types.Cli.CliEventInfo) { + return ((EcmaScript.NET.Types.Cli.CliEventInfo)val1).Add (val2, cx); + } + if (val1 is IScriptable) + val1 = ((IScriptable)val1).GetDefaultValue (null); + if (val2 is IScriptable) + val2 = ((IScriptable)val2).GetDefaultValue (null); + if (!(val1 is string) && !(val2 is string)) + if ((CliHelper.IsNumber (val1)) && (CliHelper.IsNumber (val2))) + return (double)val1 + (double)val2; + else + return ScriptConvert.ToNumber (val1) + ScriptConvert.ToNumber (val2); + return string.Concat (ScriptConvert.ToString (val1), ScriptConvert.ToString (val2)); + } + + public static object nameIncrDecr (IScriptable scopeChain, string id, int incrDecrMask) + { + IScriptable target; + object value; + { + do { + target = scopeChain; + do { + value = target.Get (id, scopeChain); + if (value != UniqueTag.NotFound) { + + goto search_brk; + } + target = target.GetPrototype (); + } + while (target != null); + scopeChain = scopeChain.ParentScope; + } + while (scopeChain != null); + throw NotFoundError (scopeChain, id); + } + + search_brk: + ; + + return doScriptableIncrDecr (target, id, scopeChain, value, incrDecrMask); + } + + public static object propIncrDecr (object obj, string id, Context cx, int incrDecrMask) + { + IScriptable start = ScriptConvert.ToObjectOrNull (cx, obj); + if (start == null) { + throw UndefReadError (obj, id); + } + + IScriptable target = start; + object value; + { + do { + value = target.Get (id, start); + if (value != UniqueTag.NotFound) { + + goto search1_brk; + } + target = target.GetPrototype (); + } + while (target != null); + start.Put (id, start, double.NaN); + return double.NaN; + } + + search1_brk: + ; + + return doScriptableIncrDecr (target, id, start, value, incrDecrMask); + } + + private static object doScriptableIncrDecr (IScriptable target, string id, IScriptable protoChainStart, object value, int incrDecrMask) + { + bool post = ((incrDecrMask & Node.POST_FLAG) != 0); + double number; + if (CliHelper.IsNumber (value)) { + number = Convert.ToDouble (value); + } + else { + number = ScriptConvert.ToNumber (value); + if (post) { + // convert result to number + value = number; + } + } + if ((incrDecrMask & Node.DECR_FLAG) == 0) { + ++number; + } + else { + --number; + } + object result = number; + target.Put (id, protoChainStart, result); + if (post) { + return value; + } + else { + return result; + } + } + + public static object elemIncrDecr (object obj, object index, Context cx, int incrDecrMask) + { + object value = getObjectElem (obj, index, cx); + bool post = ((incrDecrMask & Node.POST_FLAG) != 0); + double number; + if (CliHelper.IsNumber (value)) { + number = Convert.ToDouble (value); + } + else { + number = ScriptConvert.ToNumber (value); + if (post) { + // convert result to number + value = number; + } + } + if ((incrDecrMask & Node.DECR_FLAG) == 0) { + ++number; + } + else { + --number; + } + object result = number; + setObjectElem (obj, index, result, cx); + if (post) { + return value; + } + else { + return result; + } + } + + public static object refIncrDecr (IRef rf, Context cx, int incrDecrMask) + { + object value = rf.Get (cx); + bool post = ((incrDecrMask & Node.POST_FLAG) != 0); + double number; + if (CliHelper.IsNumber (value)) { + number = Convert.ToDouble (value); + } + else { + number = ScriptConvert.ToNumber (value); + if (post) { + // convert result to number + value = number; + } + } + if ((incrDecrMask & Node.DECR_FLAG) == 0) { + ++number; + } + else { + --number; + } + rf.Set (cx, number); + if (post) { + return value; + } + else { + return number; + } + } + + + /// Equality + /// + /// See ECMA 11.9 + /// + public static bool eq (object x, object y) + { + if (x == null || x == Undefined.Value) { + if (y == null || y == Undefined.Value) { + return true; + } + if (y is ScriptableObject) { + object test = ((ScriptableObject)y).EquivalentValues (x); + if (test != UniqueTag.NotFound) { + return ((bool)test); + } + } + return false; + } + else if (CliHelper.IsNumber (x)) { + return eqNumber (Convert.ToDouble (x), y); + } + else if (x is string) { + return eqString ((string)x, y); + } + else if (x is bool) { + bool b = ((bool)x); + if (y is bool) { + return b == ((bool)y); + } + if (y is ScriptableObject) { + object test = ((ScriptableObject)y).EquivalentValues (x); + if (test != UniqueTag.NotFound) { + return ((bool)test); + } + } + return eqNumber (b ? 1.0 : 0.0, y); + } + else if (x is IScriptable) { + if (y is IScriptable) { + if (x == y) { + return true; + } + if (x is ScriptableObject) { + object test = ((ScriptableObject)x).EquivalentValues (y); + if (test != UniqueTag.NotFound) { + return ((bool)test); + } + } + if (y is ScriptableObject) { + object test = ((ScriptableObject)y).EquivalentValues (x); + if (test != UniqueTag.NotFound) { + return ((bool)test); + } + } + if (x is Wrapper && y is Wrapper) { + return ((Wrapper)x).Unwrap () == ((Wrapper)y).Unwrap (); + } + return false; + } + else if (y is bool) { + if (x is ScriptableObject) { + object test = ((ScriptableObject)x).EquivalentValues (y); + if (test != UniqueTag.NotFound) { + return ((bool)test); + } + } + double d = ((bool)y) ? 1.0 : 0.0; + return eqNumber (d, x); + } + else if (CliHelper.IsNumber (y)) { + return eqNumber (Convert.ToDouble (y), x); + } + else if (y is string) { + return eqString ((string)y, x); + } + // covers the case when y == Undefined.instance as well + return false; + } + else { + WarnAboutNonJSObject (x); + return x == y; + } + } + + internal static bool eqNumber (double x, object y) + { + for (; ; ) { + if (y == null || y == Undefined.Value) { + return false; + } + else if (CliHelper.IsNumber (y)) { + return x == Convert.ToDouble (y); + } + else if (y is string) { + return x == ScriptConvert.ToNumber (y); + } + else if (y is bool) { + return x == (((bool)y) ? 1.0 : +0.0); + } + else if (y is IScriptable) { + if (y is ScriptableObject) { + object xval = x; + object test = ((ScriptableObject)y).EquivalentValues (xval); + if (test != UniqueTag.NotFound) { + return ((bool)test); + } + } + y = ScriptConvert.ToPrimitive (y); + } + else { + WarnAboutNonJSObject (y); + return false; + } + } + } + + private static bool eqString (string x, object y) + { + for (; ; ) { + if (y == null || y == Undefined.Value) { + return false; + } + else if (y is string) { + return x.Equals (y); + } + else if (CliHelper.IsNumber (y)) { + return ScriptConvert.ToNumber (x) == Convert.ToDouble (y); + } + else if (y is bool) { + return ScriptConvert.ToNumber (x) == (((bool)y) ? 1.0 : 0.0); + } + else if (y is IScriptable) { + if (y is ScriptableObject) { + object test = ((ScriptableObject)y).EquivalentValues (x); + if (test != UniqueTag.NotFound) { + return ((bool)test); + } + } + y = ScriptConvert.ToPrimitive (y); + continue; + } + else { + WarnAboutNonJSObject (y); + return false; + } + } + } + public static bool shallowEq (object x, object y) + { + if (x == y) { + if (!(CliHelper.IsNumber (x))) { + return true; + } + // double.NaN check + double d = Convert.ToDouble (x); + return !double.IsNaN (d); + } + if (x == null || x == Undefined.Value) { + return false; + } + else if (CliHelper.IsNumber (x)) { + if (CliHelper.IsNumber (y)) { + return Convert.ToDouble (x) == Convert.ToDouble (y); + } + } + else if (x is string) { + if (y is string) { + return x.Equals (y); + } + } + else if (x is bool) { + if (y is bool) { + return x.Equals (y); + } + } + else if (x is IScriptable) { + if (x is Wrapper && y is Wrapper) { + return ((Wrapper)x).Unwrap () == ((Wrapper)y).Unwrap (); + } + } + else { + WarnAboutNonJSObject (x); + return x == y; + } + return false; + } + + /// The instanceof operator. + /// + /// + /// a instanceof b + /// + public static bool InstanceOf (object a, object b, Context cx) + { + IScriptable sB = (b as IScriptable); + + // Check RHS is an object + if (sB == null) { + throw TypeErrorById ("msg.instanceof.not.object"); + } + + IScriptable sA = (a as IScriptable); + + // for primitive values on LHS, return false + // TODO we may want to change this so that 5 instanceof Number == true + if (sA == null) { + return false; + } + + + return sB.HasInstance (sA); + } + + /// Delegates to + /// + /// + /// true iff rhs appears in lhs' proto chain + /// + protected internal static bool jsDelegatesTo (IScriptable lhs, IScriptable rhs) + { + IScriptable proto = lhs.GetPrototype (); + + while (proto != null) { + if (proto.Equals (rhs)) + return true; + proto = proto.GetPrototype (); + } + + return false; + } + + /// The in operator. + /// + /// This is a new JS 1.3 language feature. The in operator mirrors + /// the operation of the for .. in construct, and tests whether the + /// rhs has the property given by the lhs. It is different from the + /// for .. in construct in that: + ///
- it doesn't perform ToObject on the right hand side + ///
- it returns true for DontEnum properties. + ///
+ /// the left hand operand + /// + /// the right hand operand + /// + /// + /// true if property name or element number a is a property of b + /// + public static bool In (object a, object b, Context cx) + { + if (!(b is IScriptable)) { + throw TypeErrorById ("msg.instanceof.not.object"); + } + + return hasObjectElem ((IScriptable)b, a, cx); + } + + public static bool cmp_LT (object val1, object val2) + { + double d1, d2; + if (CliHelper.IsNumber (val1) && CliHelper.IsNumber (val2)) { + d1 = Convert.ToDouble (val1); + d2 = Convert.ToDouble (val2); + } + else { + if (val1 is IScriptable) + val1 = ((IScriptable)val1).GetDefaultValue (typeof (long)); + if (val2 is IScriptable) + val2 = ((IScriptable)val2).GetDefaultValue (typeof (long)); + if (val1 is string && val2 is string) { + return String.CompareOrdinal (((string)val1), (string)val2) < 0; + } + d1 = ScriptConvert.ToNumber (val1); + d2 = ScriptConvert.ToNumber (val2); + } + return d1 < d2; + } + + public static bool cmp_LE (object val1, object val2) + { + double d1, d2; + if (CliHelper.IsNumber (val1) && CliHelper.IsNumber (val2)) { + d1 = Convert.ToDouble (val1); + d2 = Convert.ToDouble (val2); + } + else { + if (val1 is IScriptable) + val1 = ((IScriptable)val1).GetDefaultValue (typeof (long)); + if (val2 is IScriptable) + val2 = ((IScriptable)val2).GetDefaultValue (typeof (long)); + if (val1 is string && val2 is string) { + return String.CompareOrdinal (((string)val1), (string)val2) <= 0; + } + d1 = ScriptConvert.ToNumber (val1); + d2 = ScriptConvert.ToNumber (val2); + } + return d1 <= d2; + } + + + public static bool hasTopCall (Context cx) + { + return (cx.topCallScope != null); + } + + public static IScriptable getTopCallScope (Context cx) + { + IScriptable scope = cx.topCallScope; + if (scope == null) { + throw new Exception (); + } + return scope; + } + + public static object DoTopCall (ICallable callable, Context cx, IScriptable scope, IScriptable thisObj, object [] args) + { + if (scope == null) + throw new ArgumentException (); + if (cx.topCallScope != null) + throw new Exception (); + + object result; + cx.topCallScope = ScriptableObject.GetTopLevelScope (scope); + cx.useDynamicScope = cx.HasFeature (Context.Features.DynamicScope); + ContextFactory f = cx.Factory; + try { + result = f.DoTopCall (callable, cx, scope, thisObj, args); + } + finally { + cx.topCallScope = null; + // Cleanup cached references + cx.cachedXMLLib = null; + + if (cx.currentActivationCall != null) { + // Function should always call exitActivationFunction + // if it creates activation record + throw new Exception ( + "ActivationCall without exitActivationFunction() invokation." + ); + } + } + return result; + } + + /// Return possibleDynamicScope if staticTopScope + /// is present on its prototype chain and return staticTopScope + /// otherwise. + /// Should only be called when staticTopScope is top scope. + /// + internal static IScriptable checkDynamicScope (IScriptable possibleDynamicScope, IScriptable staticTopScope) + { + // Return cx.topCallScope if scope + if (possibleDynamicScope == staticTopScope) { + return possibleDynamicScope; + } + IScriptable proto = possibleDynamicScope; + for (; ; ) { + proto = proto.GetPrototype (); + if (proto == staticTopScope) { + return possibleDynamicScope; + } + if (proto == null) { + return staticTopScope; + } + } + } + + public static void initScript (BuiltinFunction funObj, IScriptable thisObj, Context cx, IScriptable scope, bool evalScript) + { + if (cx.topCallScope == null) + throw new Exception (); + + int varCount = funObj.ParamAndVarCount; + if (varCount != 0) { + + IScriptable varScope = scope; + // Never define any variables from var statements inside with + // object. See bug 38590. + while (varScope is BuiltinWith) { + varScope = varScope.ParentScope; + } + + for (int i = varCount; i-- != 0; ) { + string name = funObj.getParamOrVarName (i); + // Don't overwrite existing def if already defined in object + // or prototypes of object. + if (!ScriptableObject.HasProperty (scope, name)) { + if (!evalScript) { + // Global var definitions are supposed to be DONTDELETE + ScriptableObject.DefineProperty (varScope, name, Undefined.Value, ScriptableObject.PERMANENT); + } + else { + varScope.Put (name, varScope, Undefined.Value); + } + } + } + } + } + + public static IScriptable createFunctionActivation (BuiltinFunction funObj, IScriptable scope, object [] args) + { + return new BuiltinCall (funObj, scope, args); + } + + + public static void enterActivationFunction (Context cx, IScriptable activation) + { + if (cx.topCallScope == null) + throw new Exception (); + + BuiltinCall call = (BuiltinCall)activation; + call.parentActivationCall = cx.currentActivationCall; + cx.currentActivationCall = call; + } + + public static void exitActivationFunction (Context cx) + { + BuiltinCall call = cx.currentActivationCall; + cx.currentActivationCall = call.parentActivationCall; + call.parentActivationCall = null; + } + + internal static BuiltinCall findFunctionActivation (Context cx, IFunction f) + { + BuiltinCall call = cx.currentActivationCall; + while (call != null) { + if (call.function == f) + return call; + call = call.parentActivationCall; + } + return null; + } + + public static IScriptable NewCatchScope (Exception t, IScriptable lastCatchScope, string exceptionName, Context cx, IScriptable scope) + { + object obj; + bool cacheObj; + + if (t is EcmaScriptThrow) { + cacheObj = false; + obj = ((EcmaScriptThrow)t).Value; + } + else { + cacheObj = true; + + // Create wrapper object unless it was associated with + // the previous scope object + + if (lastCatchScope != null) { + BuiltinObject last = (BuiltinObject)lastCatchScope; + obj = last.GetAssociatedValue (t); + if (obj == null) + Context.CodeBug (); + + goto getObj_brk; + } + + EcmaScriptException re; + string errorName; + string errorMsg; + + Exception javaException = null; + + if (t is EcmaScriptError) { + EcmaScriptError ee = (EcmaScriptError)t; + re = ee; + errorName = ee.Name; + errorMsg = ee.ErrorMessage; + } + else if (t is EcmaScriptRuntimeException) { + re = (EcmaScriptRuntimeException)t; + if (t.InnerException != null) { + javaException = t.InnerException; + errorName = "JavaException"; + errorMsg = javaException.GetType ().FullName + ": " + javaException.Message; + } + else { + errorName = "InternalError"; + errorMsg = re.Message; + } + } + else { + // Script can catch only instances of JavaScriptException, + // EcmaError and EvaluatorException + throw Context.CodeBug (); + } + + string sourceUri = re.SourceName; + if (sourceUri == null) { + sourceUri = ""; + } + int line = re.LineNumber; + object [] args; + if (line > 0) { + args = new object [] { errorMsg, sourceUri, (int)line }; + } + else { + args = new object [] { errorMsg, sourceUri }; + } + + IScriptable errorObject = cx.NewObject (scope, errorName, args); + ScriptableObject.PutProperty (errorObject, "name", errorName); + + if (javaException != null) { + object wrap = cx.Wrap (scope, javaException, null); + ScriptableObject.DefineProperty (errorObject, "javaException", wrap, ScriptableObject.PERMANENT | ScriptableObject.READONLY); + } + if (re != null) { + object wrap = cx.Wrap (scope, re, null); + ScriptableObject.DefineProperty (errorObject, "rhinoException", wrap, ScriptableObject.PERMANENT | ScriptableObject.READONLY); + } + + obj = errorObject; + } + + getObj_brk: + ; + + + + BuiltinObject catchScopeObject = new BuiltinObject (); + // See ECMA 12.4 + catchScopeObject.DefineProperty (exceptionName, obj, ScriptableObject.PERMANENT); + if (cacheObj) { + catchScopeObject.AssociateValue (t, obj); + } + return catchScopeObject; + } + + public static IScriptable enterWith (object obj, Context cx, IScriptable scope) + { + IScriptable sobj = ScriptConvert.ToObjectOrNull (cx, obj); + if (sobj == null) { + throw TypeErrorById ("msg.undef.with", ScriptConvert.ToString (obj)); + } + if (sobj is XMLObject) { + XMLObject xmlObject = (XMLObject)sobj; + return xmlObject.EnterWith (scope); + } + return new BuiltinWith (scope, sobj); + } + + public static IScriptable leaveWith (IScriptable scope) + { + BuiltinWith nw = (BuiltinWith)scope; + return nw.ParentScope; + } + + public static IScriptable enterDotQuery (object value, IScriptable scope) + { + if (!(value is XMLObject)) { + throw NotXmlError (value); + } + XMLObject obj = (XMLObject)value; + return obj.EnterDotQuery (scope); + } + + public static object updateDotQuery (bool value, IScriptable scope) + { + // Return null to continue looping + BuiltinWith nw = (BuiltinWith)scope; + return nw.UpdateDotQuery (value); + } + + public static IScriptable leaveDotQuery (IScriptable scope) + { + BuiltinWith nw = (BuiltinWith)scope; + return nw.ParentScope; + } + + public static void setFunctionProtoAndParent (BaseFunction fn, IScriptable scope) + { + fn.ParentScope = scope; + fn.SetPrototype (ScriptableObject.GetFunctionPrototype (scope)); + } + + public static void setObjectProtoAndParent (ScriptableObject obj, IScriptable scope) + { + // Compared with function it always sets the scope to top scope + scope = ScriptableObject.GetTopLevelScope (scope); + obj.ParentScope = scope; + IScriptable proto = ScriptableObject.getClassPrototype (scope, obj.ClassName); + obj.SetPrototype (proto); + } + + public static void initFunction (Context cx, IScriptable scope, BuiltinFunction function, int type, bool fromEvalCode) + { + if (type == FunctionNode.FUNCTION_STATEMENT) { + string name = function.FunctionName; + if (name != null && name.Length != 0) { + if (!fromEvalCode) { + // ECMA specifies that functions defined in global and + // function scope outside eval should have DONTDELETE set. + ScriptableObject.DefineProperty (scope, name, function, ScriptableObject.PERMANENT); + } + else { + scope.Put (name, scope, function); + } + } + } + else if (type == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) { + string name = function.FunctionName; + if (name != null && name.Length != 0) { + // Always put function expression statements into initial + // activation object ignoring the with statement to follow + // SpiderMonkey + while (scope is BuiltinWith) { + scope = scope.ParentScope; + } + scope.Put (name, scope, function); + } + } + else { + throw Context.CodeBug (); + } + } + + public static IScriptable newArrayLiteral (object [] objects, int [] skipIndexces, Context cx, IScriptable scope) + { + int count = objects.Length; + int skipCount = 0; + if (skipIndexces != null) { + skipCount = skipIndexces.Length; + } + int length = count + skipCount; + int lengthObj = (int)length; + IScriptable arrayObj; + /* + * If the version is 120, then new Array(4) means create a new + * array with 4 as the first element. In this case, we have to + * set length property manually. + */ + if (cx.Version == Context.Versions.JS1_2) { + arrayObj = cx.NewObject (scope, "Array", ScriptRuntime.EmptyArgs); + ScriptableObject.PutProperty (arrayObj, "length", (object)lengthObj); + } + else { + arrayObj = cx.NewObject (scope, "Array", new object [] { lengthObj }); + } + int skip = 0; + for (int i = 0, j = 0; i != length; ++i) { + if (skip != skipCount && skipIndexces [skip] == i) { + ++skip; + continue; + } + ScriptableObject.PutProperty (arrayObj, i, objects [j]); + ++j; + } + return arrayObj; + } + + public static IScriptable newObjectLiteral (object [] propertyIds, object [] propertyValues, Context cx, IScriptable scope) + { + IScriptable obj = cx.NewObject (scope); + for (int i = 0, end = propertyIds.Length; i != end; ++i) { + object id = propertyIds [i]; + object value = propertyValues [i]; + + if (id is Node.GetterPropertyLiteral) { + BuiltinObject nativeObj = (BuiltinObject)obj; + InterpretedFunction fun = (InterpretedFunction)value; + nativeObj.DefineGetter ((string)((Node.GetterPropertyLiteral)id).Property, fun); + } + else if (id is Node.SetterPropertyLiteral) { + BuiltinObject nativeObj = (BuiltinObject)obj; + InterpretedFunction fun = (InterpretedFunction)value; + nativeObj.DefineSetter ((string)((Node.SetterPropertyLiteral)id).Property, fun); + } + else if (id is string) { + ScriptableObject.PutProperty (obj, (string)id, value); + } + else { + ScriptableObject.PutProperty (obj, (int)id, value); + } + } + return obj; + } + + public static bool isArrayObject (object obj) + { + return obj is BuiltinArray || obj is Arguments; + } + + public static object [] getArrayElements (IScriptable obj) + { + Context cx = Context.CurrentContext; + long longLen = BuiltinArray.getLengthProperty (cx, obj); + if (longLen > int.MaxValue) { + // arrays beyond MAX_INT is not in Java in any case + throw new ArgumentException (); + } + int len = (int)longLen; + if (len == 0) { + return ScriptRuntime.EmptyArgs; + } + else { + object [] result = new object [len]; + for (int i = 0; i < len; i++) { + object elem = ScriptableObject.GetProperty (obj, i); + result [i] = (elem == UniqueTag.NotFound) ? Undefined.Value : elem; + } + return result; + } + } + + internal static void checkDeprecated (Context cx, string name) + { + Context.Versions version = cx.Version; + if (version >= Context.Versions.JS1_4 || version == Context.Versions.Default) { + string msg = GetMessage ("msg.deprec.ctor", name); + if (version == Context.Versions.Default) + Context.ReportWarning (msg); + else + throw Context.ReportRuntimeError (msg); + } + } + + + private static ResourceManager m_ResourceManager = null; + + public static string GetMessage (string messageId, params object [] arguments) + { + Context cx = Context.CurrentContext; + + // Get current culture + CultureInfo culture = null; + if (cx != null) + culture = cx.CurrentCulture; + + if (m_ResourceManager == null) { + m_ResourceManager = new ResourceManager ( + "EcmaScript.NET.Resources.Messages", typeof (ScriptRuntime).Assembly); + } + + string formatString = m_ResourceManager.GetString (messageId, culture); + if (formatString == null) + throw new Exception ("Missing no message resource found for message property " + messageId); + + if (arguments == null) + arguments = new object [0]; + if (arguments.Length == 0) + return formatString; + return string.Format (formatString, arguments); + } + + public static EcmaScriptError ConstructError (string error, string message) + { + int [] linep = new int [1]; + string filename = Context.GetSourcePositionFromStack (linep); + return ConstructError (error, message, filename, linep [0], null, 0); + } + + public static EcmaScriptError ConstructError (string error, string message, string sourceName, int lineNumber, string lineSource, int columnNumber) + { + return new EcmaScriptError (error, message, sourceName, lineNumber, lineSource, columnNumber); + } + + public static EcmaScriptError TypeError (string message) + { + return ConstructError ("TypeError", message); + } + + public static EcmaScriptError TypeErrorById (string messageId, params string [] args) + { + return TypeError (GetMessage (messageId, args)); + } + + public static Exception UndefReadError (object obj, object id) + { + string idStr = (id == null) ? "null" : id.ToString (); + return TypeErrorById ("msg.undef.prop.read", ScriptConvert.ToString (obj), idStr); + } + + public static Exception UndefCallError (object obj, object id) + { + string idStr = (id == null) ? "null" : id.ToString (); + return TypeErrorById ("msg.undef.method.call", ScriptConvert.ToString (obj), idStr); + } + + public static Exception UndefWriteError (object obj, object id, object value) + { + string idStr = (id == null) ? "null" : id.ToString (); + string valueStr = (value is IScriptable) ? value.ToString () : ScriptConvert.ToString (value); + return TypeErrorById ("msg.undef.prop.write", ScriptConvert.ToString (obj), idStr, valueStr); + } + + public static Exception NotFoundError (IScriptable obj, string property) + { + // TODO: use object to improve the error message + string msg = GetMessage ("msg.is.not.defined", property); + throw ConstructError ("ReferenceError", msg); + } + + public static Exception NotFunctionError (object value) + { + return NotFunctionError (value, value); + } + + public static Exception NotFunctionError (object value, object messageHelper) + { + // TODO: Use value for better error reporting + string msg = (messageHelper == null) ? "null" : messageHelper.ToString (); + if (value == UniqueTag.NotFound) { + return TypeErrorById ("msg.function.not.found", msg); + } + return TypeErrorById ("msg.isnt.function", msg, value == null ? "null" : value.GetType ().FullName); + } + + private static Exception NotXmlError (object value) + { + throw TypeErrorById ("msg.isnt.xml.object", ScriptConvert.ToString (value)); + } + + internal static void WarnAboutNonJSObject (object nonJSObject) + { + string message = "+++ USAGE WARNING: Missed Context.Wrap() conversion:\n" + + "Runtime detected object " + nonJSObject + " of class " + nonJSObject.GetType ().FullName + " where it expected String, Number, Boolean or Scriptable instance. " + + "Please check your code for missig Context.Wrap() call."; + + Context.ReportWarning (message); + Console.Error.WriteLine (message); + } + + + private static XMLLib CurrentXMLLib (Context cx) + { + // Scripts should be running to access this + if (cx.topCallScope == null) + throw new Exception (); + + XMLLib xmlLib = cx.cachedXMLLib; + if (xmlLib == null) { + xmlLib = XMLLib.ExtractFromScope (cx.topCallScope); + if (xmlLib == null) + throw new Exception (); + cx.cachedXMLLib = xmlLib; + } + + return xmlLib; + } + + /// Escapes the reserved characters in a value of an attribute + /// + /// + /// Unescaped text + /// + /// The escaped text + /// + public static string escapeAttributeValue (object value, Context cx) + { + XMLLib xmlLib = CurrentXMLLib (cx); + return xmlLib.EscapeAttributeValue (value); + } + + /// Escapes the reserved characters in a value of a text node + /// + /// + /// Unescaped text + /// + /// The escaped text + /// + public static string escapeTextValue (object value, Context cx) + { + XMLLib xmlLib = CurrentXMLLib (cx); + return xmlLib.EscapeTextValue (value); + } + + public static IRef memberRef (object obj, object elem, Context cx, int memberTypeFlags) + { + if (!(obj is XMLObject)) { + throw NotXmlError (obj); + } + XMLObject xmlObject = (XMLObject)obj; + return xmlObject.MemberRef (cx, elem, memberTypeFlags); + } + + public static IRef memberRef (object obj, object ns, object elem, Context cx, int memberTypeFlags) + { + if (!(obj is XMLObject)) { + throw NotXmlError (obj); + } + XMLObject xmlObject = (XMLObject)obj; + return xmlObject.MemberRef (cx, ns, elem, memberTypeFlags); + } + + public static IRef nameRef (object name, Context cx, IScriptable scope, int memberTypeFlags) + { + XMLLib xmlLib = CurrentXMLLib (cx); + return xmlLib.NameRef (cx, name, scope, memberTypeFlags); + } + + public static IRef nameRef (object ns, object name, Context cx, IScriptable scope, int memberTypeFlags) + { + XMLLib xmlLib = CurrentXMLLib (cx); + return xmlLib.NameRef (cx, ns, name, scope, memberTypeFlags); + } + + private static void storeIndexResult (Context cx, int index) + { + cx.scratchIndex = index; + } + + internal static int lastIndexResult (Context cx) + { + return cx.scratchIndex; + } + + public static void storeUint32Result (Context cx, long value) + { + if (((ulong)value >> 32) != 0) + throw new ArgumentException (); + cx.scratchUint32 = value; + } + + public static long lastUint32Result (Context cx) + { + long value = cx.scratchUint32; + if ((ulong)value >> 32 != 0) + throw new Exception (); + return value; + } + + private static void storeScriptable (Context cx, IScriptable value) + { + // The previosly stored scratchScriptable should be consumed + if (cx.scratchScriptable != null) + throw new Exception (); + cx.scratchScriptable = value; + } + + public static IScriptable lastStoredScriptable (Context cx) + { + IScriptable result = cx.scratchScriptable; + cx.scratchScriptable = null; + return result; + } + + internal static string makeUrlForGeneratedScript (bool isEval, string masterScriptUrl, int masterScriptLine) + { + if (isEval) { + return masterScriptUrl + '#' + masterScriptLine + "(eval)"; + } + else { + return masterScriptUrl + '#' + masterScriptLine + "(Function)"; + } + } + + internal static bool isGeneratedScript (string sourceUrl) + { + // ALERT: this may clash with a valid URL containing (eval) or + // (Function) + return sourceUrl.IndexOf ("(eval)") >= 0 || sourceUrl.IndexOf ("(Function)") >= 0; + } + + + public static readonly object [] EmptyArgs = new object [0]; + public static readonly string [] EmptyStrings = new string [0]; + + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/ScriptableObject.cs b/src/EcmaScript.NET/ScriptableObject.cs similarity index 97% rename from Code/EcmaScript.NET/ScriptableObject.cs rename to src/EcmaScript.NET/ScriptableObject.cs index dda5f37..edd256b 100644 --- a/Code/EcmaScript.NET/ScriptableObject.cs +++ b/src/EcmaScript.NET/ScriptableObject.cs @@ -1,1410 +1,1410 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -// API class -using System; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Collections; - -using EcmaScript.NET.Debugging; -using EcmaScript.NET.Attributes; -using EcmaScript.NET.Collections; - -namespace EcmaScript.NET -{ - - /// This is the default implementation of the Scriptable interface. This - /// class provides convenient default behavior that makes it easier to - /// define host objects. - ///

- /// Various properties and methods of JavaScript objects can be conveniently - /// defined using methods of ScriptableObject. - ///

- /// Classes extending ScriptableObject must define the getClassName method. - /// - ///

- public abstract class ScriptableObject : IScriptable, DebuggableObject - { - /// Return the name of the class. - /// - /// This is typically the same name as the constructor. - /// Classes extending ScriptableObject must implement this abstract - /// method. - /// - public abstract string ClassName { get;} - - - /// Returns the parent (enclosing) scope of the object. - /// Sets the parent (enclosing) scope of the object. - public IScriptable ParentScope - { - get - { - return parentScopeObject; - } - - set - { - parentScopeObject = value; - } - - } - /// Returns an array of ids for the properties of the object. - /// - ///

All properties, even those with attribute DONTENUM, are listed.

- /// - ///

- /// an array of java.lang.Objects with an entry for every - /// listed property. Properties accessed via an integer index will - /// have a corresponding - /// Integer entry in the returned array. Properties accessed by - /// a String will have a String entry in the returned array. - /// - virtual public object [] AllIds - { - get - { - return GetIds (true); - } - - } - /// Return true if this object is sealed. - /// - /// It is an error to attempt to add or remove properties to - /// a sealed object. - /// - /// - /// true if sealed, false otherwise. - /// - public bool Sealed - { - get - { - return count < 0; - } - - } - - /// The empty property attribute. - /// - /// Used by getAttributes() and setAttributes(). - /// - /// - public const int EMPTY = 0x00; - - /// Property attribute indicating assignment to this property is ignored. - /// - /// - public const int READONLY = 0x01; - - /// Property attribute indicating property is not enumerated. - /// - /// Only enumerated properties will be returned by getIds(). - /// - /// - public const int DONTENUM = 0x02; - - /// Property attribute indicating property cannot be deleted. - /// - /// - public const int PERMANENT = 0x04; - - internal static void CheckValidAttributes (int attributes) - { - const int mask = READONLY | DONTENUM | PERMANENT; - if ((attributes & ~mask) != 0) { - throw new ArgumentException (Convert.ToString (attributes)); - } - } - - public ScriptableObject () - { - } - - public ScriptableObject (IScriptable scope, IScriptable prototype) - { - if (scope == null) - throw new ArgumentException (); - - parentScopeObject = scope; - prototypeObject = prototype; - } - - /// Returns true if the named property is defined. - /// - /// - /// the name of the property - /// - /// the object in which the lookup began - /// - /// true if and only if the property was found in the object - /// - public virtual bool Has (string name, IScriptable start) - { - return null != GetNamedSlot (name); - } - - /// Returns true if the property index is defined. - /// - /// - /// the numeric index for the property - /// - /// the object in which the lookup began - /// - /// true if and only if the property was found in the object - /// - public virtual bool Has (int index, IScriptable start) - { - return null != GetSlot (null, index); - } - - /// Returns the value of the named property or NOT_FOUND. - /// - /// If the property was created using defineProperty, the - /// appropriate getter method is called. - /// - /// - /// the name of the property - /// - /// the object in which the lookup began - /// - /// the value of the property (may be null), or NOT_FOUND - /// - public virtual object Get (string name, IScriptable start) - { - Slot slot = GetNamedSlot (name); - if (slot == null) { - return UniqueTag.NotFound; - } - return slot.GetValue (null, start, start); - } - - /// Returns the value of the indexed property or NOT_FOUND. - /// - /// - /// the numeric index for the property - /// - /// the object in which the lookup began - /// - /// the value of the property (may be null), or NOT_FOUND - /// - public virtual object Get (int index, IScriptable start) - { - Slot slot = GetSlot (null, index); - if (slot == null) { - return UniqueTag.NotFound; - } - return slot.GetValue (null, start, start); - } - - /// Sets the value of the named property, creating it if need be. - /// - /// If the property was created using defineProperty, the - /// appropriate setter method is called.

- /// - /// If the property's attributes include READONLY, no action is - /// taken. - /// This method will actually set the property in the start - /// object. - /// - ///

- /// the name of the property - /// - /// the object whose property is being set - /// - /// value to set the property to - /// - public virtual object Put (string name, IScriptable start, object value) - { - Slot slot = lastAccess; // Get local copy - if ((object)name != (object)slot.stringKey || slot.wasDeleted != 0) { - int hash = name.GetHashCode (); - slot = GetSlot (name, hash); - if (slot == null) { - if (start != this) { - start.Put (name, start, value); - return value; - } - slot = AddSlot (name, hash, null); - } - // Note: cache is not updated in put - } - if (start == this && Sealed) { - throw Context.ReportRuntimeErrorById ("msg.modify.sealed", name); - } - if ((slot.attributes & ScriptableObject.READONLY) != 0) { - // FINDME - Context cx = Context.CurrentContext; - if (cx.Version == Context.Versions.JS1_2) { - throw Context.ReportRuntimeErrorById ("msg.read-only", name); - } else { - if (cx.HasFeature (Context.Features.Strict)) { - Context.ReportWarningById ("msg.read-only", name); - } - } - return value; - } - if (this == start) { - return slot.SetValue (null, start, start, value); - } - else { - if (slot.setter != null) { - Slot newSlot = (Slot)slot.Clone (); - ((ScriptableObject)start).AddSlotImpl (newSlot.stringKey, newSlot.intKey, newSlot); - return newSlot.SetValue (null, start, start, value); - } - else { - return start.Put (name, start, value); - } - } - return value; - } - - /// Sets the value of the indexed property, creating it if need be. - /// - /// - /// the numeric index for the property - /// - /// the object whose property is being set - /// - /// value to set the property to - /// - public virtual object Put (int index, IScriptable start, object value) - { - Slot slot = GetSlot (null, index); - if (slot == null) { - if (start != this) { - return start.Put (index, start, value); - } - slot = AddSlot (null, index, null); - } - if (start == this && Sealed) { - throw Context.ReportRuntimeErrorById ("msg.modify.sealed", Convert.ToString (index)); - } - if ((slot.attributes & ScriptableObject.READONLY) != 0) { - return slot.GetValue (null, start, start); // TODO: ??? - } - if (this == start) { - return slot.SetValue (null, start, start, value); - } - else { - return start.Put (index, start, value); - } - } - - /// Removes a named property from the object. - /// - /// If the property is not found, or it has the PERMANENT attribute, - /// no action is taken. - /// - /// - /// the name of the property - /// - public virtual void Delete (string name) - { - RemoveSlot (name, name.GetHashCode ()); - } - - /// Removes the indexed property from the object. - /// - /// If the property is not found, or it has the PERMANENT attribute, - /// no action is taken. - /// - /// - /// the numeric index for the property - /// - public virtual void Delete (int index) - { - RemoveSlot (null, index); - } - - - - - - /// Get the attributes of a named property. - /// - /// The property is specified by name - /// as defined for has.

- /// - ///

- /// the identifier for the property - /// - /// the bitset of attributes - /// - /// EvaluatorException if the named property is not found - /// - public virtual int GetAttributes (string name) - { - Slot slot = GetNamedSlot (name); - if (slot == null) { - throw Context.ReportRuntimeErrorById ("msg.prop.not.found", name); - } - return slot.attributes; - } - - /// Get the attributes of an indexed property. - /// - /// - /// the numeric index for the property - /// - /// EvaluatorException if the named property is not found - /// is not found - /// - /// the bitset of attributes - /// - public virtual int GetAttributes (int index) - { - Slot slot = GetSlot (null, index); - if (slot == null) { - throw Context.ReportRuntimeErrorById ("msg.prop.not.found", Convert.ToString (index)); - } - return slot.attributes; - } - - /// Set the attributes of a named property. - /// - /// The property is specified by name - /// as defined for has.

- /// - /// The possible attributes are READONLY, DONTENUM, - /// and PERMANENT. Combinations of attributes - /// are expressed by the bitwise OR of attributes. - /// EMPTY is the state of no attributes set. Any unused - /// bits are reserved for future use. - /// - ///

- /// the name of the property - /// - /// the bitset of attributes - /// - /// EvaluatorException if the named property is not found - /// - public virtual void SetAttributes (string name, int attributes) - { - CheckValidAttributes (attributes); - Slot slot = GetNamedSlot (name); - if (slot == null) { - throw Context.ReportRuntimeErrorById ("msg.prop.not.found", name); - } - slot.attributes = (short)attributes; - } - - /// Set the attributes of an indexed property. - /// - /// - /// the numeric index for the property - /// - /// the bitset of attributes - /// - /// EvaluatorException if the named property is not found - /// - public virtual void SetAttributes (int index, int attributes) - { - CheckValidAttributes (attributes); - Slot slot = GetSlot (null, index); - if (slot == null) { - throw Context.ReportRuntimeErrorById ("msg.prop.not.found", Convert.ToString (index)); - } - slot.attributes = (short)attributes; - } - - /// Returns the prototype of the object. - public virtual IScriptable GetPrototype () - { - return prototypeObject; - } - - /// Sets the prototype of the object. - public virtual void SetPrototype (IScriptable m) - { - prototypeObject = m; - } - - /// Returns an array of ids for the properties of the object. - /// - ///

Any properties with the attribute DONTENUM are not listed.

- /// - ///

- /// an array of java.lang.Objects with an entry for every - /// listed property. Properties accessed via an integer index will - /// have a corresponding - /// Integer entry in the returned array. Properties accessed by - /// a String will have a String entry in the returned array. - /// - public virtual object [] GetIds () - { - return GetIds (false); - } - - /// Implements the [[DefaultValue]] internal method. - /// - ///

Note that the toPrimitive conversion is a no-op for - /// every type other than Object, for which [[DefaultValue]] - /// is called. See ECMA 9.1.

- /// - /// A hint of null means "no hint". - /// - ///

- /// the type hint - /// - /// the default value for the object - /// - /// See ECMA 8.6.2.6. - /// - public virtual object GetDefaultValue (Type typeHint) - { - Context cx = null; - for (int i = 0; i < 2; i++) { - bool tryToString; - if (typeHint == typeof (string)) { - tryToString = (i == 0); - } - else { - tryToString = (i == 1); - } - - string methodName; - object [] args; - if (tryToString) { - methodName = "toString"; - args = ScriptRuntime.EmptyArgs; - } - else { - methodName = "valueOf"; - args = new object [1]; - string hint; - if (typeHint == null) { - hint = "undefined"; - } - else if (typeHint == typeof (string)) { - hint = "string"; - } - else if (typeHint == typeof (IScriptable)) { - hint = "object"; - } - else if (typeHint == typeof (IFunction)) { - hint = "function"; - } - else if (typeHint == typeof (bool) || typeHint == typeof (bool)) { - hint = "boolean"; - } - else if (CliHelper.IsNumberType (typeHint) || typeHint == typeof (byte) || typeHint == typeof (sbyte)) { - hint = "number"; - } - else { - throw Context.ReportRuntimeErrorById ("msg.invalid.type", typeHint.ToString ()); - } - args [0] = hint; - } - object v = GetProperty (this, methodName); - if (!(v is IFunction)) - continue; - IFunction fun = (IFunction)v; - if (cx == null) - cx = Context.CurrentContext; - v = fun.Call (cx, fun.ParentScope, this, args); - if (v != null) { - if (!(v is IScriptable)) { - return v; - } - if (typeHint == typeof (IScriptable) || typeHint == typeof (IFunction)) { - return v; - } - if (tryToString && v is Wrapper) { - // Let a wrapped java.lang.String pass for a primitive - // string. - object u = ((Wrapper)v).Unwrap (); - if (u is string) - return u; - } - } - } - // fall through to error - string arg = (typeHint == null) ? "undefined" : typeHint.FullName; - throw ScriptRuntime.TypeErrorById ("msg.default.value", arg); - } - - /// Implements the instanceof operator. - /// - ///

This operator has been proposed to ECMA. - /// - ///

- /// The value that appeared on the LHS of the instanceof - /// operator - /// - /// true if "this" appears in value's prototype chain - /// - /// - public virtual bool HasInstance (IScriptable instance) - { - - // According to specs -- section 11.8.6 of ECMA-262 -- instanceof operator - // on objects NOT implementing [[HasInstance]] internal method should - // throw a TypeError exception. Hence, in the following script the - // catch block must get executed, (since Math object does not implement - // [[HasInstance]] method). - throw ScriptRuntime.TypeError ("msg.bad.instanceof.rhs"); - - - // Default for JS objects (other than Function) is to do prototype - // chasing. This will be overridden in NativeFunction and non-JS - // objects. - //return ScriptRuntime.jsDelegatesTo(instance, this); - } - - /// Custom == operator. - /// Must return {@link Scriptable#NOT_FOUND} if this object does not - /// have custom equality operator for the given value, - /// Boolean.TRUE if this object is equivalent to value, - /// Boolean.FALSE if this object is not equivalent to - /// value. - ///

- /// The default implementation returns Boolean.TRUE - /// if this == value or {@link Scriptable#NOT_FOUND} otherwise. - /// It indicates that by default custom equality is available only if - /// value is this in which case true is returned. - ///

- protected internal virtual object EquivalentValues (object value) - { - return (this == value) ? (object)true : UniqueTag.NotFound; - } - - /// Define a JavaScript property. - /// - /// Creates the property with an initial value and sets its attributes. - /// - /// - /// the name of the property to define. - /// - /// the initial value of the property - /// - /// the attributes of the JavaScript property - /// - public virtual void DefineProperty (string propertyName, object value, int attributes) - { - Put (propertyName, this, value); - SetAttributes (propertyName, attributes); - } - - /// Utility method to add properties to arbitrary Scriptable object. - /// If destination is instance of ScriptableObject, calls - /// defineProperty there, otherwise calls put in destination - /// ignoring attributes - /// - public static void DefineProperty (IScriptable destination, string propertyName, object value, int attributes) - { - if (!(destination is ScriptableObject)) { - destination.Put (propertyName, destination, value); - return; - } - ScriptableObject so = (ScriptableObject)destination; - so.DefineProperty (propertyName, value, attributes); - } - - - - /// Get the Object.prototype property. - /// See ECMA 15.2.4. - /// - public static IScriptable GetObjectPrototype (IScriptable scope) - { - return getClassPrototype (scope, "Object"); - } - - /// Get the Function.prototype property. - /// See ECMA 15.3.4. - /// - public static IScriptable GetFunctionPrototype (IScriptable scope) - { - return getClassPrototype (scope, "Function"); - } - - /// Get the prototype for the named class. - /// - /// For example, getClassPrototype(s, "Date") will first - /// walk up the parent chain to find the outermost scope, then will - /// search that scope for the Date constructor, and then will - /// return Date.prototype. If any of the lookups fail, or - /// the prototype is not a JavaScript object, then null will - /// be returned. - /// - /// - /// an object in the scope chain - /// - /// the name of the constructor - /// - /// the prototype for the named class, or null if it - /// cannot be found. - /// - public static IScriptable getClassPrototype (IScriptable scope, string className) - { - scope = GetTopLevelScope (scope); - object ctor = GetProperty (scope, className); - object proto; - if (ctor is BaseFunction) { - proto = ((BaseFunction)ctor).PrototypeProperty; - } - else if (ctor is IScriptable) { - IScriptable ctorObj = (IScriptable)ctor; - proto = ctorObj.Get ("prototype", ctorObj); - } - else { - return null; - } - if (proto is IScriptable) { - return (IScriptable)proto; - } - return null; - } - - /// Get the global scope. - /// - ///

Walks the parent scope chain to find an object with a null - /// parent scope (the global object). - /// - ///

- /// a JavaScript object - /// - /// the corresponding global scope - /// - public static IScriptable GetTopLevelScope (IScriptable obj) - { - for (; ; ) { - IScriptable parent = obj.ParentScope; - if (parent == null) { - return obj; - } - obj = parent; - } - } - - /// Seal this object. - /// - /// A sealed object may not have properties added or removed. Once - /// an object is sealed it may not be unsealed. - /// - /// - public virtual void SealObject () - { - lock (this) { - if (count >= 0) { - count = -1 - count; - } - } - } - - /// Gets a named property from an object or any object in its prototype chain. - ///

- /// Searches the prototype chain for a property named name. - ///

- ///

- /// a JavaScript object - /// - /// a property name - /// - /// the value of a property with name name found in - /// obj or any object in its prototype chain, or - /// Scriptable.NOT_FOUND if not found - /// - public static object GetProperty (IScriptable obj, string name) - { - IScriptable start = obj; - object result; - do { - result = obj.Get (name, start); - if (result != UniqueTag.NotFound) - break; - obj = obj.GetPrototype (); - } - while (obj != null); - return result; - } - - /// Gets an indexed property from an object or any object in its prototype chain. - ///

- /// Searches the prototype chain for a property with integral index - /// index. Note that if you wish to look for properties with numerical - /// but non-integral indicies, you should use getProperty(Scriptable,String) with - /// the string value of the index. - ///

- ///

- /// a JavaScript object - /// - /// an integral index - /// - /// the value of a property with index index found in - /// obj or any object in its prototype chain, or - /// Scriptable.NOT_FOUND if not found - /// - public static object GetProperty (IScriptable obj, int index) - { - IScriptable start = obj; - object result; - do { - result = obj.Get (index, start); - if (result != UniqueTag.NotFound) - break; - obj = obj.GetPrototype (); - } - while (obj != null); - return result; - } - - /// Returns whether a named property is defined in an object or any object - /// in its prototype chain. - ///

- /// Searches the prototype chain for a property named name. - ///

- ///

- /// a JavaScript object - /// - /// a property name - /// - /// the true if property was found - /// - public static bool HasProperty (IScriptable obj, string name) - { - return null != GetBase (obj, name); - } - - /// Returns whether an indexed property is defined in an object or any object - /// in its prototype chain. - ///

- /// Searches the prototype chain for a property with index index. - ///

- ///

- /// a JavaScript object - /// - /// a property index - /// - /// the true if property was found - /// - public static bool HasProperty (IScriptable obj, int index) - { - return null != GetBase (obj, index); - } - - /// Puts a named property in an object or in an object in its prototype chain. - ///

- /// Seaches for the named property in the prototype chain. If it is found, - /// the value of the property is changed. If it is not found, a new - /// property is added in obj. - ///

- /// a JavaScript object - /// - /// a property name - /// - /// any JavaScript value accepted by Scriptable.put - /// - public static object PutProperty (IScriptable obj, string name, object value) - { - IScriptable toBase = GetBase (obj, name); - if (toBase == null) - toBase = obj; - return toBase.Put (name, obj, value); - } - - /// Puts an indexed property in an object or in an object in its prototype chain. - ///

- /// Seaches for the indexed property in the prototype chain. If it is found, - /// the value of the property is changed. If it is not found, a new - /// property is added in obj. - ///

- /// a JavaScript object - /// - /// a property index - /// - /// any JavaScript value accepted by Scriptable.put - /// - public static object PutProperty (IScriptable obj, int index, object value) - { - IScriptable toBase = GetBase (obj, index); - if (toBase == null) - toBase = obj; - return toBase.Put (index, obj, value); - } - - /// Removes the property from an object or its prototype chain. - ///

- /// Searches for a property with name in obj or - /// its prototype chain. If it is found, the object's delete - /// method is called. - ///

- /// a JavaScript object - /// - /// a property name - /// - /// true if the property doesn't exist or was successfully removed - /// - public static bool DeleteProperty (IScriptable obj, string name) - { - IScriptable toBase = GetBase (obj, name); - if (toBase == null) - return true; - toBase.Delete (name); - return !toBase.Has (name, obj); - } - - /// Removes the property from an object or its prototype chain. - ///

- /// Searches for a property with index in obj or - /// its prototype chain. If it is found, the object's delete - /// method is called. - ///

- /// a JavaScript object - /// - /// a property index - /// - /// true if the property doesn't exist or was successfully removed - /// - public static bool DeleteProperty (IScriptable obj, int index) - { - IScriptable toBase = GetBase (obj, index); - if (toBase == null) - return true; - toBase.Delete (index); - return !toBase.Has (index, obj); - } - - /// Returns an array of all ids from an object and its prototypes. - ///

- ///

- /// a JavaScript object - /// - /// an array of all ids from all object in the prototype chain. - /// If a given id occurs multiple times in the prototype chain, - /// it will occur only once in this list. - /// - public static object [] GetPropertyIds (IScriptable obj) - { - if (obj == null) { - return ScriptRuntime.EmptyArgs; - } - object [] result = obj.GetIds (); - ObjToIntMap map = null; - for (; ; ) { - obj = obj.GetPrototype (); - if (obj == null) { - break; - } - object [] ids = obj.GetIds (); - if (ids.Length == 0) { - continue; - } - if (map == null) { - if (result.Length == 0) { - result = ids; - continue; - } - map = new ObjToIntMap (result.Length + ids.Length); - for (int i = 0; i != result.Length; ++i) { - map.intern (result [i]); - } - result = null; // Allow to GC the result - } - for (int i = 0; i != ids.Length; ++i) { - map.intern (ids [i]); - } - } - if (map != null) { - result = map.getKeys (); - } - return result; - } - - /// Call a method of an object. - /// the JavaScript object - /// - /// the name of the function property - /// - /// the arguments for the call - /// - /// - public static object CallMethod (IScriptable obj, string methodName, object [] args) - { - return CallMethod (null, obj, methodName, args); - } - - /// Call a method of an object. - /// the Context object associated with the current thread. - /// - /// the JavaScript object - /// - /// the name of the function property - /// - /// the arguments for the call - /// - public static object CallMethod (Context cx, IScriptable obj, string methodName, object [] args) - { - object funObj = GetProperty (obj, methodName); - if (!(funObj is IFunction)) { - throw ScriptRuntime.NotFunctionError (obj, methodName); - } - IFunction fun = (IFunction)funObj; - // TODO: What should be the scope when calling funObj? - // The following favor scope stored in the object on the assumption - // that is more useful especially under dynamic scope setup. - // An alternative is to check for dynamic scope flag - // and use ScriptableObject.getTopLevelScope(fun) if the flag is not - // set. But that require access to Context and messy code - // so for now it is not checked. - IScriptable scope = ScriptableObject.GetTopLevelScope (obj); - if (cx != null) { - return fun.Call (cx, scope, obj, args); - } - else { - return Context.Call (null, fun, scope, obj, args); - } - } - - private static IScriptable GetBase (IScriptable obj, string name) - { - do { - if (obj.Has (name, obj)) - break; - obj = obj.GetPrototype (); - } - while (obj != null); - return obj; - } - - private static IScriptable GetBase (IScriptable obj, int index) - { - do { - if (obj.Has (index, obj)) - break; - obj = obj.GetPrototype (); - } - while (obj != null); - return obj; - } - - /// Get arbitrary application-specific value associated with this object. - /// key object to select particular value. - /// - public object GetAssociatedValue (object key) - { - Hashtable h = associatedValues; - if (h == null) - return null; - return h [key]; - } - - /// Get arbitrary application-specific value associated with the top scope - /// of the given scope. - /// The method first calls {@link #getTopLevelScope(Scriptable scope)} - /// and then searches the prototype chain of the top scope for the first - /// object containing the associated value with the given key. - /// - /// - /// the starting scope. - /// - /// key object to select particular value. - /// - public static object GetTopScopeValue (IScriptable scope, object key) - { - scope = ScriptableObject.GetTopLevelScope (scope); - for (; ; ) { - if (scope is ScriptableObject) { - ScriptableObject so = (ScriptableObject)scope; - object value = so.GetAssociatedValue (key); - if (value != null) { - return value; - } - } - scope = scope.GetPrototype (); - if (scope == null) { - return null; - } - } - } - - /// Associate arbitrary application-specific value with this object. - /// Value can only be associated with the given object and key only once. - /// The method ignores any subsequent attempts to change the already - /// associated value. - ///

The associated values are not serilized. - ///

- /// key object to select particular value. - /// - /// the value to associate - /// - /// the passed value if the method is called first time for the - /// given key or old value for any subsequent calls. - /// - public object AssociateValue (object key, object value) - { - if (value == null) - throw new ArgumentException (); - Hashtable h = associatedValues; - if (h == null) { - lock (this) { - h = associatedValues; - if (h == null) { - h = Hashtable.Synchronized (new Hashtable ()); - associatedValues = h; - } - } - } - return InitHash (h, key, value); - } - - private object InitHash (Hashtable h, object key, object initialValue) - { - lock (h.SyncRoot) { - object current = h [key]; - if (current == null) { - h [key] = initialValue; - } - else { - initialValue = current; - } - } - return initialValue; - } - - private Slot GetNamedSlot (string name) - { - // Query last access cache and check that it was not deleted - Slot slot = lastAccess; - if ((object)name == (object)slot.stringKey && slot.wasDeleted == 0) { - return slot; - } - int hash = name.GetHashCode (); - Slot [] slots = this.slots; // Get stable local reference - int i = GetSlotPosition (slots, name, hash); - if (i < 0) { - return null; - } - slot = slots [i]; - // Update cache - here stringKey.equals(name) holds, but it can be - // that slot.stringKey != name. To make last name cache work, need - // to change the key - slot.stringKey = name; - lastAccess = slot; - return slot; - } - - private Slot GetSlot (string id, int index) - { - Slot [] slots = this.slots; // Get local copy - int i = GetSlotPosition (slots, id, index); - return (i < 0) ? null : slots [i]; - } - - private static int GetSlotPosition (Slot [] slots, string id, int index) - { - if (slots != null) { - int start = (index & 0x7fffffff) % slots.Length; - int i = start; - do { - Slot slot = slots [i]; - if (slot == null) - break; - if (slot != REMOVED && slot.intKey == index && ((object)slot.stringKey == (object)id || (id != null && id.Equals (slot.stringKey)))) { - return i; - } - if (++i == slots.Length) - i = 0; - } - while (i != start); - } - return -1; - } - - /// Add a new slot to the hash table. - /// - /// This method must be synchronized since it is altering the hash - /// table itself. Note that we search again for the slot to set - /// since another thread could have added the given property or - /// caused the table to grow while this thread was searching. - /// - private Slot AddSlot (string id, int index, Slot newSlot) - { - lock (this) { - if (Sealed) { - string str = (id != null) ? id : Convert.ToString (index); - throw Context.ReportRuntimeErrorById ("msg.add.sealed", str); - } - - - - return AddSlotImpl (id, index, newSlot); - } - } - - // Must be inside synchronized (this) - private Slot AddSlotImpl (string id, int index, Slot newSlot) - { - if (slots == null) { - slots = new Slot [5]; - } - int start = (index & 0x7fffffff) % slots.Length; - int i = start; - for (; ; ) { - Slot slot = slots [i]; - if (slot == null || slot == REMOVED) { - if ((4 * (count + 1)) > (3 * slots.Length)) { - Grow (); - return AddSlotImpl (id, index, newSlot); - } - slot = (newSlot == null) ? new Slot () : newSlot; - slot.stringKey = id; - slot.intKey = index; - slots [i] = slot; - count++; - return slot; - } - if (slot.intKey == index && ((object)slot.stringKey == (object)id || (id != null && id.Equals (slot.stringKey)))) { - return slot; - } - if (++i == slots.Length) - i = 0; - if (i == start) { - // slots should never be full or bug in grow code - throw new ApplicationException (); - } - } - } - - /// Remove a slot from the hash table. - /// - /// This method must be synchronized since it is altering the hash - /// table itself. We might be able to optimize this more, but - /// deletes are not common. - /// - private void RemoveSlot (string name, int index) - { - lock (this) { - if (Sealed) { - string str = (name != null) ? name : Convert.ToString (index); - throw Context.ReportRuntimeErrorById ("msg.remove.sealed", str); - } - - int i = GetSlotPosition (slots, name, index); - if (i >= 0) { - Slot slot = slots [i]; - if ((slot.attributes & PERMANENT) == 0) { - // Mark the slot as removed to handle a case when - // another thread manages to put just removed slot - // into lastAccess cache. - slot.wasDeleted = (sbyte)1; - if (slot == lastAccess) { - lastAccess = REMOVED; - } - count--; - if (count != 0) { - slots [i] = REMOVED; - } - else { - // With no slots it is OK to mark with null. - slots [i] = null; - } - } - } - } - } - - // Grow the hash table to accommodate new entries. - // - // Note that by assigning the new array back at the end we - // can continue reading the array from other threads. - // Must be inside synchronized (this) - private void Grow () - { - Slot [] newSlots = new Slot [slots.Length * 2 + 1]; - for (int j = slots.Length - 1; j >= 0; j--) { - Slot slot = slots [j]; - if (slot == null || slot == REMOVED) - continue; - int k = (slot.intKey & 0x7fffffff) % newSlots.Length; - while (newSlots [k] != null) - if (++k == newSlots.Length) - k = 0; - // The end of the "synchronized" statement will cause the memory - // writes to be propagated on a multiprocessor machine. We want - // to make sure that the new table is prepared to be read. - // TODO: causes the 'this' pointer to be null in calling stack frames - // on the MS JVM - //synchronized (slot) { } - newSlots [k] = slot; - } - slots = newSlots; - } - - internal virtual object [] GetIds (bool getAll) - { - Slot [] s = slots; - object [] a = ScriptRuntime.EmptyArgs; - if (s == null) - return a; - int c = 0; - for (int i = 0; i < s.Length; i++) { - Slot slot = s [i]; - if (slot == null || slot == REMOVED) - continue; - if (getAll || (slot.attributes & DONTENUM) == 0) { - if (c == 0) - a = new object [s.Length - i]; - a [c++] = slot.stringKey != null ? (object)slot.stringKey : (int)slot.intKey; - } - } - if (c == a.Length) - return a; - object [] result = new object [c]; - Array.Copy (a, 0, result, 0, c); - return result; - } - - - /// The prototype of this object. - private IScriptable prototypeObject; - - /// The parent scope of this object. - private IScriptable parentScopeObject; - - private static readonly object HAS_STATIC_ACCESSORS = typeof (void); - private static readonly Slot REMOVED = new Slot (); - - - private Slot [] slots; - // If count >= 0, it gives number of keys or if count < 0, - // it indicates sealed object where -1 - count gives number of keys - private int count; - - // cache; may be removed for smaller memory footprint - - private Slot lastAccess = REMOVED; - - // associated values are not serialized - - private volatile Hashtable associatedValues; - - public virtual void DefineSetter (string name, ICallable setter) - { - Slot slot = GetSlot (name, name.GetHashCode ()); - if (slot == null) { - slot = new Slot (); - AddSlot (name, name.GetHashCode (), slot); - } - slot.setter = setter; - } - - public virtual void DefineSetter (int index, ICallable setter) - { - Slot slot = GetSlot (null, index); - if (slot == null) { - slot = new Slot (); - AddSlot (null, index, slot); - } - slot.setter = setter; - } - - public virtual void DefineGetter (int index, ICallable getter) - { - Slot slot = GetSlot (null, index); - if (slot == null) { - slot = new Slot (); - AddSlot (null, index, slot); - } - slot.getter = getter; - } - - public virtual void DefineGetter (string name, ICallable getter) - { - Slot slot = GetSlot (name, name.GetHashCode ()); - if (slot == null) { - slot = new Slot (); - AddSlot (name, name.GetHashCode (), slot); - } - slot.getter = getter; - } - - public virtual object LookupGetter (string name) - { - Slot slot = GetSlot (name, name.GetHashCode ()); - if (slot == null || slot.getter == null) - return Undefined.Value; - return slot.getter; - } - - public virtual object LookupSetter (string name) - { - Slot slot = GetSlot (name, name.GetHashCode ()); - if (slot == null || slot.setter == null) - return Undefined.Value; - return slot.setter; - } - - private class Slot : ICloneable - { - - internal int intKey; - internal string stringKey; - internal object value; - internal short attributes; - - internal sbyte wasDeleted; - - internal ICallable getter; - internal ICallable setter; - - public object Clone () - { - Slot clone = new Slot (); - clone.intKey = intKey; - clone.stringKey = stringKey; - clone.value = value; - clone.attributes = attributes; - clone.wasDeleted = wasDeleted; - clone.getter = getter; - clone.setter = setter; - return clone; - } - - internal object GetValue (Context cx, IScriptable scope, IScriptable thisObj) - { - if (getter == null) { - return value; - } - else { - if (cx == null) - cx = Context.CurrentContext; - return getter.Call (cx, scope, thisObj, - ScriptRuntime.EmptyArgs); - } - } - - internal object SetValue (Context cx, IScriptable scope, IScriptable thisObj, object value) - { - if (setter == null) { - if (getter == null) { - return (this.value = value); - } - else { - throw ScriptRuntime.TypeError ("setting a property that has only a getter"); - } - } - else { - if (cx == null) - cx = Context.CurrentContext; - return setter.Call (cx, scope, thisObj, new object [] { value }); - } - } - - } - - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +// API class +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Collections; + +using EcmaScript.NET.Debugging; +using EcmaScript.NET.Attributes; +using EcmaScript.NET.Collections; + +namespace EcmaScript.NET +{ + + /// This is the default implementation of the Scriptable interface. This + /// class provides convenient default behavior that makes it easier to + /// define host objects. + ///

+ /// Various properties and methods of JavaScript objects can be conveniently + /// defined using methods of ScriptableObject. + ///

+ /// Classes extending ScriptableObject must define the getClassName method. + /// + ///

+ public abstract class ScriptableObject : IScriptable, DebuggableObject + { + /// Return the name of the class. + /// + /// This is typically the same name as the constructor. + /// Classes extending ScriptableObject must implement this abstract + /// method. + /// + public abstract string ClassName { get;} + + + /// Returns the parent (enclosing) scope of the object. + /// Sets the parent (enclosing) scope of the object. + public IScriptable ParentScope + { + get + { + return parentScopeObject; + } + + set + { + parentScopeObject = value; + } + + } + /// Returns an array of ids for the properties of the object. + /// + ///

All properties, even those with attribute DONTENUM, are listed.

+ /// + ///

+ /// an array of java.lang.Objects with an entry for every + /// listed property. Properties accessed via an integer index will + /// have a corresponding + /// Integer entry in the returned array. Properties accessed by + /// a String will have a String entry in the returned array. + /// + virtual public object [] AllIds + { + get + { + return GetIds (true); + } + + } + /// Return true if this object is sealed. + /// + /// It is an error to attempt to add or remove properties to + /// a sealed object. + /// + /// + /// true if sealed, false otherwise. + /// + public bool Sealed + { + get + { + return count < 0; + } + + } + + /// The empty property attribute. + /// + /// Used by getAttributes() and setAttributes(). + /// + /// + public const int EMPTY = 0x00; + + /// Property attribute indicating assignment to this property is ignored. + /// + /// + public const int READONLY = 0x01; + + /// Property attribute indicating property is not enumerated. + /// + /// Only enumerated properties will be returned by getIds(). + /// + /// + public const int DONTENUM = 0x02; + + /// Property attribute indicating property cannot be deleted. + /// + /// + public const int PERMANENT = 0x04; + + internal static void CheckValidAttributes (int attributes) + { + const int mask = READONLY | DONTENUM | PERMANENT; + if ((attributes & ~mask) != 0) { + throw new ArgumentException (Convert.ToString (attributes)); + } + } + + public ScriptableObject () + { + } + + public ScriptableObject (IScriptable scope, IScriptable prototype) + { + if (scope == null) + throw new ArgumentException (); + + parentScopeObject = scope; + prototypeObject = prototype; + } + + /// Returns true if the named property is defined. + /// + /// + /// the name of the property + /// + /// the object in which the lookup began + /// + /// true if and only if the property was found in the object + /// + public virtual bool Has (string name, IScriptable start) + { + return null != GetNamedSlot (name); + } + + /// Returns true if the property index is defined. + /// + /// + /// the numeric index for the property + /// + /// the object in which the lookup began + /// + /// true if and only if the property was found in the object + /// + public virtual bool Has (int index, IScriptable start) + { + return null != GetSlot (null, index); + } + + /// Returns the value of the named property or NOT_FOUND. + /// + /// If the property was created using defineProperty, the + /// appropriate getter method is called. + /// + /// + /// the name of the property + /// + /// the object in which the lookup began + /// + /// the value of the property (may be null), or NOT_FOUND + /// + public virtual object Get (string name, IScriptable start) + { + Slot slot = GetNamedSlot (name); + if (slot == null) { + return UniqueTag.NotFound; + } + return slot.GetValue (null, start, start); + } + + /// Returns the value of the indexed property or NOT_FOUND. + /// + /// + /// the numeric index for the property + /// + /// the object in which the lookup began + /// + /// the value of the property (may be null), or NOT_FOUND + /// + public virtual object Get (int index, IScriptable start) + { + Slot slot = GetSlot (null, index); + if (slot == null) { + return UniqueTag.NotFound; + } + return slot.GetValue (null, start, start); + } + + /// Sets the value of the named property, creating it if need be. + /// + /// If the property was created using defineProperty, the + /// appropriate setter method is called.

+ /// + /// If the property's attributes include READONLY, no action is + /// taken. + /// This method will actually set the property in the start + /// object. + /// + ///

+ /// the name of the property + /// + /// the object whose property is being set + /// + /// value to set the property to + /// + public virtual object Put (string name, IScriptable start, object value) + { + Slot slot = lastAccess; // Get local copy + if ((object)name != (object)slot.stringKey || slot.wasDeleted != 0) { + int hash = name.GetHashCode (); + slot = GetSlot (name, hash); + if (slot == null) { + if (start != this) { + start.Put (name, start, value); + return value; + } + slot = AddSlot (name, hash, null); + } + // Note: cache is not updated in put + } + if (start == this && Sealed) { + throw Context.ReportRuntimeErrorById ("msg.modify.sealed", name); + } + if ((slot.attributes & ScriptableObject.READONLY) != 0) { + // FINDME + Context cx = Context.CurrentContext; + if (cx.Version == Context.Versions.JS1_2) { + throw Context.ReportRuntimeErrorById ("msg.read-only", name); + } else { + if (cx.HasFeature (Context.Features.Strict)) { + Context.ReportWarningById ("msg.read-only", name); + } + } + return value; + } + if (this == start) { + return slot.SetValue (null, start, start, value); + } + else { + if (slot.setter != null) { + Slot newSlot = (Slot)slot.Clone (); + ((ScriptableObject)start).AddSlotImpl (newSlot.stringKey, newSlot.intKey, newSlot); + return newSlot.SetValue (null, start, start, value); + } + else { + return start.Put (name, start, value); + } + } + return value; + } + + /// Sets the value of the indexed property, creating it if need be. + /// + /// + /// the numeric index for the property + /// + /// the object whose property is being set + /// + /// value to set the property to + /// + public virtual object Put (int index, IScriptable start, object value) + { + Slot slot = GetSlot (null, index); + if (slot == null) { + if (start != this) { + return start.Put (index, start, value); + } + slot = AddSlot (null, index, null); + } + if (start == this && Sealed) { + throw Context.ReportRuntimeErrorById ("msg.modify.sealed", Convert.ToString (index)); + } + if ((slot.attributes & ScriptableObject.READONLY) != 0) { + return slot.GetValue (null, start, start); // TODO: ??? + } + if (this == start) { + return slot.SetValue (null, start, start, value); + } + else { + return start.Put (index, start, value); + } + } + + /// Removes a named property from the object. + /// + /// If the property is not found, or it has the PERMANENT attribute, + /// no action is taken. + /// + /// + /// the name of the property + /// + public virtual void Delete (string name) + { + RemoveSlot (name, name.GetHashCode ()); + } + + /// Removes the indexed property from the object. + /// + /// If the property is not found, or it has the PERMANENT attribute, + /// no action is taken. + /// + /// + /// the numeric index for the property + /// + public virtual void Delete (int index) + { + RemoveSlot (null, index); + } + + + + + + /// Get the attributes of a named property. + /// + /// The property is specified by name + /// as defined for has.

+ /// + ///

+ /// the identifier for the property + /// + /// the bitset of attributes + /// + /// EvaluatorException if the named property is not found + /// + public virtual int GetAttributes (string name) + { + Slot slot = GetNamedSlot (name); + if (slot == null) { + throw Context.ReportRuntimeErrorById ("msg.prop.not.found", name); + } + return slot.attributes; + } + + /// Get the attributes of an indexed property. + /// + /// + /// the numeric index for the property + /// + /// EvaluatorException if the named property is not found + /// is not found + /// + /// the bitset of attributes + /// + public virtual int GetAttributes (int index) + { + Slot slot = GetSlot (null, index); + if (slot == null) { + throw Context.ReportRuntimeErrorById ("msg.prop.not.found", Convert.ToString (index)); + } + return slot.attributes; + } + + /// Set the attributes of a named property. + /// + /// The property is specified by name + /// as defined for has.

+ /// + /// The possible attributes are READONLY, DONTENUM, + /// and PERMANENT. Combinations of attributes + /// are expressed by the bitwise OR of attributes. + /// EMPTY is the state of no attributes set. Any unused + /// bits are reserved for future use. + /// + ///

+ /// the name of the property + /// + /// the bitset of attributes + /// + /// EvaluatorException if the named property is not found + /// + public virtual void SetAttributes (string name, int attributes) + { + CheckValidAttributes (attributes); + Slot slot = GetNamedSlot (name); + if (slot == null) { + throw Context.ReportRuntimeErrorById ("msg.prop.not.found", name); + } + slot.attributes = (short)attributes; + } + + /// Set the attributes of an indexed property. + /// + /// + /// the numeric index for the property + /// + /// the bitset of attributes + /// + /// EvaluatorException if the named property is not found + /// + public virtual void SetAttributes (int index, int attributes) + { + CheckValidAttributes (attributes); + Slot slot = GetSlot (null, index); + if (slot == null) { + throw Context.ReportRuntimeErrorById ("msg.prop.not.found", Convert.ToString (index)); + } + slot.attributes = (short)attributes; + } + + /// Returns the prototype of the object. + public virtual IScriptable GetPrototype () + { + return prototypeObject; + } + + /// Sets the prototype of the object. + public virtual void SetPrototype (IScriptable m) + { + prototypeObject = m; + } + + /// Returns an array of ids for the properties of the object. + /// + ///

Any properties with the attribute DONTENUM are not listed.

+ /// + ///

+ /// an array of java.lang.Objects with an entry for every + /// listed property. Properties accessed via an integer index will + /// have a corresponding + /// Integer entry in the returned array. Properties accessed by + /// a String will have a String entry in the returned array. + /// + public virtual object [] GetIds () + { + return GetIds (false); + } + + /// Implements the [[DefaultValue]] internal method. + /// + ///

Note that the toPrimitive conversion is a no-op for + /// every type other than Object, for which [[DefaultValue]] + /// is called. See ECMA 9.1.

+ /// + /// A hint of null means "no hint". + /// + ///

+ /// the type hint + /// + /// the default value for the object + /// + /// See ECMA 8.6.2.6. + /// + public virtual object GetDefaultValue (Type typeHint) + { + Context cx = null; + for (int i = 0; i < 2; i++) { + bool tryToString; + if (typeHint == typeof (string)) { + tryToString = (i == 0); + } + else { + tryToString = (i == 1); + } + + string methodName; + object [] args; + if (tryToString) { + methodName = "toString"; + args = ScriptRuntime.EmptyArgs; + } + else { + methodName = "valueOf"; + args = new object [1]; + string hint; + if (typeHint == null) { + hint = "undefined"; + } + else if (typeHint == typeof (string)) { + hint = "string"; + } + else if (typeHint == typeof (IScriptable)) { + hint = "object"; + } + else if (typeHint == typeof (IFunction)) { + hint = "function"; + } + else if (typeHint == typeof (bool) || typeHint == typeof (bool)) { + hint = "boolean"; + } + else if (CliHelper.IsNumberType (typeHint) || typeHint == typeof (byte) || typeHint == typeof (sbyte)) { + hint = "number"; + } + else { + throw Context.ReportRuntimeErrorById ("msg.invalid.type", typeHint.ToString ()); + } + args [0] = hint; + } + object v = GetProperty (this, methodName); + if (!(v is IFunction)) + continue; + IFunction fun = (IFunction)v; + if (cx == null) + cx = Context.CurrentContext; + v = fun.Call (cx, fun.ParentScope, this, args); + if (v != null) { + if (!(v is IScriptable)) { + return v; + } + if (typeHint == typeof (IScriptable) || typeHint == typeof (IFunction)) { + return v; + } + if (tryToString && v is Wrapper) { + // Let a wrapped java.lang.String pass for a primitive + // string. + object u = ((Wrapper)v).Unwrap (); + if (u is string) + return u; + } + } + } + // fall through to error + string arg = (typeHint == null) ? "undefined" : typeHint.FullName; + throw ScriptRuntime.TypeErrorById ("msg.default.value", arg); + } + + /// Implements the instanceof operator. + /// + ///

This operator has been proposed to ECMA. + /// + ///

+ /// The value that appeared on the LHS of the instanceof + /// operator + /// + /// true if "this" appears in value's prototype chain + /// + /// + public virtual bool HasInstance (IScriptable instance) + { + + // According to specs -- section 11.8.6 of ECMA-262 -- instanceof operator + // on objects NOT implementing [[HasInstance]] internal method should + // throw a TypeError exception. Hence, in the following script the + // catch block must get executed, (since Math object does not implement + // [[HasInstance]] method). + throw ScriptRuntime.TypeError ("msg.bad.instanceof.rhs"); + + + // Default for JS objects (other than Function) is to do prototype + // chasing. This will be overridden in NativeFunction and non-JS + // objects. + //return ScriptRuntime.jsDelegatesTo(instance, this); + } + + /// Custom == operator. + /// Must return {@link Scriptable#NOT_FOUND} if this object does not + /// have custom equality operator for the given value, + /// Boolean.TRUE if this object is equivalent to value, + /// Boolean.FALSE if this object is not equivalent to + /// value. + ///

+ /// The default implementation returns Boolean.TRUE + /// if this == value or {@link Scriptable#NOT_FOUND} otherwise. + /// It indicates that by default custom equality is available only if + /// value is this in which case true is returned. + ///

+ protected internal virtual object EquivalentValues (object value) + { + return (this == value) ? (object)true : UniqueTag.NotFound; + } + + /// Define a JavaScript property. + /// + /// Creates the property with an initial value and sets its attributes. + /// + /// + /// the name of the property to define. + /// + /// the initial value of the property + /// + /// the attributes of the JavaScript property + /// + public virtual void DefineProperty (string propertyName, object value, int attributes) + { + Put (propertyName, this, value); + SetAttributes (propertyName, attributes); + } + + /// Utility method to add properties to arbitrary Scriptable object. + /// If destination is instance of ScriptableObject, calls + /// defineProperty there, otherwise calls put in destination + /// ignoring attributes + /// + public static void DefineProperty (IScriptable destination, string propertyName, object value, int attributes) + { + if (!(destination is ScriptableObject)) { + destination.Put (propertyName, destination, value); + return; + } + ScriptableObject so = (ScriptableObject)destination; + so.DefineProperty (propertyName, value, attributes); + } + + + + /// Get the Object.prototype property. + /// See ECMA 15.2.4. + /// + public static IScriptable GetObjectPrototype (IScriptable scope) + { + return getClassPrototype (scope, "Object"); + } + + /// Get the Function.prototype property. + /// See ECMA 15.3.4. + /// + public static IScriptable GetFunctionPrototype (IScriptable scope) + { + return getClassPrototype (scope, "Function"); + } + + /// Get the prototype for the named class. + /// + /// For example, getClassPrototype(s, "Date") will first + /// walk up the parent chain to find the outermost scope, then will + /// search that scope for the Date constructor, and then will + /// return Date.prototype. If any of the lookups fail, or + /// the prototype is not a JavaScript object, then null will + /// be returned. + /// + /// + /// an object in the scope chain + /// + /// the name of the constructor + /// + /// the prototype for the named class, or null if it + /// cannot be found. + /// + public static IScriptable getClassPrototype (IScriptable scope, string className) + { + scope = GetTopLevelScope (scope); + object ctor = GetProperty (scope, className); + object proto; + if (ctor is BaseFunction) { + proto = ((BaseFunction)ctor).PrototypeProperty; + } + else if (ctor is IScriptable) { + IScriptable ctorObj = (IScriptable)ctor; + proto = ctorObj.Get ("prototype", ctorObj); + } + else { + return null; + } + if (proto is IScriptable) { + return (IScriptable)proto; + } + return null; + } + + /// Get the global scope. + /// + ///

Walks the parent scope chain to find an object with a null + /// parent scope (the global object). + /// + ///

+ /// a JavaScript object + /// + /// the corresponding global scope + /// + public static IScriptable GetTopLevelScope (IScriptable obj) + { + for (; ; ) { + IScriptable parent = obj.ParentScope; + if (parent == null) { + return obj; + } + obj = parent; + } + } + + /// Seal this object. + /// + /// A sealed object may not have properties added or removed. Once + /// an object is sealed it may not be unsealed. + /// + /// + public virtual void SealObject () + { + lock (this) { + if (count >= 0) { + count = -1 - count; + } + } + } + + /// Gets a named property from an object or any object in its prototype chain. + ///

+ /// Searches the prototype chain for a property named name. + ///

+ ///

+ /// a JavaScript object + /// + /// a property name + /// + /// the value of a property with name name found in + /// obj or any object in its prototype chain, or + /// Scriptable.NOT_FOUND if not found + /// + public static object GetProperty (IScriptable obj, string name) + { + IScriptable start = obj; + object result; + do { + result = obj.Get (name, start); + if (result != UniqueTag.NotFound) + break; + obj = obj.GetPrototype (); + } + while (obj != null); + return result; + } + + /// Gets an indexed property from an object or any object in its prototype chain. + ///

+ /// Searches the prototype chain for a property with integral index + /// index. Note that if you wish to look for properties with numerical + /// but non-integral indicies, you should use getProperty(Scriptable,String) with + /// the string value of the index. + ///

+ ///

+ /// a JavaScript object + /// + /// an integral index + /// + /// the value of a property with index index found in + /// obj or any object in its prototype chain, or + /// Scriptable.NOT_FOUND if not found + /// + public static object GetProperty (IScriptable obj, int index) + { + IScriptable start = obj; + object result; + do { + result = obj.Get (index, start); + if (result != UniqueTag.NotFound) + break; + obj = obj.GetPrototype (); + } + while (obj != null); + return result; + } + + /// Returns whether a named property is defined in an object or any object + /// in its prototype chain. + ///

+ /// Searches the prototype chain for a property named name. + ///

+ ///

+ /// a JavaScript object + /// + /// a property name + /// + /// the true if property was found + /// + public static bool HasProperty (IScriptable obj, string name) + { + return null != GetBase (obj, name); + } + + /// Returns whether an indexed property is defined in an object or any object + /// in its prototype chain. + ///

+ /// Searches the prototype chain for a property with index index. + ///

+ ///

+ /// a JavaScript object + /// + /// a property index + /// + /// the true if property was found + /// + public static bool HasProperty (IScriptable obj, int index) + { + return null != GetBase (obj, index); + } + + /// Puts a named property in an object or in an object in its prototype chain. + ///

+ /// Seaches for the named property in the prototype chain. If it is found, + /// the value of the property is changed. If it is not found, a new + /// property is added in obj. + ///

+ /// a JavaScript object + /// + /// a property name + /// + /// any JavaScript value accepted by Scriptable.put + /// + public static object PutProperty (IScriptable obj, string name, object value) + { + IScriptable toBase = GetBase (obj, name); + if (toBase == null) + toBase = obj; + return toBase.Put (name, obj, value); + } + + /// Puts an indexed property in an object or in an object in its prototype chain. + ///

+ /// Seaches for the indexed property in the prototype chain. If it is found, + /// the value of the property is changed. If it is not found, a new + /// property is added in obj. + ///

+ /// a JavaScript object + /// + /// a property index + /// + /// any JavaScript value accepted by Scriptable.put + /// + public static object PutProperty (IScriptable obj, int index, object value) + { + IScriptable toBase = GetBase (obj, index); + if (toBase == null) + toBase = obj; + return toBase.Put (index, obj, value); + } + + /// Removes the property from an object or its prototype chain. + ///

+ /// Searches for a property with name in obj or + /// its prototype chain. If it is found, the object's delete + /// method is called. + ///

+ /// a JavaScript object + /// + /// a property name + /// + /// true if the property doesn't exist or was successfully removed + /// + public static bool DeleteProperty (IScriptable obj, string name) + { + IScriptable toBase = GetBase (obj, name); + if (toBase == null) + return true; + toBase.Delete (name); + return !toBase.Has (name, obj); + } + + /// Removes the property from an object or its prototype chain. + ///

+ /// Searches for a property with index in obj or + /// its prototype chain. If it is found, the object's delete + /// method is called. + ///

+ /// a JavaScript object + /// + /// a property index + /// + /// true if the property doesn't exist or was successfully removed + /// + public static bool DeleteProperty (IScriptable obj, int index) + { + IScriptable toBase = GetBase (obj, index); + if (toBase == null) + return true; + toBase.Delete (index); + return !toBase.Has (index, obj); + } + + /// Returns an array of all ids from an object and its prototypes. + ///

+ ///

+ /// a JavaScript object + /// + /// an array of all ids from all object in the prototype chain. + /// If a given id occurs multiple times in the prototype chain, + /// it will occur only once in this list. + /// + public static object [] GetPropertyIds (IScriptable obj) + { + if (obj == null) { + return ScriptRuntime.EmptyArgs; + } + object [] result = obj.GetIds (); + ObjToIntMap map = null; + for (; ; ) { + obj = obj.GetPrototype (); + if (obj == null) { + break; + } + object [] ids = obj.GetIds (); + if (ids.Length == 0) { + continue; + } + if (map == null) { + if (result.Length == 0) { + result = ids; + continue; + } + map = new ObjToIntMap (result.Length + ids.Length); + for (int i = 0; i != result.Length; ++i) { + map.intern (result [i]); + } + result = null; // Allow to GC the result + } + for (int i = 0; i != ids.Length; ++i) { + map.intern (ids [i]); + } + } + if (map != null) { + result = map.getKeys (); + } + return result; + } + + /// Call a method of an object. + /// the JavaScript object + /// + /// the name of the function property + /// + /// the arguments for the call + /// + /// + public static object CallMethod (IScriptable obj, string methodName, object [] args) + { + return CallMethod (null, obj, methodName, args); + } + + /// Call a method of an object. + /// the Context object associated with the current thread. + /// + /// the JavaScript object + /// + /// the name of the function property + /// + /// the arguments for the call + /// + public static object CallMethod (Context cx, IScriptable obj, string methodName, object [] args) + { + object funObj = GetProperty (obj, methodName); + if (!(funObj is IFunction)) { + throw ScriptRuntime.NotFunctionError (obj, methodName); + } + IFunction fun = (IFunction)funObj; + // TODO: What should be the scope when calling funObj? + // The following favor scope stored in the object on the assumption + // that is more useful especially under dynamic scope setup. + // An alternative is to check for dynamic scope flag + // and use ScriptableObject.getTopLevelScope(fun) if the flag is not + // set. But that require access to Context and messy code + // so for now it is not checked. + IScriptable scope = ScriptableObject.GetTopLevelScope (obj); + if (cx != null) { + return fun.Call (cx, scope, obj, args); + } + else { + return Context.Call (null, fun, scope, obj, args); + } + } + + private static IScriptable GetBase (IScriptable obj, string name) + { + do { + if (obj.Has (name, obj)) + break; + obj = obj.GetPrototype (); + } + while (obj != null); + return obj; + } + + private static IScriptable GetBase (IScriptable obj, int index) + { + do { + if (obj.Has (index, obj)) + break; + obj = obj.GetPrototype (); + } + while (obj != null); + return obj; + } + + /// Get arbitrary application-specific value associated with this object. + /// key object to select particular value. + /// + public object GetAssociatedValue (object key) + { + Hashtable h = associatedValues; + if (h == null) + return null; + return h [key]; + } + + /// Get arbitrary application-specific value associated with the top scope + /// of the given scope. + /// The method first calls {@link #getTopLevelScope(Scriptable scope)} + /// and then searches the prototype chain of the top scope for the first + /// object containing the associated value with the given key. + /// + /// + /// the starting scope. + /// + /// key object to select particular value. + /// + public static object GetTopScopeValue (IScriptable scope, object key) + { + scope = ScriptableObject.GetTopLevelScope (scope); + for (; ; ) { + if (scope is ScriptableObject) { + ScriptableObject so = (ScriptableObject)scope; + object value = so.GetAssociatedValue (key); + if (value != null) { + return value; + } + } + scope = scope.GetPrototype (); + if (scope == null) { + return null; + } + } + } + + /// Associate arbitrary application-specific value with this object. + /// Value can only be associated with the given object and key only once. + /// The method ignores any subsequent attempts to change the already + /// associated value. + ///

The associated values are not serilized. + ///

+ /// key object to select particular value. + /// + /// the value to associate + /// + /// the passed value if the method is called first time for the + /// given key or old value for any subsequent calls. + /// + public object AssociateValue (object key, object value) + { + if (value == null) + throw new ArgumentException (); + Hashtable h = associatedValues; + if (h == null) { + lock (this) { + h = associatedValues; + if (h == null) { + h = Hashtable.Synchronized (new Hashtable ()); + associatedValues = h; + } + } + } + return InitHash (h, key, value); + } + + private object InitHash (Hashtable h, object key, object initialValue) + { + lock (h.SyncRoot) { + object current = h [key]; + if (current == null) { + h [key] = initialValue; + } + else { + initialValue = current; + } + } + return initialValue; + } + + private Slot GetNamedSlot (string name) + { + // Query last access cache and check that it was not deleted + Slot slot = lastAccess; + if ((object)name == (object)slot.stringKey && slot.wasDeleted == 0) { + return slot; + } + int hash = name.GetHashCode (); + Slot [] slots = this.slots; // Get stable local reference + int i = GetSlotPosition (slots, name, hash); + if (i < 0) { + return null; + } + slot = slots [i]; + // Update cache - here stringKey.equals(name) holds, but it can be + // that slot.stringKey != name. To make last name cache work, need + // to change the key + slot.stringKey = name; + lastAccess = slot; + return slot; + } + + private Slot GetSlot (string id, int index) + { + Slot [] slots = this.slots; // Get local copy + int i = GetSlotPosition (slots, id, index); + return (i < 0) ? null : slots [i]; + } + + private static int GetSlotPosition (Slot [] slots, string id, int index) + { + if (slots != null) { + int start = (index & 0x7fffffff) % slots.Length; + int i = start; + do { + Slot slot = slots [i]; + if (slot == null) + break; + if (slot != REMOVED && slot.intKey == index && ((object)slot.stringKey == (object)id || (id != null && id.Equals (slot.stringKey)))) { + return i; + } + if (++i == slots.Length) + i = 0; + } + while (i != start); + } + return -1; + } + + /// Add a new slot to the hash table. + /// + /// This method must be synchronized since it is altering the hash + /// table itself. Note that we search again for the slot to set + /// since another thread could have added the given property or + /// caused the table to grow while this thread was searching. + /// + private Slot AddSlot (string id, int index, Slot newSlot) + { + lock (this) { + if (Sealed) { + string str = (id != null) ? id : Convert.ToString (index); + throw Context.ReportRuntimeErrorById ("msg.add.sealed", str); + } + + + + return AddSlotImpl (id, index, newSlot); + } + } + + // Must be inside synchronized (this) + private Slot AddSlotImpl (string id, int index, Slot newSlot) + { + if (slots == null) { + slots = new Slot [5]; + } + int start = (index & 0x7fffffff) % slots.Length; + int i = start; + for (; ; ) { + Slot slot = slots [i]; + if (slot == null || slot == REMOVED) { + if ((4 * (count + 1)) > (3 * slots.Length)) { + Grow (); + return AddSlotImpl (id, index, newSlot); + } + slot = (newSlot == null) ? new Slot () : newSlot; + slot.stringKey = id; + slot.intKey = index; + slots [i] = slot; + count++; + return slot; + } + if (slot.intKey == index && ((object)slot.stringKey == (object)id || (id != null && id.Equals (slot.stringKey)))) { + return slot; + } + if (++i == slots.Length) + i = 0; + if (i == start) { + // slots should never be full or bug in grow code + throw new Exception (); + } + } + } + + /// Remove a slot from the hash table. + /// + /// This method must be synchronized since it is altering the hash + /// table itself. We might be able to optimize this more, but + /// deletes are not common. + /// + private void RemoveSlot (string name, int index) + { + lock (this) { + if (Sealed) { + string str = (name != null) ? name : Convert.ToString (index); + throw Context.ReportRuntimeErrorById ("msg.remove.sealed", str); + } + + int i = GetSlotPosition (slots, name, index); + if (i >= 0) { + Slot slot = slots [i]; + if ((slot.attributes & PERMANENT) == 0) { + // Mark the slot as removed to handle a case when + // another thread manages to put just removed slot + // into lastAccess cache. + slot.wasDeleted = (sbyte)1; + if (slot == lastAccess) { + lastAccess = REMOVED; + } + count--; + if (count != 0) { + slots [i] = REMOVED; + } + else { + // With no slots it is OK to mark with null. + slots [i] = null; + } + } + } + } + } + + // Grow the hash table to accommodate new entries. + // + // Note that by assigning the new array back at the end we + // can continue reading the array from other threads. + // Must be inside synchronized (this) + private void Grow () + { + Slot [] newSlots = new Slot [slots.Length * 2 + 1]; + for (int j = slots.Length - 1; j >= 0; j--) { + Slot slot = slots [j]; + if (slot == null || slot == REMOVED) + continue; + int k = (slot.intKey & 0x7fffffff) % newSlots.Length; + while (newSlots [k] != null) + if (++k == newSlots.Length) + k = 0; + // The end of the "synchronized" statement will cause the memory + // writes to be propagated on a multiprocessor machine. We want + // to make sure that the new table is prepared to be read. + // TODO: causes the 'this' pointer to be null in calling stack frames + // on the MS JVM + //synchronized (slot) { } + newSlots [k] = slot; + } + slots = newSlots; + } + + internal virtual object [] GetIds (bool getAll) + { + Slot [] s = slots; + object [] a = ScriptRuntime.EmptyArgs; + if (s == null) + return a; + int c = 0; + for (int i = 0; i < s.Length; i++) { + Slot slot = s [i]; + if (slot == null || slot == REMOVED) + continue; + if (getAll || (slot.attributes & DONTENUM) == 0) { + if (c == 0) + a = new object [s.Length - i]; + a [c++] = slot.stringKey != null ? (object)slot.stringKey : (int)slot.intKey; + } + } + if (c == a.Length) + return a; + object [] result = new object [c]; + Array.Copy (a, 0, result, 0, c); + return result; + } + + + /// The prototype of this object. + private IScriptable prototypeObject; + + /// The parent scope of this object. + private IScriptable parentScopeObject; + + private static readonly object HAS_STATIC_ACCESSORS = typeof (void); + private static readonly Slot REMOVED = new Slot (); + + + private Slot [] slots; + // If count >= 0, it gives number of keys or if count < 0, + // it indicates sealed object where -1 - count gives number of keys + private int count; + + // cache; may be removed for smaller memory footprint + + private Slot lastAccess = REMOVED; + + // associated values are not serialized + + private volatile Hashtable associatedValues; + + public virtual void DefineSetter (string name, ICallable setter) + { + Slot slot = GetSlot (name, name.GetHashCode ()); + if (slot == null) { + slot = new Slot (); + AddSlot (name, name.GetHashCode (), slot); + } + slot.setter = setter; + } + + public virtual void DefineSetter (int index, ICallable setter) + { + Slot slot = GetSlot (null, index); + if (slot == null) { + slot = new Slot (); + AddSlot (null, index, slot); + } + slot.setter = setter; + } + + public virtual void DefineGetter (int index, ICallable getter) + { + Slot slot = GetSlot (null, index); + if (slot == null) { + slot = new Slot (); + AddSlot (null, index, slot); + } + slot.getter = getter; + } + + public virtual void DefineGetter (string name, ICallable getter) + { + Slot slot = GetSlot (name, name.GetHashCode ()); + if (slot == null) { + slot = new Slot (); + AddSlot (name, name.GetHashCode (), slot); + } + slot.getter = getter; + } + + public virtual object LookupGetter (string name) + { + Slot slot = GetSlot (name, name.GetHashCode ()); + if (slot == null || slot.getter == null) + return Undefined.Value; + return slot.getter; + } + + public virtual object LookupSetter (string name) + { + Slot slot = GetSlot (name, name.GetHashCode ()); + if (slot == null || slot.setter == null) + return Undefined.Value; + return slot.setter; + } + + private class Slot : ICloneable + { + + internal int intKey; + internal string stringKey; + internal object value; + internal short attributes; + + internal sbyte wasDeleted; + + internal ICallable getter; + internal ICallable setter; + + public object Clone () + { + Slot clone = new Slot (); + clone.intKey = intKey; + clone.stringKey = stringKey; + clone.value = value; + clone.attributes = attributes; + clone.wasDeleted = wasDeleted; + clone.getter = getter; + clone.setter = setter; + return clone; + } + + internal object GetValue (Context cx, IScriptable scope, IScriptable thisObj) + { + if (getter == null) { + return value; + } + else { + if (cx == null) + cx = Context.CurrentContext; + return getter.Call (cx, scope, thisObj, + ScriptRuntime.EmptyArgs); + } + } + + internal object SetValue (Context cx, IScriptable scope, IScriptable thisObj, object value) + { + if (setter == null) { + if (getter == null) { + return (this.value = value); + } + else { + throw ScriptRuntime.TypeError ("setting a property that has only a getter"); + } + } + else { + if (cx == null) + cx = Context.CurrentContext; + return setter.Call (cx, scope, thisObj, new object [] { value }); + } + } + + } + + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/SecurityController.cs b/src/EcmaScript.NET/SecurityController.cs similarity index 97% rename from Code/EcmaScript.NET/SecurityController.cs rename to src/EcmaScript.NET/SecurityController.cs index ad30598..0653587 100644 --- a/Code/EcmaScript.NET/SecurityController.cs +++ b/src/EcmaScript.NET/SecurityController.cs @@ -1,137 +1,137 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -namespace EcmaScript.NET -{ - - /// This class describes the support needed to implement security. - ///

- /// Three main pieces of functionality are required to implement - /// security for JavaScript. First, it must be possible to define - /// classes with an associated security domain. (This security - /// domain may be any object incorporating notion of access - /// restrictions that has meaning to an embedding; for a client-side - /// JavaScript embedding this would typically be - /// java.security.ProtectionDomain or similar object depending on an - /// origin URL and/or a digital certificate.) - /// Next it must be possible to get a security domain object that - /// allows a particular action only if all security domains - /// associated with code on the current Java stack allows it. And - /// finally, it must be possible to execute script code with - /// associated security domain injected into Java stack. - ///

- /// These three pieces of functionality are encapsulated in the - /// SecurityController class. - /// - ///

- public abstract class SecurityController - { - - private class AnonymousClassScript : IScript - { - public AnonymousClassScript (EcmaScript.NET.ICallable callable, EcmaScript.NET.IScriptable thisObj, object [] args, SecurityController enclosingInstance) - { - InitBlock (callable, thisObj, args, enclosingInstance); - } - private void InitBlock (EcmaScript.NET.ICallable callable, EcmaScript.NET.IScriptable thisObj, object [] args, SecurityController enclosingInstance) - { - this.callable = callable; - this.thisObj = thisObj; - this.args = args; - this.enclosingInstance = enclosingInstance; - } - - private EcmaScript.NET.ICallable callable; - - private EcmaScript.NET.IScriptable thisObj; - - private object [] args; - private SecurityController enclosingInstance; - public SecurityController Enclosing_Instance - { - get - { - return enclosingInstance; - } - - } - public virtual object Exec (Context cx, IScriptable scope) - { - return callable.Call (cx, scope, thisObj, args); - } - } - private static SecurityController m_Global; - - // The method must NOT be public or protected - internal static SecurityController Global - { - get - { - return m_Global; - } - } - - /// Check if global {@link SecurityController} was already installed. - public static bool HasGlobal () - { - return m_Global != null; - } - - /// Initialize global controller that will be used for all - /// security-related operations. The global controller takes precedence - /// over already installed {@link Context}-specific controllers and cause - /// any subsequent call to - /// {@link Context#setSecurityController(SecurityController)} - /// to throw an exception. - ///

- /// The method can only be called once. - /// - ///

- public static void initGlobal (SecurityController controller) - { - if (controller == null) - throw new ArgumentException (); - if (m_Global != null) { - throw new System.Security.SecurityException ("Cannot overwrite already installed global SecurityController"); - } - m_Global = controller; - } - - - /// Get dynamic security domain that allows an action only if it is allowed - /// by the current Java stack and securityDomain. If - /// securityDomain is null, return domain representing permissions - /// allowed by the current stack. - /// - public abstract object getDynamicSecurityDomain (object securityDomain); - - /// Call {@link - /// Callable#call(Context cx, Scriptable scope, Scriptable thisObj, - /// Object[] args)} - /// of callable under restricted security domain where an action is - /// allowed only if it is allowed according to the Java stack on the - /// moment of the execWithDomain call and securityDomain. - /// Any call to {@link #getDynamicSecurityDomain(Object)} during - /// execution of callable.call(cx, scope, thisObj, args) - /// should return a domain incorporate restrictions imposed by - /// securityDomain and Java stack on the moment of callWithDomain - /// invocation. - ///

- ///

- public abstract object callWithDomain (object securityDomain, Context cx, ICallable callable, IScriptable scope, IScriptable thisObj, object [] args); - - - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +namespace EcmaScript.NET +{ + + /// This class describes the support needed to implement security. + ///

+ /// Three main pieces of functionality are required to implement + /// security for JavaScript. First, it must be possible to define + /// classes with an associated security domain. (This security + /// domain may be any object incorporating notion of access + /// restrictions that has meaning to an embedding; for a client-side + /// JavaScript embedding this would typically be + /// java.security.ProtectionDomain or similar object depending on an + /// origin URL and/or a digital certificate.) + /// Next it must be possible to get a security domain object that + /// allows a particular action only if all security domains + /// associated with code on the current Java stack allows it. And + /// finally, it must be possible to execute script code with + /// associated security domain injected into Java stack. + ///

+ /// These three pieces of functionality are encapsulated in the + /// SecurityController class. + /// + ///

+ public abstract class SecurityController + { + + private class AnonymousClassScript : IScript + { + public AnonymousClassScript (EcmaScript.NET.ICallable callable, EcmaScript.NET.IScriptable thisObj, object [] args, SecurityController enclosingInstance) + { + InitBlock (callable, thisObj, args, enclosingInstance); + } + private void InitBlock (EcmaScript.NET.ICallable callable, EcmaScript.NET.IScriptable thisObj, object [] args, SecurityController enclosingInstance) + { + this.callable = callable; + this.thisObj = thisObj; + this.args = args; + this.enclosingInstance = enclosingInstance; + } + + private EcmaScript.NET.ICallable callable; + + private EcmaScript.NET.IScriptable thisObj; + + private object [] args; + private SecurityController enclosingInstance; + public SecurityController Enclosing_Instance + { + get + { + return enclosingInstance; + } + + } + public virtual object Exec (Context cx, IScriptable scope) + { + return callable.Call (cx, scope, thisObj, args); + } + } + private static SecurityController m_Global; + + // The method must NOT be public or protected + internal static SecurityController Global + { + get + { + return m_Global; + } + } + + /// Check if global {@link SecurityController} was already installed. + public static bool HasGlobal () + { + return m_Global != null; + } + + /// Initialize global controller that will be used for all + /// security-related operations. The global controller takes precedence + /// over already installed {@link Context}-specific controllers and cause + /// any subsequent call to + /// {@link Context#setSecurityController(SecurityController)} + /// to throw an exception. + ///

+ /// The method can only be called once. + /// + ///

+ public static void initGlobal (SecurityController controller) + { + if (controller == null) + throw new ArgumentException (); + if (m_Global != null) { + throw new System.Security.SecurityException ("Cannot overwrite already installed global SecurityController"); + } + m_Global = controller; + } + + + /// Get dynamic security domain that allows an action only if it is allowed + /// by the current Java stack and securityDomain. If + /// securityDomain is null, return domain representing permissions + /// allowed by the current stack. + /// + public abstract object getDynamicSecurityDomain (object securityDomain); + + /// Call {@link + /// Callable#call(Context cx, Scriptable scope, Scriptable thisObj, + /// Object[] args)} + /// of callable under restricted security domain where an action is + /// allowed only if it is allowed according to the Java stack on the + /// moment of the execWithDomain call and securityDomain. + /// Any call to {@link #getDynamicSecurityDomain(Object)} during + /// execution of callable.call(cx, scope, thisObj, args) + /// should return a domain incorporate restrictions imposed by + /// securityDomain and Java stack on the moment of callWithDomain + /// invocation. + ///

+ ///

+ public abstract object callWithDomain (object securityDomain, Context cx, ICallable callable, IScriptable scope, IScriptable thisObj, object [] args); + + + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/SpecialRef.cs b/src/EcmaScript.NET/SpecialRef.cs similarity index 96% rename from Code/EcmaScript.NET/SpecialRef.cs rename to src/EcmaScript.NET/SpecialRef.cs index e75be75..5809841 100644 --- a/Code/EcmaScript.NET/SpecialRef.cs +++ b/src/EcmaScript.NET/SpecialRef.cs @@ -1,145 +1,145 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -namespace EcmaScript.NET -{ - - class SpecialRef : IRef - { - - public enum Types - { - None = 0, - Proto = 1, - Parent = 2 - } - - private IScriptable target; - private Types type; - private string name; - - private SpecialRef (IScriptable target, Types type, string name) - { - this.target = target; - this.type = type; - this.name = name; - } - - internal static IRef createSpecial (Context cx, object obj, string name) - { - IScriptable target = ScriptConvert.ToObjectOrNull (cx, obj); - if (target == null) { - throw ScriptRuntime.UndefReadError (obj, name); - } - - Types type; - if (name.Equals ("__proto__")) { - type = Types.Proto; - } - else if (name.Equals ("__parent__")) { - type = Types.Parent; - } - else { - throw new ArgumentException (name); - } - - if (!cx.HasFeature (Context.Features.ParentProtoProperties)) { - // Clear special after checking for valid name! - type = Types.None; - } - - return new SpecialRef (target, type, name); - } - - public object Get (Context cx) - { - switch (type) { - - case Types.None: - return ScriptRuntime.getObjectProp (target, name, cx); - - case Types.Proto: - return target.GetPrototype (); - - case Types.Parent: - return target.ParentScope; - - default: - throw Context.CodeBug (); - - } - } - - public object Set (Context cx, object value) - { - switch (type) { - - case Types.None: - return ScriptRuntime.setObjectProp (target, name, value, cx); - - case Types.Proto: - case Types.Parent: { - IScriptable obj = ScriptConvert.ToObjectOrNull (cx, value); - if (obj != null) { - // Check that obj does not contain on its prototype/scope - // chain to prevent cycles - IScriptable search = obj; - do { - if (search == target) { - throw Context.ReportRuntimeErrorById ("msg.cyclic.value", name); - } - if (type == Types.Proto) { - search = search.GetPrototype (); - } - else { - search = search.ParentScope; - } - } - while (search != null); - } - if (type == Types.Proto) { - target.SetPrototype (obj); - } - else { - target.ParentScope = obj; - } - return obj; - } - - default: - throw Context.CodeBug (); - - } - } - - public bool Has (Context cx) - { - if (type == Types.None) { - return ScriptRuntime.hasObjectElem (target, name, cx); - } - return true; - } - - public bool Delete (Context cx) - { - if (type == Types.None) { - return ScriptRuntime.deleteObjectElem (target, name, cx); - } - return false; - } - - } - +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +namespace EcmaScript.NET +{ + + class SpecialRef : IRef + { + + public enum Types + { + None = 0, + Proto = 1, + Parent = 2 + } + + private IScriptable target; + private Types type; + private string name; + + private SpecialRef (IScriptable target, Types type, string name) + { + this.target = target; + this.type = type; + this.name = name; + } + + internal static IRef createSpecial (Context cx, object obj, string name) + { + IScriptable target = ScriptConvert.ToObjectOrNull (cx, obj); + if (target == null) { + throw ScriptRuntime.UndefReadError (obj, name); + } + + Types type; + if (name.Equals ("__proto__")) { + type = Types.Proto; + } + else if (name.Equals ("__parent__")) { + type = Types.Parent; + } + else { + throw new ArgumentException (name); + } + + if (!cx.HasFeature (Context.Features.ParentProtoProperties)) { + // Clear special after checking for valid name! + type = Types.None; + } + + return new SpecialRef (target, type, name); + } + + public object Get (Context cx) + { + switch (type) { + + case Types.None: + return ScriptRuntime.getObjectProp (target, name, cx); + + case Types.Proto: + return target.GetPrototype (); + + case Types.Parent: + return target.ParentScope; + + default: + throw Context.CodeBug (); + + } + } + + public object Set (Context cx, object value) + { + switch (type) { + + case Types.None: + return ScriptRuntime.setObjectProp (target, name, value, cx); + + case Types.Proto: + case Types.Parent: { + IScriptable obj = ScriptConvert.ToObjectOrNull (cx, value); + if (obj != null) { + // Check that obj does not contain on its prototype/scope + // chain to prevent cycles + IScriptable search = obj; + do { + if (search == target) { + throw Context.ReportRuntimeErrorById ("msg.cyclic.value", name); + } + if (type == Types.Proto) { + search = search.GetPrototype (); + } + else { + search = search.ParentScope; + } + } + while (search != null); + } + if (type == Types.Proto) { + target.SetPrototype (obj); + } + else { + target.ParentScope = obj; + } + return obj; + } + + default: + throw Context.CodeBug (); + + } + } + + public bool Has (Context cx) + { + if (type == Types.None) { + return ScriptRuntime.hasObjectElem (target, name, cx); + } + return true; + } + + public bool Delete (Context cx) + { + if (type == Types.None) { + return ScriptRuntime.deleteObjectElem (target, name, cx); + } + return false; + } + + } + } \ No newline at end of file diff --git a/Code/EcmaScript.NET/Token.cs b/src/EcmaScript.NET/Token.cs similarity index 96% rename from Code/EcmaScript.NET/Token.cs rename to src/EcmaScript.NET/Token.cs index 2c6732e..0a4b5b2 100644 --- a/Code/EcmaScript.NET/Token.cs +++ b/src/EcmaScript.NET/Token.cs @@ -1,669 +1,669 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; - -namespace EcmaScript.NET -{ - - /// This class implements the JavaScript scanner. - /// - /// It is based on the C source files jsscan.c and jsscan.h - /// in the jsref package. - /// - /// - public class Token - { - - // debug flags - internal static readonly bool printTrees = false; // TODO: make me a preprocessor directive - - internal static readonly bool printICode = false; // TODO: make me a preprocessor directive - - internal static readonly bool printNames = printTrees || printICode; - - /// - /// Token types. - /// - /// These values correspond to JSTokenType values in - /// jsscan.c. - /// - public const int ERROR = -1; /* well-known as the only code < EOF */ - public const int EOF = 0; /* end of file */ - public const int EOL = 1; /* end of line */ - public const int FIRST_BYTECODE_TOKEN = 2; - public const int ENTERWITH = 2; - public const int LEAVEWITH = 3; - public const int RETURN = 4; - public const int GOTO = 5; - public const int IFEQ = 6; - public const int IFNE = 7; - public const int SETNAME = 8; - public const int BITOR = 9; - public const int BITXOR = 10; - public const int BITAND = 11; - public const int EQ = 12; - public const int NE = 13; - public const int LT = 14; - public const int LE = 15; - public const int GT = 16; - public const int GE = 17; - public const int LSH = 18; - public const int RSH = 19; - public const int URSH = 20; - public const int ADD = 21; - public const int SUB = 22; - public const int MUL = 23; - public const int DIV = 24; - public const int MOD = 25; - public const int NOT = 26; - public const int BITNOT = 27; - public const int POS = 28; - public const int NEG = 29; - public const int NEW = 30; - public const int DELPROP = 31; - public const int TYPEOF = 32; - public const int GETPROP = 33; - public const int SETPROP = 34; - public const int GETELEM = 35; - public const int SETELEM = 36; - public const int CALL = 37; - public const int NAME = 38; - public const int NUMBER = 39; - public const int STRING = 40; - public const int NULL = 41; - public const int THIS = 42; - public const int FALSE = 43; - public const int TRUE = 44; - public const int SHEQ = 45; - public const int SHNE = 46; - public const int REGEXP = 47; - public const int BINDNAME = 48; - public const int THROW = 49; - public const int RETHROW = 50; - public const int IN = 51; - public const int INSTANCEOF = 52; - public const int LOCAL_LOAD = 53; - public const int GETVAR = 54; - public const int SETVAR = 55; - public const int CATCH_SCOPE = 56; - public const int ENUM_INIT_KEYS = 57; - public const int ENUM_INIT_VALUES = 58; - public const int ENUM_NEXT = 59; - public const int ENUM_ID = 60; - public const int THISFN = 61; - public const int RETURN_RESULT = 62; - public const int ARRAYLIT = 63; - public const int OBJECTLIT = 64; - public const int GET_REF = 65; - public const int SET_REF = 66; - public const int DEL_REF = 67; - public const int REF_CALL = 68; - public const int REF_SPECIAL = 69; - public const int DEFAULTNAMESPACE = 70; - public const int ESCXMLATTR = 71; - public const int ESCXMLTEXT = 72; - public const int REF_MEMBER = 73; - public const int REF_NS_MEMBER = 74; - public const int REF_NAME = 75; - public const int REF_NS_NAME = 76; // Reference for ns::y, @ns::y@[y] etc. - public const int SETPROP_GETTER = 77; - public const int SETPROP_SETTER = 78; - - // End of interpreter bytecodes - public const int LAST_BYTECODE_TOKEN = SETPROP_SETTER; - - public const int TRY = LAST_BYTECODE_TOKEN + 1; - public const int SEMI = LAST_BYTECODE_TOKEN + 2; - public const int LB = LAST_BYTECODE_TOKEN + 3; - public const int RB = LAST_BYTECODE_TOKEN + 4; - public const int LC = LAST_BYTECODE_TOKEN + 5; - public const int RC = LAST_BYTECODE_TOKEN + 6; - public const int LP = LAST_BYTECODE_TOKEN + 7; - public const int RP = LAST_BYTECODE_TOKEN + 8; - public const int COMMA = LAST_BYTECODE_TOKEN + 9; - public const int ASSIGN = LAST_BYTECODE_TOKEN + 10; - public const int ASSIGN_BITOR = LAST_BYTECODE_TOKEN + 11; - public const int ASSIGN_BITXOR = LAST_BYTECODE_TOKEN + 12; - public const int ASSIGN_BITAND = LAST_BYTECODE_TOKEN + 13; - public const int ASSIGN_LSH = LAST_BYTECODE_TOKEN + 14; - public const int ASSIGN_RSH = LAST_BYTECODE_TOKEN + 15; - public const int ASSIGN_URSH = LAST_BYTECODE_TOKEN + 16; - public const int ASSIGN_ADD = LAST_BYTECODE_TOKEN + 17; - public const int ASSIGN_SUB = LAST_BYTECODE_TOKEN + 18; - public const int ASSIGN_MUL = LAST_BYTECODE_TOKEN + 19; - public const int ASSIGN_DIV = LAST_BYTECODE_TOKEN + 20; - public const int ASSIGN_MOD = LAST_BYTECODE_TOKEN + 21; // %= - - public const int FIRST_ASSIGN = ASSIGN; - public const int LAST_ASSIGN = ASSIGN_MOD; - - public const int HOOK = LAST_BYTECODE_TOKEN + 22; - public const int COLON = LAST_BYTECODE_TOKEN + 23; - public const int OR = LAST_BYTECODE_TOKEN + 24; - public const int AND = LAST_BYTECODE_TOKEN + 25; - public const int INC = LAST_BYTECODE_TOKEN + 26; - public const int DEC = LAST_BYTECODE_TOKEN + 27; - public const int DOT = LAST_BYTECODE_TOKEN + 28; - public const int FUNCTION = LAST_BYTECODE_TOKEN + 29; - public const int EXPORT = LAST_BYTECODE_TOKEN + 30; - public const int IMPORT = LAST_BYTECODE_TOKEN + 31; - public const int IF = LAST_BYTECODE_TOKEN + 32; - public const int ELSE = LAST_BYTECODE_TOKEN + 33; - public const int SWITCH = LAST_BYTECODE_TOKEN + 34; - public const int CASE = LAST_BYTECODE_TOKEN + 35; - public const int DEFAULT = LAST_BYTECODE_TOKEN + 36; - public const int WHILE = LAST_BYTECODE_TOKEN + 37; - public const int DO = LAST_BYTECODE_TOKEN + 38; - public const int FOR = LAST_BYTECODE_TOKEN + 39; - public const int BREAK = LAST_BYTECODE_TOKEN + 40; - public const int CONTINUE = LAST_BYTECODE_TOKEN + 41; - public const int VAR = LAST_BYTECODE_TOKEN + 42; - public const int WITH = LAST_BYTECODE_TOKEN + 43; - public const int CATCH = LAST_BYTECODE_TOKEN + 44; - public const int FINALLY = LAST_BYTECODE_TOKEN + 45; - public const int VOID = LAST_BYTECODE_TOKEN + 46; - public const int RESERVED = LAST_BYTECODE_TOKEN + 47; - public const int EMPTY = LAST_BYTECODE_TOKEN + 48; - public const int BLOCK = LAST_BYTECODE_TOKEN + 49; - public const int LABEL = LAST_BYTECODE_TOKEN + 50; - public const int TARGET = LAST_BYTECODE_TOKEN + 51; - public const int LOOP = LAST_BYTECODE_TOKEN + 52; - public const int EXPR_VOID = LAST_BYTECODE_TOKEN + 53; - public const int EXPR_RESULT = LAST_BYTECODE_TOKEN + 54; - public const int JSR = LAST_BYTECODE_TOKEN + 55; - public const int SCRIPT = LAST_BYTECODE_TOKEN + 56; - public const int TYPEOFNAME = LAST_BYTECODE_TOKEN + 57; - public const int USE_STACK = LAST_BYTECODE_TOKEN + 58; - public const int SETPROP_OP = LAST_BYTECODE_TOKEN + 59; - public const int SETELEM_OP = LAST_BYTECODE_TOKEN + 60; - public const int LOCAL_BLOCK = LAST_BYTECODE_TOKEN + 61; - public const int SET_REF_OP = LAST_BYTECODE_TOKEN + 62; - public const int DOTDOT = LAST_BYTECODE_TOKEN + 63; - public const int COLONCOLON = LAST_BYTECODE_TOKEN + 64; - public const int XML = LAST_BYTECODE_TOKEN + 65; - public const int DOTQUERY = LAST_BYTECODE_TOKEN + 66; - public const int XMLATTR = LAST_BYTECODE_TOKEN + 67; - public const int XMLEND = LAST_BYTECODE_TOKEN + 68; - public const int TO_OBJECT = LAST_BYTECODE_TOKEN + 69; - public const int TO_DOUBLE = LAST_BYTECODE_TOKEN + 70; - - public const int GET = LAST_BYTECODE_TOKEN + 71; // JS 1.5 get pseudo keyword - public const int SET = LAST_BYTECODE_TOKEN + 72; // JS 1.5 set pseudo keyword - public const int CONST = LAST_BYTECODE_TOKEN + 73; - public const int SETCONST = LAST_BYTECODE_TOKEN + 74; - public const int SETCONSTVAR = LAST_BYTECODE_TOKEN + 75; - public const int CONDCOMMENT = LAST_BYTECODE_TOKEN + 76; // JScript conditional comment - public const int KEEPCOMMENT = LAST_BYTECODE_TOKEN + 77; // /*! ... */ comment - public const int DEBUGGER = LAST_BYTECODE_TOKEN + 78; - - public const int LAST_TOKEN = LAST_BYTECODE_TOKEN + 79; - - public static string name (int token) - { - //if (!printNames) { - // return Convert.ToString (token); - //} - switch (token) { - - case ERROR: - return "ERROR"; - case EOF: - return "EOF"; - case EOL: - return "EOL"; - - case ENTERWITH: - return "ENTERWITH"; - - case LEAVEWITH: - return "LEAVEWITH"; - - case RETURN: - return "RETURN"; - - case GOTO: - return "GOTO"; - - case IFEQ: - return "IFEQ"; - - case IFNE: - return "IFNE"; - - case SETNAME: - return "SETNAME"; - - case BITOR: - return "BITOR"; - - case BITXOR: - return "BITXOR"; - - case BITAND: - return "BITAND"; - - case EQ: - return "EQ"; - - case NE: - return "NE"; - - case LT: - return "LT"; - - case LE: - return "LE"; - - case GT: - return "GT"; - - case GE: - return "GE"; - - case LSH: - return "LSH"; - - case RSH: - return "RSH"; - - case URSH: - return "URSH"; - - case ADD: - return "ADD"; - - case SUB: - return "SUB"; - - case MUL: - return "MUL"; - - case DIV: - return "DIV"; - - case MOD: - return "MOD"; - - case NOT: - return "NOT"; - - case BITNOT: - return "BITNOT"; - - case POS: - return "POS"; - - case NEG: - return "NEG"; - - case NEW: - return "NEW"; - - case DELPROP: - return "DELPROP"; - - case TYPEOF: - return "TYPEOF"; - - case GETPROP: - return "GETPROP"; - - case SETPROP: - return "SETPROP"; - - case GETELEM: - return "GETELEM"; - - case SETELEM: - return "SETELEM"; - - case CALL: - return "CALL"; - - case NAME: - return "NAME"; - - case NUMBER: - return "NUMBER"; - - case STRING: - return "STRING"; - - case NULL: - return "NULL"; - - case THIS: - return "THIS"; - - case FALSE: - return "FALSE"; - - case TRUE: - return "TRUE"; - - case SHEQ: - return "SHEQ"; - - case SHNE: - return "SHNE"; - - case REGEXP: - return "OBJECT"; - - case BINDNAME: - return "BINDNAME"; - - case THROW: - return "THROW"; - - case RETHROW: - return "RETHROW"; - - case IN: - return "IN"; - - case INSTANCEOF: - return "INSTANCEOF"; - - case LOCAL_LOAD: - return "LOCAL_LOAD"; - - case GETVAR: - return "GETVAR"; - - case SETVAR: - return "SETVAR"; - - case CATCH_SCOPE: - return "CATCH_SCOPE"; - - case ENUM_INIT_KEYS: - return "ENUM_INIT_KEYS"; - - case ENUM_INIT_VALUES: - return "ENUM_INIT_VALUES"; - - case ENUM_NEXT: - return "ENUM_NEXT"; - - case ENUM_ID: - return "ENUM_ID"; - - case THISFN: - return "THISFN"; - - case RETURN_RESULT: - return "RETURN_RESULT"; - - case ARRAYLIT: - return "ARRAYLIT"; - - case OBJECTLIT: - return "OBJECTLIT"; - - case GET_REF: - return "GET_REF"; - - case SET_REF: - return "SET_REF"; - - case DEL_REF: - return "DEL_REF"; - - case REF_CALL: - return "REF_CALL"; - - case REF_SPECIAL: - return "REF_SPECIAL"; - - case DEFAULTNAMESPACE: - return "DEFAULTNAMESPACE"; - - case ESCXMLTEXT: - return "ESCXMLTEXT"; - - case ESCXMLATTR: - return "ESCXMLATTR"; - - case REF_MEMBER: - return "REF_MEMBER"; - - case REF_NS_MEMBER: - return "REF_NS_MEMBER"; - - case REF_NAME: - return "REF_NAME"; - - case REF_NS_NAME: - return "REF_NS_NAME"; - - case TRY: - return "TRY"; - - case SEMI: - return "SEMI"; - - case LB: - return "LB"; - - case RB: - return "RB"; - - case LC: - return "LC"; - - case RC: - return "RC"; - - case LP: - return "LP"; - - case RP: - return "RP"; - - case COMMA: - return "COMMA"; - - case ASSIGN: - return "ASSIGN"; - - case ASSIGN_BITOR: - return "ASSIGN_BITOR"; - - case ASSIGN_BITXOR: - return "ASSIGN_BITXOR"; - - case ASSIGN_BITAND: - return "ASSIGN_BITAND"; - - case ASSIGN_LSH: - return "ASSIGN_LSH"; - - case ASSIGN_RSH: - return "ASSIGN_RSH"; - - case ASSIGN_URSH: - return "ASSIGN_URSH"; - - case ASSIGN_ADD: - return "ASSIGN_ADD"; - - case ASSIGN_SUB: - return "ASSIGN_SUB"; - - case ASSIGN_MUL: - return "ASSIGN_MUL"; - - case ASSIGN_DIV: - return "ASSIGN_DIV"; - - case ASSIGN_MOD: - return "ASSIGN_MOD"; - - case HOOK: - return "HOOK"; - - case COLON: - return "COLON"; - - case OR: - return "OR"; - - case AND: - return "AND"; - - case INC: - return "INC"; - - case DEC: - return "DEC"; - - case DOT: - return "DOT"; - - case FUNCTION: - return "FUNCTION"; - - case EXPORT: - return "EXPORT"; - - case IMPORT: - return "IMPORT"; - - case IF: - return "IF"; - - case ELSE: - return "ELSE"; - - case SWITCH: - return "SWITCH"; - - case CASE: - return "CASE"; - - case DEFAULT: - return "DEFAULT"; - - case WHILE: - return "WHILE"; - - case DO: - return "DO"; - - case FOR: - return "FOR"; - - case BREAK: - return "BREAK"; - - case CONTINUE: - return "CONTINUE"; - - case VAR: - return "VAR"; - - case WITH: - return "WITH"; - - case CATCH: - return "CATCH"; - - case FINALLY: - return "FINALLY"; - - case RESERVED: - return "RESERVED"; - - case EMPTY: - return "EMPTY"; - - case BLOCK: - return "BLOCK"; - - case LABEL: - return "LABEL"; - - case TARGET: - return "TARGET"; - - case LOOP: - return "LOOP"; - - case EXPR_VOID: - return "EXPR_VOID"; - - case EXPR_RESULT: - return "EXPR_RESULT"; - - case JSR: - return "JSR"; - - case SCRIPT: - return "SCRIPT"; - - case TYPEOFNAME: - return "TYPEOFNAME"; - - case USE_STACK: - return "USE_STACK"; - - case SETPROP_OP: - return "SETPROP_OP"; - - case SETELEM_OP: - return "SETELEM_OP"; - - case LOCAL_BLOCK: - return "LOCAL_BLOCK"; - - case SET_REF_OP: - return "SET_REF_OP"; - - case DOTDOT: - return "DOTDOT"; - - case COLONCOLON: - return "COLONCOLON"; - - case XML: - return "XML"; - - case DOTQUERY: - return "DOTQUERY"; - - case XMLATTR: - return "XMLATTR"; - - case XMLEND: - return "XMLEND"; - - case TO_OBJECT: return "TO_OBJECT"; - case TO_DOUBLE: return "TO_DOUBLE"; - case GET: return "GET"; - case SET: return "SET"; - case CONST: return "CONST"; - case SETCONST: return "SETCONST"; - case SETCONSTVAR: return "SETCONSTVAR"; - case CONDCOMMENT: return "CONDCOMMENT"; - case KEEPCOMMENT: return "KEEPCOMMENT"; - case DEBUGGER: return "DEBUGGER"; - default: return "UNKNOWN Token Type"; - } - - // Token without name - throw new ApplicationException ("Unknown token: " + Convert.ToString (token)); - } - } +//------------------------------------------------------------------------------ +// +// +// The use and distribution terms for this software are contained in the file +// named 'LICENSE', which can be found in the resources directory of this +// distribution. +// +// By using this software in any fashion, you are agreeing to be bound by the +// terms of this license. +// +// +//------------------------------------------------------------------------------ + +using System; + +namespace EcmaScript.NET +{ + + /// This class implements the JavaScript scanner. + /// + /// It is based on the C source files jsscan.c and jsscan.h + /// in the jsref package. + /// + /// + public class Token + { + + // debug flags + internal static readonly bool printTrees = false; // TODO: make me a preprocessor directive + + internal static readonly bool printICode = false; // TODO: make me a preprocessor directive + + internal static readonly bool printNames = printTrees || printICode; + + /// + /// Token types. + /// + /// These values correspond to JSTokenType values in + /// jsscan.c. + /// + public const int ERROR = -1; /* well-known as the only code < EOF */ + public const int EOF = 0; /* end of file */ + public const int EOL = 1; /* end of line */ + public const int FIRST_BYTECODE_TOKEN = 2; + public const int ENTERWITH = 2; + public const int LEAVEWITH = 3; + public const int RETURN = 4; + public const int GOTO = 5; + public const int IFEQ = 6; + public const int IFNE = 7; + public const int SETNAME = 8; + public const int BITOR = 9; + public const int BITXOR = 10; + public const int BITAND = 11; + public const int EQ = 12; + public const int NE = 13; + public const int LT = 14; + public const int LE = 15; + public const int GT = 16; + public const int GE = 17; + public const int LSH = 18; + public const int RSH = 19; + public const int URSH = 20; + public const int ADD = 21; + public const int SUB = 22; + public const int MUL = 23; + public const int DIV = 24; + public const int MOD = 25; + public const int NOT = 26; + public const int BITNOT = 27; + public const int POS = 28; + public const int NEG = 29; + public const int NEW = 30; + public const int DELPROP = 31; + public const int TYPEOF = 32; + public const int GETPROP = 33; + public const int SETPROP = 34; + public const int GETELEM = 35; + public const int SETELEM = 36; + public const int CALL = 37; + public const int NAME = 38; + public const int NUMBER = 39; + public const int STRING = 40; + public const int NULL = 41; + public const int THIS = 42; + public const int FALSE = 43; + public const int TRUE = 44; + public const int SHEQ = 45; + public const int SHNE = 46; + public const int REGEXP = 47; + public const int BINDNAME = 48; + public const int THROW = 49; + public const int RETHROW = 50; + public const int IN = 51; + public const int INSTANCEOF = 52; + public const int LOCAL_LOAD = 53; + public const int GETVAR = 54; + public const int SETVAR = 55; + public const int CATCH_SCOPE = 56; + public const int ENUM_INIT_KEYS = 57; + public const int ENUM_INIT_VALUES = 58; + public const int ENUM_NEXT = 59; + public const int ENUM_ID = 60; + public const int THISFN = 61; + public const int RETURN_RESULT = 62; + public const int ARRAYLIT = 63; + public const int OBJECTLIT = 64; + public const int GET_REF = 65; + public const int SET_REF = 66; + public const int DEL_REF = 67; + public const int REF_CALL = 68; + public const int REF_SPECIAL = 69; + public const int DEFAULTNAMESPACE = 70; + public const int ESCXMLATTR = 71; + public const int ESCXMLTEXT = 72; + public const int REF_MEMBER = 73; + public const int REF_NS_MEMBER = 74; + public const int REF_NAME = 75; + public const int REF_NS_NAME = 76; // Reference for ns::y, @ns::y@[y] etc. + public const int SETPROP_GETTER = 77; + public const int SETPROP_SETTER = 78; + + // End of interpreter bytecodes + public const int LAST_BYTECODE_TOKEN = SETPROP_SETTER; + + public const int TRY = LAST_BYTECODE_TOKEN + 1; + public const int SEMI = LAST_BYTECODE_TOKEN + 2; + public const int LB = LAST_BYTECODE_TOKEN + 3; + public const int RB = LAST_BYTECODE_TOKEN + 4; + public const int LC = LAST_BYTECODE_TOKEN + 5; + public const int RC = LAST_BYTECODE_TOKEN + 6; + public const int LP = LAST_BYTECODE_TOKEN + 7; + public const int RP = LAST_BYTECODE_TOKEN + 8; + public const int COMMA = LAST_BYTECODE_TOKEN + 9; + public const int ASSIGN = LAST_BYTECODE_TOKEN + 10; + public const int ASSIGN_BITOR = LAST_BYTECODE_TOKEN + 11; + public const int ASSIGN_BITXOR = LAST_BYTECODE_TOKEN + 12; + public const int ASSIGN_BITAND = LAST_BYTECODE_TOKEN + 13; + public const int ASSIGN_LSH = LAST_BYTECODE_TOKEN + 14; + public const int ASSIGN_RSH = LAST_BYTECODE_TOKEN + 15; + public const int ASSIGN_URSH = LAST_BYTECODE_TOKEN + 16; + public const int ASSIGN_ADD = LAST_BYTECODE_TOKEN + 17; + public const int ASSIGN_SUB = LAST_BYTECODE_TOKEN + 18; + public const int ASSIGN_MUL = LAST_BYTECODE_TOKEN + 19; + public const int ASSIGN_DIV = LAST_BYTECODE_TOKEN + 20; + public const int ASSIGN_MOD = LAST_BYTECODE_TOKEN + 21; // %= + + public const int FIRST_ASSIGN = ASSIGN; + public const int LAST_ASSIGN = ASSIGN_MOD; + + public const int HOOK = LAST_BYTECODE_TOKEN + 22; + public const int COLON = LAST_BYTECODE_TOKEN + 23; + public const int OR = LAST_BYTECODE_TOKEN + 24; + public const int AND = LAST_BYTECODE_TOKEN + 25; + public const int INC = LAST_BYTECODE_TOKEN + 26; + public const int DEC = LAST_BYTECODE_TOKEN + 27; + public const int DOT = LAST_BYTECODE_TOKEN + 28; + public const int FUNCTION = LAST_BYTECODE_TOKEN + 29; + public const int EXPORT = LAST_BYTECODE_TOKEN + 30; + public const int IMPORT = LAST_BYTECODE_TOKEN + 31; + public const int IF = LAST_BYTECODE_TOKEN + 32; + public const int ELSE = LAST_BYTECODE_TOKEN + 33; + public const int SWITCH = LAST_BYTECODE_TOKEN + 34; + public const int CASE = LAST_BYTECODE_TOKEN + 35; + public const int DEFAULT = LAST_BYTECODE_TOKEN + 36; + public const int WHILE = LAST_BYTECODE_TOKEN + 37; + public const int DO = LAST_BYTECODE_TOKEN + 38; + public const int FOR = LAST_BYTECODE_TOKEN + 39; + public const int BREAK = LAST_BYTECODE_TOKEN + 40; + public const int CONTINUE = LAST_BYTECODE_TOKEN + 41; + public const int VAR = LAST_BYTECODE_TOKEN + 42; + public const int WITH = LAST_BYTECODE_TOKEN + 43; + public const int CATCH = LAST_BYTECODE_TOKEN + 44; + public const int FINALLY = LAST_BYTECODE_TOKEN + 45; + public const int VOID = LAST_BYTECODE_TOKEN + 46; + public const int RESERVED = LAST_BYTECODE_TOKEN + 47; + public const int EMPTY = LAST_BYTECODE_TOKEN + 48; + public const int BLOCK = LAST_BYTECODE_TOKEN + 49; + public const int LABEL = LAST_BYTECODE_TOKEN + 50; + public const int TARGET = LAST_BYTECODE_TOKEN + 51; + public const int LOOP = LAST_BYTECODE_TOKEN + 52; + public const int EXPR_VOID = LAST_BYTECODE_TOKEN + 53; + public const int EXPR_RESULT = LAST_BYTECODE_TOKEN + 54; + public const int JSR = LAST_BYTECODE_TOKEN + 55; + public const int SCRIPT = LAST_BYTECODE_TOKEN + 56; + public const int TYPEOFNAME = LAST_BYTECODE_TOKEN + 57; + public const int USE_STACK = LAST_BYTECODE_TOKEN + 58; + public const int SETPROP_OP = LAST_BYTECODE_TOKEN + 59; + public const int SETELEM_OP = LAST_BYTECODE_TOKEN + 60; + public const int LOCAL_BLOCK = LAST_BYTECODE_TOKEN + 61; + public const int SET_REF_OP = LAST_BYTECODE_TOKEN + 62; + public const int DOTDOT = LAST_BYTECODE_TOKEN + 63; + public const int COLONCOLON = LAST_BYTECODE_TOKEN + 64; + public const int XML = LAST_BYTECODE_TOKEN + 65; + public const int DOTQUERY = LAST_BYTECODE_TOKEN + 66; + public const int XMLATTR = LAST_BYTECODE_TOKEN + 67; + public const int XMLEND = LAST_BYTECODE_TOKEN + 68; + public const int TO_OBJECT = LAST_BYTECODE_TOKEN + 69; + public const int TO_DOUBLE = LAST_BYTECODE_TOKEN + 70; + + public const int GET = LAST_BYTECODE_TOKEN + 71; // JS 1.5 get pseudo keyword + public const int SET = LAST_BYTECODE_TOKEN + 72; // JS 1.5 set pseudo keyword + public const int CONST = LAST_BYTECODE_TOKEN + 73; + public const int SETCONST = LAST_BYTECODE_TOKEN + 74; + public const int SETCONSTVAR = LAST_BYTECODE_TOKEN + 75; + public const int CONDCOMMENT = LAST_BYTECODE_TOKEN + 76; // JScript conditional comment + public const int KEEPCOMMENT = LAST_BYTECODE_TOKEN + 77; // /*! ... */ comment + public const int DEBUGGER = LAST_BYTECODE_TOKEN + 78; + + public const int LAST_TOKEN = LAST_BYTECODE_TOKEN + 79; + + public static string name (int token) + { + //if (!printNames) { + // return Convert.ToString (token); + //} + switch (token) { + + case ERROR: + return "ERROR"; + case EOF: + return "EOF"; + case EOL: + return "EOL"; + + case ENTERWITH: + return "ENTERWITH"; + + case LEAVEWITH: + return "LEAVEWITH"; + + case RETURN: + return "RETURN"; + + case GOTO: + return "GOTO"; + + case IFEQ: + return "IFEQ"; + + case IFNE: + return "IFNE"; + + case SETNAME: + return "SETNAME"; + + case BITOR: + return "BITOR"; + + case BITXOR: + return "BITXOR"; + + case BITAND: + return "BITAND"; + + case EQ: + return "EQ"; + + case NE: + return "NE"; + + case LT: + return "LT"; + + case LE: + return "LE"; + + case GT: + return "GT"; + + case GE: + return "GE"; + + case LSH: + return "LSH"; + + case RSH: + return "RSH"; + + case URSH: + return "URSH"; + + case ADD: + return "ADD"; + + case SUB: + return "SUB"; + + case MUL: + return "MUL"; + + case DIV: + return "DIV"; + + case MOD: + return "MOD"; + + case NOT: + return "NOT"; + + case BITNOT: + return "BITNOT"; + + case POS: + return "POS"; + + case NEG: + return "NEG"; + + case NEW: + return "NEW"; + + case DELPROP: + return "DELPROP"; + + case TYPEOF: + return "TYPEOF"; + + case GETPROP: + return "GETPROP"; + + case SETPROP: + return "SETPROP"; + + case GETELEM: + return "GETELEM"; + + case SETELEM: + return "SETELEM"; + + case CALL: + return "CALL"; + + case NAME: + return "NAME"; + + case NUMBER: + return "NUMBER"; + + case STRING: + return "STRING"; + + case NULL: + return "NULL"; + + case THIS: + return "THIS"; + + case FALSE: + return "FALSE"; + + case TRUE: + return "TRUE"; + + case SHEQ: + return "SHEQ"; + + case SHNE: + return "SHNE"; + + case REGEXP: + return "OBJECT"; + + case BINDNAME: + return "BINDNAME"; + + case THROW: + return "THROW"; + + case RETHROW: + return "RETHROW"; + + case IN: + return "IN"; + + case INSTANCEOF: + return "INSTANCEOF"; + + case LOCAL_LOAD: + return "LOCAL_LOAD"; + + case GETVAR: + return "GETVAR"; + + case SETVAR: + return "SETVAR"; + + case CATCH_SCOPE: + return "CATCH_SCOPE"; + + case ENUM_INIT_KEYS: + return "ENUM_INIT_KEYS"; + + case ENUM_INIT_VALUES: + return "ENUM_INIT_VALUES"; + + case ENUM_NEXT: + return "ENUM_NEXT"; + + case ENUM_ID: + return "ENUM_ID"; + + case THISFN: + return "THISFN"; + + case RETURN_RESULT: + return "RETURN_RESULT"; + + case ARRAYLIT: + return "ARRAYLIT"; + + case OBJECTLIT: + return "OBJECTLIT"; + + case GET_REF: + return "GET_REF"; + + case SET_REF: + return "SET_REF"; + + case DEL_REF: + return "DEL_REF"; + + case REF_CALL: + return "REF_CALL"; + + case REF_SPECIAL: + return "REF_SPECIAL"; + + case DEFAULTNAMESPACE: + return "DEFAULTNAMESPACE"; + + case ESCXMLTEXT: + return "ESCXMLTEXT"; + + case ESCXMLATTR: + return "ESCXMLATTR"; + + case REF_MEMBER: + return "REF_MEMBER"; + + case REF_NS_MEMBER: + return "REF_NS_MEMBER"; + + case REF_NAME: + return "REF_NAME"; + + case REF_NS_NAME: + return "REF_NS_NAME"; + + case TRY: + return "TRY"; + + case SEMI: + return "SEMI"; + + case LB: + return "LB"; + + case RB: + return "RB"; + + case LC: + return "LC"; + + case RC: + return "RC"; + + case LP: + return "LP"; + + case RP: + return "RP"; + + case COMMA: + return "COMMA"; + + case ASSIGN: + return "ASSIGN"; + + case ASSIGN_BITOR: + return "ASSIGN_BITOR"; + + case ASSIGN_BITXOR: + return "ASSIGN_BITXOR"; + + case ASSIGN_BITAND: + return "ASSIGN_BITAND"; + + case ASSIGN_LSH: + return "ASSIGN_LSH"; + + case ASSIGN_RSH: + return "ASSIGN_RSH"; + + case ASSIGN_URSH: + return "ASSIGN_URSH"; + + case ASSIGN_ADD: + return "ASSIGN_ADD"; + + case ASSIGN_SUB: + return "ASSIGN_SUB"; + + case ASSIGN_MUL: + return "ASSIGN_MUL"; + + case ASSIGN_DIV: + return "ASSIGN_DIV"; + + case ASSIGN_MOD: + return "ASSIGN_MOD"; + + case HOOK: + return "HOOK"; + + case COLON: + return "COLON"; + + case OR: + return "OR"; + + case AND: + return "AND"; + + case INC: + return "INC"; + + case DEC: + return "DEC"; + + case DOT: + return "DOT"; + + case FUNCTION: + return "FUNCTION"; + + case EXPORT: + return "EXPORT"; + + case IMPORT: + return "IMPORT"; + + case IF: + return "IF"; + + case ELSE: + return "ELSE"; + + case SWITCH: + return "SWITCH"; + + case CASE: + return "CASE"; + + case DEFAULT: + return "DEFAULT"; + + case WHILE: + return "WHILE"; + + case DO: + return "DO"; + + case FOR: + return "FOR"; + + case BREAK: + return "BREAK"; + + case CONTINUE: + return "CONTINUE"; + + case VAR: + return "VAR"; + + case WITH: + return "WITH"; + + case CATCH: + return "CATCH"; + + case FINALLY: + return "FINALLY"; + + case RESERVED: + return "RESERVED"; + + case EMPTY: + return "EMPTY"; + + case BLOCK: + return "BLOCK"; + + case LABEL: + return "LABEL"; + + case TARGET: + return "TARGET"; + + case LOOP: + return "LOOP"; + + case EXPR_VOID: + return "EXPR_VOID"; + + case EXPR_RESULT: + return "EXPR_RESULT"; + + case JSR: + return "JSR"; + + case SCRIPT: + return "SCRIPT"; + + case TYPEOFNAME: + return "TYPEOFNAME"; + + case USE_STACK: + return "USE_STACK"; + + case SETPROP_OP: + return "SETPROP_OP"; + + case SETELEM_OP: + return "SETELEM_OP"; + + case LOCAL_BLOCK: + return "LOCAL_BLOCK"; + + case SET_REF_OP: + return "SET_REF_OP"; + + case DOTDOT: + return "DOTDOT"; + + case COLONCOLON: + return "COLONCOLON"; + + case XML: + return "XML"; + + case DOTQUERY: + return "DOTQUERY"; + + case XMLATTR: + return "XMLATTR"; + + case XMLEND: + return "XMLEND"; + + case TO_OBJECT: return "TO_OBJECT"; + case TO_DOUBLE: return "TO_DOUBLE"; + case GET: return "GET"; + case SET: return "SET"; + case CONST: return "CONST"; + case SETCONST: return "SETCONST"; + case SETCONSTVAR: return "SETCONSTVAR"; + case CONDCOMMENT: return "CONDCOMMENT"; + case KEEPCOMMENT: return "KEEPCOMMENT"; + case DEBUGGER: return "DEBUGGER"; + default: return "UNKNOWN Token Type"; + } + + // Token without name + throw new Exception ("Unknown token: " + Convert.ToString (token)); + } + } } \ No newline at end of file diff --git a/Code/EcmaScript.NET/TokenStream.cs b/src/EcmaScript.NET/TokenStream.cs similarity index 97% rename from Code/EcmaScript.NET/TokenStream.cs rename to src/EcmaScript.NET/TokenStream.cs index a61694b..a51c9ac 100644 --- a/Code/EcmaScript.NET/TokenStream.cs +++ b/src/EcmaScript.NET/TokenStream.cs @@ -1,1909 +1,1909 @@ -//------------------------------------------------------------------------------ -// -// -// The use and distribution terms for this software are contained in the file -// named 'LICENSE', which can be found in the resources directory of this -// distribution. -// -// By using this software in any fashion, you are agreeing to be bound by the -// terms of this license. -// -// -//------------------------------------------------------------------------------ - -using System; -using System.Text; -using System.Globalization; - -using EcmaScript.NET.Types; -using EcmaScript.NET.Collections; - -namespace EcmaScript.NET -{ - - /// This class implements the JavaScript scanner. - /// - /// It is based on the C source files jsscan.c and jsscan.h - /// in the jsref package. - /// - /// - internal class TokenStream - { - internal int Lineno - { - get - { - return lineno; - } - - } - internal string String - { - get - { - return str; - } - - } - internal double Number - { - get - { - return dNumber; - } - - } - internal int Token - { - get - { - int c; - - - for (; ; ) - { - // Eat whitespace, possibly sensitive to newlines. - for (; ; ) - { - c = Char; - if (c == EOF_CHAR) - { - return EcmaScript.NET.Token.EOF; - } - else if (c == '\n') - { - dirtyLine = false; - return EcmaScript.NET.Token.EOL; - } - else if (!isJSSpace(c)) - { - if (c != '-') - { - dirtyLine = true; - } - break; - } - } - - if (c == '@') - return EcmaScript.NET.Token.XMLATTR; - - // identifier/keyword/instanceof? - // watch out for starting with a - bool identifierStart; - bool isUnicodeEscapeStart = false; - if (c == '\\') - { - c = Char; - if (c == 'u') - { - identifierStart = true; - isUnicodeEscapeStart = true; - stringBufferTop = 0; - } - else - { - identifierStart = false; - ungetChar(c); - c = '\\'; - } - } - else - { - char ch = (char)c; - identifierStart = char.IsLetter(ch) - || ch == '$' - || ch == '_'; - if (identifierStart) - { - stringBufferTop = 0; - addToString(c); - } - } - - if (identifierStart) - { - bool containsEscape = isUnicodeEscapeStart; - for (; ; ) - { - if (isUnicodeEscapeStart) - { - // strictly speaking we should probably push-back - // all the bad characters if the u - // sequence is malformed. But since there isn't a - // correct context(is there?) for a bad Unicode - // escape sequence in an identifier, we can report - // an error here. - int escapeVal = 0; - for (int i = 0; i != 4; ++i) - { - c = Char; - escapeVal = ScriptConvert.XDigitToInt(c, escapeVal); - // Next check takes care about c < 0 and bad escape - if (escapeVal < 0) - { - break; - } - } - if (escapeVal < 0) - { - parser.AddError("msg.invalid.escape"); - return EcmaScript.NET.Token.ERROR; - } - addToString(escapeVal); - isUnicodeEscapeStart = false; - } - else - { - c = Char; - if (c == '\\') - { - c = Char; - if (c == 'u') - { - isUnicodeEscapeStart = true; - containsEscape = true; - } - else - { - parser.AddError("msg.illegal.character"); - return EcmaScript.NET.Token.ERROR; - } - } - else - { - if (c == EOF_CHAR || !IsJavaIdentifierPart((char)c)) - { - break; - } - addToString(c); - } - } - } - ungetChar(c); - - string str = StringFromBuffer; - if (!containsEscape) - { - // OPT we shouldn't have to make a string (object!) to - // check if it's a keyword. - - // Return the corresponding token if it's a keyword - int result = stringToKeyword(str); - if (result != EcmaScript.NET.Token.EOF) - { - if (result != EcmaScript.NET.Token.RESERVED) - { - return result; - } - else if (!parser.compilerEnv.isReservedKeywordAsIdentifier()) - { - return result; - } - else - { - // If implementation permits to use future reserved - // keywords in violation with the EcmaScript, - // treat it as name but issue warning - parser.AddWarning("msg.reserved.keyword", str); - } - } - } - this.str = ((string)allStrings.intern(str)); - return EcmaScript.NET.Token.NAME; - } - - // is it a number? - if (isDigit(c) || (c == '.' && isDigit(peekChar()))) - { - - stringBufferTop = 0; - int toBase = 10; - - if (c == '0') - { - c = Char; - if (c == 'x' || c == 'X') - { - toBase = 16; - c = Char; - } - else if (isDigit(c)) - { - toBase = 8; - } - else - { - addToString('0'); - } - } - - if (toBase == 16) - { - while (0 <= ScriptConvert.XDigitToInt(c, 0)) - { - addToString(c); - c = Char; - } - } - else - { - while ('0' <= c && c <= '9') - { - /* - * We permit 08 and 09 as decimal numbers, which - * makes our behavior a superset of the ECMA - * numeric grammar. We might not always be so - * permissive, so we warn about it. - */ - if (toBase == 8 && c >= '8') - { - parser.AddWarning("msg.bad.octal.literal", c == '8' ? "8" : "9"); - toBase = 10; - } - addToString(c); - c = Char; - } - } - - bool isInteger = true; - - if (toBase == 10 && (c == '.' || c == 'e' || c == 'E')) - { - isInteger = false; - if (c == '.') - { - do - { - addToString(c); - c = Char; - } - while (isDigit(c)); - } - if (c == 'e' || c == 'E') - { - addToString(c); - c = Char; - if (c == '+' || c == '-') - { - addToString(c); - c = Char; - } - if (!isDigit(c)) - { - parser.AddError("msg.missing.exponent"); - return EcmaScript.NET.Token.ERROR; - } - do - { - addToString(c); - c = Char; - } - while (isDigit(c)); - } - } - ungetChar(c); - string numString = StringFromBuffer; - - double dval; - if (toBase == 10 && !isInteger) - { - try - { - // Use Java conversion to number from string... - dval = System.Double.Parse(numString, BuiltinNumber.NumberFormatter); - } - catch (OverflowException) - { - // HACK - if (numString[0] == '-') - dval = double.NegativeInfinity; - else - dval = double.PositiveInfinity; - } - catch (Exception) - { - parser.AddError("msg.caught.nfe"); - return EcmaScript.NET.Token.ERROR; - } - } - else - { - dval = ScriptConvert.ToNumber(numString, 0, toBase); - } - - this.dNumber = dval; - return EcmaScript.NET.Token.NUMBER; - } - - // is it a string? - if (c == '"' || c == '\'') - { - // We attempt to accumulate a string the fast way, by - // building it directly out of the reader. But if there - // are any escaped characters in the string, we revert to - // building it out of a StringBuffer. - - int quoteChar = c; - stringBufferTop = 0; - - c = Char; - - while (c != quoteChar) - { - if (c == '\n' || c == EOF_CHAR) - { - ungetChar(c); - parser.AddError("msg.unterminated.string.lit"); - return EcmaScript.NET.Token.ERROR; - } - - if (c == '\\') - { - // We've hit an escaped character - - c = Char; - switch (c) - { - - case '\\': // backslash - case 'b': // backspace - case 'f': // form feed - case 'n': // line feed - case 'r': // carriage return - case 't': // horizontal tab - case 'v': // vertical tab - case 'd': // octal sequence - case 'u': // unicode sequence - case 'x': // hexadecimal sequence - // Only keep the '\' character for those - // characters that need to be escaped... - // Don't escape quoting characters... - addToString('\\'); - addToString(c); - break; - - case '\n': - // Remove line terminator after escape - break; - - - default: - if (isDigit(c)) - { - // Octal representation of a character. - // Preserve the escaping (see Y! bug #1637286) - addToString('\\'); - } - addToString(c); - break; - break; - - } - } - else - { - addToString(c); - } - - c = Char; - } - - string str = StringFromBuffer; - this.str = ((string)allStrings.intern(str)); - return EcmaScript.NET.Token.STRING; - } - - switch (c) - { - - case ';': - return EcmaScript.NET.Token.SEMI; - - case '[': - return EcmaScript.NET.Token.LB; - - case ']': - return EcmaScript.NET.Token.RB; - - case '{': - return EcmaScript.NET.Token.LC; - - case '}': - return EcmaScript.NET.Token.RC; - - case '(': - return EcmaScript.NET.Token.LP; - - case ')': - return EcmaScript.NET.Token.RP; - - case ',': - return EcmaScript.NET.Token.COMMA; - - case '?': - return EcmaScript.NET.Token.HOOK; - - case ':': - if (matchChar(':')) - { - return EcmaScript.NET.Token.COLONCOLON; - } - else - { - return EcmaScript.NET.Token.COLON; - } - - case '.': - if (matchChar('.')) - { - return EcmaScript.NET.Token.DOTDOT; - } - else if (matchChar('(')) - { - return EcmaScript.NET.Token.DOTQUERY; - } - else - { - return EcmaScript.NET.Token.DOT; - } - - case '|': - if (matchChar('|')) - { - return EcmaScript.NET.Token.OR; - } - else if (matchChar('=')) - { - return EcmaScript.NET.Token.ASSIGN_BITOR; - } - else - { - return EcmaScript.NET.Token.BITOR; - } - - - case '^': - if (matchChar('=')) - { - return EcmaScript.NET.Token.ASSIGN_BITXOR; - } - else - { - return EcmaScript.NET.Token.BITXOR; - } - - - case '&': - if (matchChar('&')) - { - return EcmaScript.NET.Token.AND; - } - else if (matchChar('=')) - { - return EcmaScript.NET.Token.ASSIGN_BITAND; - } - else - { - return EcmaScript.NET.Token.BITAND; - } - - - case '=': - if (matchChar('=')) - { - if (matchChar('=')) - return EcmaScript.NET.Token.SHEQ; - else - return EcmaScript.NET.Token.EQ; - } - else - { - return EcmaScript.NET.Token.ASSIGN; - } - - - case '!': - if (matchChar('=')) - { - if (matchChar('=')) - return EcmaScript.NET.Token.SHNE; - else - return EcmaScript.NET.Token.NE; - } - else - { - return EcmaScript.NET.Token.NOT; - } - - - case '<': - /* NB:treat HTML begin-comment as comment-till-eol */ - if (matchChar('!')) - { - if (matchChar('-')) - { - if (matchChar('-')) - { - skipLine(); - - goto retry; - } - ungetChar('-'); - } - ungetChar('!'); - } - if (matchChar('<')) - { - if (matchChar('=')) - { - return EcmaScript.NET.Token.ASSIGN_LSH; - } - else - { - return EcmaScript.NET.Token.LSH; - } - } - else - { - if (matchChar('=')) - { - return EcmaScript.NET.Token.LE; - } - else - { - return EcmaScript.NET.Token.LT; - } - } - - - case '>': - if (matchChar('>')) - { - if (matchChar('>')) - { - if (matchChar('=')) - { - return EcmaScript.NET.Token.ASSIGN_URSH; - } - else - { - return EcmaScript.NET.Token.URSH; - } - } - else - { - if (matchChar('=')) - { - return EcmaScript.NET.Token.ASSIGN_RSH; - } - else - { - return EcmaScript.NET.Token.RSH; - } - } - } - else - { - if (matchChar('=')) - { - return EcmaScript.NET.Token.GE; - } - else - { - return EcmaScript.NET.Token.GT; - } - } - - - case '*': - if (matchChar('=')) - { - return EcmaScript.NET.Token.ASSIGN_MUL; - } - else - { - return EcmaScript.NET.Token.MUL; - } - - - case '/': - // is it a // comment? - if (matchChar('/')) - { - skipLine(); - - goto retry; - } - if (matchChar('*')) - { - bool lookForSlash = false; - StringBuilder sb = new StringBuilder(); - for (; ; ) - { - c = Char; - if (c == EOF_CHAR) - { - parser.AddError("msg.unterminated.comment"); - return EcmaScript.NET.Token.ERROR; - } - sb.Append((char)c); - if (c == '*') - { - lookForSlash = true; - } - else if (c == '/') - { - if (lookForSlash) - { - sb.Remove(sb.Length - 2, 2); - string s1 = sb.ToString(); - string s2 = s1.Trim(); - if (s1.StartsWith("!")) - { - // Remove the leading '!' - this.str = s1.Substring(1); - return NET.Token.KEEPCOMMENT; - } - else if (s2.StartsWith("@cc_on") || - s2.StartsWith("@if") || - s2.StartsWith("@elif") || - s2.StartsWith("@else") || - s2.StartsWith("@end")) - { - this.str = s1; - return NET.Token.CONDCOMMENT; - } - else - { - goto retry; - } - } - } - else - { - lookForSlash = false; - } - } - } - - if (matchChar('=')) - { - return EcmaScript.NET.Token.ASSIGN_DIV; - } - else - { - return EcmaScript.NET.Token.DIV; - } - - - case '%': - if (matchChar('=')) - { - return EcmaScript.NET.Token.ASSIGN_MOD; - } - else - { - return EcmaScript.NET.Token.MOD; - } - - - case '~': - return EcmaScript.NET.Token.BITNOT; - - - case '+': - if (matchChar('=')) - { - return EcmaScript.NET.Token.ASSIGN_ADD; - } - else if (matchChar('+')) - { - return EcmaScript.NET.Token.INC; - } - else - { - return EcmaScript.NET.Token.ADD; - } - - - case '-': - if (matchChar('=')) - { - c = EcmaScript.NET.Token.ASSIGN_SUB; - } - else if (matchChar('-')) - { - if (!dirtyLine) - { - // treat HTML end-comment after possible whitespace - // after line start as comment-utill-eol - if (matchChar('>')) - { - skipLine(); - - goto retry; - } - } - c = EcmaScript.NET.Token.DEC; - } - else - { - c = EcmaScript.NET.Token.SUB; - } - dirtyLine = true; - return c; - - - default: - parser.AddError("msg.illegal.character"); - return EcmaScript.NET.Token.ERROR; - - } - - retry: - ; - } - } - - } - internal bool XMLAttribute - { - get - { - return xmlIsAttribute; - } - - } - internal int FirstXMLToken - { - get - { - xmlOpenTagsCount = 0; - xmlIsAttribute = false; - xmlIsTagContent = false; - ungetChar('<'); - return NextXMLToken; - } - - } - internal int NextXMLToken - { - get - { - stringBufferTop = 0; // remember the XML - - for (int c = Char; c != EOF_CHAR; c = Char) - { - if (xmlIsTagContent) - { - switch (c) - { - - case '>': - addToString(c); - xmlIsTagContent = false; - xmlIsAttribute = false; - break; - - case '/': - addToString(c); - if (peekChar() == '>') - { - c = Char; - addToString(c); - xmlIsTagContent = false; - xmlOpenTagsCount--; - } - break; - - case '{': - ungetChar(c); - this.str = StringFromBuffer; - return EcmaScript.NET.Token.XML; - - case '\'': - case '"': - addToString(c); - if (!readQuotedString(c)) - return EcmaScript.NET.Token.ERROR; - break; - - case '=': - addToString(c); - xmlIsAttribute = true; - break; - - case ' ': - case '\t': - case '\r': - case '\n': - addToString(c); - break; - - default: - addToString(c); - xmlIsAttribute = false; - break; - - } - - if (!xmlIsTagContent && xmlOpenTagsCount == 0) - { - this.str = StringFromBuffer; - return EcmaScript.NET.Token.XMLEND; - } - } - else - { - switch (c) - { - - case '<': - addToString(c); - c = peekChar(); - switch (c) - { - - case '!': - c = Char; // Skip ! - addToString(c); - c = peekChar(); - switch (c) - { - - case '-': - c = Char; // Skip - - addToString(c); - c = Char; - if (c == '-') - { - addToString(c); - if (!readXmlComment()) - return EcmaScript.NET.Token.ERROR; - } - else - { - // throw away the string in progress - stringBufferTop = 0; - this.str = null; - parser.AddError("msg.XML.bad.form"); - return EcmaScript.NET.Token.ERROR; - } - break; - - case '[': - c = Char; // Skip [ - addToString(c); - if (Char == 'C' && Char == 'D' && Char == 'A' && Char == 'T' && Char == 'A' && Char == '[') - { - addToString('C'); - addToString('D'); - addToString('A'); - addToString('T'); - addToString('A'); - addToString('['); - if (!readCDATA()) - return EcmaScript.NET.Token.ERROR; - } - else - { - // throw away the string in progress - stringBufferTop = 0; - this.str = null; - parser.AddError("msg.XML.bad.form"); - return EcmaScript.NET.Token.ERROR; - } - break; - - default: - if (!readEntity()) - return EcmaScript.NET.Token.ERROR; - break; - - } - break; - - case '?': - c = Char; // Skip ? - addToString(c); - if (!readPI()) - return EcmaScript.NET.Token.ERROR; - break; - - case '/': - // End tag - c = Char; // Skip / - addToString(c); - if (xmlOpenTagsCount == 0) - { - // throw away the string in progress - stringBufferTop = 0; - this.str = null; - parser.AddError("msg.XML.bad.form"); - return EcmaScript.NET.Token.ERROR; - } - xmlIsTagContent = true; - xmlOpenTagsCount--; - break; - - default: - // Start tag - xmlIsTagContent = true; - xmlOpenTagsCount++; - break; - - } - break; - - case '{': - ungetChar(c); - this.str = StringFromBuffer; - return EcmaScript.NET.Token.XML; - - default: - addToString(c); - break; - - } - } - } - - - stringBufferTop = 0; // throw away the string in progress - this.str = null; - parser.AddError("msg.XML.bad.form"); - return EcmaScript.NET.Token.ERROR; - } - - } - private string StringFromBuffer - { - get - { - return new string(stringBuffer, 0, stringBufferTop); - } - - } - private int Char - { - get - { - if (ungetCursor != 0) - { - return ungetBuffer[--ungetCursor]; - } - - for (; ; ) - { - int c; - if (sourceString != null) - { - if (sourceCursor == sourceEnd) - { - hitEOF = true; - return EOF_CHAR; - } - c = sourceString[sourceCursor++]; - } - else - { - if (sourceCursor == sourceEnd) - { - if (!fillSourceBuffer()) - { - hitEOF = true; - return EOF_CHAR; - } - } - c = sourceBuffer[sourceCursor++]; - } - - if (lineEndChar >= 0) - { - if (lineEndChar == '\r' && c == '\n') - { - lineEndChar = '\n'; - continue; - } - lineEndChar = -1; - lineStart = sourceCursor - 1; - lineno++; - } - - if (c <= 127) - { - if (c == '\n' || c == '\r') - { - lineEndChar = c; - c = '\n'; - } - } - else - { - if (isJSFormatChar(c)) - { - continue; - } - if (ScriptRuntime.isJSLineTerminator(c)) - { - lineEndChar = c; - c = '\n'; - } - } - return c; - } - } - - } - internal int Offset - { - get - { - int n = sourceCursor - lineStart; - if (lineEndChar >= 0) - { - --n; - } - return n; - } - - } - internal string Line - { - get - { - if (sourceString != null) - { - // String case - int lineEnd = sourceCursor; - if (lineEndChar >= 0) - { - --lineEnd; - } - else - { - for (; lineEnd != sourceEnd; ++lineEnd) - { - int c = sourceString[lineEnd]; - if (ScriptRuntime.isJSLineTerminator(c)) - { - break; - } - } - } - return sourceString.Substring(lineStart, (lineEnd) - (lineStart)); - } - else - { - // Reader case - int lineLength = sourceCursor - lineStart; - if (lineEndChar >= 0) - { - --lineLength; - } - else - { - // Read until the end of line - for (; ; ++lineLength) - { - int i = lineStart + lineLength; - if (i == sourceEnd) - { - try - { - if (!fillSourceBuffer()) - { - break; - } - } - catch (System.IO.IOException) - { - // ignore it, we're already displaying an error... - break; - } - // i recalculuation as fillSourceBuffer can move saved - // line buffer and change lineStart - i = lineStart + lineLength; - } - int c = sourceBuffer[i]; - if (ScriptRuntime.isJSLineTerminator(c)) - { - break; - } - } - } - return new string(sourceBuffer, lineStart, lineLength); - } - } - - } - /* - * For chars - because we need something out-of-range - * to check. (And checking EOF by exception is annoying.) - * Note distinction from EOF token type! - */ - private const int EOF_CHAR = -1; - - - internal TokenStream(Parser parser, System.IO.StreamReader sourceReader, string sourceString, int lineno) - { - this.parser = parser; - this.lineno = lineno; - if (sourceReader != null) - { - if (sourceString != null) - Context.CodeBug(); - this.sourceReader = sourceReader; - this.sourceBuffer = new char[512]; - this.sourceEnd = 0; - } - else - { - if (sourceString == null) - Context.CodeBug(); - this.sourceString = sourceString; - this.sourceEnd = sourceString.Length; - } - this.sourceCursor = 0; - } - - /* This function uses the cached op, string and number fields in - * TokenStream; if getToken has been called since the passed token - * was scanned, the op or string printed may be incorrect. - */ - internal string tokenToString(int token) - { - if (EcmaScript.NET.Token.printTrees) - { - string name = EcmaScript.NET.Token.name(token); - - switch (token) - { - - case EcmaScript.NET.Token.STRING: - case EcmaScript.NET.Token.REGEXP: - case EcmaScript.NET.Token.NAME: - return name + " `" + this.str + "'"; - - - case EcmaScript.NET.Token.NUMBER: - return "NUMBER " + this.dNumber; - } - - return name; - } - return ""; - } - - internal static bool isKeyword(string s) - { - return EcmaScript.NET.Token.EOF != stringToKeyword(s); - } - - #region Ids - private const int Id_break = EcmaScript.NET.Token.BREAK; - private const int Id_case = EcmaScript.NET.Token.CASE; - private const int Id_continue = EcmaScript.NET.Token.CONTINUE; - private const int Id_default = EcmaScript.NET.Token.DEFAULT; - private const int Id_delete = EcmaScript.NET.Token.DELPROP; - private const int Id_do = EcmaScript.NET.Token.DO; - private const int Id_else = EcmaScript.NET.Token.ELSE; - private const int Id_export = EcmaScript.NET.Token.EXPORT; - private const int Id_false = EcmaScript.NET.Token.FALSE; - private const int Id_for = EcmaScript.NET.Token.FOR; - private const int Id_function = EcmaScript.NET.Token.FUNCTION; - private const int Id_if = EcmaScript.NET.Token.IF; - private const int Id_in = EcmaScript.NET.Token.IN; - private const int Id_new = EcmaScript.NET.Token.NEW; - private const int Id_null = EcmaScript.NET.Token.NULL; - private const int Id_return = EcmaScript.NET.Token.RETURN; - private const int Id_switch = EcmaScript.NET.Token.SWITCH; - private const int Id_this = EcmaScript.NET.Token.THIS; - private const int Id_true = EcmaScript.NET.Token.TRUE; - private const int Id_typeof = EcmaScript.NET.Token.TYPEOF; - private const int Id_var = EcmaScript.NET.Token.VAR; - private const int Id_void = EcmaScript.NET.Token.VOID; - private const int Id_while = EcmaScript.NET.Token.WHILE; - private const int Id_with = EcmaScript.NET.Token.WITH; - private const int Id_abstract = EcmaScript.NET.Token.RESERVED; - private const int Id_boolean = EcmaScript.NET.Token.RESERVED; - private const int Id_byte = EcmaScript.NET.Token.RESERVED; - private const int Id_catch = EcmaScript.NET.Token.CATCH; - private const int Id_char = EcmaScript.NET.Token.RESERVED; - private const int Id_class = EcmaScript.NET.Token.RESERVED; - private const int Id_const = EcmaScript.NET.Token.RESERVED; - private const int Id_debugger = EcmaScript.NET.Token.DEBUGGER; - private const int Id_double = EcmaScript.NET.Token.RESERVED; - private const int Id_enum = EcmaScript.NET.Token.RESERVED; - private const int Id_extends = EcmaScript.NET.Token.RESERVED; - private const int Id_final = EcmaScript.NET.Token.RESERVED; - private const int Id_finally = EcmaScript.NET.Token.FINALLY; - private const int Id_float = EcmaScript.NET.Token.RESERVED; - private const int Id_goto = EcmaScript.NET.Token.RESERVED; - private const int Id_implements = EcmaScript.NET.Token.RESERVED; - private const int Id_import = EcmaScript.NET.Token.IMPORT; - private const int Id_instanceof = EcmaScript.NET.Token.INSTANCEOF; - private const int Id_int = EcmaScript.NET.Token.RESERVED; - private const int Id_interface = EcmaScript.NET.Token.RESERVED; - private const int Id_long = EcmaScript.NET.Token.RESERVED; - private const int Id_native = EcmaScript.NET.Token.RESERVED; - private const int Id_package = EcmaScript.NET.Token.RESERVED; - private const int Id_private = EcmaScript.NET.Token.RESERVED; - private const int Id_protected = EcmaScript.NET.Token.RESERVED; - private const int Id_public = EcmaScript.NET.Token.RESERVED; - private const int Id_short = EcmaScript.NET.Token.RESERVED; - private const int Id_static = EcmaScript.NET.Token.RESERVED; - private const int Id_super = EcmaScript.NET.Token.RESERVED; - private const int Id_synchronized = EcmaScript.NET.Token.RESERVED; - private const int Id_throw = EcmaScript.NET.Token.THROW; - private const int Id_throws = EcmaScript.NET.Token.RESERVED; - private const int Id_transient = EcmaScript.NET.Token.RESERVED; - private const int Id_try = EcmaScript.NET.Token.TRY; - private const int Id_volatile = EcmaScript.NET.Token.RESERVED; - #endregion - - private static int stringToKeyword(string name) - { - // The following assumes that EcmaScript.NET.Token.EOF == 0 - int id; - string s = name; - #region Generated Id Switch - L0: - { - id = 0; - string X = null; - int c; - L: - switch (s.Length) - { - case 2: - c = s[1]; - if (c == 'f') { if (s[0] == 'i') { id = Id_if; goto EL0; } } - else if (c == 'n') { if (s[0] == 'i') { id = Id_in; goto EL0; } } - else if (c == 'o') { if (s[0] == 'd') { id = Id_do; goto EL0; } } - break; - case 3: - switch (s[0]) - { - case 'f': - if (s[2] == 'r' && s[1] == 'o') { id = Id_for; goto EL0; } - break; - case 'i': - if (s[2] == 't' && s[1] == 'n') { id = Id_int; goto EL0; } - break; - case 'n': - if (s[2] == 'w' && s[1] == 'e') { id = Id_new; goto EL0; } - break; - case 't': - if (s[2] == 'y' && s[1] == 'r') { id = Id_try; goto EL0; } - break; - case 'v': - if (s[2] == 'r' && s[1] == 'a') { id = Id_var; goto EL0; } - break; - } - break; - case 4: - switch (s[0]) - { - case 'b': - X = "byte"; - id = Id_byte; - break; - case 'c': - c = s[3]; - if (c == 'e') { if (s[2] == 's' && s[1] == 'a') { id = Id_case; goto EL0; } } - else if (c == 'r') { if (s[2] == 'a' && s[1] == 'h') { id = Id_char; goto EL0; } } - break; - case 'e': - c = s[3]; - if (c == 'e') { if (s[2] == 's' && s[1] == 'l') { id = Id_else; goto EL0; } } - else if (c == 'm') { if (s[2] == 'u' && s[1] == 'n') { id = Id_enum; goto EL0; } } - break; - case 'g': - X = "goto"; - id = Id_goto; - break; - case 'l': - X = "long"; - id = Id_long; - break; - case 'n': - X = "null"; - id = Id_null; - break; - case 't': - c = s[3]; - if (c == 'e') { if (s[2] == 'u' && s[1] == 'r') { id = Id_true; goto EL0; } } - else if (c == 's') { if (s[2] == 'i' && s[1] == 'h') { id = Id_this; goto EL0; } } - break; - case 'v': - X = "void"; - id = Id_void; - break; - case 'w': - X = "with"; - id = Id_with; - break; - } - break; - case 5: - switch (s[2]) - { - case 'a': - X = "class"; - id = Id_class; - break; - case 'e': - X = "break"; - id = Id_break; - break; - case 'i': - X = "while"; - id = Id_while; - break; - case 'l': - X = "false"; - id = Id_false; - break; - case 'n': - c = s[0]; - if (c == 'c') { X = "const"; id = Id_const; } - else if (c == 'f') { X = "final"; id = Id_final; } - break; - case 'o': - c = s[0]; - if (c == 'f') { X = "float"; id = Id_float; } - else if (c == 's') { X = "short"; id = Id_short; } - break; - case 'p': - X = "super"; - id = Id_super; - break; - case 'r': - X = "throw"; - id = Id_throw; - break; - case 't': - X = "catch"; - id = Id_catch; - break; - } - break; - case 6: - switch (s[1]) - { - case 'a': - X = "native"; - id = Id_native; - break; - case 'e': - c = s[0]; - if (c == 'd') { X = "delete"; id = Id_delete; } - else if (c == 'r') { X = "return"; id = Id_return; } - break; - case 'h': - X = "throws"; - id = Id_throws; - break; - case 'm': - X = "import"; - id = Id_import; - break; - case 'o': - X = "double"; - id = Id_double; - break; - case 't': - X = "static"; - id = Id_static; - break; - case 'u': - X = "public"; - id = Id_public; - break; - case 'w': - X = "switch"; - id = Id_switch; - break; - case 'x': - X = "export"; - id = Id_export; - break; - case 'y': - X = "typeof"; - id = Id_typeof; - break; - } - break; - case 7: - switch (s[1]) - { - case 'a': - X = "package"; - id = Id_package; - break; - case 'e': - X = "default"; - id = Id_default; - break; - case 'i': - X = "finally"; - id = Id_finally; - break; - case 'o': - X = "boolean"; - id = Id_boolean; - break; - case 'r': - X = "private"; - id = Id_private; - break; - case 'x': - X = "extends"; - id = Id_extends; - break; - } - break; - case 8: - switch (s[0]) - { - case 'a': - X = "abstract"; - id = Id_abstract; - break; - case 'c': - X = "continue"; - id = Id_continue; - break; - case 'd': - X = "debugger"; - id = Id_debugger; - break; - case 'f': - X = "function"; - id = Id_function; - break; - case 'v': - X = "volatile"; - id = Id_volatile; - break; - } - break; - case 9: - c = s[0]; - if (c == 'i') { X = "interface"; id = Id_interface; } - else if (c == 'p') { X = "protected"; id = Id_protected; } - else if (c == 't') { X = "transient"; id = Id_transient; } - break; - case 10: - c = s[1]; - if (c == 'm') { X = "implements"; id = Id_implements; } - else if (c == 'n') { X = "instanceof"; id = Id_instanceof; } - break; - case 12: - X = "synchronized"; - id = Id_synchronized; - break; - } - if (X != null && X != s && !X.Equals(s)) - id = 0; - } - EL0: - - #endregion - if (id == 0) - { - return EcmaScript.NET.Token.EOF; - } - return id & 0xff; - } - - internal bool eof() - { - return hitEOF; - } - - private static bool isAlpha(int c) - { - // Use 'Z' < 'a' - if (c <= 'Z') - { - return 'A' <= c; - } - else - { - return 'a' <= c && c <= 'z'; - } - } - - internal static bool isDigit(int c) - { - return '0' <= c && c <= '9'; - } - - /* As defined in ECMA. jsscan.c uses C isspace() (which allows - * \v, I think.) note that code in getChar() implicitly accepts - * '\r' == - as well. - */ - internal static bool isJSSpace(int c) - { - if (c <= 127) - { - return c == 0x20 || c == 0x9 || c == 0xC || c == 0xB; - } - else - { - return c == 0xA0 || (int)char.GetUnicodeCategory((char)c) == (sbyte)System.Globalization.UnicodeCategory.SpaceSeparator; - } - } - - private static bool isJSFormatChar(int c) - { - return c > 127 && (int)char.GetUnicodeCategory((char)c) == (sbyte)System.Globalization.UnicodeCategory.Format; - } - - /// Parser calls the method when it gets / or /= in literal context. - internal void readRegExp(int startToken) - { - stringBufferTop = 0; - if (startToken == EcmaScript.NET.Token.ASSIGN_DIV) - { - // Miss-scanned /= - addToString('='); - } - else - { - if (startToken != EcmaScript.NET.Token.DIV) - Context.CodeBug(); - } - - int c; - bool inClass = false; - while ((c = Char) != '/' || inClass) - { - if (c == '\n' || c == EOF_CHAR) - { - ungetChar(c); - throw parser.ReportError("msg.unterminated.re.lit"); - } - if (c == '\\') - { - addToString(c); - c = Char; - } - else if (c == '[') - { - inClass = true; - } - else if (c == ']') - { - inClass = false; - } - - addToString(c); - } - - int reEnd = stringBufferTop; - - while (true) - { - if (matchChar('g')) - addToString('g'); - else if (matchChar('i')) - addToString('i'); - else if (matchChar('m')) - addToString('m'); - else - break; - } - - if (isAlpha(peekChar())) - { - throw parser.ReportError("msg.invalid.re.flag"); - } - - this.str = new string(stringBuffer, 0, reEnd); - this.regExpFlags = new string(stringBuffer, reEnd, stringBufferTop - reEnd); - } - - /// - private bool readQuotedString(int quote) - { - for (int c = Char; c != EOF_CHAR; c = Char) - { - addToString(c); - if (c == quote) - return true; - } - - stringBufferTop = 0; // throw away the string in progress - this.str = null; - parser.AddError("msg.XML.bad.form"); - return false; - } - - /// - private bool readXmlComment() - { - for (int c = Char; c != EOF_CHAR; ) - { - addToString(c); - if (c == '-' && peekChar() == '-') - { - c = Char; - addToString(c); - if (peekChar() == '>') - { - c = Char; // Skip > - addToString(c); - return true; - } - else - { - continue; - } - } - c = Char; - } - - stringBufferTop = 0; // throw away the string in progress - this.str = null; - parser.AddError("msg.XML.bad.form"); - return false; - } - - /// - private bool readCDATA() - { - for (int c = Char; c != EOF_CHAR; ) - { - addToString(c); - if (c == ']' && peekChar() == ']') - { - c = Char; - addToString(c); - if (peekChar() == '>') - { - c = Char; // Skip > - addToString(c); - return true; - } - else - { - continue; - } - } - c = Char; - } - - stringBufferTop = 0; // throw away the string in progress - this.str = null; - parser.AddError("msg.XML.bad.form"); - return false; - } - - /// - private bool readEntity() - { - int declTags = 1; - for (int c = Char; c != EOF_CHAR; c = Char) - { - addToString(c); - switch (c) - { - - case '<': - declTags++; - break; - - case '>': - declTags--; - if (declTags == 0) - return true; - break; - } - } - - stringBufferTop = 0; // throw away the string in progress - this.str = null; - parser.AddError("msg.XML.bad.form"); - return false; - } - - /// - private bool readPI() - { - for (int c = Char; c != EOF_CHAR; c = Char) - { - addToString(c); - if (c == '?' && peekChar() == '>') - { - c = Char; // Skip > - addToString(c); - return true; - } - } - - stringBufferTop = 0; // throw away the string in progress - this.str = null; - parser.AddError("msg.XML.bad.form"); - return false; - } - - private void addToString(int c) - { - int N = stringBufferTop; - if (N == stringBuffer.Length) - { - char[] tmp = new char[stringBuffer.Length * 4]; - Array.Copy(stringBuffer, 0, tmp, 0, N); - stringBuffer = tmp; - } - stringBuffer[N] = (char)c; - stringBufferTop = N + 1; - } - - private void ungetChar(int c) - { - // can not unread past across line boundary - if (ungetCursor != 0 && ungetBuffer[ungetCursor - 1] == '\n') - Context.CodeBug(); - ungetBuffer[ungetCursor++] = c; - } - - private bool matchChar(int test) - { - int c = Char; - if (c == test) - { - return true; - } - else - { - ungetChar(c); - return false; - } - } - - private int peekChar() - { - int c = Char; - ungetChar(c); - return c; - } - - private void skipLine() - { - // skip to end of line - int c; - while ((c = Char) != EOF_CHAR && c != '\n') - { - } - ungetChar(c); - } - - private bool fillSourceBuffer() - { - if (sourceString != null) - Context.CodeBug(); - if (sourceEnd == sourceBuffer.Length) - { - if (lineStart != 0) - { - Array.Copy(sourceBuffer, lineStart, sourceBuffer, 0, sourceEnd - lineStart); - sourceEnd -= lineStart; - sourceCursor -= lineStart; - lineStart = 0; - } - else - { - char[] tmp = new char[sourceBuffer.Length * 2]; - Array.Copy(sourceBuffer, 0, tmp, 0, sourceEnd); - sourceBuffer = tmp; - } - } - int n = sourceReader.Read(sourceBuffer, sourceEnd, sourceBuffer.Length - sourceEnd); - if (n <= 0) - { - return false; - } - sourceEnd += n; - return true; - } - - // stuff other than whitespace since start of line - private bool dirtyLine; - - internal string regExpFlags; - - - // Set this to an inital non-null value so that the Parser has - // something to retrieve even if an error has occured and no - // string is found. Fosters one class of error, but saves lots of - // code. - private string str = ""; - private double dNumber; - - - private char[] stringBuffer = new char[128]; - private int stringBufferTop; - private ObjToIntMap allStrings = new ObjToIntMap(50); - - // Room to backtrace from to < on failed match of the last - in