r77514 - in trunk/mcs: errors gmcs mcs tests

0 views
Skip to first unread message

Scott Peterson (lunchtimemama@gmail.com)

unread,
May 16, 2007, 5:44:30 PM5/16/07
to mono-p...@lists.ximian.com, ximian....@gmail.com, mono-svn-patche...@googlegroups.com
Author: speterson
Date: 2007-05-16 17:44:29 -0400 (Wed, 16 May 2007)
New Revision: 77514

Added:
trunk/mcs/errors/gcs0201.cs
trunk/mcs/tests/gtest-initialize-02.cs
Modified:
trunk/mcs/errors/ChangeLog
trunk/mcs/gmcs/ChangeLog
trunk/mcs/gmcs/cs-parser.jay
trunk/mcs/mcs/ChangeLog
trunk/mcs/mcs/assign.cs
trunk/mcs/mcs/expression.cs
trunk/mcs/tests/ChangeLog
Log:
errors/gcs0201.cs: Make sure that Linq syntax fails correctly when not
compiling for Linq.

gmcs/cs-parser.jay: Improved grammar for object and collection
initialization.

mcs/assing.cs:
mcs/expression.cs: Improved object and collection initialization.

tests/gtest-initialize-02.cs: Added an uber-test for object and
collection initialization.


Modified: trunk/mcs/errors/ChangeLog
===================================================================
--- trunk/mcs/errors/ChangeLog 2007-05-16 21:09:32 UTC (rev 77513)
+++ trunk/mcs/errors/ChangeLog 2007-05-16 21:44:29 UTC (rev 77514)
@@ -1,3 +1,8 @@
+2007-05-15 Scott Peterson <luncht...@gmail.com>
+ * gcs0201.cs:
+ Make sure that Linq syntax fails correctly
+ when not compiling for Linq.
+
2007-05-08 Scott Peterson <luncht...@gmail.com>
* gcs1526.cs:
* gcs1526-2.cs:

Added: trunk/mcs/errors/gcs0201.cs
===================================================================
--- trunk/mcs/errors/gcs0201.cs 2007-05-16 21:09:32 UTC (rev 77513)
+++ trunk/mcs/errors/gcs0201.cs 2007-05-16 21:44:29 UTC (rev 77514)
@@ -0,0 +1,16 @@
+// cs0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement
+// Line: 14
+using System;
+
+public class Test
+{
+ private class A
+ {
+ public string B;
+ }
+
+ static void Main ()
+ {
+ A a = new A () { B = "foo" };
+ }
+}

Modified: trunk/mcs/gmcs/ChangeLog
===================================================================
--- trunk/mcs/gmcs/ChangeLog 2007-05-16 21:09:32 UTC (rev 77513)
+++ trunk/mcs/gmcs/ChangeLog 2007-05-16 21:44:29 UTC (rev 77514)
@@ -1,3 +1,8 @@
+2007-05-15 Scott Peterson <luncht...@gmail.com>
+
+ * cs-parser.jay: Improved grammar for object and collection
+ initialization.
+
2007-04-28 Scott Peterson <luncht...@gmail.com>

This code is contributed under the MIT X11 license

Modified: trunk/mcs/gmcs/cs-parser.jay
===================================================================
--- trunk/mcs/gmcs/cs-parser.jay 2007-05-16 21:09:32 UTC (rev 77513)
+++ trunk/mcs/gmcs/cs-parser.jay 2007-05-16 21:44:29 UTC (rev 77514)
@@ -1516,7 +1516,7 @@

prop = new Property (current_class, (Expression) $3, (int) $2, false,
name, (Attributes) $1, get_block, set_block, accessors.declared_in_reverse);
-
+
current_container.AddProperty (prop);
implicit_value_parameter_type = null;

@@ -3196,6 +3196,97 @@
}
;

+opt_object_or_collection_initializer
+ : /* empty */ { $$ = null; }
+ | object_or_collection_initializer
+ ;
+
+object_or_collection_initializer
+ : object_initializer
+ | collection_initializer
+ ;
+
+object_initializer
+ : OPEN_BRACE opt_member_initializer_list CLOSE_BRACE
+ {
+ if ($2 == null)
+ $$ = null;
+ else
+ $$ = new ObjectInitializer ((ArrayList)$2);
+ }
+ | OPEN_BRACE member_initializer_list COMMA CLOSE_BRACE
+ {
+ $$ = new ObjectInitializer ((ArrayList) $2);
+ }
+ ;
+
+opt_member_initializer_list
+ : /* empty */ { $$ = null; }
+ | member_initializer_list
+ ;
+
+member_initializer_list
+ : member_initializer
+ {
+ ArrayList a = new ArrayList ();
+ a.Add ($1);
+ $$ = a;
+ }
+ | member_initializer_list COMMA member_initializer
+ {
+ ArrayList a = (ArrayList)$1;
+ a.Add ($3);
+ $$ = a;
+ }
+ ;
+
+member_initializer
+ : IDENTIFIER ASSIGN initializer_value
+ {
+ LocatedToken id = $1 as LocatedToken;
+ IInitializable i = $3 as IInitializable;
+ if (i != null)
+ $$ = new Initializer (id.Value, i);
+ else
+ $$ = new Initializer (id.Value, (Expression)$3);
+ }
+ ;
+
+initializer_value
+ : expression
+ | object_or_collection_initializer
+ ;
+
+collection_initializer
+ : OPEN_BRACE element_initializer_list CLOSE_BRACE
+ {
+ $$ = new CollectionInitializer ((ArrayList) $2);
+ }
+ | OPEN_BRACE element_initializer_list COMMA CLOSE_BRACE
+ {
+ $$ = new CollectionInitializer ((ArrayList) $2);
+ }
+ ;
+
+element_initializer_list
+ : element_initializer
+ {
+ ArrayList a = new ArrayList ();
+ a.Add ($1);
+ $$ = a;
+ }
+ | element_initializer_list COMMA element_initializer
+ {
+ ArrayList a = $1 as ArrayList;
+ a.Add ($3);
+ $$ = a;
+ }
+ ;
+
+element_initializer
+ : non_assignment_expression
+ ;
+
opt_argument_list
: /* empty */ { $$ = null; }
| argument_list
@@ -3351,12 +3442,11 @@
new_expression
: object_or_delegate_creation_expression
| array_creation_expression
- | collection_initialization_expression
| anonymous_type_expression
;

object_or_delegate_creation_expression
- : NEW type OPEN_PARENS opt_argument_list CLOSE_PARENS opt_object_initializer
+ : NEW type OPEN_PARENS opt_argument_list CLOSE_PARENS opt_object_or_collection_initializer
{
if ($6 != null) {
if (RootContext.Version < LanguageVersion.LINQ) {
@@ -3364,22 +3454,19 @@
$$ = null;
}
else
- $$ = new NewInitialize ((Expression) $2, (ArrayList) $4, (Location) $1, (ArrayList) $6);
+ $$ = new NewInitialize ((Expression) $2, (ArrayList) $4, (IInitializable) $6, (Location) $1);
}
else
$$ = new New ((Expression) $2, (ArrayList) $4, (Location) $1);
}
- ;
-
-collection_initialization_expression
- : NEW type OPEN_BRACE argument_list CLOSE_BRACE
+ | NEW type object_or_collection_initializer
{
if (RootContext.Version < LanguageVersion.LINQ) {
Report.Error (1526, (Location) $1, "A new expression requires () or [] after type");
- $$ = null;
- }
- else
- $$ = new CollectionInitialize ((Expression) $2, new ArrayList (), (Location) $1, (ArrayList) $4);
+ $$ = null;
+ }
+ else
+ $$ = new NewInitialize ((Expression) $2, new ArrayList (), (IInitializable) $3, (Location) $1);
}
;

Modified: trunk/mcs/mcs/ChangeLog
===================================================================
--- trunk/mcs/mcs/ChangeLog 2007-05-16 21:09:32 UTC (rev 77513)
+++ trunk/mcs/mcs/ChangeLog 2007-05-16 21:44:29 UTC (rev 77514)
@@ -1,3 +1,9 @@
+2007-05-15 Scott Peterson <luncht...@gmail.com>
+
+ * assign.cs:
+ * expression.cs:
+ Imporved object and collection initialization (C# 3.0).
+
2007-05-15 Marek Safar <marek...@gmail.com>

A fix for bug #81380
@@ -49,6 +55,7 @@
* expression.cs (Binary.ResolveOperator): Implemented delegate
comparison based on C# 2.0 changes.

+>>>>>>> .r77513
2007-04-28 Scott Peterson <luncht...@gmail.com>

This code is contributed under the MIT X11 license

Modified: trunk/mcs/mcs/assign.cs
===================================================================
--- trunk/mcs/mcs/assign.cs 2007-05-16 21:09:32 UTC (rev 77513)
+++ trunk/mcs/mcs/assign.cs 2007-05-16 21:44:29 UTC (rev 77514)
@@ -320,10 +320,6 @@
//
public override Expression DoResolve (EmitContext ec)
{
- // Handle initializations e.g. Person p = new Person () { Name = "Scott" };
- if (source is IInitializable)
- ((IInitializable)source).Initialize (ec, target);
-
// Create an embedded assignment if our source is an assignment.
if (source is Assign)
source = embedded = ((Assign) source).GetEmbeddedAssign (loc);
@@ -379,6 +375,11 @@

if (target == null)
return null;
+
+ // Handle initializations e.g. Person p = new Person () { Name = "Scott" };
+ IInitializable initializer = source as IInitializable;
+ if (initializer != null && !initializer.Initialize (ec, target))
+ return null;

bool same_assignment = (embedded != null) ? embedded.Target.Equals(target) : source.Equals (target);
if (same_assignment) {

Modified: trunk/mcs/mcs/expression.cs
===================================================================
--- trunk/mcs/mcs/expression.cs 2007-05-16 21:09:32 UTC (rev 77513)
+++ trunk/mcs/mcs/expression.cs 2007-05-16 21:44:29 UTC (rev 77514)
@@ -8565,30 +8565,166 @@
}
}

+ public interface IInitializable
+ {
+ bool Initialize (EmitContext ec, Expression target);
+ }
+
public class Initializer
{
public readonly string Name;
- public readonly Expression Value;
+ public readonly object Value;

public Initializer (string name, Expression value)
{
Name = name;
Value = value;
}
+
+ public Initializer (string name, IInitializable value)
+ {
+ Name = name;
+ Value = value;
+ }
}
+
+ public class ObjectInitializer : IInitializable
+ {
+ readonly ArrayList initializers;
+ public ObjectInitializer (ArrayList initializers)
+ {
+ this.initializers = initializers;
+ }
+
+ public bool Initialize (EmitContext ec, Expression target)
+ {
+ ArrayList initialized = new ArrayList (initializers.Count);
+ for (int i = initializers.Count - 1; i >= 0; i--) {
+ Initializer initializer = initializers[i] as Initializer;
+ if (initialized.Contains (initializer.Name)) {
+ //FIXME proper error
+ Console.WriteLine ("Object member can only be initialized once");
+ return false;
+ }
+
+ MemberAccess ma = new MemberAccess (target, initializer.Name);
+ Expression expr = initializer.Value as Expression;
+ // If it's an expresison, append the assign.
+ if (expr != null) {
+ Assign a = new Assign (ma, expr);
+ ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (a));
+ }
+ // If it's another initializer (object or collection), initialize it.
+ else if (!((IInitializable)initializer.Value).Initialize (ec, ma))
+ return false;
+
+ initialized.Add (initializer.Name);
+ }
+ return true;
+ }
+ }
+
+ public class CollectionInitializer : IInitializable
+ {
+ readonly ArrayList items;
+ public CollectionInitializer (ArrayList items)
+ {
+ this.items = items;
+ }
+
+ bool CheckCollection (EmitContext ec, Expression e)
+ {
+ if (e == null || e.Type == null)
+ return false;
+ bool is_ienumerable = false;
+ foreach (Type t in TypeManager.GetInterfaces (e.Type))
+ if (t == typeof (IEnumerable)) {
+ is_ienumerable = true;
+ break;
+ }
+
+ if (!is_ienumerable)
+ return false;
+
+ MethodGroupExpr mg = Expression.MemberLookup (
+ ec.ContainerType, e.Type, "Add", MemberTypes.Method,
+ Expression.AllBindingFlags, Location.Null) as MethodGroupExpr;

- public interface IInitializable
+ if (mg == null)
+ return false;
+
+ foreach (MethodInfo mi in mg.Methods) {
+ if (TypeManager.GetParameterData (mi).Count != 1)
+ continue;
+ if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
+ continue;
+ return true;
+ }
+ return false;
+ }
+
+ public bool Initialize (EmitContext ec, Expression target)
+ {
+ if (!CheckCollection (ec, target.Resolve (ec))) {
+ // FIXME throw proper error
+ Console.WriteLine ("Error: This is not a collection");
+ return false;
+ }
+
+ for (int i = items.Count - 1; i >= 0; i--) {
+ MemberAccess ma = new MemberAccess (target, "Add");
+ ArrayList array = new ArrayList ();
+ array.Add (new Argument ((Expression)items[i]));
+ Invocation invoke = new Invocation (ma, array);
+ ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (invoke));
+ }
+ return true;
+ }
+ }
+
+ public class AnonymousTypeInitializer : IInitializable
{
- void Initialize (EmitContext ec, Expression target);
+ readonly ArrayList initializers;
+ public AnonymousTypeInitializer (ArrayList initializers)
+ {
+ this.initializers = initializers;
+ }
+
+ public bool Initialize (EmitContext ec, Expression target)
+ {
+ foreach (AnonymousTypeParameter p in initializers) {
+ MemberAccess ma = new MemberAccess (target, p.Name);
+ Assign a = p.Expression as Assign;
+ Assign assign = new Assign (ma, (a != null) ? a.Source : p.Expression);
+ ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (assign));
+ }
+ return true;
+ }
}

- public class AnonymousType : Expression, IInitializable
+ public class NewInitialize : New, IInitializable
{
- private ArrayList parameters;
- private TypeContainer parent;
- private Location loc;
- private TypeContainer anonymous_type;
+ IInitializable initializer;

+ public bool Initialize (EmitContext ec, Expression target)
+ {
+ return initializer.Initialize (ec, target);
+ }
+
+ public NewInitialize (Expression requested_type, ArrayList arguments, IInitializable initializer, Location l)
+ : base (requested_type, arguments, l)
+ {
+ this.initializer = initializer;
+ }
+ }
+
+ public class AnonymousType : Expression
+ {
+ ArrayList parameters;
+ TypeContainer parent;
+ Location loc;
+ TypeContainer anonymous_type;
+
public AnonymousType (ArrayList parameters, TypeContainer parent, Location loc)
{
this.parameters = parameters;
@@ -8604,10 +8740,11 @@
anonymous_type = GetAnonymousType (ec);

TypeExpression te = new TypeExpression (anonymous_type.TypeBuilder, loc);
- return new New (te, null, loc).Resolve (ec);
+ AnonymousTypeInitializer ati = new AnonymousTypeInitializer (parameters);
+ return new NewInitialize (te, null, ati, loc).Resolve (ec);
}

- private TypeContainer GetAnonymousType (EmitContext ec)
+ TypeContainer GetAnonymousType (EmitContext ec)
{
// See if we already have an anonymous type with the right fields.
// If not, create one.
@@ -8641,7 +8778,7 @@
return CreateAnonymousType (ec);
}

- private TypeContainer CreateAnonymousType (EmitContext ec)
+ TypeContainer CreateAnonymousType (EmitContext ec)
{
TypeContainer type = new AnonymousClass (parent, loc);
foreach (AnonymousTypeParameter p in parameters) {
@@ -8660,26 +8797,14 @@
TypeExpression te = new TypeExpression (anonymous_type.TypeBuilder, loc);
new New (te, null, loc).Emit(ec);
}
-
- public void Initialize (EmitContext ec, Expression target)
- {
- LocalVariableReference lv = (LocalVariableReference)target;
- foreach (AnonymousTypeParameter p in parameters) {
- MemberAccess ma = new MemberAccess (lv, p.Name);
- Assign a = new Assign (ma, (p.Expression is Assign)
- ? ((Assign)p.Expression).Source
- : p.Expression);
- ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (a));
- }
- }
}

public class AnonymousTypeParameter : Expression
{
- private LocatedToken token;
- private string name;
- private Expression expression;
- private Type type;
+ LocatedToken token;
+ string name;
+ Expression expression;
+ Type type;

public LocatedToken Token {
get { return token; }
@@ -8722,89 +8847,4 @@
type = expression.Type;
}
}
-
- public class NewInitialize : New, IInitializable
- {
- private ArrayList initializers;
-
- public void Initialize (EmitContext ec, Expression target)
- {
- LocalVariableReference lv = (LocalVariableReference)target;
- for (int i = initializers.Count - 1; i >= 0; i--) {
- MemberAccess ma = new MemberAccess (lv, ((Initializer)initializers[i]).Name);
- Assign a = new Assign (ma, ((Initializer)initializers[i]).Value);
- ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (a));
- }
- }
-
- public NewInitialize (Expression requested_type, ArrayList arguments, Location l, ArrayList initializers)
- : base (requested_type, arguments, l)
- {
- this.initializers = initializers;
- }
- }
-
- public class CollectionInitialize : New, IInitializable
- {
- private ArrayList items;
-
- public CollectionInitialize (Expression type, ArrayList arguments, Location l, ArrayList items)
- : base (type, arguments, l)
- {
- this.items = items;
- }
-
- // A type is a valid collection if it implements IEnumerable and has a public Add method
- private bool CheckCollection (EmitContext ec)
- {
- Expression e = base.Resolve (ec);
-
- if (e == null)
- return false;
-
- bool is_ienumerable = false;
- foreach (Type t in TypeManager.GetInterfaces (e.Type))
- if (t == typeof (IEnumerable)) {
- is_ienumerable = true;
- break;
- }
-
- if (!is_ienumerable)
- return false;
-
- MethodGroupExpr mg = Expression.MemberLookup (
- ec.ContainerType, e.Type, "Add", MemberTypes.Method,
- Expression.AllBindingFlags, loc) as MethodGroupExpr;
-
- if (mg == null)
- return false;
-
- foreach (MethodInfo mi in mg.Methods) {
- if (TypeManager.GetParameterData (mi).Count != 1)
- continue;
- if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
- continue;
- return true;
- }
- return false;
- }
-
- public void Initialize (EmitContext ec, Expression target)
- {
- if (!CheckCollection (ec)) {
- // TODO throw proper error
- Console.WriteLine ("Error: This is not a collection");
- return;
- }
-
- LocalVariableReference lv = (LocalVariableReference) target;
- for (int i = items.Count - 1; i >= 0; i--) {
- MemberAccess ma = new MemberAccess (lv, "Add");
- ArrayList array = new ArrayList ();
- array.Add ((Argument)items[i]);
- Invocation invoke = new Invocation (ma, array);
- ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (invoke));
- }
- }
- }
}

Modified: trunk/mcs/tests/ChangeLog
===================================================================
--- trunk/mcs/tests/ChangeLog 2007-05-16 21:09:32 UTC (rev 77513)
+++ trunk/mcs/tests/ChangeLog 2007-05-16 21:44:29 UTC (rev 77514)
@@ -1,3 +1,8 @@
+2007-05-15 Scott Peterson <luncht...@gmail.com>
+
+ * gtest-initialize-02.cs: Uber-test for object and
+ collection initialization (C# 3.0).
+
2007-04-28 Scott Peterson <luncht...@gmail.com>

This code is contributed under the MIT X11 license

Added: trunk/mcs/tests/gtest-initialize-02.cs
===================================================================
--- trunk/mcs/tests/gtest-initialize-02.cs 2007-05-16 21:09:32 UTC (rev 77513)
+++ trunk/mcs/tests/gtest-initialize-02.cs 2007-05-16 21:44:29 UTC (rev 77514)
@@ -0,0 +1,99 @@
+// Compiler options: -langversion:linq
+// Uber-test for object and collection initialization
+using System;
+using System.Collections.Generic;
+
+public class Test
+{
+ private class Point
+ {
+ public int X;
+ public int Y;
+ }
+ private class Line
+ {
+ public Point P1 = new Point ();
+ public Point P2 = new Point ();
+ }
+ private class Rectangle
+ {
+ public Line Top = new Line ();
+ public Line Right = new Line ();
+ public Line Left = new Line ();
+ public Line Bottom = new Line ();
+ }
+ private class Library
+ {
+ public string Name;
+ public string PhoneNumber;
+ public List<string> Books;
+ public Library ()
+ {
+ Books = new List<string> { "Tale of Two Cities", "Catcher in the Rye", "Great Gatsby" };
+ }
+ }
+ private class Thing
+ {
+ public int Number;
+ public string Name;
+ }
+ private class Box
+ {
+ public Thing Thing1;
+ public Thing Thing2;
+ }
+ static int Main ()
+ {
+ Thing thing1 = new Thing() { Number = 1, Name = "Bob" };
+
+ Line line = new Line { P1 = { X = 1, Y = 5 }, P2 = { X = 3, Y = 6 } };
+ if (line.P1.X != 1 || line.P1.Y != 5 || line.P2.X != 3 || line.P2.Y != 6)
+ return 1;
+
+ Rectangle rectangle = new Rectangle () {
+ Top = {
+ P1 = { X = 0, Y = 5 },
+ P2 = { X = 5, Y = 5 } },
+ Bottom = {
+ P1 = { X = 0, Y = 0, },
+ P2 = { X = 5, Y = 0, }, },
+ Right = {
+ P1 = { X = 5, Y = 5 },
+ P2 = { X = 5, Y = 0 } },
+ Left = {
+ P1 = { X = 0, Y = 0, },
+ P2 = { X = 0, Y = 5 } } };
+ if (rectangle.Top.P1.X != 0 || rectangle.Bottom.P2.X != 5 || rectangle.Right.P2.Y != 0 || rectangle.Left.P1.Y != 0)
+ return 2;
+
+ List<string> list = new List<string> (3) { "Foo", "Bar", "Baz" };
+ if (list[0] != "Foo" || list[1] != "Bar" || list[2] != "Baz")
+ return 3;
+
+ Library library = new Library {
+ Name = "New York Public Library",
+ Books = { "Grapes of Wrath", "Dracula", },
+ PhoneNumber = "212-621-0626" };
+ if (library.Name != "New York Public Library" || library.PhoneNumber != "212-621-0626" ||
+ library.Books[0] != "Tale of Two Cities" ||
+ library.Books[1] != "Catcher in the Rye" ||
+ library.Books[2] != "Great Gatsby" ||
+ library.Books[3] != "Grapes of Wrath" ||
+ library.Books[4] != "Dracula")
+ return 4;
+
+ Box box = new Box {
+ Thing1 = new Thing { Number = 1, Name = "Wilber" },
+ Thing2 = new Thing() { Number = 2, Name = "Chris" } };
+ if (box.Thing1.Number != 1 || box.Thing1.Name != "Wilber" || box.Thing2.Number != 2 || box.Thing2.Name != "Chris")
+ return 5;
+
+ Library library2 = new Library { Books = new List<string> { "The Hound of Baskerville", "Flatland", "The Origin of Species" } };
+ if (library2.Books[0] != "The Hound of Baskerville" ||
+ library2.Books[1] != "Flatland" ||
+ library2.Books[2] != "The Origin of Species")
+ return 6;
+
+ return 0;
+ }
+}

Reply all
Reply to author
Forward
0 new messages