B.ExplicitMemberInfo ConvertInterfaceImplementations(List<InterfaceImplementation> implementations, AttributedNode node, B.TypeMember targetMember)
		{
			if (implementations.Count == 0)
				return null;
			if (implementations.Count > 1) {
				AddError(node, "Multiple explicit interface implementations are not supported");
			}
			if (implementations[0].MemberName != targetMember.Name) {
				AddError(node, "Explicit interface implementation: Implementing member with different name is not supported");
			}
			if (targetMember.Modifiers == B.TypeMemberModifiers.Private) {
				targetMember.Modifiers = B.TypeMemberModifiers.None;
			} else {
				AddError(node, "Explicit interface implementation: Only private methods can explicitly implement interfaces");
			}
			B.TypeReference tr = ConvertTypeReference(implementations[0].InterfaceType);
			if (tr is B.SimpleTypeReference) {
				B.ExplicitMemberInfo explicitInfo = new B.ExplicitMemberInfo(GetLexicalInfo(node));
				explicitInfo.InterfaceType = (B.SimpleTypeReference)tr;
				return explicitInfo;
			} else {
				AddError(node, "Explicit interface implementation: invalid base type, expecting SimpleTypeReference");
				return null;
			}
		}
		private ModifierEnum GetModifier(AST.TypeMember m)
		{
			ModifierEnum r = ModifierEnum.None;
			if (m.IsPublic)    r |= ModifierEnum.Public;
			if (m.IsProtected) r |= ModifierEnum.Protected;
			if (m.IsPrivate)   r |= ModifierEnum.Private;
			if (m.IsInternal)  r |= ModifierEnum.Internal;
			if (!m.IsVisibilitySet) {
				if (IsStrictMode(_cu.ProjectContent))
					r |= ModifierEnum.Private;
				else if (m is AST.Field)
					r |= ModifierEnum.Protected;
				else
					r |= ModifierEnum.Public;
			}
			
			if (m.IsStatic) r |= ModifierEnum.Static;
			if (m is AST.Field) {
				if (m.IsFinal) r |= ModifierEnum.Readonly;
			} else {
				if (m.IsFinal) r |= ModifierEnum.Sealed;
			}
			if (m.IsAbstract)  r |= ModifierEnum.Abstract;
			if (m.IsOverride)  r |= ModifierEnum.Override;
			if (m.IsSynthetic) r |= ModifierEnum.Synthetic;
			if (m.IsPartial)   r |= ModifierEnum.Partial;
			
			if (m.LexicalInfo.IsValid && m.DeclaringType != null
			    && m.LexicalInfo.Line < m.DeclaringType.LexicalInfo.Line)
			{ // member added through attribute
				r |= ModifierEnum.Synthetic;
			}
			return r;
		}
		void ConvertExpressions(IEnumerable input, B.ExpressionCollection output)
		{
			foreach (Expression e in input) {
				B.Expression expr = ConvertExpression(e);
				if (expr != null) {
					output.Add(expr);
				}
			}
		}
 public override void OnModule(Module node)
 {
     var imports = new[] { "UnityEngine", "System.Collections" };
     foreach (var importName in imports)
     {
         var targetImport = new Import(LexicalInfo.Empty, importName);
         if (node.Imports.Contains(targetImport))
             node.Imports.Add(targetImport);
     }
 }
		void AddToBlock(Statement n, B.Block b)
		{
			object result = ConvertStatementInternal(n);
			if (result is ArrayList) {
				foreach (B.Statement stmt in (ArrayList)result) {
					b.Add(stmt);
				}
			} else {
				B.Statement stmt = (B.Statement)result;
				if (stmt != null) {
					b.Add(stmt);
				}
			}
		}
		public override void LeaveEnumDefinition(AST.EnumDefinition node)
		{
			LeaveTypeDefinition(node);
			base.LeaveEnumDefinition(node);
		}
		public override void LeaveInterfaceDefinition(AST.InterfaceDefinition node)
		{
			LeaveTypeDefinition(node);
			base.LeaveInterfaceDefinition(node);
		}
		public static IReturnType CreateReturnType(AST.TypeReference reference, IClass callingClass,
		                                           IMethodOrProperty callingMember, int caretLine, int caretColumn,
		                                           IProjectContent projectContent)
		{
			System.Diagnostics.Debug.Assert(projectContent != null);
			if (reference == null) {
				return GetDefaultReturnType(projectContent);
			}
			if (reference is AST.ArrayTypeReference) {
				AST.ArrayTypeReference arr = (AST.ArrayTypeReference)reference;
				return new ArrayReturnType(projectContent,
				                           CreateReturnType(arr.ElementType, callingClass, callingMember,
				                                            caretLine, caretColumn, projectContent),
				                           (arr.Rank != null) ? (int)arr.Rank.Value : 1);
			} else if (reference is AST.SimpleTypeReference) {
				string name = ((AST.SimpleTypeReference)reference).Name;
				IReturnType rt;
				int typeParameterCount = (reference is AST.GenericTypeReference) ? ((AST.GenericTypeReference)reference).GenericArguments.Count : 0;
				if (name == "duck")
					rt = new BooResolver.DuckClass(new DefaultCompilationUnit(projectContent)).DefaultReturnType;
				else if (BooAmbience.ReverseTypeConversionTable.ContainsKey(name))
					rt = new GetClassReturnType(projectContent, BooAmbience.ReverseTypeConversionTable[name], typeParameterCount);
				else if (callingClass == null)
					rt = new GetClassReturnType(projectContent, name, typeParameterCount);
				else
					rt = new SearchClassReturnType(projectContent, callingClass, caretLine, caretColumn,
					                               name, typeParameterCount);
				if (typeParameterCount > 0) {
					AST.TypeReferenceCollection arguments = ((AST.GenericTypeReference)reference).GenericArguments;
					// GenericTypeReference derives from SimpleTypeReference
					IReturnType[] typeArguments = new IReturnType[arguments.Count];
					for (int i = 0; i < typeArguments.Length; i++) {
						typeArguments[i] = CreateReturnType(arguments[i], callingClass, callingMember, caretLine, caretColumn,
						                                    projectContent);
					}
					rt = new ConstructedReturnType(rt, typeArguments);
				}
				return rt;
			} else if (reference is AST.CallableTypeReference) {
				AST.CallableTypeReference ctr = (AST.CallableTypeReference)reference;
				AnonymousMethodReturnType amrt = new AnonymousMethodReturnType(new DefaultCompilationUnit(projectContent));
				if (ctr.ReturnType != null) {
					amrt.MethodReturnType = CreateReturnType(ctr.ReturnType, callingClass, callingMember, caretLine, caretColumn, projectContent);
				}
				amrt.MethodParameters = new List<IParameter>();
				AddParameters(ctr.Parameters, amrt.MethodParameters, callingMember, callingClass ?? new DefaultClass(new DefaultCompilationUnit(projectContent), "__Dummy"));
				return amrt;
			} else {
				throw new NotSupportedException("unknown reference type: " + reference.ToString());
			}
		}
		public override void OnField(AST.Field node)
		{
			DefaultField field = new DefaultField(CreateReturnType(node), node.Name, GetModifier(node), GetRegion(node), OuterClass);
			ConvertAttributes(node, field);
			OuterClass.Fields.Add(field);
		}
		public override void OnConstructor(AST.Constructor node)
		{
			if (node.IsSynthetic && node.Parameters.Count == 0) return;
			Constructor ctor = new Constructor(GetModifier(node), GetRegion(node), GetClientRegion(node), OuterClass);
			ConvertAttributes(node, ctor);
			ConvertParameters(node.Parameters, ctor);
			_currentClass.Peek().Methods.Add(ctor);
			ctor.UserData = node;
		}
		protected override void OnError(AST.Node node, Exception error)
		{
			MessageService.ShowError(error, "error processing " + node.ToCodeString());
		}
		public override bool EnterInterfaceDefinition(AST.InterfaceDefinition node)
		{
			EnterTypeDefinition(node, ClassType.Interface);
			return base.EnterInterfaceDefinition(node);
		}
		public override void OnCallableDefinition(AST.CallableDefinition node)
		{
			LoggingService.Debug("OnCallableDefinition: " + node.FullName);
			DomRegion region = GetRegion(node);
			DefaultClass c = new DefaultClass(_cu, ClassType.Delegate, GetModifier(node), region, OuterClass);
			ConvertAttributes(node, c);
			c.BaseTypes.Add(c.ProjectContent.SystemTypes.Delegate);
			c.FullyQualifiedName = node.FullName;
			if (_currentClass.Count > 0) {
				OuterClass.InnerClasses.Add(c);
			} else {
				_cu.Classes.Add(c);
			}
			_currentClass.Push(c); // necessary for CreateReturnType
			ConvertTemplates(node, c);
			IReturnType returnType = CreateReturnType(node.ReturnType);
			DefaultMethod invokeMethod = new DefaultMethod("Invoke", returnType, ModifierEnum.Public, DomRegion.Empty, DomRegion.Empty, c);
			ConvertParameters(node.Parameters, invokeMethod);
			c.Methods.Add(invokeMethod);
			invokeMethod = new DefaultMethod("BeginInvoke", c.ProjectContent.SystemTypes.IAsyncResult, ModifierEnum.Public, DomRegion.Empty, DomRegion.Empty, c);
			ConvertParameters(node.Parameters, invokeMethod);
			if (invokeMethod.Parameters == DefaultParameter.EmptyParameterList) {
				invokeMethod.Parameters = new List<IParameter>();
			}
			invokeMethod.Parameters.Add(new DefaultParameter("callback", c.ProjectContent.SystemTypes.AsyncCallback, DomRegion.Empty));
			invokeMethod.Parameters.Add(new DefaultParameter("object", c.ProjectContent.SystemTypes.Object, DomRegion.Empty));
			c.Methods.Add(invokeMethod);
			invokeMethod = new DefaultMethod("EndInvoke", returnType, ModifierEnum.Public, DomRegion.Empty, DomRegion.Empty, c);
			invokeMethod.Parameters.Add(new DefaultParameter("result", c.ProjectContent.SystemTypes.IAsyncResult, DomRegion.Empty));
			c.Methods.Add(invokeMethod);
			_currentClass.Pop();
		}
		IReturnType CreateReturnType(AST.Property property)
		{
			if (property.Type == null && property.Getter != null && property.Getter.Body != null)
				return new BooInferredReturnType(property.Getter.Body, OuterClass, false);
			return CreateReturnType(property.Type);
		}
		IReturnType CreateReturnType(AST.Method node, IMethod method)
		{
			if (node.ReturnType == null)
				return new BooInferredReturnType(node.Body, OuterClass, false);
			return CreateReturnType(node.ReturnType, method);
		}
		IReturnType CreateReturnType(AST.Field field)
		{
			if (field.Type == null) {
				if (field.Initializer != null)
					return new BooInferredReturnType(field.Initializer, OuterClass);
				else
					return GetDefaultReturnType(_cu.ProjectContent);
			} else {
				return CreateReturnType(field.Type);
			}
		}
		IReturnType CreateReturnType(AST.TypeReference reference)
		{
			return CreateReturnType(reference, null);
		}
		public override void LeaveModule(AST.Module node)
		{
			if (_currentClass.Count != 0) LeaveTypeDefinition(node);
			base.LeaveModule(node);
		}
		private void LeaveTypeDefinition(AST.TypeDefinition node)
		{
			DefaultClass c = _currentClass.Pop();
			foreach (AST.Attribute att in node.Attributes) {
				if (att.Name == "System.Reflection.DefaultMemberAttribute" && att.Arguments.Count == 1) {
					AST.StringLiteralExpression sle = att.Arguments[0] as AST.StringLiteralExpression;
					if (sle != null) {
						foreach (DefaultProperty p in c.Properties) {
							if (p.Name == sle.Value) {
								p.IsIndexer = true;
							}
						}
					}
				}
			}
			//LoggingService.Debug("Leave "+node.GetType().Name+" "+node.FullName+" (Class = "+c.FullyQualifiedName+")");
		}
		public override bool EnterEnumDefinition(AST.EnumDefinition node)
		{
			EnterTypeDefinition(node, ClassType.Enum);
			return base.EnterEnumDefinition(node);
		}
		public override void OnMethod(AST.Method node)
		{
			//LoggingService.Debug("Method: " + node.FullName + " (" + node.Modifiers + ")");
			DefaultMethod method = new DefaultMethod(node.Name, null, GetModifier(node), GetRegion(node), GetClientRegion(node), OuterClass);
			
			foreach (AST.Attribute a in node.Attributes) {
				if (a.Name == "Extension" || a.Name == "Boo.Lang.Extension"
				    || a.Name == "ExtensionAttribute" || a.Name == "Boo.Lang.ExtensionAttribute")
				{
					method.IsExtensionMethod = true;
				}
			}
			
			ConvertAttributes(node, method);
			ConvertTemplates(node, method);
			// return type must be assigned AFTER ConvertTemplates
			method.ReturnType = CreateReturnType(node, method);
			ConvertParameters(node.Parameters, method);
			_currentClass.Peek().Methods.Add(method);
			method.UserData = node;
		}
		// cannot override OnNamespaceDeclaration - it's visited too late (after the type definitions)
		void HandleNamespaceDeclaration(AST.NamespaceDeclaration node)
		{
			if (node == null)
				return;
			string[] namespaceName = node.Name.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string namePart in namespaceName) {
				_cu.UsingScope = new DefaultUsingScope {
					NamespaceName = PrependCurrentNamespace(namePart),
					Parent = _cu.UsingScope
				};
			}
		}
		public override void OnEnumMember(AST.EnumMember node)
		{
			DefaultField field = new DefaultField(OuterClass.DefaultReturnType, node.Name, ModifierEnum.Const | ModifierEnum.Public, GetRegion(node), OuterClass);
			ConvertAttributes(node, field);
			OuterClass.Fields.Add(field);
		}
		public override void OnEvent(AST.Event node)
		{
			DomRegion region = GetRegion(node);
			DefaultEvent e = new DefaultEvent(node.Name, CreateReturnType(node.Type), GetModifier(node), region, region, OuterClass);
			ConvertAttributes(node, e);
			OuterClass.Events.Add(e);
		}
		public override bool EnterModule(AST.Module node)
		{
			HandleNamespaceDeclaration(node.Namespace);
			if (!_firstModule && node.Members.Count > 0) {
				EnterTypeDefinition(node, ClassType.Module);
			}
			_firstModule = false;
			return base.EnterModule(node);
		}
		public IReturnType GetTypeOfExpression(AST.Expression expr, IClass callingClass)
		{
			AST.Node node = expr;
			AST.LexicalInfo lexInfo;
			do {
				if (node == null) return null;
				lexInfo = node.LexicalInfo;
				node = node.ParentNode;
			} while (lexInfo == null || lexInfo.FileName == null);
			if (!Initialize(ParserService.GetParseInformation(lexInfo.FileName), lexInfo.Line, lexInfo.Column))
				return null;
			if (callingClass != null)
				this.callingClass = callingClass;
			ResolveVisitor visitor = new ResolveVisitor(this);
			visitor.Visit(expr);
			if (visitor.ResolveResult == null)
				return null;
			else
				return visitor.ResolveResult.ResolvedType;
		}
		public override void OnProperty(AST.Property node)
		{
			DefaultProperty property = new DefaultProperty(node.Name, CreateReturnType(node), GetModifier(node), GetRegion(node), GetClientRegion(node), OuterClass);
			ConvertAttributes(node, property);
			ConvertParameters(node.Parameters, property);
			if (node.Getter != null && node.Getter.Body != null) {
				property.GetterRegion = GetClientRegion(node.Getter);
			}
			if (node.Setter != null && node.Setter.Body != null) {
				property.SetterRegion = GetClientRegion(node.Setter);
			}
			property.IsIndexer = (node.Name == "self");
			OuterClass.Properties.Add(property);
			property.UserData = node;
		}
		private void EnterTypeDefinition(AST.TypeDefinition node, ClassType classType)
		{
			//LoggingService.Debug("Enter " + node.GetType().Name + " (" + node.FullName + ")");
			foreach (AST.Attribute att in node.Attributes) {
				if (att.Name == "Boo.Lang.ModuleAttribute")
					classType = ClassType.Module;
			}
			DomRegion region = GetClientRegion(node);
			DefaultClass c = new DefaultClass(_cu, classType, GetModifier(node), region, OuterClass);
			c.FullyQualifiedName = node.FullName;
			if (_currentClass.Count > 0)
				_currentClass.Peek().InnerClasses.Add(c);
			else
				_cu.Classes.Add(c);
			_currentClass.Push(c);
			ConvertAttributes(node, c);
			ConvertTemplates(node, c);
			if (node.BaseTypes != null) {
				foreach (AST.TypeReference r in node.BaseTypes) {
					c.BaseTypes.Add(CreateReturnType(r));
				}
			}
		}
		public IReturnType ConvertType(AST.TypeReference typeRef)
		{
			return ConvertVisitor.CreateReturnType(typeRef, callingClass, callingMember,
			                                       caretLine, caretColumn, pc);
		}
		public override void LeaveClassDefinition(AST.ClassDefinition node)
		{
			LeaveTypeDefinition(node);
			base.LeaveClassDefinition(node);
		}