[Mono-list] break, continue implemented.
Miguel de Icaza
miguel@ximian.com
Tue, 16 Oct 2001 00:48:30 -0400
Hey guys,
Tonight as I was taking a rest from watching TV (as I got sick over
the weekend) I hacked break/continue support into the compiler, which
means that we are not just missing throw and goto to be done with the
jump statements.
Comes with nice test suite.
Miguel.
Index: mcs/ChangeLog
===================================================================
RCS file: /cvs/public/mcs/mcs/ChangeLog,v
retrieving revision 1.134
diff -u -r1.134 ChangeLog
--- mcs/ChangeLog 2001/10/15 00:03:43 1.134
+++ mcs/ChangeLog 2001/10/16 00:50:46
@@ -1,3 +1,18 @@
+2001-10-15 Miguel de Icaza <miguel@ximian.com>
+
+ * statement.cs (Break::Emit): Implement.
+ (Continue::Emit): Implement.
+
+ (For::Emit): Track old being/end loops; Set Begin loop, ack end loop
+ (While::Emit): Track old being/end loops; Set Begin loop, ack end loop
+ (Do::Emit): Track old being/end loops; Set Begin loop, ack end loop
+ (Foreach::Emit): Track old being/end loops; Set Begin loop, ack
+ end loop
+
+ * codegen.cs (EmitContext::LoopEnd, EmitContext::LoopBegin): New
+ properties that track the label for the current loop (begin of the
+ loop and end of the loop).
+
2001-10-14 Miguel de Icaza <miguel@ximian.com>
* expression.cs: LocalTemporary: a new expression used to
Index: mcs/codegen.cs
===================================================================
RCS file: /cvs/public/mcs/mcs/codegen.cs,v
retrieving revision 1.35
diff -u -r1.35 codegen.cs
--- mcs/codegen.cs 2001/10/12 14:18:21 1.35
+++ mcs/codegen.cs 2001/10/16 00:50:46
@@ -108,7 +108,7 @@
// value on structure method invocations)
// </summary>
public Hashtable temporary_storage;
-
+
public EmitContext (TypeContainer parent, ILGenerator ig, Type return_type,
int code_flags, bool is_constructor)
{
@@ -170,5 +170,15 @@
return location;
}
+
+ //
+ // Current loop begin and end labels.
+ //
+ public Label LoopBegin, LoopEnd;
+
+ //
+ // Whether we are inside a loop and break/continue are possible.
+ //
+ public bool InLoop;
}
}
Index: mcs/cs-parser.jay
===================================================================
RCS file: /cvs/public/mcs/mcs/cs-parser.jay,v
retrieving revision 1.65
diff -u -r1.65 cs-parser.jay
--- mcs/cs-parser.jay 2001/10/12 14:18:21 1.65
+++ mcs/cs-parser.jay 2001/10/16 00:50:56
@@ -2654,14 +2654,14 @@
break_statement
: BREAK SEMICOLON
{
- $$ = new Break ();
+ $$ = new Break (lexer.Location);
}
;
continue_statement
: CONTINUE SEMICOLON
{
- $$ = new Continue ();
+ $$ = new Continue (lexer.Location);
}
;
Index: mcs/expression.cs
===================================================================
RCS file: /cvs/public/mcs/mcs/expression.cs,v
retrieving revision 1.84
diff -u -r1.84 expression.cs
--- mcs/expression.cs 2001/10/15 00:03:43 1.84
+++ mcs/expression.cs 2001/10/16 00:51:16
@@ -1969,10 +1969,17 @@
//
throw new Exception ("Implement me");
} else if (expr.ExprClass == ExprClass.PropertyAccess){
- //
- // FIXME: Verify that we have both get and set methods
- //
- throw new Exception ("Implement me");
+ PropertyExpr pe = (PropertyExpr) expr;
+
+ bool a, b;
+
+ a = pe.VerifyReadable ();
+ b = pe.VerifyAssignable ();
+ type = expr_type;
+
+ if (a && b)
+ return this;
+ return null;
} else {
report118 (loc, expr, "variable, indexer or property access");
}
@@ -2007,7 +2014,8 @@
{
ILGenerator ig = ec.ig;
Type expr_type = expr.Type;
-
+ ExprClass eclass;
+
if (method != null) {
// Note that operators are static anyway
@@ -2091,7 +2099,8 @@
case Operator.PostIncrement:
case Operator.PostDecrement:
- if (expr.ExprClass == ExprClass.Variable){
+ eclass = expr.ExprClass;
+ if (eclass == ExprClass.Variable){
//
// Resolve already verified that it is an "incrementable"
//
@@ -2104,8 +2113,12 @@
else
ig.Emit (OpCodes.Add);
((LValue) expr).Store (ec);
+ } else if (eclass == ExprClass.PropertyAccess){
+ throw new Exception ("Handle Properties here");
+ } else if (eclass == ExprClass.IndexerAccess) {
+ throw new Exception ("Handle Indexers here");
} else {
- throw new Exception ("Handle Indexers and Properties here");
+ Console.WriteLine ("Unknown exprclass: " + eclass);
}
break;
@@ -4743,20 +4756,26 @@
return true;
}
-
- override public Expression DoResolve (EmitContext ec)
+
+ public bool VerifyReadable ()
{
- //
- // Not really sure who should call perform the test below
- // given that `assignable' has special code for this.
- //
if (!PropertyInfo.CanRead){
Report.Error (154, loc,
"The property `" + PropertyInfo.Name +
"' can not be used in " +
"this context because it lacks a get accessor");
- return null;
+ return false;
}
+
+ return true;
+ }
+
+ override public Expression DoResolve (EmitContext ec)
+ {
+ //
+ // Not really sure who should call perform the test below
+ // given that `assignable' has special code for this.
+ //
return this;
}
Index: mcs/statement.cs
===================================================================
RCS file: /cvs/public/mcs/mcs/statement.cs,v
retrieving revision 1.19
diff -u -r1.19 statement.cs
--- mcs/statement.cs 2001/10/10 02:36:47 1.19
+++ mcs/statement.cs 2001/10/16 00:51:22
@@ -122,12 +122,25 @@
{
ILGenerator ig = ec.ig;
Label loop = ig.DefineLabel ();
-
+ Label old_begin = ec.LoopBegin;
+ Label old_end = ec.LoopEnd;
+ bool old_inloop = ec.InLoop;
+
+ ec.LoopBegin = ig.DefineLabel ();
+ ec.LoopEnd = ig.DefineLabel ();
+ ec.InLoop = true;
+
ig.MarkLabel (loop);
EmbeddedStatement.Emit (ec);
+ ig.MarkLabel (ec.LoopBegin);
EmitBoolExpression (ec, Expr);
ig.Emit (OpCodes.Brtrue, loop);
+ ig.MarkLabel (ec.LoopEnd);
+ ec.LoopBegin = old_begin;
+ ec.LoopEnd = old_end;
+ ec.InLoop = old_inloop;
+
return false;
}
}
@@ -145,16 +158,25 @@
public override bool Emit (EmitContext ec)
{
ILGenerator ig = ec.ig;
- Label while_eval = ig.DefineLabel ();
- Label exit = ig.DefineLabel ();
+ Label old_begin = ec.LoopBegin;
+ Label old_end = ec.LoopEnd;
+ bool old_inloop = ec.InLoop;
+
+ ec.LoopBegin = ig.DefineLabel ();
+ ec.LoopEnd = ig.DefineLabel ();
+ ec.InLoop = true;
- ig.MarkLabel (while_eval);
+ ig.MarkLabel (ec.LoopBegin);
EmitBoolExpression (ec, Expr);
- ig.Emit (OpCodes.Brfalse, exit);
+ ig.Emit (OpCodes.Brfalse, ec.LoopEnd);
Statement.Emit (ec);
- ig.Emit (OpCodes.Br, while_eval);
- ig.MarkLabel (exit);
+ ig.Emit (OpCodes.Br, ec.LoopBegin);
+ ig.MarkLabel (ec.LoopEnd);
+ ec.LoopBegin = old_begin;
+ ec.LoopEnd = old_end;
+ ec.InLoop = old_inloop;
+
return false;
}
}
@@ -179,21 +201,31 @@
public override bool Emit (EmitContext ec)
{
ILGenerator ig = ec.ig;
+ Label old_begin = ec.LoopBegin;
+ Label old_end = ec.LoopEnd;
+ bool old_inloop = ec.InLoop;
Label loop = ig.DefineLabel ();
- Label exit = ig.DefineLabel ();
if (! (InitStatement is EmptyStatement))
InitStatement.Emit (ec);
+ ec.LoopBegin = ig.DefineLabel ();
+ ec.LoopEnd = ig.DefineLabel ();
+ ec.InLoop = true;
+
ig.MarkLabel (loop);
EmitBoolExpression (ec, Test);
- ig.Emit (OpCodes.Brfalse, exit);
+ ig.Emit (OpCodes.Brfalse, ec.LoopEnd);
Statement.Emit (ec);
+ ig.MarkLabel (ec.LoopBegin);
if (!(Increment is EmptyStatement))
Increment.Emit (ec);
ig.Emit (OpCodes.Br, loop);
- ig.MarkLabel (exit);
+ ig.MarkLabel (ec.LoopEnd);
+ ec.LoopBegin = old_begin;
+ ec.LoopEnd = old_end;
+ ec.InLoop = old_inloop;
return false;
}
}
@@ -312,24 +344,46 @@
}
public class Break : Statement {
- public Break ()
+ Location loc;
+
+ public Break (Location l)
{
+ loc = l;
}
public override bool Emit (EmitContext ec)
{
- throw new Exception ("Unimplemented");
+ ILGenerator ig = ec.ig;
+
+ if (!ec.InLoop){
+ Report.Error (139, loc, "No enclosing loop to continue to");
+ return false;
+ }
+
+ ig.Emit (OpCodes.Br, ec.LoopEnd);
+ return false;
}
}
public class Continue : Statement {
- public Continue ()
+ Location loc;
+
+ public Continue (Location l)
{
+ loc = l;
}
public override bool Emit (EmitContext ec)
{
- throw new Exception ("Unimplemented");
+ Label begin = ec.LoopBegin;
+
+ if (!ec.InLoop){
+ Report.Error (139, loc, "No enclosing loop to continue to");
+ return false;
+ }
+
+ ec.ig.Emit (OpCodes.Br, begin);
+ return false;
}
}
@@ -996,10 +1050,13 @@
//
// Instantiate the enumerator
- Label end = ig.DefineLabel ();
+ Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
Label end_try = ig.DefineLabel ();
- Label loop = ig.DefineLabel ();
-
+ bool old_inloop = ec.InLoop;
+ ec.LoopBegin = ig.DefineLabel ();
+ ec.LoopEnd = ig.DefineLabel ();
+ ec.InLoop = true;
+
//
// FIXME: This code does not work for cases like:
// foreach (int a in ValueTypeVariable){
@@ -1021,7 +1078,7 @@
// if the beast implement IDisposable, we get rid of it
//
Label l = ig.BeginExceptionBlock ();
- ig.MarkLabel (loop);
+ ig.MarkLabel (ec.LoopBegin);
ig.Emit (OpCodes.Ldloc, enumerator);
ig.Emit (OpCodes.Callvirt, TypeManager.bool_movenext_void);
ig.Emit (OpCodes.Brfalse, end_try);
@@ -1030,7 +1087,7 @@
conv.Emit (ec);
Variable.Store (ec);
Statement.Emit (ec);
- ig.Emit (OpCodes.Br, loop);
+ ig.Emit (OpCodes.Br, ec.LoopBegin);
ig.MarkLabel (end_try);
// The runtime provides this for us.
@@ -1055,7 +1112,12 @@
// ig.Emit (OpCodes.Endfinally);
ig.EndExceptionBlock ();
- ig.MarkLabel (end);
+
+ ig.MarkLabel (ec.LoopEnd);
+
+ ec.LoopBegin = old_begin;
+ ec.LoopEnd = old_end;
+ ec.InLoop = old_inloop;
return false;
}
Index: tests/makefile
===================================================================
RCS file: /cvs/public/mcs/tests/makefile,v
retrieving revision 1.21
diff -u -r1.21 makefile
--- tests/makefile 2001/10/15 00:03:43 1.21
+++ tests/makefile 2001/10/16 00:51:23
@@ -4,7 +4,7 @@
TEST_SOURCES = \
test-1 test-2 test-3 test-4 test-6 test-7 test-8 test-9 test-10 \
test-11 test-12 test-13 test-16 test-17 test-18 test-20 test-21 \
- test-23 test-24
+ test-23 test-24 test-25
TEST_NOPASS = \
test-5