//
// Authors: Marek Safar (marek.safar@gmail.com)
//
-// Licensed under the terms of the GNU GPL
+// Dual licensed under the terms of the MIT X11 or GNU GPL
//
-// (C) 2007 Novell, Inc
+// Copyright 2007-2008 Novell, Inc
//
using System;
using System.Reflection;
-using System.Collections;
+using System.Collections.Generic;
namespace Mono.CSharp.Linq
{
- // NOTES:
- // Expression should be IExpression to save some memory and make a few things
- // easier to read
- //
- //
-
public class QueryExpression : AQueryClause
{
- LocatedToken variable;
-
- public QueryExpression (LocatedToken variable, AQueryClause query)
- : base (null, query.Location)
+ public QueryExpression (AQueryClause start)
+ : base (null, null, Location.Null)
{
- this.variable = variable;
- this.next = query;
+ this.next = start;
}
- public override Expression BuildQueryClause (EmitContext ec, Expression lSide, Parameter parentParameter, TransparentIdentifiersScope ti)
+ public override Expression BuildQueryClause (ResolveContext ec, Expression lSide, Parameter parentParameter)
{
- Parameter p = CreateBlockParameter (variable);
- return next.BuildQueryClause (ec, lSide, p, ti);
+ return next.BuildQueryClause (ec, lSide, parentParameter);
}
- public override Expression DoResolve (EmitContext ec)
+ protected override Expression DoResolve (ResolveContext ec)
{
- Expression e = BuildQueryClause (ec, null, null, null);
- e = e.Resolve (ec);
+ int counter = QueryBlock.TransparentParameter.Counter;
+
+ Expression e = BuildQueryClause (ec, null, null);
+ if (e != null)
+ e = e.Resolve (ec);
+
+ //
+ // Reset counter in probing mode to ensure that all transparent
+ // identifier anonymous types are created only once
+ //
+ if (ec.IsInProbingMode)
+ QueryBlock.TransparentParameter.Counter = counter;
+
return e;
}
}
}
- public abstract class AQueryClause : Expression
+ public abstract class AQueryClause : ShimExpression
{
- class QueryExpressionAccess : MemberAccess
+ protected class QueryExpressionAccess : MemberAccess
{
public QueryExpressionAccess (Expression expr, string methodName, Location loc)
: base (expr, methodName, loc)
{
}
- protected override Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
- Type queried_type, string name, string class_name, MemberTypes mt, BindingFlags bf)
+ protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
{
- Report.Error (1935, loc, "An implementation of `{0}' query expression pattern could not be found. " +
+ ec.Report.Error (1935, loc, "An implementation of `{0}' query expression pattern could not be found. " +
"Are you missing `System.Linq' using directive or `System.Core.dll' assembly reference?",
name);
- return null;
}
}
- class QueryExpressionInvocation : Invocation, MethodGroupExpr.IErrorHandler
+ protected class QueryExpressionInvocation : Invocation, OverloadResolver.IErrorHandler
{
- public QueryExpressionInvocation (QueryExpressionAccess expr, ArrayList arguments)
+ public QueryExpressionInvocation (QueryExpressionAccess expr, Arguments arguments)
: base (expr, arguments)
{
}
- protected override MethodGroupExpr DoResolveOverload (EmitContext ec)
+ protected override MethodGroupExpr DoResolveOverload (ResolveContext ec)
{
- mg.CustomErrorHandler = this;
- MethodGroupExpr rmg = mg.OverloadResolve (ec, Arguments, false, loc);
+ MethodGroupExpr rmg = mg.OverloadResolve (ec, ref arguments, this, OverloadResolver.Restrictions.None);
return rmg;
}
- public bool NoExactMatch (EmitContext ec, MethodBase method)
+ #region IErrorHandler Members
+
+ bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext ec, MemberSpec best, MemberSpec ambiguous)
+ {
+ ec.Report.SymbolRelatedToPreviousError (best);
+ ec.Report.SymbolRelatedToPreviousError (ambiguous);
+ ec.Report.Error (1940, loc, "Ambiguous implementation of the query pattern `{0}' for source type `{1}'",
+ best.Name, mg.InstanceExpression.GetSignatureForError ());
+ return true;
+ }
+
+ bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
+ {
+ return false;
+ }
+
+ bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
+ {
+ return false;
+ }
+
+ bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
{
- ParameterData pd = TypeManager.GetParameterData (method);
- Type source_type = pd.ExtensionMethodType;
+ var ms = (MethodSpec) best;
+ TypeSpec source_type = ms.Parameters.ExtensionMethodType;
if (source_type != null) {
- Argument a = (Argument) Arguments [0];
+ Argument a = arguments[0];
- if (source_type.IsGenericType && source_type.ContainsGenericParameters) {
- TypeInferenceContext tic = new TypeInferenceContext (source_type.GetGenericArguments ());
- tic.OutputTypeInference (ec, a.Expr, source_type);
- if (tic.FixAllTypes ()) {
- source_type = source_type.GetGenericTypeDefinition ().MakeGenericType (tic.InferredTypeArguments);
+ if (TypeManager.IsGenericType (source_type) && TypeManager.ContainsGenericParameters (source_type)) {
+ TypeInferenceContext tic = new TypeInferenceContext (source_type.TypeArguments);
+ tic.OutputTypeInference (rc, a.Expr, source_type);
+ if (tic.FixAllTypes (rc)) {
+ source_type = source_type.GetDefinition ().MakeGenericType (tic.InferredTypeArguments);
}
}
- if (!Convert.ImplicitConversionExists (ec, a.Expr, source_type)) {
- Report.Error (1936, loc, "An implementation of `{0}' query expression pattern for source type `{1}' could not be found",
- mg.Name, TypeManager.CSharpName (a.Type));
+ if (!Convert.ImplicitConversionExists (rc, a.Expr, source_type)) {
+ rc.Report.Error (1936, loc, "An implementation of `{0}' query expression pattern for source type `{1}' could not be found",
+ best.Name, TypeManager.CSharpName (a.Type));
return true;
}
}
- if (!method.IsGenericMethod)
- return false;
+ if (best.Name == "SelectMany") {
+ rc.Report.Error (1943, loc,
+ "An expression type is incorrect in a subsequent `from' clause in a query expression with source type `{0}'",
+ arguments[0].GetSignatureForError ());
+ } else {
+ rc.Report.Error (1942, loc,
+ "An expression type in `{0}' clause is incorrect. Type inference failed in the call to `{1}'",
+ best.Name.ToLowerInvariant (), best.Name);
+ }
- Report.Error (1942, loc, "Type inference failed to infer type argument for `{0}' clause. " +
- "Try specifying the type argument explicitly",
- mg.Name.ToLower ());
return true;
}
+
+ #endregion
}
public AQueryClause next;
- /*protected*/ public Expression expr;
+ public QueryBlock block;
- protected AQueryClause (Expression expr, Location loc)
+ protected AQueryClause (QueryBlock block, Expression expr, Location loc)
+ : base (expr)
{
- this.expr = expr;
+ this.block = block;
this.loc = loc;
}
protected override void CloneTo (CloneContext clonectx, Expression target)
{
+ base.CloneTo (clonectx, target);
+
AQueryClause t = (AQueryClause) target;
- if (expr != null)
- t.expr = expr.Clone (clonectx);
-
+
+ if (block != null)
+ t.block = (QueryBlock) clonectx.LookupBlock (block);
+
if (next != null)
- t.next = (AQueryClause)next.Clone (clonectx);
+ t.next = (AQueryClause) next.Clone (clonectx);
}
- public override Expression DoResolve (EmitContext ec)
+ protected override Expression DoResolve (ResolveContext ec)
{
- return expr.DoResolve (ec);
+ return expr.Resolve (ec);
}
- public virtual Expression BuildQueryClause (EmitContext ec, Expression lSide, Parameter parameter, TransparentIdentifiersScope ti)
+ public virtual Expression BuildQueryClause (ResolveContext ec, Expression lSide, Parameter parameter)
{
- ArrayList args = new ArrayList (1);
- args.Add (CreateSelectorArgument (ec, expr, parameter, ti));
+ Arguments args = null;
+ CreateArguments (ec, parameter, ref args);
lSide = CreateQueryExpression (lSide, args);
if (next != null) {
+ parameter = CreateChildrenParameters (parameter);
+
Select s = next as Select;
if (s == null || s.IsRequired (parameter))
- return next.BuildQueryClause (ec, lSide, parameter, ti);
+ return next.BuildQueryClause (ec, lSide, parameter);
// Skip transparent select clause if any clause follows
if (next.next != null)
- return next.next.BuildQueryClause (ec, lSide, parameter, ti);
+ return next.next.BuildQueryClause (ec, lSide, parameter);
}
return lSide;
}
- protected static Parameter CreateBlockParameter (LocatedToken li)
- {
- return new ImplicitQueryParameter (li);
- }
-
- protected Invocation CreateQueryExpression (Expression lSide, ArrayList arguments)
- {
- return new QueryExpressionInvocation (
- new QueryExpressionAccess (lSide, MethodName, loc), arguments);
- }
-
- protected Invocation CreateQueryExpression (Expression lSide, TypeArguments typeArguments, ArrayList arguments)
- {
- return new QueryExpressionInvocation (
- new QueryExpressionAccess (lSide, MethodName, typeArguments, loc), arguments);
- }
-
- protected Argument CreateSelectorArgument (EmitContext ec, Expression expr, Parameter parameter, TransparentIdentifiersScope ti)
+ protected virtual Parameter CreateChildrenParameters (Parameter parameter)
{
- return CreateSelectorArgument (ec, expr, new Parameter [] { parameter }, ti);
+ // Have to clone the parameter for any children use, it carries block sensitive data
+ return parameter.Clone ();
}
- protected Argument CreateSelectorArgument (EmitContext ec, Expression expr, Parameter[] parameters, TransparentIdentifiersScope ti)
+ protected virtual void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args)
{
- Parameters p = new Parameters (parameters);
+ args = new Arguments (2);
- LambdaExpression selector = new LambdaExpression (
- null, null, (TypeContainer)ec.TypeContainer, p, ec.CurrentBlock, loc);
- selector.Block = new SelectorBlock (ec.CurrentBlock, p, ti, loc);
- selector.Block.AddStatement (new Return (expr, loc));
+ LambdaExpression selector = new LambdaExpression (loc);
- if (!ec.IsInProbingMode) {
- selector.CreateAnonymousHelpers ();
+ block.SetParameter (parameter);
+ selector.Block = block;
+ selector.Block.AddStatement (new ContextualReturn (expr));
- // TODO: I am not sure where this should be done to work
- // correctly with anonymous containerss and was called only once
- // FIXME: selector.RootScope == null for nested anonymous
- // methods only ?
- if (selector.RootScope != null)
- selector.RootScope.DefineType ();
- }
-
- return new Argument (selector);
+ args.Add (new Argument (selector));
}
- public override void Emit (EmitContext ec)
+ protected Invocation CreateQueryExpression (Expression lSide, Arguments arguments)
{
- throw new NotSupportedException ();
+ return new QueryExpressionInvocation (
+ new QueryExpressionAccess (lSide, MethodName, loc), arguments);
}
protected abstract string MethodName { get; }
- public virtual AQueryClause Next {
+ public AQueryClause Next {
set {
next = value;
}
//
public abstract class ARangeVariableQueryClause : AQueryClause
{
- LocatedToken variable;
- protected Expression element_selector;
-
- protected ARangeVariableQueryClause (LocatedToken variable, Expression expr, Location loc)
- : base (expr, loc)
+ sealed class RangeAnonymousTypeParameter : AnonymousTypeParameter
{
- this.variable = variable;
- }
+ public RangeAnonymousTypeParameter (Expression initializer, RangeVariable parameter)
+ : base (initializer, parameter.Name, parameter.Location)
+ {
+ }
- protected virtual void AddSelectorArguments (EmitContext ec, ArrayList args, Parameter parentParameter,
- ref Parameter parameter, TransparentIdentifiersScope ti)
- {
- args.Add (CreateSelectorArgument (ec, expr, parentParameter, ti));
- args.Add (CreateSelectorArgument (ec, element_selector,
- new Parameter [] { parentParameter, parameter }, ti));
+ protected override void Error_InvalidInitializer (ResolveContext ec, string initializer)
+ {
+ ec.Report.Error (1932, loc, "A range variable `{0}' cannot be initialized with `{1}'",
+ Name, initializer);
+ }
}
- //
- // Customization for range variables which not only creates a lambda expression but
- // also builds a chain of range varible pairs
- //
- public override Expression BuildQueryClause (EmitContext ec, Expression lSide, Parameter parentParameter, TransparentIdentifiersScope ti)
+ class RangeParameterReference : ParameterReference
{
- Parameter parameter = CreateBlockParameter (variable);
+ Parameter parameter;
- if (next != null) {
- //
- // Builds transparent identifiers, each identifier includes its parent
- // type at index 0, and new value at index 1. This is not valid for the
- // first one which includes two values directly.
- //
- ArrayList transp_args = new ArrayList (2);
- transp_args.Add (new AnonymousTypeParameter (parentParameter));
- transp_args.Add (CreateAnonymousTypeVariable (parameter));
- element_selector = new AnonymousTypeDeclaration (transp_args, (TypeContainer) ec.TypeContainer, loc);
+ public RangeParameterReference (Parameter p)
+ : base (null, p.Location)
+ {
+ this.parameter = p;
}
- ArrayList args = new ArrayList ();
- AddSelectorArguments (ec, args, parentParameter, ref parameter, ti);
+ protected override Expression DoResolve (ResolveContext ec)
+ {
+ pi = ec.CurrentBlock.ParametersBlock.GetParameterInfo (parameter);
+ return base.DoResolve (ec);
+ }
+ }
- lSide = CreateQueryExpression (lSide, args);
- if (next != null) {
- //
- // Parameter identifiers go to the scope
- //
- string[] identifiers;
- if (ti == null) {
- identifiers = new string [] { parentParameter.Name, parameter.Name };
- } else {
- identifiers = new string [] { parameter.Name };
- }
+ protected RangeVariable identifier;
- TransparentParameter tp = new TransparentParameter (loc);
- return next.BuildQueryClause (ec, lSide, tp,
- new TransparentIdentifiersScope (ti, tp, identifiers));
- }
+ protected ARangeVariableQueryClause (QueryBlock block, RangeVariable identifier, Expression expr, Location loc)
+ : base (block, expr, loc)
+ {
+ this.identifier = identifier;
+ }
- return lSide;
+ public FullNamedExpression IdentifierType { get; set; }
+
+ protected Invocation CreateCastExpression (Expression lSide)
+ {
+ return new QueryExpressionInvocation (
+ new QueryExpressionAccess (lSide, "Cast", new TypeArguments (IdentifierType), loc), null);
}
-
- protected override void CloneTo (CloneContext clonectx, Expression target)
+
+ protected override Parameter CreateChildrenParameters (Parameter parameter)
{
- ARangeVariableQueryClause t = (ARangeVariableQueryClause) target;
- if (element_selector != null)
- t.element_selector = element_selector.Clone (clonectx);
- base.CloneTo (clonectx, t);
+ return new QueryBlock.TransparentParameter (parameter.Clone (), GetIntoVariable ());
}
-
- //
- // For transparent identifiers, creates an instance of variable expression
- //
- protected virtual AnonymousTypeParameter CreateAnonymousTypeVariable (Parameter parameter)
+
+ protected static Expression CreateRangeVariableType (ResolveContext rc, Parameter parameter, RangeVariable name, Expression init)
+ {
+ var args = new List<AnonymousTypeParameter> (2);
+
+ //
+ // The first argument is the reference to the parameter
+ //
+ args.Add (new AnonymousTypeParameter (new RangeParameterReference (parameter), parameter.Name, parameter.Location));
+
+ //
+ // The second argument is the linq expression
+ //
+ args.Add (new RangeAnonymousTypeParameter (init, name));
+
+ //
+ // Create unique anonymous type
+ //
+ return new NewAnonymousType (args, rc.MemberContext.CurrentMemberDefinition.Parent, name.Location);
+ }
+
+ protected virtual RangeVariable GetIntoVariable ()
{
- return new AnonymousTypeParameter (parameter);
+ return identifier;
}
}
- public class QueryStartClause : AQueryClause
+ public sealed class RangeVariable : INamedBlockVariable
{
- public QueryStartClause (Expression expr)
- : base (expr, expr.Location)
+ Block block;
+
+ public RangeVariable (string name, Location loc)
{
+ Name = name;
+ Location = loc;
}
- public override Expression BuildQueryClause (EmitContext ec, Expression lSide, Parameter parameter, TransparentIdentifiersScope ti)
- {
- return next.BuildQueryClause (ec, expr, parameter, ti);
+ #region Properties
+
+ public Block Block {
+ get {
+ return block;
+ }
+ set {
+ block = value;
+ }
}
- public override Expression DoResolve (EmitContext ec)
- {
- Expression e = BuildQueryClause (ec, null, null, null);
- return e.Resolve (ec);
+ public bool IsDeclared {
+ get {
+ return true;
+ }
}
- protected override string MethodName {
- get { throw new NotSupportedException (); }
+ public Location Location { get; private set; }
+
+ public string Name { get; private set; }
+
+ #endregion
+
+ public Expression CreateReferenceExpression (ResolveContext rc, Location loc)
+ {
+ Expression expr = null;
+
+ //
+ // We know the variable name is somewhere in the scope. This generates
+ // an access expression from current block
+ //
+ var pb = rc.CurrentBlock.ParametersBlock;
+ while (true) {
+ if (pb is QueryBlock) {
+ for (int i = pb.Parameters.Count - 1; i >= 0; --i) {
+ var p = pb.Parameters[i];
+ if (p.Name == Name)
+ return pb.GetParameterReference (i, loc);
+
+ var tp = p as QueryBlock.TransparentParameter;
+ while (tp != null) {
+ if (expr == null)
+ expr = pb.GetParameterReference (i, loc);
+ else
+ expr = new TransparentMemberAccess (expr, tp.Name);
+
+ if (tp.Identifier == Name)
+ return new TransparentMemberAccess (expr, Name);
+
+ if (tp.Parent.Name == Name)
+ return new TransparentMemberAccess (expr, Name);
+
+ tp = tp.Parent as QueryBlock.TransparentParameter;
+ }
+ }
+
+ expr = null;
+ }
+
+ if (pb == block)
+ return null;
+
+ pb = pb.Parent.ParametersBlock;
+ }
}
}
- public class Cast : QueryStartClause
+ class QueryStartClause : ARangeVariableQueryClause
{
- // We don't have to clone cast type
- readonly Expression type_expr;
-
- public Cast (Expression type, Expression expr)
- : base (expr)
+ public QueryStartClause (QueryBlock block, Expression expr, RangeVariable identifier, Location loc)
+ : base (block, identifier, expr, loc)
{
- this.type_expr = type;
+ block.AddRangeVariable (identifier);
}
-
- public override Expression BuildQueryClause (EmitContext ec, Expression lSide, Parameter parameter, TransparentIdentifiersScope ti)
+
+ public override Expression BuildQueryClause (ResolveContext ec, Expression lSide, Parameter parameter)
{
- lSide = CreateQueryExpression (expr, new TypeArguments (loc, type_expr), null);
- if (next != null)
- return next.BuildQueryClause (ec, lSide, parameter, ti);
+/*
+ expr = expr.Resolve (ec);
+ if (expr == null)
+ return null;
- return lSide;
+ if (expr.Type == InternalType.Dynamic || expr.Type == TypeManager.void_type) {
+ ec.Report.Error (1979, expr.Location,
+ "Query expression with a source or join sequence of type `{0}' is not allowed",
+ TypeManager.CSharpName (expr.Type));
+ return null;
+ }
+*/
+
+ if (IdentifierType != null)
+ expr = CreateCastExpression (expr);
+
+ if (parameter == null)
+ lSide = expr;
+
+ return next.BuildQueryClause (ec, lSide, new ImplicitLambdaParameter (identifier.Name, identifier.Location));
+ }
+
+ protected override Expression DoResolve (ResolveContext ec)
+ {
+ Expression e = BuildQueryClause (ec, null, null);
+ return e.Resolve (ec);
}
protected override string MethodName {
- get { return "Cast"; }
+ get { throw new NotSupportedException (); }
}
}
public class GroupBy : AQueryClause
{
Expression element_selector;
-
- public GroupBy (Expression elementSelector, Expression keySelector, Location loc)
- : base (keySelector, loc)
+ QueryBlock element_block;
+
+ public GroupBy (QueryBlock block, Expression elementSelector, QueryBlock elementBlock, Expression keySelector, Location loc)
+ : base (block, keySelector, loc)
{
- this.element_selector = elementSelector;
+ //
+ // Optimizes clauses like `group A by A'
+ //
+ if (!elementSelector.Equals (keySelector)) {
+ this.element_selector = elementSelector;
+ this.element_block = elementBlock;
+ }
}
- public override Expression BuildQueryClause (EmitContext ec, Expression lSide, Parameter parameter, TransparentIdentifiersScope ti)
+ protected override void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args)
{
- ArrayList args = new ArrayList (2);
- args.Add (CreateSelectorArgument (ec, expr, parameter, ti));
-
- // A query can be optimized when selector is not group by specific
- if (!element_selector.Equals (lSide))
- args.Add (CreateSelectorArgument (ec, element_selector, parameter, ti));
+ base.CreateArguments (ec, parameter, ref args);
- lSide = CreateQueryExpression (lSide, args);
- if (next != null)
- return next.BuildQueryClause (ec, lSide, parameter, ti);
+ if (element_selector != null) {
+ LambdaExpression lambda = new LambdaExpression (element_selector.Location);
- return lSide;
+ element_block.SetParameter (parameter.Clone ());
+ lambda.Block = element_block;
+ lambda.Block.AddStatement (new ContextualReturn (element_selector));
+ args.Add (new Argument (lambda));
+ }
}
-
+
protected override void CloneTo (CloneContext clonectx, Expression target)
{
GroupBy t = (GroupBy) target;
- t.element_selector = element_selector.Clone (clonectx);
+ if (element_selector != null) {
+ t.element_selector = element_selector.Clone (clonectx);
+ t.element_block = (QueryBlock) element_block.Clone (clonectx);
+ }
+
base.CloneTo (clonectx, t);
}
}
}
- public class Join : ARangeVariableQueryClause
+ public class Join : SelectMany
{
- Expression projection;
- Expression inner_selector, outer_selector;
+ QueryBlock inner_selector, outer_selector;
- public Join (LocatedToken variable, Expression inner, Expression outerSelector, Expression innerSelector, Location loc)
- : base (variable, inner, loc)
+ public Join (QueryBlock block, RangeVariable lt, Expression inner, QueryBlock outerSelector, QueryBlock innerSelector, Location loc)
+ : base (block, lt, inner, loc)
{
this.outer_selector = outerSelector;
this.inner_selector = innerSelector;
}
- protected override void AddSelectorArguments (EmitContext ec, ArrayList args, Parameter parentParameter,
- ref Parameter parameter, TransparentIdentifiersScope ti)
+ protected override void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args)
{
+ args = new Arguments (4);
+
+ if (IdentifierType != null)
+ expr = CreateCastExpression (expr);
+
args.Add (new Argument (expr));
- args.Add (CreateSelectorArgument (ec, outer_selector, parentParameter, ti));
- args.Add (CreateSelectorArgument (ec, inner_selector, parameter, ti));
-
- parameter = CreateResultSelectorParameter (parameter);
- if (projection == null) {
- ArrayList join_args = new ArrayList (2);
- join_args.Add (new AnonymousTypeParameter (parentParameter));
- join_args.Add (new AnonymousTypeParameter (parameter));
- projection = new AnonymousTypeDeclaration (join_args, (TypeContainer) ec.TypeContainer, loc);
- }
- args.Add (CreateSelectorArgument (ec, projection,
- new Parameter [] { parentParameter, parameter }, ti));
+ outer_selector.SetParameter (parameter.Clone ());
+ var lambda = new LambdaExpression (outer_selector.StartLocation);
+ lambda.Block = outer_selector;
+ args.Add (new Argument (lambda));
+
+ inner_selector.SetParameter (new ImplicitLambdaParameter (identifier.Name, identifier.Location));
+ lambda = new LambdaExpression (inner_selector.StartLocation);
+ lambda.Block = inner_selector;
+ args.Add (new Argument (lambda));
+
+ base.CreateArguments (ec, parameter, ref args);
}
-
+
protected override void CloneTo (CloneContext clonectx, Expression target)
{
Join t = (Join) target;
- t.projection = projection.Clone (clonectx);
- t.inner_selector = inner_selector.Clone (clonectx);
- t.outer_selector = outer_selector.Clone (clonectx);
+ t.inner_selector = (QueryBlock) inner_selector.Clone (clonectx);
+ t.outer_selector = (QueryBlock) outer_selector.Clone (clonectx);
base.CloneTo (clonectx, t);
}
- protected virtual Parameter CreateResultSelectorParameter (Parameter parameter)
- {
- return parameter;
- }
-
- public override AQueryClause Next {
- set {
- // Use select as join projection
- if (value is Select) {
- projection = value.expr;
- next = value.next;
- return;
- }
-
- base.Next = value;
- }
- }
-
protected override string MethodName {
get { return "Join"; }
}
public class GroupJoin : Join
{
- readonly LocatedToken into_variable;
+ readonly RangeVariable into;
- public GroupJoin (LocatedToken variable, Expression inner, Expression outerSelector, Expression innerSelector,
- LocatedToken into, Location loc)
- : base (variable, inner, outerSelector, innerSelector, loc)
+ public GroupJoin (QueryBlock block, RangeVariable lt, Expression inner,
+ QueryBlock outerSelector, QueryBlock innerSelector, RangeVariable into, Location loc)
+ : base (block, lt, inner, outerSelector, innerSelector, loc)
{
- this.into_variable = into;
+ this.into = into;
}
- protected override Parameter CreateResultSelectorParameter (Parameter parameter)
+ protected override RangeVariable GetIntoVariable ()
{
- //
- // into variable is used as result selector and it's passed as
- // transparent identifiers to the next clause
- //
- return CreateBlockParameter (into_variable);
+ return into;
}
protected override string MethodName {
public class Let : ARangeVariableQueryClause
{
- class RangeAnonymousTypeParameter : AnonymousTypeParameter
- {
- readonly Parameter parameter;
-
- public RangeAnonymousTypeParameter (Expression initializer, Parameter parameter)
- : base (initializer, parameter.Name, parameter.Location)
- {
- this.parameter = parameter;
- }
-
- public override Expression DoResolve (EmitContext ec)
- {
- Expression e = base.DoResolve (ec);
- if (e != null) {
- //
- // Spread resolved initializer type
- //
- parameter.ParameterType = type;
- parameter.Resolve (ec);
- }
-
- return e;
- }
-
- protected override void Error_InvalidInitializer (Expression initializer)
- {
- Report.Error (1932, loc, "A range variable `{0}' cannot be initialized with `{1}'",
- Name, initializer.GetSignatureForError ());
- }
- }
-
- public Let (LocatedToken variable, Expression expr, Location loc)
- : base (variable, expr, loc)
- {
- }
-
- protected override void AddSelectorArguments (EmitContext ec, ArrayList args, Parameter parentParameter,
- ref Parameter parameter, TransparentIdentifiersScope ti)
+ public Let (QueryBlock block, RangeVariable identifier, Expression expr, Location loc)
+ : base (block, identifier, expr, loc)
{
- args.Add (CreateSelectorArgument (ec, element_selector, parentParameter, ti));
}
- protected override AnonymousTypeParameter CreateAnonymousTypeVariable (Parameter parameter)
+ protected override void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args)
{
- return new RangeAnonymousTypeParameter (expr, parameter);
+ expr = CreateRangeVariableType (ec, parameter, identifier, expr);
+ base.CreateArguments (ec, parameter, ref args);
}
protected override string MethodName {
public class Select : AQueryClause
{
- public Select (Expression expr, Location loc)
- : base (expr, loc)
+ public Select (QueryBlock block, Expression expr, Location loc)
+ : base (block, expr, loc)
{
}
public class SelectMany : ARangeVariableQueryClause
{
- public SelectMany (LocatedToken variable, Expression expr)
- : base (variable, expr, expr.Location)
+ public SelectMany (QueryBlock block, RangeVariable identifier, Expression expr, Location loc)
+ : base (block, identifier, expr, loc)
{
}
- protected override string MethodName {
- get { return "SelectMany"; }
- }
+ protected override void CreateArguments (ResolveContext ec, Parameter parameter, ref Arguments args)
+ {
+ if (args == null) {
+ if (IdentifierType != null)
+ expr = CreateCastExpression (expr);
- public override AQueryClause Next {
- set {
- element_selector = value.expr;
+ base.CreateArguments (ec, parameter, ref args);
+ }
- // Can be optimized as SelectMany element selector
- if (value is Select)
- return;
+ Expression result_selector_expr;
+ QueryBlock result_block;
- next = value;
+ var target = GetIntoVariable ();
+ var target_param = new ImplicitLambdaParameter (target.Name, target.Location);
+
+ //
+ // When select follows use it as a result selector
+ //
+ if (next is Select) {
+ result_selector_expr = next.Expr;
+
+ result_block = next.block;
+ result_block.SetParameters (parameter, target_param);
+
+ next = next.next;
+ } else {
+ result_selector_expr = CreateRangeVariableType (ec, parameter, target, new SimpleName (target.Name, target.Location));
+
+ result_block = new QueryBlock (ec.Compiler, block.Parent, block.StartLocation);
+ result_block.SetParameters (parameter, target_param);
}
+
+ LambdaExpression result_selector = new LambdaExpression (Location);
+ result_selector.Block = result_block;
+ result_selector.Block.AddStatement (new ContextualReturn (result_selector_expr));
+
+ args.Add (new Argument (result_selector));
+ }
+
+ protected override string MethodName {
+ get { return "SelectMany"; }
}
}
public class Where : AQueryClause
{
- public Where (Expression expr, Location loc)
- : base (expr, loc)
+ public Where (QueryBlock block, BooleanExpression expr, Location loc)
+ : base (block, expr, loc)
{
}
public class OrderByAscending : AQueryClause
{
- public OrderByAscending (Expression expr)
- : base (expr, expr.Location)
+ public OrderByAscending (QueryBlock block, Expression expr)
+ : base (block, expr, expr.Location)
{
}
public class OrderByDescending : AQueryClause
{
- public OrderByDescending (Expression expr)
- : base (expr, expr.Location)
+ public OrderByDescending (QueryBlock block, Expression expr)
+ : base (block, expr, expr.Location)
{
}
public class ThenByAscending : OrderByAscending
{
- public ThenByAscending (Expression expr)
- : base (expr)
+ public ThenByAscending (QueryBlock block, Expression expr)
+ : base (block, expr)
{
}
public class ThenByDescending : OrderByDescending
{
- public ThenByDescending (Expression expr)
- : base (expr)
+ public ThenByDescending (QueryBlock block, Expression expr)
+ : base (block, expr)
{
}
}
}
- class ImplicitQueryParameter : ImplicitLambdaParameter
+ //
+ // Implicit query block
+ //
+ public class QueryBlock : ParametersBlock
{
- public sealed class ImplicitType : Expression
+ //
+ // Transparent parameters are used to package up the intermediate results
+ // and pass them onto next clause
+ //
+ public sealed class TransparentParameter : ImplicitLambdaParameter
{
- public static ImplicitType Instance = new ImplicitType ();
-
- private ImplicitType ()
- {
- }
+ public static int Counter;
+ const string ParameterNamePrefix = "<>__TranspIdent";
- protected override void CloneTo (CloneContext clonectx, Expression target)
- {
- // Nothing to clone
- }
+ public readonly Parameter Parent;
+ public readonly string Identifier;
- public override Expression DoResolve (EmitContext ec)
+ public TransparentParameter (Parameter parent, RangeVariable identifier)
+ : base (ParameterNamePrefix + Counter++, identifier.Location)
{
- throw new NotSupportedException ();
+ Parent = parent;
+ Identifier = identifier.Name;
}
- public override void Emit (EmitContext ec)
+ public new static void Reset ()
{
- throw new NotSupportedException ();
+ Counter = 0;
}
}
- public ImplicitQueryParameter (LocatedToken variable)
- : base (variable.Value, variable.Location)
- {
- }
- }
-
- //
- // Transparent parameters are used to package up the intermediate results
- // and pass them onto next clause
- //
- public class TransparentParameter : ImplicitLambdaParameter
- {
- static int counter;
- const string ParameterNamePrefix = "<>__TranspIdent";
-
- public TransparentParameter (Location loc)
- : base (ParameterNamePrefix + counter++, loc)
+ public QueryBlock (CompilerContext ctx, Block parent, Location start)
+ : base (parent, ParametersCompiled.EmptyReadOnlyParameters, start)
{
+ flags |= Flags.CompilerGenerated;
}
- }
-
- //
- // Transparent identifiers are stored in nested anonymous types, each type can contain
- // up to 2 identifiers or 1 identifier and parent type.
- //
- public class TransparentIdentifiersScope
- {
- readonly string [] identifiers;
- readonly TransparentIdentifiersScope parent;
- readonly TransparentParameter parameter;
- public TransparentIdentifiersScope (TransparentIdentifiersScope parent,
- TransparentParameter parameter, string [] identifiers)
+ public void AddRangeVariable (RangeVariable variable)
{
- this.parent = parent;
- this.parameter = parameter;
- this.identifiers = identifiers;
+ variable.Block = this;
+ AddLocalName (variable.Name, variable);
}
- public MemberAccess GetIdentifier (string name)
+ public override void Error_AlreadyDeclared (string name, INamedBlockVariable variable, string reason)
{
- TransparentIdentifiersScope ident = FindIdentifier (name);
- if (ident == null)
- return null;
-
- return new MemberAccess (CreateIdentifierNestingExpression (ident), name);
+ TopBlock.Report.Error (1931, variable.Location,
+ "A range variable `{0}' conflicts with a previous declaration of `{0}'",
+ name);
}
- TransparentIdentifiersScope FindIdentifier (string name)
+ public override void Error_AlreadyDeclared (string name, INamedBlockVariable variable)
{
- foreach (string s in identifiers) {
- if (s == name)
- return this;
- }
-
- if (parent == null)
- return null;
-
- return parent.FindIdentifier (name);
+ TopBlock.Report.Error (1930, variable.Location,
+ "A range variable `{0}' has already been declared in this scope",
+ name);
}
- Expression CreateIdentifierNestingExpression (TransparentIdentifiersScope end)
+ public override void Error_AlreadyDeclaredTypeParameter (string name, Location loc)
{
- Expression expr = new SimpleName (parameter.Name, parameter.Location);
- TransparentIdentifiersScope current = this;
- while (current != end)
- {
- current = current.parent;
- expr = new MemberAccess (expr, current.parameter.Name);
- }
-
- return expr;
+ TopBlock.Report.Error (1948, loc,
+ "A range variable `{0}' conflicts with a method type parameter",
+ name);
}
- }
-
- //
- // Lambda expression block which contains transparent identifiers
- //
- class SelectorBlock : ToplevelBlock
- {
- readonly TransparentIdentifiersScope transparent_identifiers;
- public SelectorBlock (Block block, Parameters parameters,
- TransparentIdentifiersScope transparentIdentifiers, Location loc)
- : base (block, parameters, loc)
+ public void SetParameter (Parameter parameter)
{
- this.transparent_identifiers = transparentIdentifiers;
+ base.parameters = new ParametersCompiled (parameter);
+ base.parameter_info = new ParameterInfo[] {
+ new ParameterInfo (this, 0)
+ };
}
- public override Expression GetTransparentIdentifier (string name)
+ public void SetParameters (Parameter first, Parameter second)
{
- Expression expr = null;
- if (transparent_identifiers != null)
- expr = transparent_identifiers.GetIdentifier (name);
-
- if (expr != null || Container == null)
- return expr;
-
- return Container.GetTransparentIdentifier (name);
+ base.parameters = new ParametersCompiled (first, second);
+ base.parameter_info = new ParameterInfo[] {
+ new ParameterInfo (this, 0),
+ new ParameterInfo (this, 1)
+ };
}
}
- //
- // This block is actually never used, it is used by parser only
- //
- public class QueryBlock : Block
+ sealed class TransparentMemberAccess : MemberAccess
{
- Hashtable range_variables = new Hashtable ();
-
- public QueryBlock (Block parent, Location start)
- : base (parent, start, Location.Null)
+ public TransparentMemberAccess (Expression expr, string name)
+ : base (expr, name)
{
}
- protected override void AddVariable (LocalInfo li)
+ public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
{
- string name = li.Name;
- if (range_variables.Contains (name)) {
- Location conflict = (Location)range_variables [name];
- Report.SymbolRelatedToPreviousError (conflict, name);
- Error_AlreadyDeclared (li.Location, name);
- return;
- }
+ rc.Report.Error (1947, loc,
+ "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
+ Name);
- range_variables.Add (name, li.Location);
- }
-
- protected override void Error_AlreadyDeclared (Location loc, string var, string reason)
- {
- Report.Error (1931, loc, "A range variable `{0}' conflicts with a previous declaration of `{0}'",
- var);
- }
-
- protected override void Error_AlreadyDeclared (Location loc, string var)
- {
- Report.Error (1930, loc, "A range variable `{0}' has already been declared in this scope",
- var);
- }
-
- protected override void Error_AlreadyDeclaredTypeParameter (Location loc, string name)
- {
- Report.Error (1948, loc, "A range variable `{0}' conflicts with a method type parameter",
- name);
+ return null;
}
}
}