progress
This commit is contained in:
parent
16e76d6b31
commit
484dbfc9d9
529 changed files with 113694 additions and 0 deletions
465
AspClassic.VBScript/VBScript.cs
Normal file
465
AspClassic.VBScript/VBScript.cs
Normal file
|
@ -0,0 +1,465 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using VB = AspClassic.Parser;
|
||||
using AspClassic.Scripting;
|
||||
using AspClassic.Scripting.Runtime;
|
||||
//using AspClassic.Scripting.Debugging.CompilerServices;
|
||||
//using AspClassic.Scripting.Debugging;
|
||||
using System.Dynamic;
|
||||
#if USE35
|
||||
using AspClassic.Scripting.Ast;
|
||||
using AspClassic.Scripting.Utils;
|
||||
#else
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
#endif
|
||||
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.IO;
|
||||
using Dlrsoft.VBScript.Binders;
|
||||
using Dlrsoft.VBScript.Compiler;
|
||||
using Dlrsoft.VBScript.Runtime;
|
||||
|
||||
namespace Dlrsoft.VBScript
|
||||
{
|
||||
public class VBScript
|
||||
{
|
||||
public const string ERR_PARAMETER = "err";
|
||||
public const string TRACE_PARAMETER = "__trace";
|
||||
|
||||
private IList<Assembly> _assemblies;
|
||||
private ExpandoObject _globals = new ExpandoObject();
|
||||
private Scope _dlrGlobals;
|
||||
|
||||
public VBScript(IList<Assembly> assms, Scope dlrGlobals)
|
||||
{
|
||||
_assemblies = assms;
|
||||
_dlrGlobals = dlrGlobals;
|
||||
AddAssemblyNamesAndTypes();
|
||||
}
|
||||
|
||||
// _addNamespacesAndTypes builds a tree of ExpandoObjects representing
|
||||
// .NET namespaces, with TypeModel objects at the leaves. Though Sympl is
|
||||
// case-insensitive, we store the names as they appear in .NET reflection
|
||||
// in case our globals object or a namespace object gets passed as an IDO
|
||||
// to another language or library, where they may be looking for names
|
||||
// case-sensitively using EO's default lookup.
|
||||
//
|
||||
public void AddAssemblyNamesAndTypes() {
|
||||
foreach (var assm in _assemblies) {
|
||||
foreach (var typ in assm.GetExportedTypes()) {
|
||||
string[] names = typ.FullName.Split('.');
|
||||
var table = _globals;
|
||||
for (int i = 0; i < names.Length - 1; i++) {
|
||||
string name = names[i].ToLower();
|
||||
if (DynamicObjectHelpers.HasMember(
|
||||
(IDynamicMetaObjectProvider)table, name)) {
|
||||
// Must be Expando since only we have put objs in
|
||||
// the tables so far.
|
||||
table = (ExpandoObject)(DynamicObjectHelpers
|
||||
.GetMember(table, name));
|
||||
} else {
|
||||
var tmp = new ExpandoObject();
|
||||
DynamicObjectHelpers.SetMember(table, name, tmp);
|
||||
table = tmp;
|
||||
}
|
||||
}
|
||||
DynamicObjectHelpers.SetMember(table, names[names.Length - 1],
|
||||
new TypeModel(typ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ExecuteFile executes the file in a new module scope and stores the
|
||||
// scope on Globals, using either the provided name, globalVar, or the
|
||||
// file's base name. This function returns the module scope.
|
||||
//
|
||||
public IDynamicMetaObjectProvider ExecuteFile(string filename) {
|
||||
return ExecuteFile(filename, null);
|
||||
}
|
||||
|
||||
public IDynamicMetaObjectProvider ExecuteFile(string filename,
|
||||
string globalVar) {
|
||||
var moduleEO = CreateScope();
|
||||
ExecuteFileInScope(filename, moduleEO);
|
||||
|
||||
globalVar = globalVar ?? Path.GetFileNameWithoutExtension(filename);
|
||||
DynamicObjectHelpers.SetMember(this._globals, globalVar, moduleEO);
|
||||
|
||||
return moduleEO;
|
||||
}
|
||||
|
||||
// ExecuteFileInScope executes the file in the given module scope. This
|
||||
// does NOT store the module scope on Globals. This function returns
|
||||
// nothing.
|
||||
//
|
||||
public void ExecuteFileInScope(string filename,
|
||||
IDynamicMetaObjectProvider moduleEO) {
|
||||
var f = new StreamReader(filename);
|
||||
// Simple way to convey script rundir for RuntimeHelpes.SymplImport
|
||||
// to load .sympl files.
|
||||
DynamicObjectHelpers.SetMember(moduleEO, "__file__",
|
||||
Path.GetFullPath(filename));
|
||||
try {
|
||||
var moduleFun = ParseFileToLambda(filename, f);
|
||||
var d = moduleFun;
|
||||
d(this, moduleEO);
|
||||
} finally {
|
||||
f.Close();
|
||||
}
|
||||
}
|
||||
|
||||
internal AspClassic.Scripting.Utils.Action<VBScript, IDynamicMetaObjectProvider>
|
||||
ParseFileToLambda(string filename, TextReader reader) {
|
||||
var scanner = new VB.Scanner(reader);
|
||||
var errorTable = new List<VB.SyntaxError>();
|
||||
|
||||
var block = new VB.Parser().ParseScriptFile(scanner, errorTable);
|
||||
|
||||
if (errorTable.Count > 0)
|
||||
{
|
||||
List<VBScriptSyntaxError> errors = new List<VBScriptSyntaxError>();
|
||||
foreach (VB.SyntaxError error in errorTable)
|
||||
{
|
||||
errors.Add(new VBScriptSyntaxError(
|
||||
filename,
|
||||
SourceUtil.ConvertSpan(error.Span),
|
||||
(int)error.Type,
|
||||
error.Type.ToString())
|
||||
);
|
||||
}
|
||||
throw new VBScriptCompilerException(errors);
|
||||
}
|
||||
|
||||
VBScriptSourceCodeReader sourceReader = reader as VBScriptSourceCodeReader;
|
||||
ISourceMapper mapper = null;
|
||||
if (sourceReader != null)
|
||||
{
|
||||
mapper = sourceReader.SourceMapper;
|
||||
}
|
||||
|
||||
var scope = new AnalysisScope(
|
||||
null,
|
||||
filename,
|
||||
this,
|
||||
Expression.Parameter(typeof(VBScript), "vbscriptRuntime"),
|
||||
Expression.Parameter(typeof(IDynamicMetaObjectProvider), "fileModule"),
|
||||
mapper);
|
||||
|
||||
//Generate function table
|
||||
List<Expression> body = new List<Expression>();
|
||||
|
||||
//Add the built in globals
|
||||
ParameterExpression err = Expression.Parameter(typeof(ErrObject), ERR_PARAMETER);
|
||||
scope.Names.Add(ERR_PARAMETER, err);
|
||||
body.Add(
|
||||
Expression.Assign(
|
||||
err,
|
||||
Expression.New(typeof(ErrObject))
|
||||
)
|
||||
);
|
||||
|
||||
if (Trace)
|
||||
{
|
||||
ParameterExpression trace = Expression.Parameter(typeof(ITrace), TRACE_PARAMETER);
|
||||
scope.Names.Add(TRACE_PARAMETER, trace);
|
||||
body.Add(
|
||||
Expression.Assign(
|
||||
trace,
|
||||
Expression.Convert(
|
||||
Expression.Dynamic(
|
||||
scope.GetRuntime().GetGetMemberBinder(TRACE_PARAMETER),
|
||||
typeof(object),
|
||||
scope.GetModuleExpr()
|
||||
),
|
||||
typeof(ITrace)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
//Put module variables and functions into the scope
|
||||
VBScriptAnalyzer.AnalyzeFile(block, scope);
|
||||
|
||||
//Generate the module level code other than the methods:
|
||||
if (block.Statements != null)
|
||||
{
|
||||
foreach (var s in block.Statements)
|
||||
{
|
||||
if (s is VB.MethodDeclaration)
|
||||
{
|
||||
//Make sure methods are created first before being executed
|
||||
body.Insert(0, VBScriptGenerator.GenerateExpr(s, scope));
|
||||
}
|
||||
else
|
||||
{
|
||||
Expression stmt = VBScriptGenerator.GenerateExpr(s, scope);
|
||||
if (scope.VariableScope.IsOnErrorResumeNextOn)
|
||||
{
|
||||
stmt = VBScriptGenerator.WrapTryCatchExpression(stmt, scope);
|
||||
}
|
||||
Expression debugInfo = null;
|
||||
Expression clearDebugInfo = null;
|
||||
if (Trace && s is VB.Statement && !(s is VB.BlockStatement))
|
||||
{
|
||||
debugInfo = VBScriptGenerator.GenerateDebugInfo(s, scope, out clearDebugInfo);
|
||||
body.Add(debugInfo);
|
||||
}
|
||||
|
||||
body.Add(stmt);
|
||||
|
||||
if (clearDebugInfo != null)
|
||||
{
|
||||
body.Add(clearDebugInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body.Add(Expression.Constant(null)); //Stop anything from returning
|
||||
|
||||
if (scope.Errors.Count > 0)
|
||||
{
|
||||
throw new VBScriptCompilerException(scope.Errors);
|
||||
}
|
||||
|
||||
//if (Debug)
|
||||
//{
|
||||
// Expression registerRuntimeVariables = VBScriptGenerator.GenerateRuntimeVariablesExpression(scope);
|
||||
|
||||
// body.Insert(0, registerRuntimeVariables);
|
||||
//}
|
||||
|
||||
var moduleFun = Expression.Lambda<AspClassic.Scripting.Utils.Action<VBScript, IDynamicMetaObjectProvider>>(
|
||||
Expression.Block(
|
||||
scope.Names.Values,
|
||||
body),
|
||||
scope.RuntimeExpr,
|
||||
scope.ModuleExpr);
|
||||
|
||||
//if (!Debug)
|
||||
//{
|
||||
return moduleFun.Compile();
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// Expression<Action<VBScript, IDynamicMetaObjectProvider>> lambda = (Expression<Action<VBScript, IDynamicMetaObjectProvider>>)DebugContext.TransformLambda(moduleFun);
|
||||
// return lambda.Compile();
|
||||
//}
|
||||
}
|
||||
|
||||
// Execute a single expression parsed from string in the provided module
|
||||
// scope and returns the resulting value.
|
||||
//
|
||||
public void ExecuteExpr(string expr_str,
|
||||
IDynamicMetaObjectProvider moduleEO) {
|
||||
var moduleFun = ParseExprToLambda(new StringReader(expr_str));
|
||||
var d = moduleFun;
|
||||
d(this, moduleEO);
|
||||
}
|
||||
|
||||
internal AspClassic.Scripting.Utils.Action<VBScript, IDynamicMetaObjectProvider>
|
||||
ParseExprToLambda(TextReader reader) {
|
||||
var scanner = new VB.Scanner(reader);
|
||||
var errorTable = new List<VB.SyntaxError>();
|
||||
var ast = new VB.Parser().ParseScriptFile(scanner, errorTable);
|
||||
|
||||
VBScriptSourceCodeReader sourceReader = reader as VBScriptSourceCodeReader;
|
||||
ISourceMapper mapper = null;
|
||||
if (sourceReader != null)
|
||||
{
|
||||
mapper = sourceReader.SourceMapper;
|
||||
}
|
||||
|
||||
var scope = new AnalysisScope(
|
||||
null,
|
||||
"__snippet__",
|
||||
this,
|
||||
Expression.Parameter(typeof(VBScript), "vbscriptRuntime"),
|
||||
Expression.Parameter(typeof(IDynamicMetaObjectProvider), "fileModule"),
|
||||
mapper
|
||||
);
|
||||
|
||||
List<Expression> body = new List<Expression>();
|
||||
body.Add(Expression.Convert(VBScriptGenerator.GenerateExpr(ast, scope), typeof(object)));
|
||||
|
||||
if (scope.Errors.Count > 0)
|
||||
{
|
||||
throw new VBScriptCompilerException(scope.Errors);
|
||||
}
|
||||
|
||||
var moduleFun = Expression.Lambda<AspClassic.Scripting.Utils.Action<VBScript, IDynamicMetaObjectProvider>>(
|
||||
Expression.Block(body),
|
||||
scope.RuntimeExpr,
|
||||
scope.ModuleExpr
|
||||
);
|
||||
return moduleFun.Compile();
|
||||
}
|
||||
|
||||
|
||||
public IDynamicMetaObjectProvider Globals { get { return _globals; } }
|
||||
public IDynamicMetaObjectProvider DlrGlobals { get { return _dlrGlobals; } }
|
||||
public bool Trace { get; set; }
|
||||
|
||||
public static ExpandoObject CreateScope() {
|
||||
return new ExpandoObject();
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////
|
||||
// Canonicalizing Binders
|
||||
/////////////////////////
|
||||
|
||||
// We need to canonicalize binders so that we can share L2 dynamic
|
||||
// dispatch caching across common call sites. Every call site with the
|
||||
// same operation and same metadata on their binders should return the
|
||||
// same rules whenever presented with the same kinds of inputs. The
|
||||
// DLR saves the L2 cache on the binder instance. If one site somewhere
|
||||
// produces a rule, another call site performing the same operation with
|
||||
// the same metadata could get the L2 cached rule rather than computing
|
||||
// it again. For this to work, we need to place the same binder instance
|
||||
// on those functionally equivalent call sites.
|
||||
|
||||
private Dictionary<string, VBScriptGetMemberBinder> _getMemberBinders =
|
||||
new Dictionary<string, VBScriptGetMemberBinder>();
|
||||
public VBScriptGetMemberBinder GetGetMemberBinder (string name) {
|
||||
lock (_getMemberBinders) {
|
||||
// Don't lower the name. Sympl is case-preserving in the metadata
|
||||
// in case some DynamicMetaObject ignores ignoreCase. This makes
|
||||
// some interop cases work, but the cost is that if a Sympl program
|
||||
// spells ".foo" and ".Foo" at different sites, they won't share rules.
|
||||
if (_getMemberBinders.ContainsKey(name))
|
||||
return _getMemberBinders[name];
|
||||
var b = new VBScriptGetMemberBinder(name);
|
||||
_getMemberBinders[name] = b;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string, VBScriptSetMemberBinder> _setMemberBinders =
|
||||
new Dictionary<string, VBScriptSetMemberBinder>();
|
||||
public VBScriptSetMemberBinder GetSetMemberBinder (string name) {
|
||||
lock (_setMemberBinders) {
|
||||
// Don't lower the name. Sympl is case-preserving in the metadata
|
||||
// in case some DynamicMetaObject ignores ignoreCase. This makes
|
||||
// some interop cases work, but the cost is that if a Sympl program
|
||||
// spells ".foo" and ".Foo" at different sites, they won't share rules.
|
||||
if (_setMemberBinders.ContainsKey(name))
|
||||
return _setMemberBinders[name];
|
||||
var b = new VBScriptSetMemberBinder(name);
|
||||
_setMemberBinders[name] = b;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<CallInfo, VBScriptInvokeBinder> _invokeBinders =
|
||||
new Dictionary<CallInfo, VBScriptInvokeBinder>();
|
||||
public VBScriptInvokeBinder GetInvokeBinder (CallInfo info) {
|
||||
lock (_invokeBinders) {
|
||||
if (_invokeBinders.ContainsKey(info))
|
||||
return _invokeBinders[info];
|
||||
var b = new VBScriptInvokeBinder(info);
|
||||
_invokeBinders[info] = b;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<InvokeMemberBinderKey, VBScriptInvokeMemberBinder>
|
||||
_invokeMemberBinders =
|
||||
new Dictionary<InvokeMemberBinderKey, VBScriptInvokeMemberBinder>();
|
||||
public VBScriptInvokeMemberBinder GetInvokeMemberBinder
|
||||
(InvokeMemberBinderKey info) {
|
||||
lock (_invokeMemberBinders) {
|
||||
if (_invokeMemberBinders.ContainsKey(info))
|
||||
return _invokeMemberBinders[info];
|
||||
var b = new VBScriptInvokeMemberBinder(info.Name, info.Info);
|
||||
_invokeMemberBinders[info] = b;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<CallInfo, VBScriptCreateInstanceBinder>
|
||||
_createInstanceBinders =
|
||||
new Dictionary<CallInfo, VBScriptCreateInstanceBinder>();
|
||||
public VBScriptCreateInstanceBinder GetCreateInstanceBinder(CallInfo info) {
|
||||
lock (_createInstanceBinders) {
|
||||
if (_createInstanceBinders.ContainsKey(info))
|
||||
return _createInstanceBinders[info];
|
||||
var b = new VBScriptCreateInstanceBinder(info);
|
||||
_createInstanceBinders[info] = b;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<CallInfo, VBScriptGetIndexBinder> _getIndexBinders =
|
||||
new Dictionary<CallInfo, VBScriptGetIndexBinder>();
|
||||
public VBScriptGetIndexBinder GetGetIndexBinder(CallInfo info) {
|
||||
lock (_getIndexBinders) {
|
||||
if (_getIndexBinders.ContainsKey(info))
|
||||
return _getIndexBinders[info];
|
||||
var b = new VBScriptGetIndexBinder(info);
|
||||
_getIndexBinders[info] = b;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<CallInfo, VBScriptSetIndexBinder> _setIndexBinders =
|
||||
new Dictionary<CallInfo, VBScriptSetIndexBinder>();
|
||||
public VBScriptSetIndexBinder GetSetIndexBinder(CallInfo info) {
|
||||
lock (_setIndexBinders) {
|
||||
if (_setIndexBinders.ContainsKey(info))
|
||||
return _setIndexBinders[info];
|
||||
var b = new VBScriptSetIndexBinder(info);
|
||||
_setIndexBinders[info] = b;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<ExpressionType, VBScriptBinaryOperationBinder>
|
||||
_binaryOperationBinders =
|
||||
new Dictionary<ExpressionType, VBScriptBinaryOperationBinder>();
|
||||
public VBScriptBinaryOperationBinder GetBinaryOperationBinder
|
||||
(ExpressionType op) {
|
||||
lock (_binaryOperationBinders) {
|
||||
if (_binaryOperationBinders.ContainsKey(op))
|
||||
return _binaryOperationBinders[op];
|
||||
var b = new VBScriptBinaryOperationBinder(op);
|
||||
_binaryOperationBinders[op] = b;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<ExpressionType, VBScriptUnaryOperationBinder>
|
||||
_unaryOperationBinders =
|
||||
new Dictionary<ExpressionType, VBScriptUnaryOperationBinder>();
|
||||
public VBScriptUnaryOperationBinder GetUnaryOperationBinder
|
||||
(ExpressionType op) {
|
||||
lock (_unaryOperationBinders) {
|
||||
if (_unaryOperationBinders.ContainsKey(op))
|
||||
return _unaryOperationBinders[op];
|
||||
var b = new VBScriptUnaryOperationBinder(op);
|
||||
_unaryOperationBinders[op] = b;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
//private DebugContext _debugContext;
|
||||
//public DebugContext DebugContext
|
||||
//{
|
||||
// get
|
||||
// {
|
||||
// if (_debugContext == null)
|
||||
// {
|
||||
// _debugContext = DebugContext.CreateInstance();
|
||||
// ITracePipeline pipeLine = TracePipeline.CreateInstance(_debugContext);
|
||||
// pipeLine.TraceCallback = new VBScriptTraceCallbackListener();
|
||||
// }
|
||||
|
||||
// return _debugContext;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue