exec superceded by load

exec superceded by load

git-svn-id: c3b8989232654601f1acea7403f771adaaa44a81@1567 2c1201b4-01cd-e047-a400-b836ae1fbc61

#region license
// Copyright (c) 2004, Rodrigo B. de Oliveira (rbo@acm.org)
// All rights reserved.
//
// This file is part of Boo Explorer.
//
// Boo Explorer is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Boo Explorer is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Foobar; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#endregion

"""
Interactive Forms-based Console
"""
namespace booish.gui

import System
import System.Drawing
import System.IO
import System.Windows.Forms
import ICSharpCode.TextEditor
import ICSharpCode.TextEditor.Document
import ICSharpCode.TextEditor.Actions
import ICSharpCode.TextEditor.Gui.CompletionWindow
import Boo.Lang.Compiler.TypeSystem

interface ICompletionWindowImageProvider:
	ImageList as ImageList:
		get
	NamespaceIndex as int:
		get
	ClassIndex as int:
		get
	InterfaceIndex as int:
		get
	EnumIndex as int:
		get
	StructIndex as int:
		get
	CallableIndex as int:
		get
	MethodIndex as int:
		get
	FieldIndex as int:
		get
	LiteralIndex as int:
		get
	PropertyIndex as int:
		get
	EventIndex as int:
		get

class InteractiveInterpreterControl(TextEditorControl):

	enum InputState:
		SingleLine = 0
		Block = 1

	class NullCompletionWindowImageProvider(ICompletionWindowImageProvider):

		public static final Instance = NullCompletionWindowImageProvider()

		[getter(ImageList)]
		_imageList = System.Windows.Forms.ImageList()

		NamespaceIndex as int:
			get:
				return 0
		ClassIndex as int:
			get:
				return 0
		InterfaceIndex as int:
			get:
				return 0
		EnumIndex as int:
			get:
				return 0
		StructIndex as int:
			get:
				return 0
		CallableIndex as int:
			get:
				return 0
		MethodIndex as int:
			get:
				return 0
		FieldIndex as int:
			get:
				return 0
		LiteralIndex as int:
			get:
				return 0
		PropertyIndex as int:
			get:
				return 0
		EventIndex as int:
			get:
				return 0

	class LineHistory:

		_lines = []
		_current = 0

		event CurrentLineChanged as EventHandler

		def Add([required] line as string):
			if len(line) > 0 and line != LastLine:
				_lines.Add(line)
			_current = len(_lines)

		LastLine as string:
			get:
				return null if 0 == len(_lines)
				return _lines[-1]

		CurrentLine as string:
			get:
				return null if 0 == len(_lines)
				return _lines[_current]

		def Up():
			MoveTo(_current - 1)

		def Down():
			MoveTo(_current + 1)

		def MoveTo(index as int):
			return if 0 == len(_lines)
			old = _current
			_current = index % len(_lines)
			if old != _current:
				CurrentLineChanged(self, EventArgs.Empty)

	_state = InputState.SingleLine

	_block = System.IO.StringWriter()

	[getter(Interpreter)]
	_interpreter as Boo.Lang.Interpreter.InteractiveInterpreter

	_codeCompletionWindow as CodeCompletionWindow

	[property(CompletionWindowImageProvider, value is not null)]
	_imageProvider as ICompletionWindowImageProvider = NullCompletionWindowImageProvider()

	_lineHistory as LineHistory

	// HACK: when the completion window is shown through CTRL+SPACE
	// it behaves very strangely, the best we can do right now is
	// to prevent the user from typing
	_blockKeys = false

	def constructor():
		self._interpreter = Boo.Lang.Interpreter.InteractiveInterpreter(
								RememberLastValue: true,
								Print: self.print)
		self._interpreter.SetValue("cls", cls)
		self._lineHistory = LineHistory(CurrentLineChanged: _lineHistory_CurrentLineChanged)
		self.Document.HighlightingStrategy = GetBooHighlighting()
		self.EnableFolding =  false
		self.ShowLineNumbers =  false
		self.ShowSpaces = false
		self.ShowTabs =  true
		self.ShowEOLMarkers = false
		self.AllowCaretBeyondEOL = false
		self.ShowInvalidLines = false
		self.Dock = DockStyle.Fill

	CaretColumn:
		get:
			return self.ActiveTextAreaControl.Caret.Column

	CurrentLineText:
		get:
			segment = GetLastLineSegment()
			return self.Document.GetText(segment)[4:]

	override def OnLoad(args as EventArgs):
		super(args)
		prompt()

	def Eval(code as string):
		try:
			_interpreter.LoopEval(code)
		ensure:
			_state = InputState.SingleLine

	private def ConsumeCurrentLine():
		text as string = CurrentLineText # was accessing Control.text member
		_lineHistory.Add(text)
		print("")
		return text

	private def GetLastLineSegment():
		return self.Document.GetLineSegment(self.Document.LineSegmentCollection.Count)

	private def SingleLineInputState():
		code = ConsumeCurrentLine()
		if code[-1:] in ":", "\\":
			_state = InputState.Block
			_block.GetStringBuilder().Length = 0
			_block.WriteLine(code)
		else:
			Eval(code)

	private def BlockInputState():
		code = ConsumeCurrentLine()
		if 0 == len(code):
			Eval(_block.ToString())
		else:
			_block.WriteLine(code)

	def print(msg):
		AppendText("${msg}\r\n")

	def prompt():
		AppendText((">>> ", "... ")[_state])

	def ClearLine():
		segment = GetLastLineSegment()
		self.Document.Replace(segment.Offset + 4,
			self.CurrentLineText.Length,
			"")

	def AppendText(text as string):
		segment = GetLastLineSegment()
		self.Document.Insert(segment.Offset + segment.TotalLength, text)
		MoveCaretToEnd()

	def MoveCaretToEnd():
		segment = GetLastLineSegment()
		newOffset = segment.Offset + segment.TotalLength
		MoveCaretToOffset(newOffset)

	def MoveCaretToOffset(offset as int):
		self.ActiveTextAreaControl.Caret.Position = self.Document.OffsetToPosition(offset)

	override def InitializeTextAreaControl(newControl as TextAreaControl):
		super(newControl)
		newControl.TextArea.DoProcessDialogKey += HandleDialogKey
		newControl.TextArea.KeyEventHandler += HandleKeyPress

	InCodeCompletion:
		get:
			return _codeCompletionWindow is not null and not _codeCompletionWindow.IsDisposed

	private def DotComplete(ch as System.Char):
		ShowCompletionWindow(
			CodeCompletionDataProvider(_imageProvider, GetSuggestions()),
			ch)

	private def ShowCompletionWindow(completionDataProvider, ch as System.Char):
		_codeCompletionWindow = CodeCompletionWindow.ShowCompletionWindow(
					self.ParentForm,
					self,
					"<code>",
					completionDataProvider,
					ch)
		if _codeCompletionWindow is not null:
			_codeCompletionWindow.Closed += def():
				_blockKeys = false

	private def CtrlSpaceComplete():
		_blockKeys = true
		ShowCompletionWindow(
			GlobalsCompletionDataProvider(_imageProvider, self._interpreter),
			Char.MinValue)

	private def GetSuggestions():
		code = CurrentLineText.Insert(self.CaretColumn-4, ".__codecomplete__")
		code = code.Insert(0, _block.ToString()) if InputState.Block == _state
		suggestion = _interpreter.SuggestCodeCompletion(code) as INamespace
		return array(IEntity, 0) if suggestion is null
		return GetChildNamespaces(suggestion) if code.StartsWith("import ")
		return TypeSystemServices.GetAllMembers(suggestion)

	private def GetChildNamespaces(parent as INamespace):
		return array(member
					for member in parent.GetMembers()
					if member.EntityType == EntityType.Namespace)

	private def HandleDialogKey(key as Keys):
		return false if InCodeCompletion

		if key == Keys.Enter:
			try:
				(SingleLineInputState, BlockInputState)[_state]()
			except x:
				print(x)
			prompt()
			return true

		if key == Keys.Up:
			_lineHistory.Up()
			return true
		if key == Keys.Down:
			_lineHistory.Down()
			return true

		if key == (Keys.Control | Keys.Space):
			CtrlSpaceComplete()
			return true

		if key in Keys.Home, Keys.Shift|Keys.Home, Keys.Control|Keys.Home:
			MoveCaretToOffset(GetLastLineSegment().Offset + 4)
			return true

		if key == Keys.Escape:
			ClearLine()
			return true

		if key in Keys.Back, Keys.Left:
			if self.CaretColumn < 5:
				return true
		else:
			if self.CaretColumn < 4:
				MoveCaretToEnd()

		return false

	private def HandleKeyPress(ch as System.Char) as bool:
		return true if _blockKeys

		if InCodeCompletion:
			_codeCompletionWindow.ProcessKeyEvent(ch)

		if ch == "."[0]:
			DotComplete(ch)

		return false

	private def cls():
		self.Document.TextContent = ""
		self.ActiveTextAreaControl.Refresh()

	private def _lineHistory_CurrentLineChanged():
		segment = GetLastLineSegment()
		self.Document.Replace(segment.Offset + 4,
			self.CurrentLineText.Length,
			_lineHistory.CurrentLine)

	def GetBooHighlighting():
		return HighlightingManager.Manager.FindHighlighter("Boo")

	static def InstallDefaultSyntaxModeProvider():
		HighlightingManager.Manager.AddSyntaxModeFileProvider(
			FileSyntaxModeProvider(Path.GetDirectoryName(Application.ExecutablePath)))

#region license
// Copyright (c) 2004, Rodrigo B. de Oliveira (rbo@acm.org)
// All rights reserved.
//
// This file is part of Boo Explorer.
//
// Boo Explorer is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Boo Explorer is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Foobar; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#endregion

"""
Interactive Forms-based Console
"""
namespace booish.gui

import System
import System.Drawing
import System.IO
import System.Windows.Forms
import ICSharpCode.TextEditor
import ICSharpCode.TextEditor.Document
import ICSharpCode.TextEditor.Actions
import ICSharpCode.TextEditor.Gui.CompletionWindow
import Boo.Lang.Compiler.TypeSystem

interface ICompletionWindowImageProvider:
	ImageList as ImageList:
		get
	NamespaceIndex as int:
		get
	ClassIndex as int:
		get
	InterfaceIndex as int:
		get
	EnumIndex as int:
		get
	StructIndex as int:
		get
	CallableIndex as int:
		get
	MethodIndex as int:
		get
	FieldIndex as int:
		get
	LiteralIndex as int:
		get
	PropertyIndex as int:
		get
	EventIndex as int:
		get

class InteractiveInterpreterControl(TextEditorControl):

	enum InputState:
		SingleLine = 0
		Block = 1

	class NullCompletionWindowImageProvider(ICompletionWindowImageProvider):

		public static final Instance = NullCompletionWindowImageProvider()

		[getter(ImageList)]
		_imageList = System.Windows.Forms.ImageList()

		NamespaceIndex as int:
			get:
				return 0
		ClassIndex as int:
			get:
				return 0
		InterfaceIndex as int:
			get:
				return 0
		EnumIndex as int:
			get:
				return 0
		StructIndex as int:
			get:
				return 0
		CallableIndex as int:
			get:
				return 0
		MethodIndex as int:
			get:
				return 0
		FieldIndex as int:
			get:
				return 0
		LiteralIndex as int:
			get:
				return 0
		PropertyIndex as int:
			get:
				return 0
		EventIndex as int:
			get:
				return 0

	class LineHistory:

		_lines = []
		_current = 0

		event CurrentLineChanged as EventHandler

		def Add([required] line as string):
			if len(line) > 0 and line != LastLine:
				_lines.Add(line)
			_current = len(_lines)

		LastLine as string:
			get:
				return null if 0 == len(_lines)
				return _lines[-1]

		CurrentLine as string:
			get:
				return null if 0 == len(_lines)
				return _lines[_current]

		def Up():
			MoveTo(_current - 1)

		def Down():
			MoveTo(_current + 1)

		def MoveTo(index as int):
			return if 0 == len(_lines)
			old = _current
			_current = index % len(_lines)
			if old != _current:
				CurrentLineChanged(self, EventArgs.Empty)

	_state = InputState.SingleLine

	_block = System.IO.StringWriter()

	[getter(Interpreter)]
	_interpreter as Boo.Lang.Interpreter.InteractiveInterpreter

	_codeCompletionWindow as CodeCompletionWindow

	[property(CompletionWindowImageProvider, value is not null)]
	_imageProvider as ICompletionWindowImageProvider = NullCompletionWindowImageProvider()

	_lineHistory as LineHistory

	// HACK: when the completion window is shown through CTRL+SPACE
	// it behaves very strangely, the best we can do right now is
	// to prevent the user from typing
	_blockKeys = false

	def constructor():
		self._interpreter = Boo.Lang.Interpreter.InteractiveInterpreter(
								RememberLastValue: true,
								Print: self.print)
		self._interpreter.SetValue("cls", cls)
		self._interpreter.SetValue("exec", exec)
		self._lineHistory = LineHistory(CurrentLineChanged: _lineHistory_CurrentLineChanged)
		self.Document.HighlightingStrategy = GetBooHighlighting()
		self.EnableFolding =  false
		self.ShowLineNumbers =  false
		self.ShowSpaces = false
		self.ShowTabs =  true
		self.ShowEOLMarkers = false
		self.AllowCaretBeyondEOL = false
		self.ShowInvalidLines = false
		self.Dock = DockStyle.Fill

	CaretColumn:
		get:
			return self.ActiveTextAreaControl.Caret.Column

	CurrentLineText:
		get:
			segment = GetLastLineSegment()
			return self.Document.GetText(segment)[4:]

	override def OnLoad(args as EventArgs):
		super(args)
		prompt()

	def Eval(code as string):
		try:
			_interpreter.LoopEval(code)
		ensure:
			_state = InputState.SingleLine

	private def ConsumeCurrentLine():
		text as string = CurrentLineText # was accessing Control.text member
		_lineHistory.Add(text)
		print("")
		return text

	private def GetLastLineSegment():
		return self.Document.GetLineSegment(self.Document.LineSegmentCollection.Count)

	private def SingleLineInputState():
		code = ConsumeCurrentLine()
		if code[-1:] in ":", "\\":
			_state = InputState.Block
			_block.GetStringBuilder().Length = 0
			_block.WriteLine(code)
		else:
			Eval(code)

	private def BlockInputState():
		code = ConsumeCurrentLine()
		if 0 == len(code):
			Eval(_block.ToString())
		else:
			_block.WriteLine(code)

	def print(msg):
		AppendText("${msg}\r\n")

	def prompt():
		AppendText((">>> ", "... ")[_state])

	def ClearLine():
		segment = GetLastLineSegment()
		self.Document.Replace(segment.Offset + 4,
			self.CurrentLineText.Length,
			"")

	def AppendText(text as string):
		segment = GetLastLineSegment()
		self.Document.Insert(segment.Offset + segment.TotalLength, text)
		MoveCaretToEnd()

	def MoveCaretToEnd():
		segment = GetLastLineSegment()
		newOffset = segment.Offset + segment.TotalLength
		MoveCaretToOffset(newOffset)

	def MoveCaretToOffset(offset as int):
		self.ActiveTextAreaControl.Caret.Position = self.Document.OffsetToPosition(offset)

	override def InitializeTextAreaControl(newControl as TextAreaControl):
		super(newControl)
		newControl.TextArea.DoProcessDialogKey += HandleDialogKey
		newControl.TextArea.KeyEventHandler += HandleKeyPress

	InCodeCompletion:
		get:
			return _codeCompletionWindow is not null and not _codeCompletionWindow.IsDisposed

	private def DotComplete(ch as System.Char):
		ShowCompletionWindow(
			CodeCompletionDataProvider(_imageProvider, GetSuggestions()),
			ch)

	private def ShowCompletionWindow(completionDataProvider, ch as System.Char):
		_codeCompletionWindow = CodeCompletionWindow.ShowCompletionWindow(
					self.ParentForm,
					self,
					"<code>",
					completionDataProvider,
					ch)
		if _codeCompletionWindow is not null:
			_codeCompletionWindow.Closed += def():
				_blockKeys = false

	private def CtrlSpaceComplete():
		_blockKeys = true
		ShowCompletionWindow(
			GlobalsCompletionDataProvider(_imageProvider, self._interpreter),
			Char.MinValue)

	private def GetSuggestions():
		code = CurrentLineText.Insert(self.CaretColumn-4, ".__codecomplete__")
		code = code.Insert(0, _block.ToString()) if InputState.Block == _state
		suggestion = _interpreter.SuggestCodeCompletion(code) as INamespace
		return array(IEntity, 0) if suggestion is null
		return GetChildNamespaces(suggestion) if code.StartsWith("import ")
		return TypeSystemServices.GetAllMembers(suggestion)

	private def GetChildNamespaces(parent as INamespace):
		return array(member
					for member in parent.GetMembers()
					if member.EntityType == EntityType.Namespace)

	private def HandleDialogKey(key as Keys):
		return false if InCodeCompletion

		if key == Keys.Enter:
			try:
				(SingleLineInputState, BlockInputState)[_state]()
			except x:
				print(x)
			prompt()
			return true

		if key == Keys.Up:
			_lineHistory.Up()
			return true
		if key == Keys.Down:
			_lineHistory.Down()
			return true

		if key == (Keys.Control | Keys.Space):
			CtrlSpaceComplete()
			return true

		if key in Keys.Home, Keys.Shift|Keys.Home, Keys.Control|Keys.Home:
			MoveCaretToOffset(GetLastLineSegment().Offset + 4)
			return true

		if key == Keys.Escape:
			ClearLine()
			return true

		if key in Keys.Back, Keys.Left:
			if self.CaretColumn < 5:
				return true
		else:
			if self.CaretColumn < 4:
				MoveCaretToEnd()

		return false

	private def HandleKeyPress(ch as System.Char) as bool:
		return true if _blockKeys

		if InCodeCompletion:
			_codeCompletionWindow.ProcessKeyEvent(ch)

		if ch == "."[0]:
			DotComplete(ch)

		return false

	private def cls():
		self.Document.TextContent = ""
		self.ActiveTextAreaControl.Refresh()

	private def exec(scriptName as string):
		_interpreter.Eval(Boo.IO.TextFile.ReadFile(scriptName))

	private def _lineHistory_CurrentLineChanged():
		segment = GetLastLineSegment()
		self.Document.Replace(segment.Offset + 4,
			self.CurrentLineText.Length,
			_lineHistory.CurrentLine)

	def GetBooHighlighting():
		return HighlightingManager.Manager.FindHighlighter("Boo")

	static def InstallDefaultSyntaxModeProvider():
		HighlightingManager.Manager.AddSyntaxModeFileProvider(
			FileSyntaxModeProvider(Path.GetDirectoryName(Application.ExecutablePath)))


transient is now an attribute

transient is now an attribute

#region license
// Copyright (c) 2003, 2004, 2005 Rodrigo B. de Oliveira (rbo@acm.org)
// 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 Rodrigo B. de Oliveira 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.Lang.Useful.Attributes

import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import System.Runtime.CompilerServices
import System.Runtime.Serialization

class SingletonAttribute(AbstractAstAttribute):
"""
Implements the singleton design pattern for a class.

Guarantees that accessing the singleton instance is thread-safe.
Guarantees that singleton instance is not initialized until Instance is called (lazy instantiation).
Guarantees that all constructors are private.
Guarantees that a private default constructor exists. (One need not be provided.)
Guarantees that serializable singletons remain singletons through serialization/deserialization.

Enforces constraint that no parameterized constructors exist on the singleton class.
Enforces constraint that no static members exist on the singleton class (as a recommendation at the Warning level).

@author Marcus Griep (neoeinstein+boo@gmail.com)
@author Sorin Ionescu (sorin.ionescu@gmail.com)
@author Rodrigo B. de Oliveira
"""
	_suppressStaticWarning as bool
	_classDef as ClassDefinition

	[property(AccessorName)]
	_accessorName = ReferenceExpression(Name: DEFAULT_INSTANCE_PROPERTY_NAME)

	public static final NESTED_CLASS_NAME = "\$Nested"
	public static final INSTANCE_FIELD_NAME = "instance"
	public static final SERIALIZATION_OBJECT_CLASS_NAME = "\$ObjectForSerialization"
	public static final DEFAULT_INSTANCE_PROPERTY_NAME = "Instance"

	public static final ISERIALIZABLE_FULL_NAME = typeof(ISerializable).FullName
	public static final GETOBJECTDATA_METHOD_NAME = typeof(ISerializable).GetMethods()[0].Name
	public static final IOBJECTREFERENCE_FULL_NAME = typeof(IObjectReference).FullName
	public static final STREAMINGCONTEXT_FULL_NAME = typeof(StreamingContext).FullName
	public static final SERIALIZATIONINFO_FULL_NAME = typeof(SerializationInfo).FullName
	public static final COMPILERGENERATEDATTRIBUTE_FULL_NAME = typeof(CompilerGeneratedAttribute).FullName

	override def Apply(node as Node):
		if not node isa ClassDefinition:
			InvalidNodeForAttribute("Class");
			return

		_classDef = node as ClassDefinition

		# A singleton class cannot be inherited from, so we make it final here.
		_classDef.Modifiers |= TypeMemberModifiers.Final
		EnforceMemberConstraints()

		CreateInstanceProperty()
		CreateNestedClass()

		if _classDef.Modifiers & TypeMemberModifiers.Transient == TypeMemberModifiers.None:
			CreateSerializationObjectReference()
			CreateDeserializer()
			_classDef.BaseTypes.Add(SimpleTypeReference(ISERIALIZABLE_FULL_NAME))

	private def EnforceMemberConstraints():
	"""
	Checks all type members to ensure compliance with singleton specification.
	In this case, we discourage the use of static members on a singleton class
	but we do not make disallow it.  The attribute will funtion properly
	regardless of whether or not a class strictly follows the pattern.  Also,
	we ensure that every instance constructor is private, and if the user
	never provided an instance constructor, we provide the default one as
	private so that Boo doesn't automatically create the default public
	constructor.  There may be a static constructor, but we do not factor this
	in because we warn about it as aforementioned.
	"""
		forRemoval = []
		for member as TypeMember in _classDef.Members:
			if member.IsStatic and not _suppressStaticWarning:
				Context.Warnings.Add(
					CompilerWarningFactory.CustomWarning(
						member.LexicalInfo,
						"Static members should not be mixed with the SingletonAttribute pattern (${_classDef.Name}.${member.Name})."))
				_suppressStaticWarning = true

			// Because we only warn about static members,
			// we must take care not to override a possible
			// static constructor.  If a static constructor
			// is found, it doesn't count toward an instance
			// constructor, so we don't modify 'foundConstructor'.
			ctor = member as Constructor

			if ctor is not null and not member.IsStatic:
				if ctor.Parameters.Count == 0:
					ctor.Modifiers |= TypeMemberModifiers.Private
					ctor.Modifiers &= ~(TypeMemberModifiers.Public)
					foundDefaultConstructor = true
				else:
					Context.Warnings.Add(
						CompilerWarningFactory.CustomWarning(
							ctor.LexicalInfo,
							"SingletonAttribute pattern will never instantiate parameterized constructors.  '${ctor}' has been removed from '${_classDef.Name}'."))
					forRemoval.Add(ctor)
					foundParameterizedConstructor = true

		unless foundDefaultConstructor:
			defaultConstructor = [|
				private def constructor():
					pass
			|]
			AddCompilerGeneratedAttribute(defaultConstructor)
			_classDef.Members.Add(defaultConstructor)
			if foundParameterizedConstructor:
				Context.Warnings.Add(
					CompilerWarningFactory.CustomWarning(
						_classDef.LexicalInfo,
						"Default private constructor added to '${_classDef.Name}'."))

		for member in forRemoval:
			_classDef.Members.Remove(member)

	private def CreateInstanceProperty():
	"""
	Creates the public, static, read-only property 'Instance' and
	adds it to the singleton.  This property accesses
	'\$Nested.instance' to return the actual singleton instance.
	"""
		classRef = SimpleTypeReference(_classDef.Name)

		instanceProperty = [|
			static Accessor as $classRef:
				get:
					return self.$NESTED_CLASS_NAME.$INSTANCE_FIELD_NAME
		|]

		instanceProperty.Name = AccessorName.Name

		if AccessorName.LexicalInfo == LexicalInfo.Empty:
			instanceProperty.LexicalInfo = _classDef.LexicalInfo
		else:
			instanceProperty.LexicalInfo = AccessorName.LexicalInfo

		AddCompilerGeneratedAttribute(instanceProperty)

		_classDef.Members.Add(instanceProperty)

	private def CreateNestedClass():
	"""
	Creates the nested class and calls helper functions to generate
	the nested members.  This class is marked private to ensure that
	only the singleton class will be able to access it.  Note that
	accessing this nested class will cause the lazy initialization
	to trigger.  The reason for this internal class is to allow accesses
	to other static methods without triggering initialization of the
	instance until it is called for.  This is the most elegant solution
	I know of for the .Net framework to allow for this functionality.
	"""
		classRef = ReferenceExpression(_classDef.Name)

		nestedInstanceClass = [|
			[transient]
			private final class $NESTED_CLASS_NAME:
				static def constructor():
					self.$INSTANCE_FIELD_NAME = $classRef()

				private def constructor():
					pass

				public static final $INSTANCE_FIELD_NAME as $(_classDef.Name)
		|]

		AddCompilerGeneratedAttribute(nestedInstanceClass)

		_classDef.Members.Add(nestedInstanceClass)

	private def CreateSerializationObjectReference():
		classRef = ReferenceExpression(_classDef.Name)

		nestedReferenceClass = [|
			private final class $SERIALIZATION_OBJECT_CLASS_NAME($IOBJECTREFERENCE_FULL_NAME):
				public def GetRealObject(context as $STREAMINGCONTEXT_FULL_NAME):
					return $(classRef).$(AccessorName.Name)
		|]

		AddCompilerGeneratedAttribute(nestedReferenceClass)

		_classDef.Members.Add(nestedReferenceClass)

	private def CreateDeserializer():
		objRef = ReferenceExpression(SERIALIZATION_OBJECT_CLASS_NAME)

		deserializer = [|
			def $GETOBJECTDATA_METHOD_NAME(info as $SERIALIZATIONINFO_FULL_NAME, context as $STREAMINGCONTEXT_FULL_NAME):
				info.SetType($objRef)
		|]

		MakeExplicit(deserializer, ISERIALIZABLE_FULL_NAME)

		AddCompilerGeneratedAttribute(deserializer)

		_classDef.Members.Add(deserializer)

	private def AddCompilerGeneratedAttribute(node as TypeMember):
		node.Attributes.Add(
			Attribute(COMPILERGENERATEDATTRIBUTE_FULL_NAME))

	private def MakeExplicit(method as Method, interfaceName as string):
		method.ExplicitInfo = ExplicitMemberInfo(InterfaceType: SimpleTypeReference(interfaceName))

#region license
// Copyright (c) 2003, 2004, 2005 Rodrigo B. de Oliveira (rbo@acm.org)
// 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 Rodrigo B. de Oliveira 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.Lang.Useful.Attributes

import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import System.Runtime.CompilerServices
import System.Runtime.Serialization

class SingletonAttribute(AbstractAstAttribute):
"""
Implements the singleton design pattern for a class.

Guarantees that accessing the singleton instance is thread-safe.
Guarantees that singleton instance is not initialized until Instance is called (lazy instantiation).
Guarantees that all constructors are private.
Guarantees that a private default constructor exists. (One need not be provided.)
Guarantees that serializable singletons remain singletons through serialization/deserialization.

Enforces constraint that no parameterized constructors exist on the singleton class.
Enforces constraint that no static members exist on the singleton class (as a recommendation at the Warning level).

@author Marcus Griep (neoeinstein+boo@gmail.com)
@author Sorin Ionescu (sorin.ionescu@gmail.com)
@author Rodrigo B. de Oliveira
"""
	_suppressStaticWarning as bool
	_classDef as ClassDefinition

	[property(AccessorName)]
	_accessorName = ReferenceExpression(Name: DEFAULT_INSTANCE_PROPERTY_NAME)

	public static final NESTED_CLASS_NAME = "\$Nested"
	public static final INSTANCE_FIELD_NAME = "instance"
	public static final SERIALIZATION_OBJECT_CLASS_NAME = "\$ObjectForSerialization"
	public static final DEFAULT_INSTANCE_PROPERTY_NAME = "Instance"

	public static final ISERIALIZABLE_FULL_NAME = typeof(ISerializable).FullName
	public static final GETOBJECTDATA_METHOD_NAME = typeof(ISerializable).GetMethods()[0].Name
	public static final IOBJECTREFERENCE_FULL_NAME = typeof(IObjectReference).FullName
	public static final STREAMINGCONTEXT_FULL_NAME = typeof(StreamingContext).FullName
	public static final SERIALIZATIONINFO_FULL_NAME = typeof(SerializationInfo).FullName
	public static final COMPILERGENERATEDATTRIBUTE_FULL_NAME = typeof(CompilerGeneratedAttribute).FullName

	override def Apply(node as Node):
		if not node isa ClassDefinition:
			InvalidNodeForAttribute("Class");
			return

		_classDef = node as ClassDefinition

		# A singleton class cannot be inherited from, so we make it final here.
		_classDef.Modifiers |= TypeMemberModifiers.Final
		EnforceMemberConstraints()

		CreateInstanceProperty()
		CreateNestedClass()

		if _classDef.Modifiers & TypeMemberModifiers.Transient == TypeMemberModifiers.None:
			CreateSerializationObjectReference()
			CreateDeserializer()
			_classDef.BaseTypes.Add(SimpleTypeReference(ISERIALIZABLE_FULL_NAME))

	private def EnforceMemberConstraints():
	"""
	Checks all type members to ensure compliance with singleton specification.
	In this case, we discourage the use of static members on a singleton class
	but we do not make disallow it.  The attribute will funtion properly
	regardless of whether or not a class strictly follows the pattern.  Also,
	we ensure that every instance constructor is private, and if the user
	never provided an instance constructor, we provide the default one as
	private so that Boo doesn't automatically create the default public
	constructor.  There may be a static constructor, but we do not factor this
	in because we warn about it as aforementioned.
	"""
		forRemoval = []
		for member as TypeMember in _classDef.Members:
			if member.IsStatic and not _suppressStaticWarning:
				Context.Warnings.Add(
					CompilerWarningFactory.CustomWarning(
						member.LexicalInfo,
						"Static members should not be mixed with the SingletonAttribute pattern (${_classDef.Name}.${member.Name})."))
				_suppressStaticWarning = true

			// Because we only warn about static members,
			// we must take care not to override a possible
			// static constructor.  If a static constructor
			// is found, it doesn't count toward an instance
			// constructor, so we don't modify 'foundConstructor'.
			ctor = member as Constructor

			if ctor is not null and not member.IsStatic:
				if ctor.Parameters.Count == 0:
					ctor.Modifiers |= TypeMemberModifiers.Private
					ctor.Modifiers &= ~(TypeMemberModifiers.Public)
					foundDefaultConstructor = true
				else:
					Context.Warnings.Add(
						CompilerWarningFactory.CustomWarning(
							ctor.LexicalInfo,
							"SingletonAttribute pattern will never instantiate parameterized constructors.  '${ctor}' has been removed from '${_classDef.Name}'."))
					forRemoval.Add(ctor)
					foundParameterizedConstructor = true

		unless foundDefaultConstructor:
			defaultConstructor = [|
				private def constructor():
					pass
			|]
			AddCompilerGeneratedAttribute(defaultConstructor)
			_classDef.Members.Add(defaultConstructor)
			if foundParameterizedConstructor:
				Context.Warnings.Add(
					CompilerWarningFactory.CustomWarning(
						_classDef.LexicalInfo,
						"Default private constructor added to '${_classDef.Name}'."))

		for member in forRemoval:
			_classDef.Members.Remove(member)

	private def CreateInstanceProperty():
	"""
	Creates the public, static, read-only property 'Instance' and
	adds it to the singleton.  This property accesses
	'\$Nested.instance' to return the actual singleton instance.
	"""
		classRef = SimpleTypeReference(_classDef.Name)

		instanceProperty = [|
			static Accessor as $classRef:
				get:
					return self.$NESTED_CLASS_NAME.$INSTANCE_FIELD_NAME
		|]

		instanceProperty.Name = AccessorName.Name

		if AccessorName.LexicalInfo == LexicalInfo.Empty:
			instanceProperty.LexicalInfo = _classDef.LexicalInfo
		else:
			instanceProperty.LexicalInfo = AccessorName.LexicalInfo

		AddCompilerGeneratedAttribute(instanceProperty)

		_classDef.Members.Add(instanceProperty)

	private def CreateNestedClass():
	"""
	Creates the nested class and calls helper functions to generate
	the nested members.  This class is marked private to ensure that
	only the singleton class will be able to access it.  Note that
	accessing this nested class will cause the lazy initialization
	to trigger.  The reason for this internal class is to allow accesses
	to other static methods without triggering initialization of the
	instance until it is called for.  This is the most elegant solution
	I know of for the .Net framework to allow for this functionality.
	"""
		classRef = ReferenceExpression(_classDef.Name)

		nestedInstanceClass = [|
			private transient final class $NESTED_CLASS_NAME:
				static def constructor():
					self.$INSTANCE_FIELD_NAME = $classRef()

				private def constructor():
					pass

				public static final $INSTANCE_FIELD_NAME as $(_classDef.Name)
		|]

		AddCompilerGeneratedAttribute(nestedInstanceClass)

		_classDef.Members.Add(nestedInstanceClass)

	private def CreateSerializationObjectReference():
		classRef = ReferenceExpression(_classDef.Name)

		nestedReferenceClass = [|
			private final class $SERIALIZATION_OBJECT_CLASS_NAME($IOBJECTREFERENCE_FULL_NAME):
				public def GetRealObject(context as $STREAMINGCONTEXT_FULL_NAME):
					return $(classRef).$(AccessorName.Name)
		|]

		AddCompilerGeneratedAttribute(nestedReferenceClass)

		_classDef.Members.Add(nestedReferenceClass)

	private def CreateDeserializer():
		objRef = ReferenceExpression(SERIALIZATION_OBJECT_CLASS_NAME)

		deserializer = [|
			def $GETOBJECTDATA_METHOD_NAME(info as $SERIALIZATIONINFO_FULL_NAME, context as $STREAMINGCONTEXT_FULL_NAME):
				info.SetType($objRef)
		|]

		MakeExplicit(deserializer, ISERIALIZABLE_FULL_NAME)

		AddCompilerGeneratedAttribute(deserializer)

		_classDef.Members.Add(deserializer)

	private def AddCompilerGeneratedAttribute(node as TypeMember):
		node.Attributes.Add(
			Attribute(COMPILERGENERATEDATTRIBUTE_FULL_NAME))

	private def MakeExplicit(method as Method, interfaceName as string):
		method.ExplicitInfo = ExplicitMemberInfo(InterfaceType: SimpleTypeReference(interfaceName))


Changed internal-generic-type-3 testcase to not fail on peverify step for having an empty struct.
Boo should disallow empty value types, or figure out how to emit them properly if possible.

git-svn-id: fcce7d6ce0ac15bf24f68871b5145d46fc068279@2657 2c1201b4-01cd-e047-a400-b836ae1fbc61

public struct GenericStruct of T:
	Field as T

assert typeof(GenericStruct of *).MakeGenericType(int) == typeof(GenericStruct of int)

public struct GenericStruct of T:
	pass

assert typeof(GenericStruct of *).MakeGenericType(int) == typeof(GenericStruct of int)


make the jvm error visible in case of a failure

namespace Boojay.Compilation.Tests

import NUnit.Framework
import Boo.Lang.Parser
import Boo.Lang.Compiler
import Boo.Lang.Compiler.IO
import Boo.Lang.Compiler.Ast
import Boojay.Compilation

[TestFixture]
partial class IntegrationTestFixture:

	def runTestCase(fname as string):
		unit = parse(fname)
		main = unit.Modules[0]
		compile(unit)
		output = runJavaClass(moduleClass(main))
		Assert.IsNotNull(main.Documentation, "Expecting documentation for '${fname}'")
		Assert.AreEqual(normalizeWhiteSpace(main.Documentation), normalizeWhiteSpace(output))

	def normalizeWhiteSpace(s as string):
		return s.Trim().Replace("\r\n", "\n")

	def compile(unit as CompileUnit):
		compiler = newBoojayCompiler()
		result = compiler.Run(unit)
		assert 0 == len(result.Errors), result.Errors.ToString(true)

	def parse(fname as string):
		return BooParser.ParseFile(System.IO.Path.GetFullPath(fname))

	def moduleClass(module as Module):
		return module.FullName + "Module"

	def runJavaClass(className as string):
		p = shellp("java", "-cp . ${className}")
		p.WaitForExit()
		if p.ExitCode != 0: raise p.StandardError.ReadToEnd()
		return p.StandardOutput.ReadToEnd()

namespace Boojay.Compilation.Tests

import NUnit.Framework
import Boo.Lang.Parser
import Boo.Lang.Compiler
import Boo.Lang.Compiler.IO
import Boo.Lang.Compiler.Ast
import Boojay.Compilation

[TestFixture]
partial class IntegrationTestFixture:

	def runTestCase(fname as string):
		unit = parse(fname)
		main = unit.Modules[0]
		compile(unit)
		output = runJavaClass(moduleClass(main))
		Assert.IsNotNull(main.Documentation, "Expecting documentation for '${fname}'")
		Assert.AreEqual(normalizeWhiteSpace(main.Documentation), normalizeWhiteSpace(output))

	def normalizeWhiteSpace(s as string):
		return s.Trim().Replace("\r\n", "\n")

	def compile(unit as CompileUnit):
		compiler = newBoojayCompiler()
		result = compiler.Run(unit)
		assert 0 == len(result.Errors), result.Errors.ToString(true)

	def parse(fname as string):
		return BooParser.ParseFile(System.IO.Path.GetFullPath(fname))

	def moduleClass(module as Module):
		return module.FullName + "Module"

	def runJavaClass(className as string):
		return shell("java", "-cp . ${className}")


OK, let's try this one more time...

OK, let's try this one more time...

""" Simple script to upload a new release asset to GitHub.

    Authentication is done using oAuth2 tokens. The token to use should
    be available as an environment variable named GITHUB_TOKEN.

    usage: booi github-release.boo -- <release> <path/to/build.zip>

    Note that It will remove any prior assets with the same name before
    uploading the new one.

"""

from System import Environment
from System.IO import Path
from System.Net import WebClient, WebException, HttpWebResponse
from System.Collections.Generic import List
import System.Web.Script.Serialization from System.Web.Extensions

class Release:
""" Models the Json responses from GitHub http://developer.github.com/v3/repos/releases/
    Using dynamic types is buggy under some Mono versions, so this is the
    only solution to make it work.
"""
    class Asset:
        property url as string
        property id as int
        property name as string
        property label as string
        property state as string
        property content_type as string
        property size as int
        property download_count as int
        property created_at as string
        property updated_at as string

    property assets as List[of Asset]
    property url as string
    property html_url as string
    property assets_url as string
    property upload_url as string
    property id as int
    property tag_name as string
    property target_commitish as string
    property name as string
    property body as string
    property draft as bool
    property prerelease as bool
    property created_at as string
    property published_at as string

def client():
""" WebClient doesn't keep the headers between requests, so we instantiate
    a new one every time we want to use it.
"""
    wc = WebClient()
    wc.Headers['Authorization'] = 'token ' + Environment.GetEnvironmentVariable('GITHUB_TOKEN')
    # The API requires this custom Accept header while in beta
    wc.Headers.Add('Accept', 'application/vnd.github.manifold-preview')
    wc.Headers.Add('user-agent', 'boo-lang')
    return wc

if len(argv) < 2:
    print 'Usage: github-release <release> <path/to/build.zip>'
    return

if not Environment.GetEnvironmentVariable('GITHUB_TOKEN'):
    raise 'GITHUB_TOKEN environment variable not set'

MAX_UPLOAD_RETRIES = 5
USERNAME = 'boo-lang'
REPO = 'boo'
API_URL = "https://api.github.com/repos/$USERNAME/$REPO/releases"
RELEASE_NAME = argv[0]
ASSET_FILE = argv[1]
ASSET_NAME = Path.GetFileName(ASSET_FILE)

json = JavaScriptSerializer()

print "Looking for release $RELEASE_NAME"
try:
    result = client().DownloadString(API_URL)
except wx as WebException:
    var e = wx.Response cast HttpWebResponse
    using sr = System.IO.StreamReader(e.GetResponseStream()):
        print sr.ReadToEnd()
    raise
releases = json.Deserialize[of List[of Release]](result)
release = releases.Find({rel | rel.tag_name == RELEASE_NAME})

if not release:
    raise "Release $RELEASE_NAME not found"

for asset in release.assets:
    if asset.name == ASSET_NAME:
        print "Removing asset $(asset.id)"
        client().UploadData(asset.url as string, "DELETE", array(byte, 0))
        break

upload_url = (release.upload_url as string).Replace('{?name}', "?name=$ASSET_NAME")
print "Uploading $ASSET_FILE to $upload_url"
retries = 0
:retry
try:
    client().UploadFile(upload_url, ASSET_FILE)
except ex as WebException:
    var e2 = ex.Response cast HttpWebResponse
    using sr = System.IO.StreamReader(e2.GetResponseStream()):
        print sr.ReadToEnd()
    retries += 1
    if retries >= MAX_UPLOAD_RETRIES:
        print "Too many retries, giving up..."
        raise ex
    print "Upload failed ($(ex.Message)), retrying..."
    goto retry

""" Simple script to upload a new release asset to GitHub.

    Authentication is done using oAuth2 tokens. The token to use should
    be available as an environment variable named GITHUB_TOKEN.

    usage: booi github-release.boo -- <release> <path/to/build.zip>

    Note that It will remove any prior assets with the same name before
    uploading the new one.

"""

from System import Environment
from System.IO import Path
from System.Net import WebClient, WebException, HttpWebResponse
from System.Collections.Generic import List
import System.Web.Script.Serialization from System.Web.Extensions

class Release:
""" Models the Json responses from GitHub http://developer.github.com/v3/repos/releases/
    Using dynamic types is buggy under some Mono versions, so this is the
    only solution to make it work.
"""
    class Asset:
        property url as string
        property id as int
        property name as string
        property label as string
        property state as string
        property content_type as string
        property size as int
        property download_count as int
        property created_at as string
        property updated_at as string

    property assets as List[of Asset]
    property url as string
    property html_url as string
    property assets_url as string
    property upload_url as string
    property id as int
    property tag_name as string
    property target_commitish as string
    property name as string
    property body as string
    property draft as bool
    property prerelease as bool
    property created_at as string
    property published_at as string

def client():
""" WebClient doesn't keep the headers between requests, so we instantiate
    a new one every time we want to use it.
"""
    wc = WebClient()
    wc.Headers['Authorization'] = 'token ' + Environment.GetEnvironmentVariable('GITHUB_TOKEN')
    # The API requires this custom Accept header while in beta
    wc.Headers.Add('Accept', 'application/vnd.github.manifold-preview')
    wc.Headers.Add('user-agent', 'boo-lang')
    return wc

if len(argv) < 2:
    print 'Usage: github-release <release> <path/to/build.zip>'
    return

if not Environment.GetEnvironmentVariable('GITHUB_TOKEN'):
    raise 'GITHUB_TOKEN environment variable not set'

MAX_UPLOAD_RETRIES = 5
USERNAME = 'boo-lang'
REPO = 'boo'
API_URL = "https://api.github.com/repos/$USERNAME/$REPO/releases"
RELEASE_NAME = argv[0]
ASSET_FILE = argv[1]
ASSET_NAME = Path.GetFileName(ASSET_FILE)

json = JavaScriptSerializer()

print "Looking for release $RELEASE_NAME"
try:
    result = client().DownloadString(API_URL)
except wx as WebException:
    var e = wx.Response cast HttpWebResponse
    using sr = System.IO.StreamReader(e.GetResponseStream()):
        print sr.ReadToEnd()
    raise
releases = json.Deserialize[of List[of Release]](result)
release = releases.Find({rel | rel.tag_name == RELEASE_NAME})

if not release:
    raise "Release $RELEASE_NAME not found"

for asset in release.assets:
    if asset.name == ASSET_NAME:
        print "Removing asset $(asset.id)"
        client().UploadData(asset.url as string, "DELETE", array(byte, 0))
        break

upload_url = (release.upload_url as string).Replace('{?name}', "?name=$ASSET_NAME")
print "Uploading $ASSET_FILE to $upload_url"
retries = 0
:retry
try:
    client().UploadFile(upload_url, ASSET_FILE)
except ex as WebException:
    var e = ex.Response cast HttpWebResponse
    using sr = System.IO.StreamReader(e.GetResponseStream()):
        print sr.ReadToEnd()
    retries += 1
    if retries >= MAX_UPLOAD_RETRIES:
        print "Too many retries, giving up..."
        raise ex
    print "Upload failed ($(ex.Message)), retrying..."
    goto retry


Use a transform for Hash indexers

Use a transform for Hash indexers

namespace BooJs.Lang

import BooJs.Lang.Globals
import BooJs.Lang.Extensions

class Builtins:

    [Transform( '%%COMPILER_VERSION%%' )]
    static public final BOO_COMPILER_VERSION = '%%COMPILER_VERSION%%'
    static public final BOO_RUNTIME_VERSION = 'defined in boo.js'

    static public final STOP = 'STOP'

    class Duck(Object, Boo.Lang.IQuackFu):
    """ Implementes the IQuackFu interface
    """
        def QuackGet(name as string, params as (object)) as object:
            pass

        def QuackSet(name as string, params as (object), value as object) as object:
            pass

        def QuackInvoke(name as string, args as (object)) as object:
            pass

    interface ICallable:
    """ Define the ICallable interface
    """
        def Call(args as (object)) as object

    class Hash(Object):
    """ Simple hash/dictionary based on Javascript's object
    """
        self[key as string] as object:
            [Transform( $0[$1] )]
            get: pass
            [Transform( $0[$1] = $2 )]
            set: pass

        [Transform( Boo.Hash() )]
        def constructor():
            pass
        [Transform( Boo.Hash($1) )]
        def constructor(items as object*):
            pass

        # Use a transform to ensure we can use it with plain object literals too
        [Transform( Boo.Hash.keys($0) )]
        def keys() as (string):
            pass
        [Transform( Boo.Hash.values($0) )]
        def values() as (object):
            pass
        [Transform( Boo.enumerate($0) )]
        def items() as ((object)):
            pass

    class AssertionError(Error):
    """ BooJs specific error to signal failures in assertions
    """
        def constructor():
            pass
        def constructor(msg as string):
            pass

    [Transform( Boo.ReturnValue )]
    class ReturnValue:
        public value as object

        def constructor(val as object):
            value = val

    static def range(stop as int) as int*:
        pass
    static def range(start as int, stop as int) as int*:
        pass
    static def range(start as int, stop as int, step as int) as int*:
        pass

    static def print(*list as (object)) as void:
        pass

    static def cat(*list as (object)) as (object):
    """ Concatenates the given enumerable arguments """
        pass

    static def join(items as (object), separator as string) as string:
        pass
    static def join(items as (object)) as string:
        pass
    #static def join(items as Array, separator as string) as string:
    #    pass
    #static def join(items as Array) as string:
    #    pass
    static def map(items as (object), callback as callable) as (object):
        pass

    static def reduce[of T](items as (T), callback as callable) as T:
        pass
    static def reduce[of T](items as (T), callback as callable, initial as T) as T:
        pass

    static def zip(*arrays as (object)) as (object):
        pass

    static def reversed(items as (object)) as (object):
        pass
    static def reversed(items as string) as (object):
        pass

    # TODO: The annotation does not work :(
    #[TypeInferenceRule(TypeInferenceRules.ArrayOfTypeReferencedByFirstArgument)]
    #def array(type as System.Type, enumerable as System.Collections.IEnumerable):
    #    pass

    #[TypeInferenceRule(TypeInferenceRules.ArrayOfTypeReferencedByFirstArgument)]
    #def array(type as System.Type, num as int):
    #    pass

    static def array(type as System.Type, enumerable as (object)) as (object): #Array:
        pass
    static def array(type as System.Type, num as int) as (object): #Array
        pass
    static def array(enumerable as (object)) as (object): #Array:
        pass

    # Allows to iterate accesing indices/keys
    static def enumerate(enumerable as (object)) as (object): #Array:
        pass

namespace BooJs.Lang

import BooJs.Lang.Globals
import BooJs.Lang.Extensions

class Builtins:

    [Transform( '%%COMPILER_VERSION%%' )]
    static public final BOO_COMPILER_VERSION = '%%COMPILER_VERSION%%'
    static public final BOO_RUNTIME_VERSION = 'defined in boo.js'

    static public final STOP = 'STOP'

    class Duck(Object, Boo.Lang.IQuackFu):
    """ Implementes the IQuackFu interface
    """
        def QuackGet(name as string, params as (object)) as object:
            pass

        def QuackSet(name as string, params as (object), value as object) as object:
            pass

        def QuackInvoke(name as string, args as (object)) as object:
            pass

    interface ICallable:
    """ Define the ICallable interface
    """
        def Call(args as (object)) as object

    class Hash(Object):
    """ Simple hash/dictionary based on Javascript's object
    """
        self[key as string] as object:
            get: pass
            set: pass

        [Transform( Boo.Hash() )]
        def constructor():
            pass
        [Transform( Boo.Hash($1) )]
        def constructor(items as object*):
            pass

        # Use a transform to ensure we can use it with plain object literals too
        [Transform( Boo.Hash.keys($0) )]
        def keys() as (string):
            pass
        [Transform( Boo.Hash.values($0) )]
        def values() as (object):
            pass
        [Transform( Boo.enumerate($0) )]
        def items() as ((object)):
            pass

    class AssertionError(Error):
    """ BooJs specific error to signal failures in assertions
    """
        def constructor():
            pass
        def constructor(msg as string):
            pass

    [Transform( Boo.ReturnValue )]
    class ReturnValue:
        public value as object

        def constructor(val as object):
            value = val

    static def range(stop as int) as int*:
        pass
    static def range(start as int, stop as int) as int*:
        pass
    static def range(start as int, stop as int, step as int) as int*:
        pass

    static def print(*list as (object)) as void:
        pass

    static def cat(*list as (object)) as (object):
    """ Concatenates the given enumerable arguments """
        pass

    static def join(items as (object), separator as string) as string:
        pass
    static def join(items as (object)) as string:
        pass
    #static def join(items as Array, separator as string) as string:
    #    pass
    #static def join(items as Array) as string:
    #    pass
    static def map(items as (object), callback as callable) as (object):
        pass

    static def reduce[of T](items as (T), callback as callable) as T:
        pass
    static def reduce[of T](items as (T), callback as callable, initial as T) as T:
        pass

    static def zip(*arrays as (object)) as (object):
        pass

    static def reversed(items as (object)) as (object):
        pass
    static def reversed(items as string) as (object):
        pass

    # TODO: The annotation does not work :(
    #[TypeInferenceRule(TypeInferenceRules.ArrayOfTypeReferencedByFirstArgument)]
    #def array(type as System.Type, enumerable as System.Collections.IEnumerable):
    #    pass

    #[TypeInferenceRule(TypeInferenceRules.ArrayOfTypeReferencedByFirstArgument)]
    #def array(type as System.Type, num as int):
    #    pass

    static def array(type as System.Type, enumerable as (object)) as (object): #Array:
        pass
    static def array(type as System.Type, num as int) as (object): #Array
        pass
    static def array(enumerable as (object)) as (object): #Array:
        pass

    # Allows to iterate accesing indices/keys
    static def enumerate(enumerable as (object)) as (object): #Array:
        pass


use cross platform PathSeparator

use cross platform PathSeparator

namespace Boojay.Compilation.Tests

import System.IO

import NUnit.Framework from nunit.framework

import Boo.Lang.Parser
import Boo.Lang.Compiler
import Boo.Lang.Compiler.IO
import Boo.Lang.Compiler.Ast
import Boojay.Compilation
import Useful.Attributes

[TestFixture]
partial class IntegrationTest:

	def runTestCase(testFile as string):
		unit = parse(fullpathFor(testFile))
		main = unit.Modules[0]
		compile(unit)
		output = runJavaClass(moduleClassFor(main))
		Assert.IsNotNull(main.Documentation, "Expecting documentation for '${testFile}'")
		Assert.AreEqual(normalizeWhiteSpace(main.Documentation), normalizeWhiteSpace(output))

	def fullpathFor(testFile as string):
		return Path.Combine(testParentFolder(), testFile)

	def binFolder():
		return Path.GetFullPath(Path.Combine(testParentFolder(), "bin"))

	def distFolder():
		return Path.GetFullPath(Path.Combine(testParentFolder(), "dist"))

	[once]
	def testParentFolder():
		folder = "."
		while not Directory.Exists(Path.Combine(folder, "tests")):
			folder = Path.Combine(folder, "..")
			assert Directory.Exists(folder)
		return folder

	def normalizeWhiteSpace(s as string):
		return s.Trim().Replace("\r\n", "\n")

	def parse(fname as string):
		return BooParser.ParseFile(System.IO.Path.GetFullPath(fname))

	def moduleClassFor(module as Module):
		return module.FullName.Replace("-", "_") + "Module"

	def runJavaClass(className as string):
		classPath = (binFolder(), distFolder() + "/boojay.lang.jar")

		p = shellp("java", "-cp ${join(classPath, Path.PathSeparator)} ${className}")
		p.WaitForExit()
		if p.ExitCode != 0: raise p.StandardError.ReadToEnd()
		return p.StandardOutput.ReadToEnd()

namespace Boojay.Compilation.Tests

import System.IO

import NUnit.Framework from nunit.framework

import Boo.Lang.Parser
import Boo.Lang.Compiler
import Boo.Lang.Compiler.IO
import Boo.Lang.Compiler.Ast
import Boojay.Compilation
import Useful.Attributes

[TestFixture]
partial class IntegrationTest:

	def runTestCase(testFile as string):
		unit = parse(fullpathFor(testFile))
		main = unit.Modules[0]
		compile(unit)
		output = runJavaClass(moduleClassFor(main))
		Assert.IsNotNull(main.Documentation, "Expecting documentation for '${testFile}'")
		Assert.AreEqual(normalizeWhiteSpace(main.Documentation), normalizeWhiteSpace(output))

	def fullpathFor(testFile as string):
		return Path.Combine(testParentFolder(), testFile)

	def binFolder():
		return Path.GetFullPath(Path.Combine(testParentFolder(), "bin"))

	def distFolder():
		return Path.GetFullPath(Path.Combine(testParentFolder(), "dist"))

	[once]
	def testParentFolder():
		folder = "."
		while not Directory.Exists(Path.Combine(folder, "tests")):
			folder = Path.Combine(folder, "..")
			assert Directory.Exists(folder)
		return folder

	def normalizeWhiteSpace(s as string):
		return s.Trim().Replace("\r\n", "\n")

	def parse(fname as string):
		return BooParser.ParseFile(System.IO.Path.GetFullPath(fname))

	def moduleClassFor(module as Module):
		return module.FullName.Replace("-", "_") + "Module"

	def runJavaClass(className as string):
		p = shellp("java", "-cp .:${binFolder()}:${distFolder()}/boojay.lang.jar ${className}")
		p.WaitForExit()
		if p.ExitCode != 0: raise p.StandardError.ReadToEnd()
		return p.StandardOutput.ReadToEnd()


Ctrl-Space now shows all members of the current class (instance, static and inherited).

git-svn-id: c3b8989232654601f1acea7403f771adaaa44a81@1322 2c1201b4-01cd-e047-a400-b836ae1fbc61

namespace BooBinding.CodeCompletion

import BooBinding
import System
import System.Collections
import System.Diagnostics
import System.IO
import ICSharpCode.SharpDevelop.Services
import SharpDevelop.Internal.Parser
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast as AST
import Boo.Lang.Compiler.IO
import Boo.Lang.Compiler.Steps

class Resolver:
	_parserService as IParserService

	def CtrlSpace(parserService as IParserService, caretLine as int, caretColumn as int, fileName as string) as ArrayList:
		_parserService = parserService
		result = ArrayList(BooAmbience.TypeConversionTable.Values)
		// Add special boo types (types defined in Boo.dll)
		result.Add("hash")
		result.Add("list")
		result.Add("System") // system namespace can be used everywhere

		parseInfo = parserService.GetParseInformation(fileName)
		cu = parseInfo.MostRecentCompilationUnit as CompilationUnit
		if cu != null:
			curClass = parserService.GetInnermostClass(cu, caretLine, caretColumn) as IClass
			result = AddCurrentClassMembers(result, curClass) if curClass != null

		return result

	def AddCurrentClassMembers(result as ArrayList, curClass as IClass) as ArrayList:
		result = _parserService.ListMembers(result, curClass, curClass, false)
		// Add static members, but only from this class (not from base classes)
		for method as IMethod in curClass.Methods:
			result.Add(method) if (method.Modifiers & ModifierEnum.Static) == ModifierEnum.Static
		for field as IField in curClass.Fields:
			result.Add(field) if (field.Modifiers & ModifierEnum.Static) == ModifierEnum.Static
		for property as IProperty in curClass.Properties:
			result.Add(property) if (property.Modifiers & ModifierEnum.Static) == ModifierEnum.Static
		for e as Event in curClass.Events:
			result.Add(e) if (e.Modifiers & ModifierEnum.Static) == ModifierEnum.Static
		return result

	def Resolve(parserService as IParserService, expression as string, caretLine as int, caretColumn as int, fileName as string, fileContent as string) as ResolveResult:
		if expression == null or expression == '':
			return null

		_parserService = parserService
		try:
			int.Parse(expression)
			return null
		except exception as Exception:
			pass

		parseInfo = parserService.GetParseInformation(fileName)
		cu = parseInfo.MostRecentCompilationUnit as CompilationUnit
		if cu == null:
			print "BooResolver: No parse information!"
			return null

		callingClass as Class = parserService.GetInnermostClass(cu, caretLine, caretColumn)
		returnClass as Class = null
		returnClass = callingClass if expression == "self"
		return null if returnClass == null
		return ResolveResult(returnClass, parserService.ListMembers(ArrayList(), returnClass, callingClass, false))

namespace BooBinding.CodeCompletion

import BooBinding
import System
import System.Collections
import System.Diagnostics
import System.IO
import ICSharpCode.SharpDevelop.Services
import SharpDevelop.Internal.Parser
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast as AST
import Boo.Lang.Compiler.IO
import Boo.Lang.Compiler.Steps

class Resolver:
	def CtrlSpace(parserService as IParserService, caretLine as int, caretColumn as int, fileName as string) as ArrayList:
		result = ArrayList(BooAmbience.TypeConversionTable.Values)
		// Add special boo types (types defining in Boo.dll)
		result.Add("hash")
		result.Add("list")
		result.Add("System") // system namespace can be used everywhere

		//parseInfo = parserService.GetParseInformation(fileName)
		//cu = parseInfo.MostRecentCompilationUnit as CompilationUnit
		//if cu != null:
		//	curClass = parserService.GetInnermostClass(cu, caretLine, caretColumn) as Class
		//	if
		return result

	def Resolve(parserService as IParserService, expression as string, caretLine as int, caretColumn as int, fileName as string, fileContent as string) as ResolveResult:
		if expression == null or expression == '':
			return null

		try:
			int.Parse(expression)
			return null
		except exception as Exception:
			pass

		//self._caretLine = caretLineNumber
		//self._caretColumn = caretColumn
		//self._parserService = parserService
		parseInfo = parserService.GetParseInformation(fileName)
		cu = parseInfo.MostRecentCompilationUnit as CompilationUnit
		if cu == null:
			print "BooResolver: No parse information!"
			return null

		callingClass as Class = parserService.GetInnermostClass(cu, caretLine, caretColumn)
		returnClass as Class = null
		if callingClass == null:
			print "BooResolver: CallingClass not found!"
			return null
		if expression == "self":
			returnClass = callingClass
		return null if returnClass == null
		return ResolveResult(returnClass, parserService.ListMembers(ArrayList(), returnClass, callingClass, false))


test case for TryCast matching

test case for TryCast matching

namespace Boo.PatternMatching.Tests

import NUnit.Framework
import Boo.PatternMatching
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast

[TestFixture]
class CodeMatchingTest:

	[Test]
	def TestAssignment():

		code = [| a = 21*2 |]

		Assert.AreEqual("a", variableName(code))
		Assert.AreEqual(code.Right, rvalue(code))

	[Test]
	def TestSlicing():

		code = [| a[b] |]
		match code:
			case [| $target[$arg] |]:
				match target:
					case ReferenceExpression(Name: "a"):
						pass
				match arg:
					case ReferenceExpression(Name: "b"):
						pass

	[Test]
	def TestTryCast():
		code = [| a as int |]
		match code:
			case [| $name as $type |]:
				assert name.ToString() == "a"
				assert type.ToString() == "int"

	def variableName(code as Expression):
		match code:
			case [| $(ReferenceExpression(Name: l)) = $_ |]:
				return l

	def rvalue(code as Expression):
		match code:
			case [| $_ = $r |]:
				return r

namespace Boo.PatternMatching.Tests

import NUnit.Framework
import Boo.PatternMatching
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast

[TestFixture]
class CodeMatchingTest:

	[Test]
	def TestAssignment():

		code = [| a = 21*2 |]

		Assert.AreEqual("a", variableName(code))
		Assert.AreEqual(code.Right, rvalue(code))

	[Test]
	def TestSlicing():

		code = [| a[b] |]
		match code:
			case [| $target[$arg] |]:
				match target:
					case ReferenceExpression(Name: "a"):
						pass
				match arg:
					case ReferenceExpression(Name: "b"):
						pass

	def variableName(code as Expression):
		match code:
			case [| $(ReferenceExpression(Name: l)) = $_ |]:
				return l

	def rvalue(code as Expression):
		match code:
			case [| $_ = $r |]:
				return r