aspclassic-core/AspClassic.VBScript/Compiler/AnalysisScope.cs
Jelle Luteijn 484dbfc9d9 progress
2022-05-15 11:19:49 +02:00

295 lines
No EOL
8.5 KiB
C#

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}
}