/// Encapsulates the emission of a boolean test and jumping to a
/// destination.
///
- /// This will emit the bool expression in `bool_expr' and if
- /// `target_is_for_true' is true, then the code will generate a
+ /// This will emit the bool expression in 'bool_expr' and if
+ /// 'target_is_for_true' is true, then the code will generate a
/// brtrue to the target. Otherwise a brfalse.
/// </remarks>
public static void EmitBoolExpression (EmitContext ec, Expression bool_expr,
ig.Emit (OpCodes.Br, ec.LoopBegin);
//
- // Inform that we are infinite (ie, `we return'), only
- // if we do not `break' inside the code.
+ // Inform that we are infinite (ie, 'we return'), only
+ // if we do not 'break' inside the code.
//
ret = may_return == false;
ig.MarkLabel (ec.LoopEnd);
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;
}
}
} else {
if (Expr == null){
- Report.Error (126, loc, "An object of type `" +
+ Report.Error (126, loc, "An object of type '" +
TypeManager.MonoBASIC_Name (ec.ReturnType) + "' is " +
"expected for the return statement");
return true;
public override bool Resolve (EmitContext ec)
{
label = block.LookupLabel (target);
+
if (label == null){
Report.Error (
30132, loc,
- "No such label `" + target + "' in this scope");
+ "No such label '" + target + "' in this scope");
return false;
}
if (!label.IsDefined)
label.AddUsageVector (ec.CurrentBranching.CurrentUsageVector);
- ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
-
+ ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
+ label.AddReference ();
return true;
}
protected override bool DoEmit (EmitContext ec)
{
Label l = label.LabelTarget (ec);
- ec.ig.Emit (OpCodes.Br, l);
+ if (ec.InTry || ec.InCatch)
+ ec.ig.Emit (OpCodes.Leave, l);
+ else
+ ec.ig.Emit (OpCodes.Br, l);
return false;
}
this.label_name = label_name;
this.Location = l;
}
+
+ public string LabelName {
+ get {
+ return label_name;
+ }
+ }
public Label LabelTarget (EmitContext ec)
{
- if (defined)
+ if (defined)
return label;
label = ec.ig.DefineLabel ();
+
defined = true;
return label;
vectors = new ArrayList ();
vectors.Add (vector.Clone ());
+
}
public override bool Resolve (EmitContext ec)
{
- if (vectors != null)
+ if (vectors != null) {
ec.CurrentBranching.CurrentUsageVector.MergeJumpOrigins (vectors);
+ }
else {
ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.NEVER;
ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.NEVER;
referenced = true;
+
return true;
}
return false;
}
+ public void AddReference ()
+ {
+ referenced = true;
+ }
}
/// <summary>
- /// `goto default' statement
+ /// 'goto default' statement
/// </summary>
public class GotoDefault : Statement {
}
/// <summary>
- /// `goto case' statement
+ /// 'goto case' statement
/// </summary>
public class GotoCase : Statement {
Expression expr;
}
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 {
- ec.ig.Emit (OpCodes.Ldloc_0);
- ec.ig.Emit (OpCodes.Ret);
+ if(type == ExitType.SUB) {
+ ec.ig.Emit (OpCodes.Ret);
+ } else {
+ ec.ig.Emit (OpCodes.Ldloc_0);
+ ec.ig.Emit (OpCodes.Ret);
+ }
}
// current one.
// </summary>
public class MyBitVector {
- public readonly int Count;
+ private int count;
+ public int Count { get { return count; } }
public readonly MyBitVector InheritsFrom;
bool is_dirty;
public MyBitVector (MyBitVector InheritsFrom, int Count)
{
this.InheritsFrom = InheritsFrom;
- this.Count = Count;
+ this.count = Count;
}
// <summary>
}
// <summary>
- // Get/set bit `index' in the bit vector.
+ // Get/set bit 'index' in the bit vector.
// </summary>
public bool this [int index]
{
get {
- if (index > Count)
+ if (index > count)
throw new ArgumentOutOfRangeException ();
// We're doing a "copy-on-write" strategy here; as long
}
set {
- if (index > Count)
+ if (index > count)
throw new ArgumentOutOfRangeException ();
// Only copy the vector if we're actually modifying it.
}
// <summary>
- // Performs an `or' operation on the bit vector. The `new_vector' may have a
+ // Performs an 'or' operation on the bit vector. The 'new_vector' may have a
// different size than the current one.
// </summary>
public void Or (MyBitVector new_vector)
}
// <summary>
- // Perfonrms an `and' operation on the bit vector. The `new_vector' may have
+ // Perfonrms an 'and' operation on the bit vector. The 'new_vector' may have
// a different size than the current one.
// </summary>
public void And (MyBitVector new_vector)
return retval;
}
+
+ public void ExpandBy(int howMany)
+ {
+ if (howMany < 1)
+ throw new ArgumentException("howMany");
+ initialize_vector();
+ count = vector.Count + howMany;
+ BitArray newVector = new BitArray(count, false);
+ for (int i = 0; i < vector.Count; i++)
+ newVector [i] = vector [i];
+ vector = newVector;
+ }
BitArray Vector {
get {
int id;
// <summary>
- // Performs an `And' operation on the FlowReturns status
+ // Performs an 'And' operation on the FlowReturns status
// (for instance, a block only returns ALWAYS if all its siblings
// always return).
// </summary>
// The number of locals in this block.
// </summary>
public readonly int CountLocals;
+
+ // <summary>
+ // The number of locals in this block added after starting usage track.
+ // </summary>
+ public int ExtraLocals { get { return locals.Count - CountLocals; } }
+
// <summary>
// If not null, then we inherit our state from this vector and do a
: this (parent, parent.CountParameters, parent.CountLocals)
{ }
+ public void AddExtraLocals(int howMany)
+ {
+ locals.ExpandBy(howMany);
+ }
+
// <summary>
// This does a deep copy of the usage vector.
// </summary>
}
//
- // State of parameter `number'.
+ // State of parameter 'number'.
//
public bool this [int number]
{
}
//
- // State of the local variable `vi'.
- // If the local variable is a struct, use a non-zero `field_idx'
+ // State of the local variable 'vi'.
+ // If the local variable is a struct, use a non-zero 'field_idx'
// to check an individual field in it.
//
public bool this [VariableInfo vi, int field_idx]
if (!child.is_finally) {
if (child.Breaks != FlowReturns.UNREACHABLE) {
// If Returns is already set, perform an
- // `And' operation on it, otherwise just set just.
+ // 'And' operation on it, otherwise just set just.
if (!new_returns_set) {
new_returns = child.Returns;
new_returns_set = true;
}
// If Breaks is already set, perform an
- // `And' operation on it, otherwise just set just.
+ // 'And' operation on it, otherwise just set just.
if (!new_breaks_set) {
new_breaks = child.Breaks;
new_breaks_set = true;
// 6 Console.WriteLine (a);
//
// The if block in lines 3-4 always returns, so we must not look
- // at the initialization of `a' in line 4 - thus it'll still be
+ // at the initialization of 'a' in line 4 - thus it'll still be
// uninitialized in line 6.
//
// On the other hand, the following is allowed:
// 5 return;
// 6 Console.WriteLine (a);
//
- // Here, `a' is initialized in line 3 and we must not look at
+ // Here, 'a' is initialized in line 3 and we must not look at
// line 5 since it always returns.
//
if (child.is_finally) {
new_locals.Or (child.locals);
}
- // An `out' parameter must be assigned in all branches which do
+ // An 'out' parameter must be assigned in all branches which do
// not always throw an exception.
if (parameters != null) {
if (child.Breaks != FlowReturns.EXCEPTION) {
// <summary>
// Tells control flow analysis that the current code position may be reached with
- // a forward jump from any of the origins listed in `origin_vectors' which is a
+ // a forward jump from any of the origins listed in 'origin_vectors' which is a
// list of UsageVectors.
//
// This is used when resolving forward gotos - in the following example, the
- // variable `a' is uninitialized in line 8 becase this line may be reached via
+ // variable 'a' is uninitialized in line 8 becase this line may be reached via
// the goto in line 4:
//
// 1 int a;
Report.Debug (1, "MERGING FINALLY ORIGIN DONE", this);
}
// <summary>
- // Performs an `or' operation on the locals and the parameters.
+ // Performs an 'or' operation on the locals and the parameters.
// </summary>
public void Or (UsageVector new_vector)
{
}
// <summary>
- // Performs an `and' operation on the locals.
+ // Performs an 'and' operation on the locals.
// </summary>
public void AndLocals (UsageVector new_vector)
{
}
// <summary>
- // Creates a new flow branching for `block'.
+ // Creates a new flow branching for 'block'.
// This is used from Block.Resolve to create the top-level branching of
// the block.
// </summary>
num_params = 0;
for (int i = 0; i < count; i++) {
- Parameter.Modifier mod = param_info.ParameterModifier (i);
+ //Parameter.Modifier mod = param_info.ParameterModifier (i);
// if ((mod & Parameter.Modifier.OUT) == 0)
// continue;
}
// <summary>
- // Creates a new flow branching which is contained in `parent'.
- // You should only pass non-null for the `block' argument if this block
+ // Creates a new flow branching which is contained in 'parent'.
+ // You should only pass non-null for the 'block' argument if this block
// introduces any new variables - in this case, we need to create a new
// usage vector with a different size than our parent's one.
// </summary>
}
// <summary>
- // Creates a sibling for a `finally' block.
+ // Creates a sibling for a 'finally' block.
// </summary>
public void CreateSiblingForFinally ()
{
case FlowBranchingType.LOOP_BLOCK:
// The code following a loop is reachable unless the loop always
- // returns or it's an infinite loop without any `break's in it.
+ // returns or it's an infinite loop without any 'break's in it.
reachable = !CurrentUsageVector.AlwaysReturns &&
(CurrentUsageVector.Breaks != FlowReturns.UNREACHABLE);
break;
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;
MyStructInfo struct_info = StructInfo;
if ((struct_info == null) || (struct_info.HasNonPublicFields && (Name != null))) {
- Report.Error (165, loc, "Use of unassigned local variable `" + Name + "'");
+ Report.Error (165, loc, "Use of unassigned local variable '" + Name + "'");
ec.CurrentBranching.SetVariableAssigned (this);
return false;
}
if (!ec.CurrentBranching.IsVariableAssigned (this, i+1)) {
if (Name != null) {
Report.Error (165, loc,
- "Use of unassigned local variable `" +
+ "Use of unassigned local variable '" +
Name + "'");
ec.CurrentBranching.SetVariableAssigned (this);
return false;
FieldInfo field = struct_info [i];
Report.Error (171, loc,
- "Field `" + TypeManager.MonoBASIC_Name (VariableType) +
+ "Field '" + TypeManager.MonoBASIC_Name (VariableType) +
"." + field.Name + "' must be fully initialized " +
"before control leaves the constructor");
return false;
if (!ec.CurrentBranching.IsVariableAssigned (this, field_idx)) {
Report.Error (170, loc,
- "Use of possibly unassigned field `" + name + "'");
+ "Use of possibly unassigned field '" + name + "'");
ec.CurrentBranching.SetVariableAssigned (this, field_idx);
return false;
}
ec.CurrentBranching.SetVariableAssigned (this, StructInfo [name]);
}
+ 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;
+ }
+ }
+ return this.FieldAlias;
+ }
+ }
+
public bool Resolve (DeclSpace decl)
{
if (struct_info != null)
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 LabeledStatement LookupLabel (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 (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);
-
- if (variables_initialized)
- throw new Exception ();
-
- // Console.WriteLine ("Adding {0} to {1}", name, ID);
- 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 ();
- }
-
- bool has_ret = false;
-
- public override bool Resolve (EmitContext ec)
- {
- Block prev_block = ec.CurrentBlock;
- bool ok = true;
-
- ec.CurrentBlock = this;
-
- if (!variables_initialized)
- UpdateVariableInfo (ec);
-
- ec.StartFlowBranching (this);
-
- Report.Debug (1, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
-
- ArrayList new_statements = new ArrayList ();
- bool unreachable = false, warning_shown = false;
-
- foreach (Statement s in statements){
- if (unreachable && !(s is LabeledStatement)) {
- if (!warning_shown && !(s is EmptyStatement)) {
- warning_shown = true;
- Warning_DeadCodeFound (s.loc);
- }
- 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;
-
- // 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 ((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 ((returns == FlowReturns.ALWAYS) ||
- (returns == FlowReturns.EXCEPTION) ||
- (returns == FlowReturns.UNREACHABLE))
- has_ret = true;
-
- return ok;
- }
-
- 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 class StatementSequence : Expression {
Block stmtBlock;
ArrayList args, originalArgs;
Expression expr;
bool isRetValRequired;
bool isLeftHandSide;
+ 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 StatementSequence (Block parent, Location loc, Expression expr, string name,
+ Expression type_expr, ArrayList a, bool isRetValRequired,
+ bool isLeftHandSide)
+ : this (parent, loc, expr, a)
+ {
+ this.memberName = name;
+ this.type_expr = type_expr;
+ this.isRetValRequired = isRetValRequired;
+ this.isLeftHandSide = isLeftHandSide;
+ }
+
public StatementSequence (Block parent, Location loc, Expression expr, ArrayList a,
bool isRetValRequired, bool isLeftHandSide)
: this (parent, loc, expr, a)
{
this.isRetValRequired = isRetValRequired;
this.isLeftHandSide = isLeftHandSide;
+ if (expr is MemberAccess) {
+ this.expr = ((MemberAccess)expr).Expr;
+ this.memberName = ((MemberAccess)expr).Identifier;
+ this.isIndexerAccess = false;
+ } else if (expr is IndexerAccess) {
+ this.expr = ((IndexerAccess) expr).Instance;
+ this.memberName = "";
+ this.isIndexerAccess = true;
+ }
}
public StatementSequence (Block parent, Location loc, Expression expr, ArrayList a)
stmtBlock.IsLateBindingRequired = true;
this.loc = loc;
this.isRetValRequired = this.isLeftHandSide = false;
+ this.memberName = "";
+ this.type_expr = null;
}
public ArrayList Arguments {
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;
}
stmtBlock.AddStatement (new StatementExpression ((ExpressionStatement) assign_stmt, loc));
}
- Expression tempExpr = expr;
- string memName = "";
- bool isIndexerAccess = true;
- if (expr is MemberAccess) {
- tempExpr = ((MemberAccess)expr).Expr;
- memName = ((MemberAccess)expr).Identifier;
- isIndexerAccess = false;
- } else if (expr is IndexerAccess) {
- tempExpr = ((IndexerAccess) expr).Instance;
- }
+ //string memName = "";
+ //bool isIndexerAccess = true;
ArrayList invocationArgs = new ArrayList ();
- if (isIndexerAccess) {
- invocationArgs.Add (new Argument (tempExpr, Argument.AType.Expression));
+ if (isIndexerAccess || memberName == "") {
+ invocationArgs.Add (new Argument (expr, Argument.AType.Expression));
invocationArgs.Add (new Argument (v1, Argument.AType.Expression));
invocationArgs.Add (new Argument (NullLiteral.Null, Argument.AType.Expression));
Expression tmp = null;
stmtBlock.AddStatement (new StatementExpression ((ExpressionStatement) invStmt, loc));
return;
}
- invocationArgs.Add (new Argument (tempExpr, Argument.AType.Expression));
- invocationArgs.Add (new Argument (NullLiteral.Null, Argument.AType.Expression));
- invocationArgs.Add (new Argument (new StringLiteral (memName), Argument.AType.Expression));
+
+ if (expr != null)
+ invocationArgs.Add (new Argument (expr, Argument.AType.Expression));
+ else
+ invocationArgs.Add (new Argument (NullLiteral.Null, Argument.AType.Expression));
+ if (type_expr != null)
+ invocationArgs.Add (new Argument (type_expr, Argument.AType.Expression));
+ else
+ invocationArgs.Add (new Argument (NullLiteral.Null, Argument.AType.Expression));
+ invocationArgs.Add (new Argument (new StringLiteral (memberName), Argument.AType.Expression));
invocationArgs.Add (new Argument (v1, Argument.AType.Expression));
if (ArgumentNames != null && ArgumentNames.Count > 0)
invocationArgs.Add (new Argument (v2, Argument.AType.Expression));
bool isCopyBackRequired = false;
if (!isLeftHandSide) {
for (int i = 0; i < argCount; i++) {
- Argument origArg = (Argument) originalArgs [i];
+ Argument origArg = (Argument) Arguments [i];
Expression origExpr = origArg.Expr;
if (!(origExpr is Constant || origArg.ArgType == Argument.AType.NoArg))
isCopyBackRequired = true;
rank_specifier.Add (new IntLiteral (argCount));
arrayInitializers = new ArrayList ();
for (int i = 0; i < argCount; i++) {
- Argument a = (Argument) originalArgs [i];
+ Argument a = (Argument) Arguments [i];
Expression origExpr = a.Expr;
if (origExpr is Constant || a.ArgType == Argument.AType.NoArg || origExpr is New)
arrayInitializers.Add (new BoolLiteral (false));
inv_stmt.IsLateBinding = true;
stmtBlock.AddStatement (new StatementExpression ((ExpressionStatement) inv_stmt, loc));
- for (int i = 0; i< argCount; i ++) {
+ if (! isCopyBackRequired)
+ return;
+
+ for (int i = argCount - 1; i >= 0; i --) {
Argument arg = (Argument) originalArgs [i];
Expression origExpr = (Expression) arg.Expr;
if (arg.ArgType == Argument.AType.NoArg)
public override void Emit (EmitContext ec)
{
stmtBlock.Emit (ec);
- //ec.ig.Emit (OpCodes.Ldloc_0);
}
}
public class SwitchLabel {
- Expression label;
- object converted;
+ public enum LabelType : byte {
+ Operator, Range, Label, Else
+ }
+
+ Expression label, start, end;
+ LabelType label_type;
+ Expression label_condition, start_condition, end_condition;
+ Binary.Operator oper;
public Location loc;
public Label ILLabel;
public Label ILLabelCode;
//
// if expr == null, then it is the default case.
//
- public SwitchLabel (Expression expr, Location l)
+ public SwitchLabel (Expression start, Expression end, LabelType ltype, Binary.Operator oper, Location l) {
+ this.start = start;
+ this.end = end;
+ this.label_type = ltype;
+ this.oper = oper;
+ this.loc = l;
+ label_condition = start_condition = end_condition = null;
+ }
+
+ public SwitchLabel (Expression expr, LabelType ltype, Binary.Operator oper, Location l)
{
label = expr;
+ start = end = null;
+ label_condition = start_condition = end_condition = null;
loc = l;
+ this.label_type = ltype;
+ this.oper = oper;
}
public Expression Label {
}
}
- public object Converted {
+ public LabelType Type {
+ get {
+ return label_type;
+ }
+ }
+
+ public Expression ConditionStart {
+ get {
+ return start_condition;
+ }
+ }
+
+ public Expression ConditionEnd {
+ get {
+ return end_condition;
+ }
+ }
+
+ public Expression ConditionLabel {
get {
- return converted;
+ return label_condition;
}
}
// Resolves the expression, reduces it to a literal if possible
// and then converts it to the requested type.
//
- public bool ResolveAndReduce (EmitContext ec, Type required_type)
+ public bool ResolveAndReduce (EmitContext ec, Expression expr)
{
ILLabel = ec.ig.DefineLabel ();
ILLabelCode = ec.ig.DefineLabel ();
- if (label == null)
+ Expression e = null;
+ switch (label_type) {
+ case LabelType.Label :
+ if (label == null)
+ return false;
+ e = label.Resolve (ec);
+ if (e != null)
+ e = Expression.ConvertImplicit (ec, e, expr.Type, loc);
+ if (e == null)
+ return false;
+ label_condition = new Binary (Binary.Operator.Equality, expr, e, loc);
+ if ((label_condition = label_condition.DoResolve (ec)) == null)
+ return false;
+ return true;
+ case LabelType.Operator :
+ e = label.Resolve (ec);
+ label_condition = new Binary (oper, expr, e, loc);
+ if ((label_condition = label_condition.DoResolve (ec)) == null)
+ return false;
+ return true;
+ case LabelType.Range :
+ if (start == null || end == null)
+ return false;
+ e = start.Resolve (ec);
+ if (e != null)
+ e = Expression.ConvertImplicit (ec, e, expr.Type, loc);
+ if (e == null)
+ return false;
+ start_condition = new Binary (Binary.Operator.GreaterThanOrEqual, expr, e, loc);
+ start_condition = start_condition.Resolve (ec);
+ e = end.Resolve (ec);
+ if (e != null)
+ e = Expression.ConvertImplicit (ec, e, expr.Type, loc);
+ if (e == null)
+ return false;
+ end_condition = new Binary (Binary.Operator.LessThanOrEqual, expr, e, loc);
+ end_condition = end_condition.Resolve (ec);
+ if (start_condition == null || end_condition == null)
+ return false;
return true;
-
- Expression e = label.Resolve (ec);
-
- if (e == null)
- return false;
-
- if (!(e is Constant)){
- Console.WriteLine ("Value is: " + label);
- Report.Error (150, loc, "A constant value is expected");
- return false;
- }
- if (e is StringConstant || e is NullLiteral){
- if (required_type == TypeManager.string_type){
- converted = e;
- ILLabel = ec.ig.DefineLabel ();
- return true;
- }
+ case LabelType.Else :
+ break;
}
-
- converted = Expression.ConvertIntLiteral ((Constant) e, required_type, loc);
- if (converted == null)
- return false;
-
return true;
}
}
// The types allowed to be implicitly cast from
// on the governing type
//
- static Type [] allowed_types;
+ //static Type [] allowed_types;
public Switch (Expression e, ArrayList sects, Location l)
{
//
Expression SwitchGoverningType (EmitContext ec, Type t)
{
- if (t == TypeManager.int32_type ||
- t == TypeManager.uint32_type ||
- t == TypeManager.char_type ||
- t == TypeManager.byte_type ||
- t == TypeManager.sbyte_type ||
- t == TypeManager.ushort_type ||
+ if (t == TypeManager.byte_type ||
t == TypeManager.short_type ||
- t == TypeManager.uint64_type ||
+ t == TypeManager.int32_type ||
t == TypeManager.int64_type ||
+ t == TypeManager.decimal_type ||
+ t == TypeManager.float_type ||
+ t == TypeManager.double_type ||
+ t == TypeManager.date_type ||
+ t == TypeManager.char_type ||
+ t == TypeManager.object_type ||
t == TypeManager.string_type ||
t == TypeManager.bool_type ||
t.IsSubclassOf (TypeManager.enum_type))
return Expr;
-
+/*
if (allowed_types == null){
allowed_types = new Type [] {
TypeManager.sbyte_type,
if (converted != null){
Report.Error (-12, loc, "More than one conversion to an integral " +
- " type exists for type `" +
+ " type exists for type '" +
TypeManager.MonoBASIC_Name (Expr.Type)+"'");
return null;
} else
converted = e;
}
return converted;
+*/
+ return null;
}
void error152 (string n)
{
Report.Error (
- 152, "The label `" + n + ":' " +
+ 152, "The label '" + n + ":' " +
"is already present on this switch statement");
}
//
bool CheckSwitch (EmitContext ec)
{
- Type compare_type;
+ //Type compare_type;
bool error = false;
Elements = new CaseInsensitiveHashtable ();
got_default = false;
+/*
if (TypeManager.IsEnumType (SwitchType)){
compare_type = TypeManager.EnumToUnderlying (SwitchType);
} else
compare_type = SwitchType;
+*/
- foreach (SwitchSection ss in Sections){
- foreach (SwitchLabel sl in ss.Labels){
- if (!sl.ResolveAndReduce (ec, SwitchType)){
+ for (int secIndex = 0; secIndex < Sections.Count; secIndex ++) {
+ SwitchSection ss = (SwitchSection) Sections [secIndex];
+ for (int labelIndex = 0; labelIndex < ss.Labels.Count; labelIndex ++) {
+ SwitchLabel sl = (SwitchLabel) ss.Labels [labelIndex];
+ if (!sl.ResolveAndReduce (ec, Expr)){
error = true;
continue;
}
- if (sl.Label == null){
+ if (sl.Type == SwitchLabel.LabelType.Else){
if (got_default){
error152 ("default");
error = true;
got_default = true;
continue;
}
-
- object key = sl.Converted;
-
- if (key is Constant)
- key = ((Constant) key).GetValue ();
-
- if (key == null)
- key = NullLiteral.Null;
-
- string lname = null;
- if (compare_type == TypeManager.uint64_type){
- ulong v = (ulong) key;
-
- if (Elements.Contains (v))
- lname = v.ToString ();
- else
- Elements.Add (v, sl);
- } else if (compare_type == TypeManager.int64_type){
- long v = (long) key;
-
- if (Elements.Contains (v))
- lname = v.ToString ();
- else
- Elements.Add (v, sl);
- } else if (compare_type == TypeManager.uint32_type){
- uint v = (uint) key;
-
- if (Elements.Contains (v))
- lname = v.ToString ();
- else
- Elements.Add (v, sl);
- } else if (compare_type == TypeManager.char_type){
- char v = (char) key;
-
- if (Elements.Contains (v))
- lname = v.ToString ();
- else
- Elements.Add (v, sl);
- } else if (compare_type == TypeManager.byte_type){
- byte v = (byte) key;
-
- if (Elements.Contains (v))
- lname = v.ToString ();
- else
- Elements.Add (v, sl);
- } else if (compare_type == TypeManager.sbyte_type){
- sbyte v = (sbyte) key;
-
- if (Elements.Contains (v))
- lname = v.ToString ();
- else
- Elements.Add (v, sl);
- } else if (compare_type == TypeManager.short_type){
- short v = (short) key;
-
- if (Elements.Contains (v))
- lname = v.ToString ();
- else
- Elements.Add (v, sl);
- } else if (compare_type == TypeManager.ushort_type){
- ushort v = (ushort) key;
-
- if (Elements.Contains (v))
- lname = v.ToString ();
- else
- Elements.Add (v, sl);
- } else if (compare_type == TypeManager.string_type){
- if (key is NullLiteral){
- if (Elements.Contains (NullLiteral.Null))
- lname = "null";
- else
- Elements.Add (NullLiteral.Null, null);
- } else {
- string s = (string) key;
-
- if (Elements.Contains (s))
- lname = s;
- else
- Elements.Add (s, sl);
- }
- } else if (compare_type == TypeManager.int32_type) {
- int v = (int) key;
-
- if (Elements.Contains (v))
- lname = v.ToString ();
- else
- Elements.Add (v, sl);
- } else if (compare_type == TypeManager.bool_type) {
- bool v = (bool) key;
-
- if (Elements.Contains (v))
- lname = v.ToString ();
- else
- Elements.Add (v, sl);
- }
- else
- {
- throw new Exception ("Unknown switch type!" +
- SwitchType + " " + compare_type);
- }
-
- if (lname != null){
- error152 ("case + " + lname);
- error = true;
- }
}
}
if (error)
}
}
+/*
/// <summary>
/// This method emits code for a lookup-based switch statement (non-string)
/// Basically it groups the cases into blocks that are at least half full,
}
//
// This simple emit switch works, but does not take advantage of the
- // `switch' opcode.
+ // 'switch' opcode.
// TODO: remove non-string logic from here
// TODO: binary search strings?
//
return all_return;
}
+*/
public override bool Resolve (EmitContext ec)
{
new_expr = SwitchGoverningType (ec, Expr.Type);
if (new_expr == null){
- Report.Error (151, loc, "An integer type or string was expected for switch");
+ Report.Error (30338, loc, "'Select' expression cannot be of type '" + Expr.Type +"'");
return false;
}
protected override bool DoEmit (EmitContext ec)
{
- // Store variable for comparission purposes
- LocalBuilder value = ec.ig.DeclareLocal (SwitchType);
- new_expr.Emit (ec);
- ec.ig.Emit (OpCodes.Stloc, value);
-
ILGenerator ig = ec.ig;
-
- default_target = ig.DefineLabel ();
-
//
// Setup the codegen context
//
ec.LoopEnd = ig.DefineLabel ();
ec.Switch = this;
- // Emit Code.
- bool all_return;
- if (SwitchType == TypeManager.string_type)
- all_return = SimpleSwitchEmit (ec, value);
- else
- all_return = TableSwitchEmit (ec, value);
+ for (int secIndex = 0; secIndex < Sections.Count; secIndex ++) {
+ SwitchSection section = (SwitchSection) Sections [secIndex];
+ Label sLabel = ig.DefineLabel ();
+ Label lLabel = ig.DefineLabel ();
+ ArrayList Labels = section.Labels;
+ for (int labelIndex = 0; labelIndex < Labels.Count; labelIndex ++) {
+ SwitchLabel sl = (SwitchLabel) Labels [labelIndex];
+ switch (sl.Type) {
+ case SwitchLabel.LabelType.Range :
+ if (labelIndex + 1 == Labels.Count) {
+ EmitBoolExpression (ec, sl.ConditionStart, sLabel, false);
+ EmitBoolExpression (ec, sl.ConditionEnd, sLabel, false);
+ ig.Emit (OpCodes.Br, lLabel);
+ } else {
+ Label newLabel = ig.DefineLabel ();
+ EmitBoolExpression (ec, sl.ConditionStart, newLabel, false);
+ EmitBoolExpression (ec, sl.ConditionEnd, newLabel, false);
+ ig.Emit (OpCodes.Br, lLabel);
+ ig.MarkLabel (newLabel);
+ }
+ break;
+ case SwitchLabel.LabelType.Else :
+ // Nothing to be done here
+ break;
+ case SwitchLabel.LabelType.Operator :
+ EmitBoolExpression (ec, sl.ConditionLabel, lLabel, true);
+ if (labelIndex + 1 == Labels.Count)
+ ig.Emit (OpCodes.Br, sLabel);
+ break;
+ case SwitchLabel.LabelType.Label :
+ EmitBoolExpression (ec, sl.ConditionLabel, lLabel, true);
+ if (labelIndex + 1 == Labels.Count)
+ ig.Emit (OpCodes.Br, sLabel);
+ break;
+ }
+
+ }
+ ig.MarkLabel (lLabel);
+ section.Block.Emit (ec);
+ ig.MarkLabel (sLabel);
+ }
// Restore context state.
ig.MarkLabel (ec.LoopEnd);
//
ec.LoopEnd = old_end;
ec.Switch = old_switch;
-
- return all_return;
+ return true;
}
}
if (type.IsValueType){
Report.Error (30582, loc, "lock statement requires the expression to be " +
- " a reference type (type is: `" +
+ " a reference type (type is: '" +
TypeManager.MonoBASIC_Name (type) + "'");
return false;
}
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'
+ // 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.
// As a workaround, emit an explicit ret here.
return true;
}
+
}
public class Using : Statement {
}
/// <summary>
- /// Implementation of the foreach C# statement
+ /// Implementation of the for each statement
/// </summary>
public class Foreach : Statement {
Expression type;
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;
return false;
//FlowReturns returns = ec.EndFlowBranching ();
-
+ ec.EndFlowBranching ();
return true;
}
//
- // Retrieves a `public bool MoveNext ()' method from the Type `t'
+ // Retrieves a 'public bool MoveNext ()' method from the Type 't'
//
static MethodInfo FetchMethodMoveNext (Type t)
{
}
//
- // Retrieves a `public T get_Current ()' method from the Type `t'
+ // Retrieves a 'public T get_Current ()' method from the Type 't'
//
static MethodInfo FetchMethodGetCurrent (Type t)
{
//
// Ok, we can access it, now make sure that we can do something
- // with this `GetEnumerator'
+ // with this 'GetEnumerator'
//
if (mi.ReturnType == TypeManager.ienumerator_type ||
void error1579 (Type t)
{
Report.Error (1579, loc,
- "foreach statement cannot operate on variables of type `" +
+ "foreach statement cannot operate on variables of type '" +
t.FullName + "' because that class does not provide a " +
" GetEnumerator method or it is inaccessible");
}
//
// FIXME: possible optimization.
- // We might be able to avoid creating `empty' if the type is the sam
+ // We might be able to avoid creating 'empty' if the type is the sam
//
bool EmitCollectionForeach (EmitContext ec)
{
//
bool old_in_try = ec.InTry;
- if (hm.is_disposable)
+ if (hm.is_disposable) {
+ ig.BeginExceptionBlock ();
ec.InTry = true;
+ }
Label end_try = ig.DefineLabel ();
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);
//
// FIXME: possible optimization.
- // We might be able to avoid creating `empty' if the type is the sam
+ // We might be able to avoid creating 'empty' if the type is the sam
//
bool EmitArrayForeach (EmitContext ec)
{
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);
ig.Emit (OpCodes.Ldloc, dim_count [dim]);
//
- // FIXME: Maybe we can cache the computation of `get'?
+ // FIXME: Maybe we can cache the computation of 'get'?
//
Type [] args = new Type [rank];
MethodInfo get;
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;
}