public Return (Expression expr, Location l)
{
+ expr = Parser.SetValueRequiredFlag (expr);
Expr = expr;
loc = l;
}
if (ec.CurrentBranching.InTryBlock ())
ec.CurrentBranching.AddFinallyVector (vector);
- vector.Returns = FlowReturns.ALWAYS;
- vector.Breaks = FlowReturns.ALWAYS;
+ if (! ec.InTry && ! ec.InCatch) {
+ vector.Returns = FlowReturns.ALWAYS;
+ vector.Breaks = FlowReturns.ALWAYS;
+ }
return true;
}
public class LabeledStatement : Statement {
public readonly Location Location;
- //string label_name;
+ string label_name;
bool defined;
bool referenced;
Label label;
public LabeledStatement (string label_name, Location l)
{
- //this.label_name = label_name;
+ this.label_name = label_name;
this.Location = l;
}
+
+ public string LabelName {
+ get {
+ return label_name;
+ }
+ }
public Label LabelTarget (EmitContext ec)
{
}
if (ec.InTry || ec.InCatch) {
- if (!ec.HasReturnLabel) {
- ec.ReturnLabel = ec.ig.DefineLabel ();
- ec.HasReturnLabel = true;
- }
- ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel);
+ if (ec.HasExitLabel)
+ ec.ig.Emit (OpCodes.Leave, ec.ExitLabel);
} else {
if(type == ExitType.SUB) {
ec.ig.Emit (OpCodes.Ret);
public Expression Type;
public LocalBuilder LocalBuilder;
public Type VariableType;
+ public string Alias;
+ FieldBase FieldAlias;
public readonly string Name;
public readonly Location Location;
public readonly int Block;
-
+
public int Number;
public bool Used;
public bool Assigned;
public bool ReadOnly;
+ public VariableInfo (Expression type, string name, int block, Location l, string Alias)
+ : this (type, name, block, l)
+ {
+ this.Alias = Alias;
+ }
+
public VariableInfo (Expression type, string name, int block, Location l)
{
Type = type;
Location = l;
}
+ public VariableInfo (TypeContainer tc, int block, Location l, string Alias)
+ : this (tc, block, l)
+ {
+ this.Alias = Alias;
+ }
+
public VariableInfo (TypeContainer tc, int block, Location l)
{
VariableType = tc.TypeBuilder;
return false;
}
}
-*/
- return true;
- }
-
- public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
- {
- if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsVariableAssigned (this) ||
- (struct_info == null))
- return true;
-
- int field_idx = StructInfo [name];
- if (field_idx == 0)
- return true;
-
- if (!ec.CurrentBranching.IsVariableAssigned (this, field_idx)) {
- Report.Error (170, loc,
- "Use of possibly unassigned field '" + name + "'");
- ec.CurrentBranching.SetVariableAssigned (this, field_idx);
- return false;
- }
-
- return true;
- }
-
- public void SetAssigned (EmitContext ec)
- {
- if (ec.DoFlowAnalysis)
- ec.CurrentBranching.SetVariableAssigned (this);
- }
-
- public void SetFieldAssigned (EmitContext ec, string name)
- {
- if (ec.DoFlowAnalysis && (struct_info != null))
- ec.CurrentBranching.SetVariableAssigned (this, StructInfo [name]);
- }
-
- public bool Resolve (DeclSpace decl)
- {
- if (struct_info != null)
- return true;
-
- if (VariableType == null)
- VariableType = decl.ResolveType (Type, false, Location);
-
- if (VariableType == null)
- return false;
-
- struct_info = MyStructInfo.GetStructInfo (VariableType);
-
- return true;
- }
-
- public void MakePinned ()
- {
- TypeManager.MakePinned (LocalBuilder);
- }
-
- public override string ToString ()
- {
- return "VariableInfo (" + Number + "," + Type + "," + Location + ")";
- }
- }
-
- /// <summary>
- /// Block represents a C# block.
- /// </summary>
- ///
- /// <remarks>
- /// This class is used in a number of places: either to represent
- /// explicit blocks that the programmer places or implicit blocks.
- ///
- /// Implicit blocks are used as labels or to introduce variable
- /// declarations.
- /// </remarks>
- public class Block : Statement {
- public readonly Block Parent;
- public readonly bool Implicit;
- public readonly Location StartLocation;
- public Location EndLocation;
-
- //
- // The statements in this block
- //
- public ArrayList statements;
-
- //
- // An array of Blocks. We keep track of children just
- // to generate the local variable declarations.
- //
- // Statements and child statements are handled through the
- // statements.
- //
- ArrayList children;
-
- //
- // Labels. (label, block) pairs.
- //
- CaseInsensitiveHashtable labels;
-
- //
- // Keeps track of (name, type) pairs
- //
- CaseInsensitiveHashtable variables;
-
- //
- // Keeps track of constants
- CaseInsensitiveHashtable constants;
-
- //
- // Maps variable names to ILGenerator.LocalBuilders
- //
- //CaseInsensitiveHashtable local_builders;
-
- // to hold names of variables required for late binding
- public const string lateBindingArgs = "1_LBArgs";
- public const string lateBindingArgNames = "1_LBArgsNames";
- public const string lateBindingCopyBack = "1_LBCopyBack";
-
- bool isLateBindingRequired = false;
-
- bool used = false;
-
- static int id;
-
- int this_id;
-
- public Block (Block parent)
- : this (parent, false, Location.Null, Location.Null)
- { }
-
- public Block (Block parent, bool implicit_block)
- : this (parent, implicit_block, Location.Null, Location.Null)
- { }
-
- public Block (Block parent, bool implicit_block, Parameters parameters)
- : this (parent, implicit_block, parameters, Location.Null, Location.Null)
- { }
-
- public Block (Block parent, Location start, Location end)
- : this (parent, false, start, end)
- { }
-
- public Block (Block parent, Parameters parameters, Location start, Location end)
- : this (parent, false, parameters, start, end)
- { }
-
- public Block (Block parent, bool implicit_block, Location start, Location end)
- : this (parent, implicit_block, Parameters.EmptyReadOnlyParameters,
- start, end)
- { }
-
- public Block (Block parent, bool implicit_block, Parameters parameters,
- Location start, Location end)
- {
- if (parent != null)
- parent.AddChild (this);
- else {
- // Top block
- // Add variables that may be required for late binding
- variables = new CaseInsensitiveHashtable ();
- ArrayList rank_specifier = new ArrayList ();
- ArrayList element = new ArrayList ();
- element.Add (new EmptyExpression ());
- rank_specifier.Add (element);
- Expression e = Mono.MonoBASIC.Parser.DecomposeQI ("System.Object[]", start);
- AddVariable (e, Block.lateBindingArgs, null, start);
- e = Mono.MonoBASIC.Parser.DecomposeQI ("System.String[]", start);
- AddVariable (e, Block.lateBindingArgNames, null, start);
- e = Mono.MonoBASIC.Parser.DecomposeQI ("System.Boolean[]", start);
- AddVariable (e, Block.lateBindingCopyBack, null, start);
- }
-
- this.Parent = parent;
- this.Implicit = implicit_block;
- this.parameters = parameters;
- this.StartLocation = start;
- this.EndLocation = end;
- this.loc = start;
- this_id = id++;
- statements = new ArrayList ();
- }
-
- public bool IsLateBindingRequired {
- get {
- return isLateBindingRequired;
- }
- set {
- isLateBindingRequired = value;
- }
- }
-
- public int ID {
- get {
- return this_id;
- }
- }
-
- void AddChild (Block b)
- {
- if (children == null)
- children = new ArrayList ();
-
- children.Add (b);
- }
-
- public void SetEndLocation (Location loc)
- {
- EndLocation = loc;
- }
-
- /// <summary>
- /// Adds a label to the current block.
- /// </summary>
- ///
- /// <returns>
- /// false if the name already exists in this block. true
- /// otherwise.
- /// </returns>
- ///
-/**
- public bool AddLabel (string name, LabeledStatement target)
- {
- if (labels == null)
- labels = new CaseInsensitiveHashtable ();
- if (labels.Contains (name))
- return false;
-
- labels.Add (name, target);
- return true;
- }
-**/
-
-
- public bool AddLabel (string name, LabeledStatement target, Location loc)
- {
-/**
- if (switch_block != null)
- return switch_block.AddLabel (name, target, loc);
-**/
- Block cur = this;
- while (cur != null) {
-
- if (cur.DoLookupLabel (name) != null) {
- Report.Error (
- 140, loc, "The label '" + name +"' is a duplicate");
- return false;
- }
-
- if (!Implicit)
- break;
-
- cur = cur.Parent;
- }
-
- while (cur != null) {
- if (cur.DoLookupLabel (name) != null) {
- Report.Error (
- 158, loc,
- "The label '"+ name +"' shadows another label " +
- "by the same name in a containing scope.");
- return false;
- }
-
- if (children != null) {
- foreach (Block b in children) {
- LabeledStatement s = b.DoLookupLabel (name);
- if (s == null)
- continue;
- Report.Error (
- 158, s.Location,
- "The label '"+ name +"' shadows another " +
- "label by the same name in a " +
- "containing scope.");
- return false;
- }
- }
- cur = cur.Parent;
- }
- if (labels == null)
- labels = new CaseInsensitiveHashtable ();
- if (labels.Contains (name))
- return false;
-
- labels.Add (name, target);
- return true;
-
- }
-
- public LabeledStatement LookupLabel (string name)
- {
- Block cur = this;
- LabeledStatement s = DoLookupLabel (name);
- if (s != null) {
- return s;
-}
- if (children == null)
- return null;
-
- foreach (Block child in children) {
- if (!child.Implicit)
- continue;
-
- s = child.LookupLabel (name);
- if (s != null) {
- cur = child;
- return s;
-}
- }
-
- return null;
- }
-
- public LabeledStatement DoLookupLabel (string name)
- {
- if (labels != null){
- if (labels.Contains (name))
- return ((LabeledStatement) labels [name]);
- }
-/**
- if (Parent != null)
- return Parent.LookupLabel (name);
-**/
- return null;
- }
-
- VariableInfo this_variable = null;
-
- // <summary>
- // Returns the "this" instance variable of this block.
- // See AddThisVariable() for more information.
- // </summary>
- public VariableInfo ThisVariable {
- get {
- if (this_variable != null)
- return this_variable;
- else if (Parent != null)
- return Parent.ThisVariable;
- else
- return null;
- }
- }
-
- Hashtable child_variable_names;
-
- // <summary>
- // Marks a variable with name @name as being used in a child block.
- // If a variable name has been used in a child block, it's illegal to
- // declare a variable with the same name in the current block.
- // </summary>
- public void AddChildVariableName (string name)
- {
- if (child_variable_names == null)
- child_variable_names = new CaseInsensitiveHashtable ();
-
- if (!child_variable_names.Contains (name))
- child_variable_names.Add (name, true);
- }
-
- // <summary>
- // Marks all variables from block @block and all its children as being
- // used in a child block.
- // </summary>
- public void AddChildVariableNames (Block block)
- {
- if (block.Variables != null) {
- foreach (string name in block.Variables.Keys)
- AddChildVariableName (name);
- }
-
- foreach (Block child in block.children) {
- if (child.Variables != null) {
- foreach (string name in child.Variables.Keys)
- AddChildVariableName (name);
- }
- }
- }
-
- // <summary>
- // Checks whether a variable name has already been used in a child block.
- // </summary>
- public bool IsVariableNameUsedInChildBlock (string name)
- {
- if (child_variable_names == null)
- return false;
-
- return child_variable_names.Contains (name);
- }
-
- // <summary>
- // This is used by non-static 'struct' constructors which do not have an
- // initializer - in this case, the constructor must initialize all of the
- // struct's fields. To do this, we add a "this" variable and use the flow
- // analysis code to ensure that it's been fully initialized before control
- // leaves the constructor.
- // </summary>
- public VariableInfo AddThisVariable (TypeContainer tc, Location l)
- {
- if (this_variable != null)
- return this_variable;
-
- this_variable = new VariableInfo (tc, ID, l);
-
- if (variables == null)
- variables = new CaseInsensitiveHashtable ();
- variables.Add ("this", this_variable);
-
- return this_variable;
- }
-
- public VariableInfo AddVariable (EmitContext ec, Expression type, string name, Location l)
- {
- if (!variables_initialized)
- throw new InvalidOperationException();
-
- VariableInfo vi = AddVariable(type, name, null, loc);
-
- int priorCount = count_variables;
- DeclSpace ds = ec.DeclSpace;
-
- if (!vi.Resolve (ds)) {
- vi.Number = -1;
- } else {
- vi.Number = ++count_variables;
- if (vi.StructInfo != null)
- count_variables += vi.StructInfo.Count;
- }
- if (priorCount < count_variables)
- ec.CurrentBranching.CurrentUsageVector.AddExtraLocals(count_variables - priorCount);
-
- return vi;
- }
-
- public VariableInfo AddVariable (Expression type, string name, Parameters pars, Location l)
- {
- if (variables == null)
- variables = new CaseInsensitiveHashtable ();
-
- VariableInfo vi = GetVariableInfo (name);
- if (vi != null) {
- if (vi.Block != ID)
- Report.Error (30616, l, "A local variable named '" + name + "' " +
- "cannot be declared in this scope since it would " +
- "give a different meaning to '" + name + "', which " +
- "is already used in a 'parent or current' scope to " +
- "denote something else");
- else
- Report.Error (30290, l, "A local variable '" + name + "' is already " +
- "defined in this scope");
- return null;
- }
-
- if (IsVariableNameUsedInChildBlock (name)) {
- Report.Error (136, l, "A local variable named '" + name + "' " +
- "cannot be declared in this scope since it would " +
- "give a different meaning to '" + name + "', which " +
- "is already used in a 'child' scope to denote something " +
- "else");
- return null;
- }
-
- if (pars != null) {
- int idx = 0;
- Parameter p = pars.GetParameterByName (name, out idx);
- if (p != null) {
- Report.Error (30616, l, "A local variable named '" + name + "' " +
- "cannot be declared in this scope since it would " +
- "give a different meaning to '" + name + "', which " +
- "is already used in a 'parent or current' scope to " +
- "denote something else");
- return null;
- }
- }
-
- vi = new VariableInfo (type, name, ID, l);
-
- variables.Add (name, vi);
-
- return vi;
- }
-
- public bool AddConstant (Expression type, string name, Expression value, Parameters pars, Location l)
- {
- if (AddVariable (type, name, pars, l) == null)
- return false;
-
- if (constants == null)
- constants = new CaseInsensitiveHashtable ();
-
- constants.Add (name, value);
- return true;
- }
-
- public Hashtable Variables {
- get {
- return variables;
- }
- }
-
- public VariableInfo GetVariableInfo (string name)
- {
- if (variables != null) {
- object temp;
- temp = variables [name];
-
- if (temp != null){
- return (VariableInfo) temp;
- }
- }
-
- if (Parent != null)
- return Parent.GetVariableInfo (name);
-
- return null;
- }
-
- public Expression GetVariableType (string name)
- {
- VariableInfo vi = GetVariableInfo (name);
-
- if (vi != null)
- return vi.Type;
-
- return null;
- }
-
- public Expression GetConstantExpression (string name)
- {
- if (constants != null) {
- object temp;
- temp = constants [name];
-
- if (temp != null)
- return (Expression) temp;
- }
-
- if (Parent != null)
- return Parent.GetConstantExpression (name);
-
- return null;
- }
-
- /// <summary>
- /// True if the variable named @name has been defined
- /// in this block
- /// </summary>
- public bool IsVariableDefined (string name)
- {
- // Console.WriteLine ("Looking up {0} in {1}", name, ID);
- if (variables != null) {
- if (variables.Contains (name))
- return true;
- }
-
- if (Parent != null)
- return Parent.IsVariableDefined (name);
-
- return false;
- }
-
- /// <summary>
- /// True if the variable named @name is a constant
- /// </summary>
- public bool IsConstant (string name)
- {
- Expression e = null;
-
- e = GetConstantExpression (name);
-
- return e != null;
- }
-
- /// <summary>
- /// Use to fetch the statement associated with this label
- /// </summary>
- public Statement this [string name] {
- get {
- return (Statement) labels [name];
- }
- }
-
- Parameters parameters = null;
- public Parameters Parameters {
- get {
- if (Parent != null)
- return Parent.Parameters;
-
- return parameters;
- }
- }
-
- /// <returns>
- /// A list of labels that were not used within this block
- /// </returns>
- public string [] GetUnreferenced ()
- {
- // FIXME: Implement me
- return null;
- }
-
- public void AddStatement (Statement s)
- {
- statements.Add (s);
- used = true;
- }
-
- public bool Used {
- get {
- return used;
- }
- }
-
- public void Use ()
- {
- used = true;
- }
-
- bool variables_initialized = false;
- int count_variables = 0, first_variable = 0;
-
- void UpdateVariableInfo (EmitContext ec)
- {
- DeclSpace ds = ec.DeclSpace;
-
- first_variable = 0;
-
- if (Parent != null)
- first_variable += Parent.CountVariables;
-
- count_variables = first_variable;
- if (variables != null) {
- foreach (VariableInfo vi in variables.Values) {
- if (!vi.Resolve (ds)) {
- vi.Number = -1;
- continue;
- }
-
- vi.Number = ++count_variables;
-
- if (vi.StructInfo != null)
- count_variables += vi.StructInfo.Count;
- }
- }
-
- variables_initialized = true;
- }
-
- //
- // <returns>
- // The number of local variables in this block
- // </returns>
- public int CountVariables
- {
- get {
- if (!variables_initialized)
- throw new Exception ();
-
- return count_variables;
- }
- }
-
- /// <summary>
- /// Emits the variable declarations and labels.
- /// </summary>
- /// <remarks>
- /// tc: is our typecontainer (to resolve type references)
- /// ig: is the code generator:
- /// toplevel: the toplevel block. This is used for checking
- /// that no two labels with the same name are used.
- /// </remarks>
- public void EmitMeta (EmitContext ec, Block toplevel)
- {
- //DeclSpace ds = ec.DeclSpace;
- ILGenerator ig = ec.ig;
-
- if (!variables_initialized)
- UpdateVariableInfo (ec);
-
- //
- // Process this block variables
- //
- if (variables != null){
- //local_builders = new CaseInsensitiveHashtable ();
-
- foreach (DictionaryEntry de in variables){
- string name = (string) de.Key;
- /*
- if (!isLateBindingRequired) {
- if (name.Equals (Block.lateBindingArgs) ||
- name.Equals (Block.lateBindingArgNames) ||
- name.Equals (Block.lateBindingCopyBack))
- continue;
- }
- */
- VariableInfo vi = (VariableInfo) de.Value;
-
- if (vi.VariableType == null)
- continue;
-
- vi.LocalBuilder = ig.DeclareLocal (vi.VariableType);
-
- if (CodeGen.SymbolWriter != null)
- vi.LocalBuilder.SetLocalSymInfo (name);
-
- if (constants == null)
- continue;
-
- Expression cv = (Expression) constants [name];
- if (cv == null)
- continue;
-
- Expression e = cv.Resolve (ec);
- if (e == null)
- continue;
-
- if (!(e is Constant)){
- Report.Error (133, vi.Location,
- "The expression being assigned to '" +
- name + "' must be constant (" + e + ")");
- continue;
- }
-
- constants.Remove (name);
- constants.Add (name, e);
- }
- }
-
- //
- // Now, handle the children
- //
- if (children != null){
- foreach (Block b in children)
- b.EmitMeta (ec, toplevel);
- }
- }
-
- public void UsageWarning ()
- {
- string name;
-
- if (variables != null){
- foreach (DictionaryEntry de in variables){
- VariableInfo vi = (VariableInfo) de.Value;
-
- if (vi.Used)
- continue;
-
- name = (string) de.Key;
-
- if (vi.Assigned){
- Report.Warning (
- 219, vi.Location, "The variable '" + name +
- "' is assigned but its value is never used");
- } else {
- Report.Warning (
- 168, vi.Location, "The variable '" +
- name +
- "' is declared but never used");
- }
- }
- }
-
- if (children != null)
- foreach (Block b in children)
- b.UsageWarning ();
+*/
+ return true;
}
- bool has_ret = false;
-
- public override bool Resolve (EmitContext ec)
+ public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
{
- Block prev_block = ec.CurrentBlock;
- bool ok = true;
+ if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsVariableAssigned (this) ||
+ (struct_info == null))
+ return true;
- ec.CurrentBlock = this;
+ int field_idx = StructInfo [name];
+ if (field_idx == 0)
+ return true;
- if (!variables_initialized)
- UpdateVariableInfo (ec);
-
- ec.StartFlowBranching (this);
+ if (!ec.CurrentBranching.IsVariableAssigned (this, field_idx)) {
+ Report.Error (170, loc,
+ "Use of possibly unassigned field '" + name + "'");
+ ec.CurrentBranching.SetVariableAssigned (this, field_idx);
+ return false;
+ }
- Report.Debug (1, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
+ return true;
+ }
- ArrayList new_statements = new ArrayList ();
- bool unreachable = false, warning_shown = false;
+ public void SetAssigned (EmitContext ec)
+ {
+ if (ec.DoFlowAnalysis)
+ ec.CurrentBranching.SetVariableAssigned (this);
+ }
- foreach (Statement s in statements){
+ public void SetFieldAssigned (EmitContext ec, string name)
+ {
+ if (ec.DoFlowAnalysis && (struct_info != null))
+ ec.CurrentBranching.SetVariableAssigned (this, StructInfo [name]);
+ }
- if (unreachable && !(s is LabeledStatement)) {
- if (!warning_shown && !(s is EmptyStatement)) {
- warning_shown = true;
- Warning_DeadCodeFound (s.loc);
+ public FieldBase GetFieldAlias (EmitContext ec) {
+ if ( this.FieldAlias != null )
+ return this.FieldAlias;
+ else
+ {
+ ArrayList fields = ec.TypeContainer.Fields;
+ for (int i = 0; i < fields.Count; i++)
+ {
+ if (((Field) fields[i]).Name == this.Alias)
+ {
+ this.FieldAlias = (Field) fields[i];
+ break;
}
- continue;
- }
-
- if (s.Resolve (ec) == false) {
- ok = false;
- continue;
- }
-
- if (s is LabeledStatement)
- unreachable = false;
- else
- unreachable = ! ec.CurrentBranching.IsReachable ();
-
- new_statements.Add (s);
- }
-
- statements = new_statements;
-
- Report.Debug (1, "RESOLVE BLOCK DONE", StartLocation, ec.CurrentBranching);
-
- FlowReturns returns = ec.EndFlowBranching ();
- ec.CurrentBlock = prev_block;
+ }
+ return this.FieldAlias;
+ }
+ }
+
+ public bool Resolve (DeclSpace decl)
+ {
+ if (struct_info != null)
+ return true;
- // If we're a non-static 'struct' constructor which doesn't have an
- // initializer, then we must initialize all of the struct's fields.
- if ((this_variable != null) && (returns != FlowReturns.EXCEPTION) &&
- !this_variable.IsAssigned (ec, loc))
- ok = false;
+ if (VariableType == null)
+ VariableType = decl.ResolveType (Type, false, Location);
- if ((labels != null) && (RootContext.WarningLevel >= 2)) {
- foreach (LabeledStatement label in labels.Values)
- if (!label.HasBeenReferenced)
- Report.Warning (164, label.Location,
- "This label has not been referenced");
- }
+ if (VariableType == null)
+ return false;
- if ((returns == FlowReturns.ALWAYS) ||
- (returns == FlowReturns.EXCEPTION) ||
- (returns == FlowReturns.UNREACHABLE))
- has_ret = true;
+ struct_info = MyStructInfo.GetStructInfo (VariableType);
- return ok;
+ return true;
}
-
- protected override bool DoEmit (EmitContext ec)
- {
- Block prev_block = ec.CurrentBlock;
-
- ec.CurrentBlock = this;
- ec.Mark (StartLocation);
- foreach (Statement s in statements)
- s.Emit (ec);
-
- ec.Mark (EndLocation);
-
- ec.CurrentBlock = prev_block;
- return has_ret;
+ public void MakePinned ()
+ {
+ TypeManager.MakePinned (LocalBuilder);
}
-
- public override string ToString ()
- {
- return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation);
- }
+ public override string ToString ()
+ {
+ return "VariableInfo (" + Number + "," + Type + "," + Location + ")";
+ }
}
+
public class StatementSequence : Expression {
Block stmtBlock;
ArrayList args, originalArgs;
bool isIndexerAccess;
string memberName;
Expression type_expr;
+ bool is_resolved = false;
public StatementSequence (Block parent, Location loc, Expression expr)
: this (parent, loc, expr, null)
public override Expression DoResolve (EmitContext ec)
{
+ if (is_resolved)
+ return this;
if (!stmtBlock.Resolve (ec))
return null;
eclass = ExprClass.Value;
type = TypeManager.object_type;
+ is_resolved = true;
return this;
}
protected override bool DoEmit (EmitContext ec)
{
ILGenerator ig = ec.ig;
- Label finish = ig.DefineLabel ();;
bool returns;
ec.TryCatchLevel++;
- ig.BeginExceptionBlock ();
+ Label finish = ig.BeginExceptionBlock ();
+ ec.HasExitLabel = true;
+ ec.ExitLabel = finish;
+
bool old_in_try = ec.InTry;
ec.InTry = true;
returns = Block.Emit (ec);
ec.InCatch = old_in_catch;
- ig.MarkLabel (finish);
if (Fini != null){
ig.BeginFinallyBlock ();
bool old_in_finally = ec.InFinally;
if (!returns || ec.InTry || ec.InCatch)
return returns;
+ return true;
+ }
+ }
+
+ public class Pending_Assign {
+ Statement assign;
+ Block block_to_be_inserted;
+ int statement_index;
+
+ public Pending_Assign (Block block, Statement assign, int index)
+ {
+ this.assign = assign;
+ this.block_to_be_inserted = block;
+ this.statement_index = index;
+ }
+
+ public void AddAssign()
+ {
+ block_to_be_inserted.statements.Insert( statement_index, assign );
+ }
+ }
+
+ public class On_Error : Statement {
+ public readonly Block method_block;
+ ArrayList targets;
+ LabeledStatement[] labeledstatements;
+
+ public On_Error (Block method_block, Location l)
+ {
+ //Goto
+ this.method_block = method_block;
+ base.loc = l;
+ targets = new ArrayList();
+ }
+
+ public int AddTarget ( string target )
+ {
+ int i = targets.IndexOf( target ) ;
+
+ if ( i == -1 )
+ return targets.Add ( target );
+ else
+ return i;
+ }
+
+ public ArrayList Targets {
+ get {
+ return targets;
+ }
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ this.labeledstatements = new LabeledStatement[targets.Count];
+
+ bool ok = true;
+
+ ec.StartFlowBranching (FlowBranchingType.EXCEPTION, method_block.StartLocation);
+
+ Report.Debug (1, "START OF TRY BLOCK", method_block.StartLocation);
+
+ bool old_in_try = ec.InTry;
+ ec.InTry = true;
+
+ if (!method_block.Resolve (ec))
+ ok = false;
+
+ ec.InTry = old_in_try;
+
+ FlowBranching.UsageVector vector = ec.CurrentBranching.CurrentUsageVector;
+
+ ec.EndFlowBranching ();
+
+ ec.CurrentBranching.CurrentUsageVector.Or (vector);
+
+ Report.Debug (1, "END OF TRY", ec.CurrentBranching);
+
+ //This statement has more than one label in cases of more than one 'on error goto' specification.
+ for ( int i = 0 ; i < targets.Count ; i++ )
+ {
+ labeledstatements[i] = method_block.Parent.LookupLabel ((string) targets[i]);
+
+ // If this is a forward goto.
+ if (!labeledstatements[i].IsDefined)
+ labeledstatements[i].AddUsageVector (ec.CurrentBranching.CurrentUsageVector);
+
+ labeledstatements[i].AddReference ();
+ }
+ ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
+
+ return ok;
+ }
+ protected override bool DoEmit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ //Try
+
+ bool returns;
+
+ ec.TryCatchLevel++;
+
+ Label finish = ig.BeginExceptionBlock ();
+ ec.HasExitLabel = true;
+ ec.ExitLabel = finish;
+
+ bool old_in_try = ec.InTry;
+ ec.InTry = true;
+ returns = method_block.Emit (ec);
+ ec.InTry = old_in_try;
+ bool old_in_catch = ec.InCatch;
+ ec.InCatch = true;
+
+ Label error = ig.DefineLabel();
+ Label endfilter = ig.DefineLabel();
+ Label verification = ig.DefineLabel();
+
+ ig.BeginExceptFilterBlock();
+ ig.Emit (OpCodes.Isinst, Type.GetType("System.Exception") );
+ ig.Emit (OpCodes.Brtrue_S, verification );
+
+ ig.Emit (OpCodes.Br_S, error);
+
+ ig.MarkLabel ( verification );
+ ig.Emit (OpCodes.Ldloc_0);
+ ig.Emit (OpCodes.Brfalse_S, error);
+
+ ig.Emit (OpCodes.Ldloc_1);
+ ig.Emit (OpCodes.Brtrue_S, error);
+
+ ig.Emit (OpCodes.Ldc_I4_1);
+ ig.Emit (OpCodes.Br_S, endfilter);
+
+ ig.MarkLabel (error);
+ ig.Emit (OpCodes.Ldc_I4_0);
+
+ ig.MarkLabel ( endfilter );
+
+
+ Label endcatch = ig.DefineLabel();
+ Label verification2 = ig.DefineLabel();
+
+ ig.BeginCatchBlock (null);
+ ig.Emit (OpCodes.Castclass, Type.GetType("System.Exception"));
+ ig.Emit (OpCodes.Dup);
+
+ Type t = typeof(Microsoft.VisualBasic.CompilerServices.ProjectData);
+ MethodInfo mi = t.GetMethod("SetProjectError", new Type[] { typeof(System.Exception) } );
+ ig.Emit (OpCodes.Call, mi);
+ ig.Emit (OpCodes.Stloc_3);
+ ig.Emit (OpCodes.Ldloc_1);
+ ig.Emit (OpCodes.Brfalse_S, verification2 );
+ ig.Emit (OpCodes.Leave_S, finish );
+ ig.MarkLabel ( verification2 );
+ ig.Emit (OpCodes.Ldc_I4_M1);
+ ig.Emit (OpCodes.Stloc_1);
+ ig.Emit (OpCodes.Ldloc_0);
+
+ Label[] lbswitch = new Label[targets.Count + 1];
+ for ( int i = 0; i <= targets.Count; i++ )
+ lbswitch[i] = ig.DefineLabel();
+
+ ig.Emit (OpCodes.Switch, lbswitch);
+ ig.MarkLabel ( lbswitch[0] ) ;
+ ig.Emit (OpCodes.Leave_S, endcatch);
+
+ Label[] labels = new Label[targets.Count];
+ for ( int i = 0; i < targets.Count; i++ )
+ {
+ labels[i] = labeledstatements[i].LabelTarget(ec);
+
+ ig.MarkLabel ( lbswitch[i+1] ) ;
+ ig.Emit ( OpCodes.Leave, labels[i] );
+ }
+
+ ig.MarkLabel ( endcatch );
+ ig.Emit ( OpCodes.Rethrow );
+
+ ec.InCatch = old_in_catch;
+
+ ig.EndExceptionBlock ();
+ ec.TryCatchLevel--;
+
+ Label end = ig.DefineLabel();
+ //ig.MarkLabel ( finish ) ;
+ ig.Emit (OpCodes.Ldloc_1);
+ ig.Emit (OpCodes.Brfalse_S, end );
+
+ mi = t.GetMethod("ClearProjectError");
+ ig.Emit (OpCodes.Call, mi);
+
+ ig.MarkLabel(end) ;
+
+ if (!returns)
+ return returns;
+
// Unfortunately, System.Reflection.Emit automatically emits a leave
// to the end of the finally block. This is a problem if 'returns'
// is true since we may jump to a point after the end of the method.
return true;
}
+
}
public class Using : Statement {
if (expr == null)
return false;
+ if ( variable.VariableInfo.Alias != null )
+ {
+ FieldBase fb = variable.VariableInfo.GetFieldAlias(ec);
+
+ if ( fb == null )
+ {
+ Report.Error (451, loc,"Name '" + variable.VariableInfo.Name + "' is not declared.");
+ return false;
+ }
+ else
+ type = fb.Type;
+ }
+
var_type = ec.DeclSpace.ResolveType (type, false, loc);
if (var_type == null)
return false;
ig.Emit (OpCodes.Ldloc, enumerator);
ig.Emit (OpCodes.Callvirt, hm.move_next);
ig.Emit (OpCodes.Brfalse, end_try);
+
+
+ FieldBase fb = null;
+ if ( variable.VariableInfo.Alias != null )
+ {
+ fb = variable.VariableInfo.GetFieldAlias(ec);
+
+ if( (fb.ModFlags & Modifiers.STATIC) == 0 )
+ ig.Emit (OpCodes.Ldarg_0);
+ }
+
ig.Emit (OpCodes.Ldloc, enumerator);
ig.Emit (OpCodes.Callvirt, hm.get_current);
- variable.EmitAssign (ec, conv);
+
+ if ( fb == null)
+ variable.EmitAssign (ec, conv);
+ else
+ variable.EmitAssign (ec, conv, fb);
+
statement.Emit (ec);
ig.Emit (OpCodes.Br, ec.LoopBegin);
ig.MarkLabel (end_try);
loop = ig.DefineLabel ();
ig.MarkLabel (loop);
+ FieldBase fb = null;
+ if ( variable.VariableInfo.Alias != null )
+ {
+ fb = variable.VariableInfo.GetFieldAlias(ec);
+
+ if( (fb.ModFlags & Modifiers.STATIC) == 0 )
+ ig.Emit (OpCodes.Ldarg_0);
+ }
+
ig.Emit (OpCodes.Ldloc, copy);
ig.Emit (OpCodes.Ldloc, counter);
ArrayAccess.EmitLoadOpcode (ig, var_type);
- variable.EmitAssign (ec, conv);
+ if ( fb == null)
+ variable.EmitAssign (ec, conv);
+ else
+ variable.EmitAssign (ec, conv, fb);
statement.Emit (ec);
public AddHandler (Expression evt_id, Expression evt_handler, Location l)
{
EvtId = evt_id;
- EvtHandler = evt_handler;
+ EvtHandler = Parser.SetAddressOf (evt_handler);
loc = l;
resolved = false;
//Console.WriteLine ("Adding handler '" + evt_handler + "' for Event '" + evt_id +"'");
public RemoveHandler (Expression evt_id, Expression evt_handler, Location l)
{
EvtId = evt_id;
- EvtHandler = evt_handler;
+ EvtHandler = Parser.SetAddressOf (evt_handler);
loc = l;
}
}
public class RedimClause {
- public Expression Expr;
- public ArrayList NewIndexes;
+ private Expression RedimTarget;
+ private ArrayList NewIndexes;
+ private Expression AsType;
- public RedimClause (Expression e, ArrayList args)
+ private LocalTemporary localTmp = null;
+ private Expression origRedimTarget = null;
+ private StatementExpression ReDimExpr;
+
+ public RedimClause (Expression e, ArrayList args, Expression e_as)
{
- Expr = e;
+ if (e is SimpleName)
+ ((SimpleName) e).IsInvocation = false;
+ if (e is MemberAccess)
+ ((MemberAccess) e).IsInvocation = false;
+
+ RedimTarget = e;
+ NewIndexes = args;
+ AsType = e_as;
+ }
+
+ public bool Resolve (EmitContext ec, bool Preserve, Location loc)
+ {
+ RedimTarget = RedimTarget.Resolve (ec);
+
+ if (AsType != null) {
+ Report.Error (30811, loc, "'ReDim' statements can no longer be used to declare array variables");
+ return false;
+ }
+
+ if (!RedimTarget.Type.IsArray) {
+ Report.Error (49, loc, "'ReDim' statement requires an array");
+ return false;
+ }
+
+ ArrayList args = new ArrayList();
+ foreach (Argument a in NewIndexes) {
+ if (a.Resolve(ec, loc))
+ args.Add (a.Expr);
+ }
+
+ for (int x = 0; x < args.Count; x++) {
+ args[x] = new Binary (Binary.Operator.Addition,
+ (Expression) args[x], new IntLiteral (1), Location.Null);
+ }
+
NewIndexes = args;
+ if (RedimTarget.Type.GetArrayRank() != NewIndexes.Count) {
+ Report.Error (30415, loc, "'ReDim' cannot change the number of dimensions of an array.");
+ return false;
+ }
+
+ Type BaseType = RedimTarget.Type.GetElementType();
+ Expression BaseTypeExpr = MonoBASIC.Parser.DecomposeQI(BaseType.FullName.ToString(), Location.Null);
+ ArrayCreation acExpr = new ArrayCreation (BaseTypeExpr, NewIndexes, "", null, Location.Null);
+ if (Preserve)
+ {
+ ExpressionStatement PreserveExpr = null;
+ if (RedimTarget is PropertyGroupExpr) {
+ localTmp = new LocalTemporary (ec, RedimTarget.Type);
+ PropertyGroupExpr pe = RedimTarget as PropertyGroupExpr;
+ origRedimTarget = new PropertyGroupExpr (pe.Properties, pe.Arguments, pe.InstanceExpression, loc);
+ if ((origRedimTarget = origRedimTarget.Resolve (ec)) == null) {
+ Report.Error (-1, loc, "'ReDim' vs PropertyGroup");
+ return false;
+ }
+ PreserveExpr = (ExpressionStatement) new Preserve(localTmp, acExpr, loc);
+ } else
+ PreserveExpr = (ExpressionStatement) new Preserve(RedimTarget, acExpr, loc);
+ ReDimExpr = (StatementExpression) new StatementExpression ((ExpressionStatement) new Assign (RedimTarget, PreserveExpr, loc), loc);
+ }
+ else
+ ReDimExpr = (StatementExpression) new StatementExpression ((ExpressionStatement) new Assign (RedimTarget, acExpr, loc), loc);
+ ReDimExpr.Resolve(ec);
+ return true;
}
+
+ public void DoEmit (EmitContext ec)
+ {
+ if (ReDimExpr == null)
+ return;
+
+ if (localTmp != null && origRedimTarget != null) {
+ origRedimTarget.Emit (ec);
+ localTmp.Store (ec);
+ }
+ ReDimExpr.Emit(ec);
+ }
+
}
public class ReDim : Statement {
ArrayList RedimTargets;
- Type BaseType;
bool Preserve;
- private StatementExpression ReDimExpr;
-
public ReDim (ArrayList targets, bool opt_preserve, Location l)
{
loc = l;
public override bool Resolve (EmitContext ec)
{
- Expression RedimTarget;
- ArrayList NewIndexes;
-
- foreach (RedimClause rc in RedimTargets) {
- RedimTarget = rc.Expr;
- NewIndexes = rc.NewIndexes;
-
- RedimTarget = RedimTarget.Resolve (ec);
- if (!RedimTarget.Type.IsArray)
- Report.Error (49, "'ReDim' statement requires an array");
-
- ArrayList args = new ArrayList();
- foreach (Argument a in NewIndexes) {
- if (a.Resolve(ec, loc))
- args.Add (a.Expr);
- }
-
- for (int x = 0; x < args.Count; x++) {
- args[x] = new Binary (Binary.Operator.Addition,
- (Expression) args[x], new IntLiteral (1), Location.Null);
- }
-
- NewIndexes = args;
- if (RedimTarget.Type.GetArrayRank() != args.Count)
- Report.Error (30415, "'ReDim' cannot change the number of dimensions of an array.");
-
- BaseType = RedimTarget.Type.GetElementType();
- Expression BaseTypeExpr = MonoBASIC.Parser.DecomposeQI(BaseType.FullName.ToString(), Location.Null);
- ArrayCreation acExpr = new ArrayCreation (BaseTypeExpr, NewIndexes, "", null, Location.Null);
- // TODO: we are in a foreach we probably can't reuse ReDimExpr, must turn it into an array(list)
- if (Preserve)
- {
- ExpressionStatement PreserveExpr = (ExpressionStatement) new Preserve(RedimTarget, acExpr, loc);
- ReDimExpr = (StatementExpression) new StatementExpression ((ExpressionStatement) new Assign (RedimTarget, PreserveExpr, loc), loc);
- }
- else
- ReDimExpr = (StatementExpression) new StatementExpression ((ExpressionStatement) new Assign (RedimTarget, acExpr, loc), loc);
- ReDimExpr.Resolve(ec);
- }
- return true;
+ bool result = true;
+ foreach (RedimClause rc in RedimTargets)
+ result = rc.Resolve(ec, Preserve, loc) && result;
+ return result;
}
protected override bool DoEmit (EmitContext ec)
{
- ReDimExpr.Emit(ec);
+ foreach (RedimClause rc in RedimTargets)
+ rc.DoEmit(ec);
return false;
}