Sophie

Sophie

distrib > Mageia > 5 > x86_64 > by-pkgid > f4c6d82570d6aeb5e9ac6aa8d8ddccb1 > files > 78

boo-0.9.4.9-6.mga5.noarch.rpm

#region license
// Copyright (c) 2005, Sorin Ionescu (sorin.ionescu@gmail.com)
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
// 
//     * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//     * Neither the name of Sorin Ionescu nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#endregion

namespace Boo.Examples.Attributes

import System;
import System.Runtime.Remoting.Messaging
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.Steps

class AsyncAttribute(AbstractAstAttribute):
"""
Adds asynchronous helpers Begin<Method>/End<Method>
for a method.
"""	
	_method          as Method
	_accessModifiers as TypeMemberModifiers
	_disposed		 as ReferenceExpression
	
	def constructor():
		pass
		
	def constructor(disposed as ReferenceExpression):
		_disposed = disposed
	
	override def Apply(node as Node):	
		assert node isa Method
		
		_method = node
		
		if _method.IsProtected and _method.IsInternal:
			_accessModifiers = TypeMemberModifiers.Protected
			_accessModifiers = _accessModifiers | TypeMemberModifiers.Internal
			
		elif _method.IsPublic:
			_accessModifiers = TypeMemberModifiers.Public
			
		elif _method.IsProtected:
			_accessModifiers = TypeMemberModifiers.Protected
			
		elif _method.IsInternal:
			_accessModifiers = TypeMemberModifiers.Internal
			
		elif _method.IsPrivate:
			_accessModifiers = TypeMemberModifiers.Private
		
		EmitBeginMethod()
		EmitEndMethod()
	
	private def EmitBeginMethod():
		beginMethod = Method(
						self.LexicalInfo,
						Name: "Begin" + _method.Name,
						Modifiers: _accessModifiers,
						ReturnType: CodeBuilder.CreateTypeReference(typeof(IAsyncResult)))
		beginMethod.Parameters.ExtendWithClones(_method.Parameters)			
		beginMethod.Parameters.Add(
				ParameterDeclaration(
					"callback",
					CodeBuilder.CreateTypeReference(typeof(AsyncCallback))))
		beginMethod.Parameters.Add(
				ParameterDeclaration(
					"state",
					CodeBuilder.CreateTypeReference(typeof(object))))
		
		asyncInvocation = MethodInvocationExpression(
							Target: MemberReferenceExpression(
										ReferenceExpression(_method.Name),
										"BeginInvoke"))
		for parameter in beginMethod.Parameters:
			asyncInvocation.Arguments.Add(
					ReferenceExpression(parameter.Name))
		
		EmitDisposedObjectCheck(beginMethod) if _disposed is not null
		beginMethod.Body.Add(ReturnStatement(asyncInvocation))			
		_method.DeclaringType.Members.Add(beginMethod)
		
	private def EmitEndMethod():
		endMethod = Method(
						self.LexicalInfo,
						Name: "End" + _method.Name,
						Modifiers: _accessModifiers)		
		endMethod.Parameters.Add(
			ParameterDeclaration(
				"result",
				CodeBuilder.CreateTypeReference(typeof(IAsyncResult))))	
		
		asyncInvocation = MethodInvocationExpression(
							Target: MemberReferenceExpression(
										ReferenceExpression(_method.Name),
										"EndInvoke"))			
		asyncInvocation.Arguments.Add(ReferenceExpression("result"))
		
		EmitDisposedObjectCheck(endMethod) if _disposed is not null
		endMethod.Body.Add(ReturnStatement(asyncInvocation))
		
		_method.DeclaringType.Members.Add(endMethod)
		
		# cache the voidType reference because we are going
		# to lose the context after this method returns
		# (see AbstractCompilerComponent.Dispose)
		voidType = Context.TypeSystemServices.VoidType
		Context.Parameters.Pipeline.AfterStep += def (sender, e as CompilerStepEventArgs):
			if e.Step isa ProcessMethodBodies:
				if _method.ReturnType.Entity is voidType:
					returnStatement = endMethod.Body.Statements[-1] as ReturnStatement
					endMethod.Body.Statements.Replace(
							returnStatement,
							ExpressionStatement(returnStatement.Expression))
							
	private def EmitDisposedObjectCheck(method as Method):
		exceptionCreation = MethodInvocationExpression(
								Target: MemberReferenceExpression(
											ReferenceExpression("System"), "ObjectDisposedException"))								
		exceptionCreation.Arguments.Add(StringLiteralExpression(_method.DeclaringType.Name))
		# TODO: Access Boo resources to get the exception message.
		exceptionCreation.Arguments.Add(StringLiteralExpression("<Resources.ObjectDisposedExceptionMessage>"))
		
		trueBlock = Block()
		trueBlock.Add(RaiseStatement(exceptionCreation))
		method.Body.Add(IfStatement(_disposed.CloneNode(), trueBlock, null))