This commit is contained in:
Jelle Luteijn 2022-05-15 11:19:49 +02:00
parent 16e76d6b31
commit 484dbfc9d9
529 changed files with 113694 additions and 0 deletions

View file

@ -0,0 +1,295 @@
using System;
using System.Collections.Generic;
using System.Text;
using AspClassic.Scripting.Runtime;
using System.Dynamic;
#if USE35
using AspClassic.Scripting.Ast;
#else
using System.Linq.Expressions;
#endif
using AspClassic.Scripting.Utils;
namespace Dlrsoft.VBScript.Compiler
{
// AnalysisScope holds identifier information so that we can do name binding
// during analysis. It manages a map from names to ParameterExprs so ET
// definition locations and reference locations can alias the same variable.
//
// These chain from inner most BlockExprs, through LambdaExprs, to the root
// which models a file or top-level expression. The root has non-None
// ModuleExpr and RuntimeExpr, which are ParameterExprs.
//
internal class AnalysisScope
{
private AnalysisScope _parent;
private string _name;
// Need runtime for interning VBScript constants at code gen time.
private VBScript _runtime;
private ParameterExpression _runtimeParam;
private ParameterExpression _moduleParam;
private ParameterExpression _traceParam;
private ISourceMapper _mapper;
// Need IsLambda when support return to find tightest closing fun.
private bool _isLambda = false;
private bool _isLambdaBody = false;
private bool _isDoLoop = false;
private bool _isForLoop = false;
private bool _isWith = false;
private bool _isOptionExplicitOn = false;
private bool _isOnErrorResumeNextOn = false;
private LabelTarget _loopBreak = null;
private LabelTarget _continueBreak = null;
private LabelTarget _methodExit = null;
private Dictionary<string, ParameterExpression> _names;
private Set<string> _functionTable;
private IList<VBScriptSyntaxError> _errors;
private Expression _withExpression;
private IDictionary<string, SymbolDocumentInfo> _docInfos;
public AnalysisScope(AnalysisScope parent, string name)
: this(parent, name, null, null, null, null) { }
public AnalysisScope(AnalysisScope parent,
string name,
VBScript runtime,
ParameterExpression runtimeParam,
ParameterExpression moduleParam,
ISourceMapper mapper)
{
_parent = parent;
_name = name;
_runtime = runtime;
_runtimeParam = runtimeParam;
_moduleParam = moduleParam;
_mapper = mapper;
if (_moduleParam != null)
{
_functionTable = new Set<string>(StringComparer.InvariantCultureIgnoreCase);
_errors = new List<VBScriptSyntaxError>();
_docInfos = new Dictionary<string, SymbolDocumentInfo>();
}
_names = new Dictionary<string, ParameterExpression>();
}
public AnalysisScope Parent { get { return _parent; } }
public ParameterExpression ModuleExpr { get { return _moduleParam; } }
public ParameterExpression RuntimeExpr { get { return _runtimeParam; } }
public VBScript Runtime { get { return _runtime; } }
public ISourceMapper SourceMapper { get { return _mapper; } }
public string Name { get { return _name; } }
public bool IsModule { get { return _moduleParam != null; } }
public bool IsOptionExplicitOn
{
get { return _isOptionExplicitOn; }
set { _isOptionExplicitOn = value; }
}
public bool IsOnErrorResumeNextOn
{
get { return _isOnErrorResumeNextOn; }
set { _isOnErrorResumeNextOn = value; }
}
public bool IsLambda
{
get { return _isLambda; }
set { _isLambda = value; }
}
public bool IsLambdaBody
{
get { return _isLambdaBody; }
set { _isLambdaBody = value; }
}
public bool IsDoLoop
{
get { return _isDoLoop; }
set { _isDoLoop = value; }
}
public bool IsForLoop
{
get { return _isForLoop; }
set { _isForLoop = value; }
}
public bool IsWith
{
get { return _isWith; }
set { _isWith = value; }
}
public Expression WithExpression
{
get { return _withExpression; }
set { _withExpression = value; }
}
public Expression NearestWithExpression
{
get
{
var curScope = this;
while (!curScope.IsWith && !curScope.IsLambdaBody && !curScope.IsModule) //With cannot across those boundaries
{
curScope = curScope.Parent;
}
return curScope.WithExpression;
}
}
public Expression ErrExpression
{
get
{
return this.ModuleScope.Names[Dlrsoft.VBScript.VBScript.ERR_PARAMETER];
}
}
public Expression TraceExpression
{
get
{
return this.ModuleScope.Names[Dlrsoft.VBScript.VBScript.TRACE_PARAMETER];
}
}
public LabelTarget LoopBreak
{
get { return _loopBreak; }
set { _loopBreak = value; }
}
public LabelTarget LoopContinue
{
get { return _continueBreak; }
set { _continueBreak = value; }
}
public LabelTarget MethodExit
{
get { return _methodExit; }
set { _methodExit = value; }
}
public Dictionary<string, ParameterExpression> Names
{
get { return _names; }
set { _names = value; }
}
public ParameterExpression GetModuleExpr()
{
var curScope = this;
while (!curScope.IsModule)
{
curScope = curScope.Parent;
}
return curScope.ModuleExpr;
}
public AnalysisScope ModuleScope
{
get
{
var curScope = this;
while (!curScope.IsModule)
{
curScope = curScope.Parent;
}
return curScope;
}
}
public AnalysisScope VariableScope
{
get
{
var curScope = this;
while (!curScope.IsModule && !curScope.IsLambdaBody)
{
curScope = curScope.Parent;
}
return curScope;
}
}
public Set<string> FunctionTable
{
get
{
return ModuleScope._functionTable;
}
}
public IList<VBScriptSyntaxError> Errors
{
get { return _errors; }
}
public VBScript GetRuntime()
{
var curScope = this;
while (curScope.Runtime == null)
{
curScope = curScope.Parent;
}
return curScope.Runtime;
}
//Can only call it on ModuleScope
public SymbolDocumentInfo GetDocumentInfo(string path)
{
SymbolDocumentInfo docInfo;
if (_docInfos.ContainsKey(path))
{
docInfo = _docInfos[path];
}
else
{
docInfo = Expression.SymbolDocument(path);
_docInfos.Add(path, docInfo);
}
return docInfo;
}
public void GetVariablesInScope(List<string> names, List<ParameterExpression> parameters)
{
AnalysisScope scope = this;
while (!scope.IsModule)
{
foreach (string name in _names.Keys)
{
names.Add(name);
parameters.Add(_names[name]);
}
scope = scope.Parent;
}
//Now we are dealing with module scope. We want to exclude lambda variables
Set<string> functionTable = FunctionTable;
foreach (string name in _names.Keys)
{
if (!functionTable.Contains(name))
{
names.Add(name);
parameters.Add(_names[name]);
}
}
}
} //AnalysisScope}
}

View file

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
using AspClassic.Scripting;
namespace Dlrsoft.VBScript.Compiler
{
public class DocSpan
{
public DocSpan(string uri, SourceSpan span)
{
this.Uri = uri;
this.Span = span;
}
public string Uri { get; set; }
public SourceSpan Span { get; set; }
}
}

View file

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
using AspClassic.Scripting;
namespace Dlrsoft.VBScript.Compiler
{
public interface ISourceMapper
{
DocSpan Map(SourceSpan span);
}
}

View file

@ -0,0 +1,88 @@
/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Microsoft Public License. A
* copy of the license can be found in the License.html file at the root of this distribution. If
* you cannot locate the Microsoft Public License, please send an email to
* dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
* by the terms of the Microsoft Public License.
*
* You must not remove this notice, or any other, from this software.
*
*
* ***************************************************************************/
using System.Collections;
using System.Collections.Generic;
namespace Dlrsoft.VBScript.Compiler {
/// <summary>
/// A simple hashset, built on Dictionary{K, V}
/// </summary>
internal sealed class Set<T> : ICollection<T> {
private readonly Dictionary<T, object> _data;
internal Set() {
_data = new Dictionary<T, object>();
}
internal Set(IEqualityComparer<T> comparer) {
_data = new Dictionary<T, object>(comparer);
}
internal Set(IList<T> list) {
_data = new Dictionary<T, object>(list.Count);
foreach (T t in list) {
Add(t);
}
}
internal Set(IEnumerable<T> list) {
_data = new Dictionary<T, object>();
foreach (T t in list) {
Add(t);
}
}
internal Set(int capacity) {
_data = new Dictionary<T, object>(capacity);
}
public void Add(T item) {
_data[item] = null;
}
public void Clear() {
_data.Clear();
}
public bool Contains(T item) {
return _data.ContainsKey(item);
}
public void CopyTo(T[] array, int arrayIndex) {
_data.Keys.CopyTo(array, arrayIndex);
}
public int Count {
get { return _data.Count; }
}
public bool IsReadOnly {
get { return false; }
}
public bool Remove(T item) {
return _data.Remove(item);
}
public IEnumerator<T> GetEnumerator() {
return _data.Keys.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return _data.Keys.GetEnumerator();
}
}
}

View file

@ -0,0 +1,179 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using AspClassic.Scripting;
namespace Dlrsoft.VBScript.Compiler
{
public class SourceUtil
{
public static int GetLineCount(string source)
{
int lineCount = 0;
if (string.IsNullOrEmpty(source))
return lineCount;
int start = 0;
int len = source.Length;
while (start < len)
{
int pos = source.IndexOf('\r', start);
if (pos > -1)
{
lineCount++;
}
else
{
break;
}
start = pos + 1;
if (start < len && source[start] == '\n')
{
start++;
}
}
//Last line with CR/LF
//We got an empty line in this situation
if (len >= start)
{
lineCount++;
}
return lineCount;
}
public static Range[] GetLineRanges(string source)
{
if (string.IsNullOrEmpty(source))
return new Range[]{};
List<Range> lineRanges = new List<Range>();
int start = 0;
int len = source.Length;
while (start < len)
{
int pos = source.IndexOf('\r', start);
if (pos < 0)
{
break;
}
if (pos + 1 < len && source[pos + 1] == '\n')
{
pos++;
}
lineRanges.Add(new Range(start, pos));
start = pos + 1;
}
//Last line with CR/LF
if (len > start)
{
lineRanges.Add(new Range(start, len-1));
}
return lineRanges.ToArray();
}
public static LineColumn GetLineColumn(Range[] lineRanges, int index)
{
IComparer comparer = new RangeComparer();
int i = Array.BinarySearch(lineRanges, 0, lineRanges.Length, index, comparer);
return new LineColumn(i + 1, index - lineRanges[i].Start + 1);
}
public static SourceSpan GetSpan(Range[] lineRanges, int start, int end)
{
LineColumn lcStart = GetLineColumn(lineRanges, start);
SourceLocation slStart = new SourceLocation(start, lcStart.Line, lcStart.Column);
LineColumn lcEnd = GetLineColumn(lineRanges, end);
SourceLocation slEnd = new SourceLocation(end, lcEnd.Line, lcEnd.Column);
return new SourceSpan(slStart, slEnd);
}
internal static SourceSpan ConvertSpan(AspClassic.Parser.Span span)
{
AspClassic.Parser.Location start = span.Start;
AspClassic.Parser.Location end = span.Finish;
return new SourceSpan(
new SourceLocation(start.Index, start.Line, start.Column),
new SourceLocation(end.Index, end.Line, end.Column)
);
}
}
public struct Range
{
public int Start;
public int End;
public Range(int start, int end)
{
this.Start = start;
this.End = end;
}
}
public struct LineColumn
{
public int Line;
public int Column;
public LineColumn(int line, int column)
{
this.Line = line;
this.Column = column;
}
}
internal class RangeComparer : IComparer
{
#region IComparer Members
public int Compare(object range, object index)
{
Range theRange = (Range)range;
int theIndex = (int)index;
if (theRange.End < theIndex)
{
return -1;
}
else if (theRange.Start > theIndex)
{
return 1;
}
return 0;
}
#endregion
}
internal class SpanComparer : IComparer<SourceSpan>
{
#region IComparer Members
public int Compare(SourceSpan x, SourceSpan y)
{
if (x.End.Line < y.Start.Line)
{
return -1;
}
else if (x.Start.Line > y.End.Line)
{
return 1;
}
else
{
return 0;
}
}
#endregion
}
}

View file

@ -0,0 +1,136 @@
using System;
using System.Collections.Generic;
using System.Text;
using VB = AspClassic.Parser;
using AspClassic.Scripting.Runtime;
using System.Dynamic;
#if USE35
using AspClassic.Scripting.Ast;
#else
using System.Linq.Expressions;
#endif
using AspClassic.Scripting.Utils;
using System.Reflection;
using System.IO;
using Dlrsoft.VBScript.Binders;
using Dlrsoft.VBScript.Compiler;
using Dlrsoft.VBScript.Runtime;
using Debug = System.Diagnostics.Debug;
namespace Dlrsoft.VBScript.Compiler
{
/// <summary>
/// The analysis phase. We don't do much except for generating the global functions, constants and variables table
/// </summary>
internal class VBScriptAnalyzer
{
public static void AnalyzeFile(AspClassic.Parser.ScriptBlock block, AnalysisScope scope)
{
Debug.Assert(scope.IsModule);
if (block.Statements != null)
{
foreach (VB.Statement s in block.Statements)
{
AnalyzeStatement(s, scope);
}
}
}
private static void AnalyzeStatement(VB.Statement s, AnalysisScope scope)
{
if (s is VB.MethodDeclaration)
{
string methodName = ((VB.MethodDeclaration)s).Name.Name.ToLower();
scope.FunctionTable.Add(methodName);
ParameterExpression method = Expression.Parameter(typeof(object));
scope.Names[methodName] = method;
}
else if (s is VB.LocalDeclarationStatement)
{
AnalyzeDeclarationExpr((VB.LocalDeclarationStatement)s, scope);
}
else if (s is VB.IfBlockStatement)
{
AnalyzeIfBlockStatement((VB.IfBlockStatement)s, scope);
}
else if (s is VB.SelectBlockStatement)
{
AnalyzeSelectBlockStatement((VB.SelectBlockStatement)s, scope);
}
else if (s is VB.BlockStatement)
{
AnalyzeBlockStatement((VB.BlockStatement)s, scope);
}
}
private static void AnalyzeDeclarationExpr(VB.LocalDeclarationStatement stmt, AnalysisScope scope)
{
bool isConst = false;
if (stmt.Modifiers != null)
{
if (stmt.Modifiers.ModifierTypes == VB.ModifierTypes.Const)
{
isConst = true;
}
}
foreach (VB.VariableDeclarator d in stmt.VariableDeclarators)
{
foreach (VB.VariableName v in d.VariableNames)
{
string name = v.Name.Name.ToLower();
ParameterExpression p = Expression.Parameter(typeof(object), name);
scope.Names.Add(name, p);
}
}
}
private static void AnalyzeIfBlockStatement(VB.IfBlockStatement block, AnalysisScope scope)
{
AnalyzeBlockStatement(block, scope);
if (block.ElseIfBlockStatements != null && block.ElseIfBlockStatements.Count > 0)
{
foreach (VB.ElseIfBlockStatement elseif in block.ElseIfBlockStatements)
{
AnalyzeBlockStatement(elseif, scope);
}
}
if (block.ElseBlockStatement != null)
{
AnalyzeBlockStatement(block.ElseBlockStatement, scope);
}
}
private static void AnalyzeSelectBlockStatement(VB.SelectBlockStatement block, AnalysisScope scope)
{
AnalyzeBlockStatement(block, scope);
if (block.CaseBlockStatements != null && block.CaseBlockStatements.Count > 0)
{
foreach (VB.CaseBlockStatement caseStmt in block.CaseBlockStatements)
{
AnalyzeBlockStatement(caseStmt, scope);
}
}
if (block.CaseElseBlockStatement != null)
{
AnalyzeBlockStatement(block.CaseElseBlockStatement, scope);
}
}
public static void AnalyzeBlockStatement(VB.BlockStatement block, AnalysisScope scope)
{
if (block.Statements != null)
{
foreach (VB.Statement stmt in block.Statements)
{
AnalyzeStatement(stmt, scope);
}
}
}
}
}

View file

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Dlrsoft.VBScript.Compiler
{
public class VBScriptCompilerException : Exception
{
private IList<VBScriptSyntaxError> _errors;
public VBScriptCompilerException(IList<VBScriptSyntaxError> errors)
{
_errors = errors;
}
public IList<VBScriptSyntaxError> SyntaxErrors
{
get { return _errors; }
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using AspClassic.Scripting;
namespace Dlrsoft.VBScript.Compiler
{
public class VBScriptSourceCodeReader : SourceCodeReader
{
private ISourceMapper _mapper;
public VBScriptSourceCodeReader(TextReader textReader, Encoding encoding, ISourceMapper mapper)
: base(textReader, encoding)
{
_mapper = mapper;
}
public ISourceMapper SourceMapper
{
get { return _mapper; }
}
}
}

View file

@ -0,0 +1,66 @@
using System;
using System.Collections;
using System.Collections.Generic;
using AspClassic.Scripting;
using System.Text;
namespace Dlrsoft.VBScript.Compiler
{
public class VBScriptSourceMapper : ISourceMapper
{
//Here the range is start line number and the end line number
private List<SourceSpan> _spans = new List<SourceSpan>(); //use ArrayList so that we can use the binary search method
private IDictionary<SourceSpan, DocSpan> _mappings = new Dictionary<SourceSpan, DocSpan>();
static private SpanComparer _comparer = new SpanComparer();
public VBScriptSourceMapper() {}
public void AddMapping(SourceSpan generatedSpan, DocSpan span)
{
_spans.Add(generatedSpan);
_mappings[generatedSpan] = span;
}
#region ISourceMapper Members
public DocSpan Map(SourceSpan span)
{
int generatedStartLine = span.Start.Line;
int index = _spans.BinarySearch(span, _comparer);
SourceSpan containingSpan = (SourceSpan)_spans[index];
DocSpan docSpan = _mappings[containingSpan];
int rawStartIndex = docSpan.Span.Start.Index + span.Start.Index - containingSpan.Start.Index;
int lineOffSet = generatedStartLine - containingSpan.Start.Line;
int rawStartLine = docSpan.Span.Start.Line + lineOffSet;
int rawStartColumn;
if (lineOffSet == 0)
{
rawStartColumn = docSpan.Span.Start.Column + span.Start.Column;
}
else
{
rawStartColumn = span.Start.Column;
}
int lines = span.End.Line - generatedStartLine;
int rawEndIndex = rawStartIndex + span.End.Index + span.Start.Index;
int rawEndLine = rawStartLine + lines;
int rawEndColumn;
if (lines == 0)
{
rawEndColumn = rawStartColumn + span.End.Column - span.Start.Column;
}
else
{
rawEndColumn = span.End.Column;
}
return new DocSpan(docSpan.Uri,
new SourceSpan(
new SourceLocation(rawStartIndex, rawStartLine, rawStartColumn),
new SourceLocation(rawEndIndex, rawEndLine, rawEndColumn)
)
);
}
#endregion
}
}

View file

@ -0,0 +1,27 @@
using System;
using System.IO;
using System.Dynamic;
using System.Collections.Generic;
using System.Text;
using AspClassic.Scripting;
using AspClassic.Scripting.Utils;
namespace Dlrsoft.VBScript.Compiler
{
public class VBScriptStringContentProvider : TextContentProvider {
private readonly string _code;
private ISourceMapper _mapper;
public VBScriptStringContentProvider(string code, ISourceMapper mapper)
{
ContractUtils.RequiresNotNull(code, "code");
_code = code;
_mapper = mapper;
}
public override SourceCodeReader GetReader() {
return new VBScriptSourceCodeReader(new StringReader(_code), null, _mapper);
}
}
}

View file

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Text;
using AspClassic.Scripting;
namespace Dlrsoft.VBScript.Compiler
{
public class VBScriptSyntaxError
{
public VBScriptSyntaxError(string fileName, SourceSpan span, int errCode, string errorDesc)
{
this.FileName = fileName;
this.Span = span;
this.ErrorCode = errCode;
this.ErrorDescription = errorDesc;
}
public string FileName { get; set; }
public SourceSpan Span { get; set; }
public int ErrorCode { get; set; }
public string ErrorDescription { get; set; }
}
}