R-sharp/R#/Interpreter/RInterpreter.vb

780 lines
30 KiB
VB.net
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#Region "Microsoft.VisualBasic::69dffa75cf99bbb6e1bf56348a769ae0, R#\Interpreter\RInterpreter.vb"
' Author:
'
' asuka (amethyst.asuka@gcmodeller.org)
' xie (genetics@smrucc.org)
' xieguigang (xie.guigang@live.com)
'
' Copyright (c) 2018 GPL3 Licensed
'
'
' GNU GENERAL PUBLIC LICENSE (GPL3)
'
'
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY; without even the implied warranty of
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
' GNU General Public License for more details.
'
' You should have received a copy of the GNU General Public License
' along with this program. If not, see <http://www.gnu.org/licenses/>.
' /********************************************************************************/
' Summaries:
' Code Statistics:
' Total Lines: 714
' Code Lines: 428 (59.94%)
' Comment Lines: 183 (25.63%)
' - Xml Docs: 72.68%
'
' Blank Lines: 103 (14.43%)
' File Size: 29.15 KB
' Class RInterpreter
'
' Properties: configFile, debug, globalEnvir, globalSymbols, isExecCancel
' redirectError2stdout, Rsharp, silent, strict, verbose
' warnings
'
' Constructor: (+2 Overloads) Sub New
'
' Function: [Imports], [Set], (+3 Overloads) Evaluate, FromEnvironmentConfiguration, getDataStream
' InitializeEnvironment, (+4 Overloads) Invoke, (+2 Overloads) LoadLibrary, options, Parse
' RedirectOutput, Run, RunInternal, SetTaskCancelHook, Source
'
' Sub: _construct, (+3 Overloads) Add, (+2 Overloads) Dispose, Inspect, (+2 Overloads) Print
' PrintMemory
'
'
' /********************************************************************************/
#End Region
Imports System.IO
Imports System.Reflection
Imports System.Runtime.CompilerServices
Imports System.Threading
Imports Microsoft.VisualBasic.ApplicationServices
Imports Microsoft.VisualBasic.ApplicationServices.Debugging.Diagnostics
Imports Microsoft.VisualBasic.ApplicationServices.Debugging.Logging
Imports Microsoft.VisualBasic.ApplicationServices.Terminal
Imports Microsoft.VisualBasic.ComponentModel.Collection
Imports Microsoft.VisualBasic.ComponentModel.DataSourceModel
Imports Microsoft.VisualBasic.Language
Imports Microsoft.VisualBasic.Linq
Imports Microsoft.VisualBasic.Serialization.JSON
Imports SMRUCC.Rsharp.Development
Imports SMRUCC.Rsharp.Development.Components
Imports SMRUCC.Rsharp.Development.Configuration
Imports SMRUCC.Rsharp.Development.Package
Imports SMRUCC.Rsharp.Interpreter.ExecuteEngine
Imports SMRUCC.Rsharp.Interpreter.ExecuteEngine.ExpressionSymbols
Imports SMRUCC.Rsharp.Interpreter.ExecuteEngine.ExpressionSymbols.Closure
Imports SMRUCC.Rsharp.Interpreter.ExecuteEngine.ExpressionSymbols.DataSets
Imports SMRUCC.Rsharp.Runtime
Imports SMRUCC.Rsharp.Runtime.Components
Imports SMRUCC.Rsharp.Runtime.Components.Interface
Imports SMRUCC.Rsharp.Runtime.Internal
Imports SMRUCC.Rsharp.Runtime.Internal.Invokes
Imports SMRUCC.Rsharp.Runtime.Internal.Object
Imports SMRUCC.Rsharp.Runtime.Interop
Imports REnv = SMRUCC.Rsharp.Runtime.Internal.Invokes
Imports std = System.Math
Imports Strings = Microsoft.VisualBasic.Strings
Imports LibDir = Microsoft.VisualBasic.FileIO.Directory
Namespace Interpreter
Public Class RInterpreter : Implements IDisposable
Dim cts As CancellationTokenSource
''' <summary>
''' Global runtime environment.(全局环境)
''' </summary>
Public ReadOnly Property globalEnvir As GlobalEnvironment
Public ReadOnly Property warnings As New List(Of Message)
''' <summary>
''' R# running in debug mode.
''' </summary>
''' <returns></returns>
''' <remarks>
''' 调试模式下,除了输出表达式的字符串信息之外
''' 还会改变stop的行为在非调试模式下stop函数只会丢出错误消息并且终止脚本的运行
''' 但是在调试模式下面stop函数则会令程序抛出异常方便开发人员进行错误的定位
''' </remarks>
Public Property debug As Boolean = False
Public Property silent As Boolean = False
Public ReadOnly Property verbose As Boolean
Get
Return globalEnvir.verboseOption()
End Get
End Property
''' <summary>
''' 是否重定向错误消息输出至<see cref="RedirectOutput"/>函数所定义的输出设备之中
''' </summary>
''' <returns></returns>
Public Property redirectError2stdout As Boolean = False
''' <summary>
''' 是否在严格模式下运行R#脚本?默认为严格模式,即:
'''
''' 1. 所有的变量必须使用``let``关键词进行申明
''' </summary>
''' <returns></returns>
Public Property strict As Boolean = True
''' <summary>
''' Get value of a <see cref="Symbol"/>
''' </summary>
''' <param name="name"></param>
''' <returns></returns>
Default Public ReadOnly Property GetValue(name As String) As Object
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Get
Return globalEnvir(name).value
End Get
End Property
Public Const lastVariableName$ = "$"
Public ReadOnly Property configFile As ConfigFile
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Get
Return globalEnvir.options.file
End Get
End Property
''' <summary>
''' get all symbols inside the global environment
''' </summary>
''' <returns></returns>
Public ReadOnly Property globalSymbols As Symbol()
Get
Return globalEnvir.ToArray
End Get
End Property
Public ReadOnly Property isExecCancel As Boolean
Get
If cts Is Nothing Then
Return False
Else
Return cts.IsCancellationRequested
End If
End Get
End Property
''' <summary>
''' 直接无参数调用这个构造函数则会使用默认的配置文件创建R#脚本解释器引擎实例
''' </summary>
''' <param name="envirConf"></param>
Sub New(Optional envirConf As Options = Nothing, Optional env_label As String = Nothing)
If envirConf Is Nothing Then
envirConf = New Options(ConfigFile.localConfigs, saveConfig:=False)
End If
Call _construct(New GlobalEnvironment(Me, envirConf, env_label:=env_label))
End Sub
Private Sub _construct(env As GlobalEnvironment)
_globalEnvir = env
_globalEnvir.Push(lastVariableName, Nothing, False, TypeCodes.generic)
_globalEnvir.Push("PI", std.PI, True, TypeCodes.double)
_globalEnvir.Push("E", std.E, True, TypeCodes.double)
_globalEnvir.Push(".GlobalEnv", globalEnvir, True, TypeCodes.environment)
_globalEnvir.Push(".Machine", New DotMachine().toList, True, TypeCodes.list)
For Each dllName As String In env.options.environments.SafeQuery
Dim searchContext As New List(Of String)
Dim dllfile As String = LibDLL.getDllFromAppDir(dllName, env, searchContext)
If dllfile.FileExists Then
Try
Call env.polyglot.Register(dllpath:=dllfile)
Catch ex As Exception
Call env.AddMessage({$"can not load assembly: {dllfile}!", ex.ToString}, MSG_TYPES.WRN)
End Try
Else
Call env.AddMessage($"ignore missing script engine module: {dllfile}...", MSG_TYPES.WRN)
End If
Next
' config R# interpreter engine
strict = env.options.strict
End Sub
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Sub New(env As GlobalEnvironment)
Call _construct(env)
End Sub
Public Function SetTaskCancelHook(cts As CancellationTokenSource) As RInterpreter
Me.cts = cts
Return Me
End Function
Public Function RedirectOutput(out As StreamWriter, env As OutputEnvironments) As RInterpreter
Call globalEnvir.RedirectOutput(out, env)
Return Me
End Function
''' <summary>
''' open the data file as stream from a given
''' package with a specific resource reference
''' name.
''' </summary>
''' <param name="dataName"></param>
''' <param name="package"></param>
''' <returns></returns>
Public Function getDataStream(dataName As String, package As String) As Stream
Dim pkgDir As IFileSystemEnvironment
Dim alternativeName As String = dataName.createAlternativeName
' 优先从已经加载的程序包位置进行加载操作
If globalEnvir.attachedNamespace.hasNamespace(package) Then
pkgDir = globalEnvir.attachedNamespace(package).libpath
ElseIf Not RFileSystem.PackageInstalled(package, globalEnvir) Then
Return Nothing
Else
pkgDir = LibDir.FromLocalFileSystem($"{RFileSystem.GetPackageDir(globalEnvir)}/{package}")
End If
If pkgDir.FileExists(dataName) Then
Return pkgDir.OpenFile(dataName, FileMode.Open, FileAccess.Read)
ElseIf pkgDir.FileExists(alternativeName) Then
Return pkgDir.OpenFile(alternativeName, FileMode.Open, FileAccess.Read)
End If
' for missing data package just
' returns nothing
Return Nothing
End Function
Public Function options(Optional names As String() = Nothing,
Optional verbose As Boolean? = Nothing,
Optional strict As Boolean? = Nothing) As Object
Dim setOption As Boolean = False
If Not verbose Is Nothing Then
globalEnvir.options.setOption(NameOf(verbose), verbose.Value)
setOption = True
ElseIf Not strict Is Nothing Then
Me.globalEnvir.options.setOption(NameOf(strict), strict.Value)
Me.strict = strict
setOption = True
End If
If setOption AndAlso Not names.IsNullOrEmpty Then
Return Internal.debug.stop({"can not set options with get options!"}, globalEnvir)
ElseIf setOption Then
Return globalEnvir
Else
Return New list With {
.slots = names _
.ToDictionary(Function(name) name,
Function(opt)
Return CObj(globalEnvir.options.getOption(opt))
End Function)
}
End If
End Function
Public Sub PrintMemory(Optional dev As TextWriter = Nothing)
Dim table$()() = globalEnvir _
.Select(Function(v)
Dim value$ = Symbol.GetValueViewString(v)
Return {
v.name,
v.typeCode.ToString,
v.typeof.FullName,
$"[{v.length}] {value}"
}
End Function) _
.ToArray
With dev Or App.StdOut
Call .DoCall(Sub(device)
Call table.PrintTable(
dev:=device,
leftMargin:=3,
title:={"name", "mode", "typeof", "value"}
)
End Sub)
End With
End Sub
''' <summary>
''' A shortcut of ``print(expr)``
''' </summary>
''' <param name="expr"></param>
''' <param name="auto">
''' 在自动条件下,会忽略掉<paramref name="expr"/>为<see cref="invisible"/>
''' 的结果打印
''' </param>
Public Sub Print(expr As String, Optional auto As Boolean = True)
Dim result As Object = Evaluate(expr)
If auto AndAlso Not result Is Nothing AndAlso TypeOf result Is invisible Then
Return
Else
' do expression evaluation and then
' print($expr)
Call REnv.print(result, , globalEnvir)
End If
End Sub
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Sub Print(obj As Object)
Call REnv.print(obj,, globalEnvir)
End Sub
''' <summary>
''' do call ``str`` function for inspect the structure of the given <paramref name="obj"/>
''' </summary>
''' <param name="obj"></param>
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Sub Inspect(obj As Object)
Call REnv.str(obj,, globalEnvir)
End Sub
''' <summary>
''' imports {<paramref name="pkgs"/>} from "<paramref name="baseDll"/>";
''' </summary>
''' <param name="pkgs"></param>
''' <param name="baseDll"></param>
''' <returns></returns>
''' <remarks>
''' attach_lib_dir
''' </remarks>
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function [Imports](pkgs As String(), baseDll As String) As Object
Return New [Imports](VectorLiteral.FromArray(pkgs), New Literal(baseDll)).Evaluate(globalEnvir)
End Function
''' <summary>
''' Load packages from package name or dll module file
''' </summary>
''' <param name="packageName">
''' package namespace or dll module file path
''' </param>
Public Function LoadLibrary(packageName$, Optional silent As Boolean = False, Optional ignoreMissingStartupPackages As Boolean = False) As RInterpreter
If packageName.FileExists Then
' is a dll file
Call ExpressionSymbols.[Imports].LoadLibrary(packageName, globalEnvir, {"*"})
Else
Dim result As Message = globalEnvir.LoadLibrary(packageName, silent, ignoreMissingStartupPackages:=ignoreMissingStartupPackages)
If Not result Is Nothing Then
Call Internal.debug.PrintMessageInternal(result, globalEnvir)
End If
End If
Return Me
End Function
''' <summary>
''' Imports static api function from given package module
''' </summary>
''' <param name="package"></param>
''' <returns></returns>
Public Function LoadLibrary(package As Type) As RInterpreter
Call globalEnvir.LoadLibrary(package)
Return Me
End Function
''' <summary>
''' Create a new symbol inside the R# runtime environment
''' </summary>
''' <param name="name$"></param>
''' <param name="value"></param>
''' <param name="type"></param>
<MethodImpl(MethodImplOptions.AggressiveInlining)>
<DebuggerStepThrough>
Public Sub Add(name$, value As Object, Optional type As TypeCodes = TypeCodes.generic)
Call globalEnvir.Push(name, value, [readonly]:=False, mode:=type)
End Sub
<MethodImpl(MethodImplOptions.AggressiveInlining)>
<DebuggerStepThrough>
Public Sub Add(name$, closure As [Delegate])
globalEnvir.Push(name, New RMethodInfo(name, closure), [readonly]:=False, mode:=TypeCodes.closure)
End Sub
<MethodImpl(MethodImplOptions.AggressiveInlining)>
<DebuggerStepThrough>
Public Sub Add(name$, closure As MethodInfo, Optional target As Object = Nothing)
globalEnvir.Push(name, New RMethodInfo(name, closure, target), [readonly]:=False, mode:=TypeCodes.closure)
End Sub
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function [Set](name As String, value As Object) As Object
Return globalEnvir.Push(name, value, [readonly]:=False)
End Function
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function Invoke(Of T)(funcName$, ParamArray args As Object()) As T
Return DirectCast(Invoke(funcName, args), T)
End Function
''' <summary>
''' direct invoke
''' </summary>
''' <param name="funcName">
''' the function name, can be prefixed with the package namespace
''' </param>
''' <param name="args">
''' the argument without names, this function will pass the
''' argument value to target R# function directly with aligned
''' with the function argument list.
''' </param>
''' <returns></returns>
Public Function Invoke(funcName$, ParamArray args As Object()) As Object
Dim find As Object
If Strings.InStr(funcName, "::") > 0 Then
Dim nsRef As NamedValue(Of String) = funcName.GetTagValue("::")
find = FunctionInvoke.GetFunctionVar(
funcName:=New Literal(nsRef.Value),
env:=globalEnvir,
[namespace]:=nsRef.Name
)
Else
find = FunctionInvoke.GetFunctionVar(New Literal(funcName), globalEnvir)
End If
If TypeOf find Is Message Then
Return find
Else
Return DirectCast(find, RFunction).Invoke(args, globalEnvir)
End If
End Function
''' <summary>
''' invoke a R function by name
''' </summary>
''' <param name="funcName">the R function name</param>
''' <param name="args">the named parameter list</param>
''' <returns></returns>
''' <remarks>
''' the named parameter list will be aligned with the function
''' argument list and then do function invoke.
''' </remarks>
Public Function Invoke(funcName$, args As NamedValue(Of Object)()) As Object
Dim find As Object = FunctionInvoke.GetFunctionVar(New Literal(funcName), globalEnvir)
Dim parameters As InvokeParameter() = args _
.Select(Function(a, i)
Return New InvokeParameter(a.Name, a.Value, i + 1)
End Function) _
.ToArray
If TypeOf find Is Message Then
Return find
Else
Return DirectCast(find, RFunction).Invoke(globalEnvir, parameters)
End If
End Function
Public Function Invoke(funcName As String, ParamArray args As (name As String, value As Object)()) As Object
Dim find As Object = FunctionInvoke.GetFunctionVar(New Literal(funcName), globalEnvir)
Dim parameters As InvokeParameter() = args _
.Select(Function(a, i)
Return New InvokeParameter(a.name, a.value, i + 1)
End Function) _
.ToArray
If TypeOf find Is Message Then
Return find
Else
Return DirectCast(find, RFunction).Invoke(globalEnvir, parameters)
End If
End Function
''' <summary>
''' Run R# script program from text data.
''' </summary>
''' <param name="script">The script text</param>
''' <returns></returns>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
<DebuggerStepThrough>
Public Function Evaluate(script As String) As Object
Return RunInternal(Rscript.FromText(script), {})
End Function
<MethodImpl(MethodImplOptions.AggressiveInlining)>
<DebuggerStepThrough>
Public Function Evaluate(script$, ParamArray args As (param As String, value As Object)()) As Object
Return RunInternal(Rscript.FromText(script), args.Select(Function(i) New NamedValue(Of Object)(i.param, i.value)).ToArray)
End Function
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function Run(program As Program) As Object
' Return finalizeResult(program.Execute(globalEnvir))
Dim last As Symbol = Me.globalEnvir(lastVariableName)
Dim result As Object = program.Execute(globalEnvir)
' set last variable in current environment
Call last.setValue(result, globalEnvir)
Return result
End Function
''' <summary>
'''
''' </summary>
''' <param name="source">The script file name</param>
''' <param name="arguments"></param>
''' <returns></returns>
Private Function InitializeEnvironment(source$, arguments As NamedValue(Of Object)()) As Environment
Dim env As Environment
If source Is Nothing OrElse Strings.InStr(source, "<in_memory_") = 1 Then
env = globalEnvir
Else
env = New StackFrame With {
.File = source,
.Line = 0,
.Method = New Method With {
.Method = MethodBase.GetCurrentMethod.Name,
.[Module] = "n/a",
.[Namespace] = "SMRUCC/R#"
}
}.DoCall(Function(stackframe)
Return New Environment(globalEnvir, stackframe, isInherits:=True)
End Function)
End If
Dim symbol$
Dim obj As Object
For Each var As NamedValue(Of Object) In arguments
symbol = var.Name
obj = var.Value
Call env.Push(symbol, obj, [readonly]:=False)
Next
If debug AndAlso arguments.Length > 0 Then
Call "Initialize of the environment with pre-define symbols:".__DEBUG_ECHO
Call arguments.Keys.GetJson.__INFO_ECHO
If arguments.Any(Function(a) a.Name = "!script") Then
Dim magic As vbObject = arguments _
.Where(Function(a) a.Name = "!script") _
.First _
.Value
Dim magicList As list = DirectCast(magic.target, MagicScriptSymbol).toList
Call Invokes.base.str(magicList, env:=env)
End If
End If
Return env
End Function
'Friend Function finalizeResult(result As Object) As Object
' Dim last As Symbol = Me.globalEnvir(lastVariableName)
' ' set last variable in current environment
' Call last.SetValue(result, globalEnvir)
' 'If Program.isException(result) Then
' ' Call VBDebugger.WaitOutput()
' ' Call Internal.debug.PrintMessageInternal(message:=result)
' 'End If
' If globalEnvir.messages > 0 Then
' Call VBDebugger.WaitOutput()
' For Each message As Message In globalEnvir.messages
' Call Internal.debug.PrintMessageInternal(message, globalEnvir)
' Next
' Call globalEnvir.messages.Clear()
' End If
' Return result
'End Function
Public Function Parse(text As String) As Program
Dim error$ = Nothing
Dim Rscript As Rscript = Rscript.AutoHandleScript(text)
Dim program As Program = Program.CreateProgram(Rscript, debug:=debug, [error]:=[error])
Return program
End Function
''' <summary>
'''
''' </summary>
''' <param name="Rscript"></param>
''' <param name="arguments">
''' symbol values that will be pushed into the runtime environment context
''' </param>
''' <param name="globalEnvir"></param>
''' <returns></returns>
Private Function RunInternal(Rscript As Rscript, arguments As NamedValue(Of Object)(), Optional ByRef globalEnvir As Environment = Nothing) As Object
Dim error$ = Nothing
Dim program As Program = Program.CreateProgram(Rscript, debug:=debug, [error]:=[error])
Dim result As Object
globalEnvir = InitializeEnvironment(Rscript.fileName, arguments)
If Not [error].StringEmpty Then
result = Internal.debug.stop([error], globalEnvir)
Else
If debug Then
#Disable Warning
Call VBDebugger.WriteLine(vbNewLine)
Call VBDebugger.WriteLine(program.ToString)
Call VBDebugger.WriteLine(vbNewLine)
#Enable Warning
End If
result = program.Execute(globalEnvir)
End If
' fix bugs of warning message populates
' to upper global environment
If Not globalEnvir Is Me.globalEnvir Then
Call globalEnvir.Dispose()
End If
' set last variable in current environment
Call Me.globalEnvir(lastVariableName).setValue(result, globalEnvir)
Return result
End Function
''' <summary>
''' Run R# script program from a given script file.
''' (运行脚本的时候调用的是<see cref="globalEnvir"/>全局环境)
''' </summary>
''' <param name="filepath">The script file path.</param>
''' <param name="arguments"></param>
''' <returns></returns>
'''
<MethodImpl(MethodImplOptions.AggressiveInlining)>
Public Function Source(filepath$,
Optional arguments As NamedValue(Of Object)() = Nothing,
Optional ByRef globalEnv As Environment = Nothing) As Object
' when source a given script by path
' then an object list variable with special name will be push into
' the environment
'
' let !script = list(dir = dirname, file = filename, fullName = filepath)
Dim script As MagicScriptSymbol = CreateMagicScriptSymbol(filepath, R:=Me)
Dim result As Object
If filepath.FileExists Then
Dim Rscript As Rscript = Rscript.FromFile(filepath)
arguments = arguments _
.SafeQuery _
.JoinIterates(New NamedValue(Of Object)("!script", New vbObject(script))) _
.ToArray
result = RunInternal(Rscript, arguments, globalEnv)
Else
result = Internal.debug.stop({
$"cannot open the connection.",
$"cannot open file '{filepath.FileName}': No such file or directory",
$"file: {filepath.GetFullPath}",
$"function: source"
}, globalEnvir)
End If
Return result
End Function
Public Shared ReadOnly Property Rsharp As New RInterpreter
Public Shared Function Evaluate(script$, ParamArray args As NamedValue(Of Object)()) As Object
SyncLock Rsharp
With Rsharp
If Not args.IsNullOrEmpty Then
Dim name$
Dim value As Object
For Each var As NamedValue(Of Object) In args
name = var.Name
value = var.Value
Call .globalEnvir.Push(name, value, [readonly]:=False, mode:=TypeCodes.generic)
Next
End If
Return .Evaluate(script)
End With
End SyncLock
End Function
''' <summary>
'''
''' </summary>
''' <param name="configs">
''' the filepath of the configuration file
''' </param>
''' <returns></returns>
<MethodImpl(MethodImplOptions.AggressiveInlining)>
<DebuggerStepThrough>
Public Shared Function FromEnvironmentConfiguration(configs As String) As RInterpreter
Return New RInterpreter(New Options(configs, saveConfig:=False))
End Function
Private disposedValue As Boolean
Protected Overridable Sub Dispose(disposing As Boolean)
If Not disposedValue Then
If disposing Then
' TODO: dispose managed state (managed objects)
Call warnings.Clear()
Call globalEnvir.Dispose()
End If
' TODO: free unmanaged resources (unmanaged objects) and override finalizer
' TODO: set large fields to null
disposedValue = True
End If
End Sub
' ' TODO: override finalizer only if 'Dispose(disposing As Boolean)' has code to free unmanaged resources
' Protected Overrides Sub Finalize()
' ' Do not change this code. Put cleanup code in 'Dispose(disposing As Boolean)' method
' Dispose(disposing:=False)
' MyBase.Finalize()
' End Sub
Public Sub Dispose() Implements IDisposable.Dispose
' Do not change this code. Put cleanup code in 'Dispose(disposing As Boolean)' method
Call Dispose(disposing:=True)
Call System.GC.SuppressFinalize(Me)
End Sub
Public Shared Narrowing Operator CType(R As RInterpreter) As Environment
Return R.globalEnvir
End Operator
End Class
End Namespace