added test to verify that provider can list constructors

namespace Boojay.Compilation.Tests

import System
import System.IO
import NUnit.Framework

import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.TypeSystem
import Boo.Lang.Compiler.TypeSystem.Services

import Boojay.Compilation.TypeSystem

[TestFixture]
class JarTypeSystemProviderTest(TestWithCompilerContext):

	_jar as string
	_jarWithNamespace as string
	_jarWithComplexNamespace as string

	_subject as JarTypeSystemProvider

	[SetUp]
	override def SetUp():
		super()

		code = [|
			import java.lang

			class Foo:
				def getName():
					return "Bar"
		|]

		codeWithNamespace = [|
			namespace Foo

			import java.lang

			class Bar:
				def getName():
					return "Baz"
		|]

		codeWithComplexNamespace = [|
			namespace Foo.More

			import java.lang

			class Bar:
				def getName():
					return "Baz"
		|]

		_jar = GenerateTempJarWith(code)
		_jarWithNamespace = GenerateTempJarWith(codeWithNamespace)
		_jarWithComplexNamespace = GenerateTempJarWith(codeWithComplexNamespace)

		_subject = JarTypeSystemProvider()

	[Test]
	def ClassName():

		WithCompilerContext:

			compileUnit = _subject.ForJar(_jar)
			foo = ResolveType(compileUnit, "Foo")
			Assert.AreEqual("Foo", foo.Name)

	[Test]
	def ClassNameInNamespace():

		WithCompilerContext:

			compileUnit = _subject.ForJar(_jarWithNamespace)
			bar = ResolveType(compileUnit, "Foo.Bar")
			Assert.AreEqual("Bar", bar.Name)
			Assert.AreEqual("Foo.Bar", bar.FullName)

	[Test]
	def ClassNameInComplexNamespace():

		WithCompilerContext:

			compileUnit = _subject.ForJar(_jarWithComplexNamespace)
			bar = ResolveType(compileUnit, "Foo.More.Bar")
			Assert.AreEqual("Bar", bar.Name)
			Assert.AreEqual("Foo.More.Bar", bar.FullName)

	[Test]
	def ClassesAreCached():

		WithCompilerContext:

			compileUnit = _subject.ForJar(_jar)
			resolveFoo = { ResolveType(compileUnit, "Foo") }
			Assert.AreSame(resolveFoo(), resolveFoo())

	[Test]
	def Constructors():
		WithCompilerContext:

			compileUnit = _subject.ForJar(_jar)
			foo = ResolveType(compileUnit, "Foo")
			Assert.AreEqual(1, foo.GetConstructors().Length)

	[Test]
	def ParameterlessInstanceMethod():

		WithCompilerContext:

			compileUnit = _subject.ForJar(_jar)
			getName as IMethod = ResolveQualifiedName(compileUnit, "Foo.getName")
			Assert.AreEqual(EntityType.Method, getName.EntityType)
			Assert.AreEqual("getName", getName.Name)
			Assert.AreEqual("Foo.getName", getName.FullName)
			Assert.AreSame(ResolveType(compileUnit, "Foo"), getName.DeclaringType)
			Assert.AreEqual(0, getName.GetParameters().Length)

	def ResolveType(compileUnit as ICompileUnit, typeName as string) as IType:
		return ResolveQualifiedName(compileUnit, typeName)

	def ResolveQualifiedName(compileUnit as ICompileUnit, typeName as string):
		return my(NameResolutionService).ResolveQualifiedName(compileUnit.RootNamespace, typeName)

	def GenerateTempJarWith(code as Module):
		jar = Path.GetTempFileName()
		compile(CompileUnit(code))
		GenerateJar(jar, "${type.FullName.Replace('.', '/')}.class" for type in code.Members)
		return jar

namespace Boojay.Compilation.Tests

import System
import System.IO
import NUnit.Framework

import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.TypeSystem
import Boo.Lang.Compiler.TypeSystem.Services

import Boojay.Compilation.TypeSystem

[TestFixture]
class JarTypeSystemProviderTest(TestWithCompilerContext):

	_jar as string
	_jarWithNamespace as string
	_jarWithComplexNamespace as string

	_subject as JarTypeSystemProvider

	[SetUp]
	override def SetUp():
		super()

		code = [|
			import java.lang

			class Foo:
				def getName():
					return "Bar"
		|]

		codeWithNamespace = [|
			namespace Foo

			import java.lang

			class Bar:
				def getName():
					return "Baz"
		|]

		codeWithComplexNamespace = [|
			namespace Foo.More

			import java.lang

			class Bar:
				def getName():
					return "Baz"
		|]

		_jar = GenerateTempJarWith(code)
		_jarWithNamespace = GenerateTempJarWith(codeWithNamespace)
		_jarWithComplexNamespace = GenerateTempJarWith(codeWithComplexNamespace)

		_subject = JarTypeSystemProvider()

	[Test]
	def ClassName():

		WithCompilerContext:

			compileUnit = _subject.ForJar(_jar)
			foo = ResolveType(compileUnit, "Foo")
			Assert.AreEqual("Foo", foo.Name)

	[Test]
	def ClassNameInNamespace():

		WithCompilerContext:

			compileUnit = _subject.ForJar(_jarWithNamespace)
			bar = ResolveType(compileUnit, "Foo.Bar")
			Assert.AreEqual("Bar", bar.Name)
			Assert.AreEqual("Foo.Bar", bar.FullName)

	[Test]
	def ClassNameInComplexNamespace():

		WithCompilerContext:

			compileUnit = _subject.ForJar(_jarWithComplexNamespace)
			bar = ResolveType(compileUnit, "Foo.More.Bar")
			Assert.AreEqual("Bar", bar.Name)
			Assert.AreEqual("Foo.More.Bar", bar.FullName)

	[Test]
	def ClassesAreCached():

		WithCompilerContext:

			compileUnit = _subject.ForJar(_jar)
			resolveFoo = { ResolveType(compileUnit, "Foo") }
			Assert.AreSame(resolveFoo(), resolveFoo())

	[Test]
	def ParameterlessInstanceMethod():

		WithCompilerContext:

			compileUnit = _subject.ForJar(_jar)
			getName as IMethod = ResolveQualifiedName(compileUnit, "Foo.getName")
			Assert.AreEqual(EntityType.Method, getName.EntityType)
			Assert.AreEqual("getName", getName.Name)
			Assert.AreEqual("Foo.getName", getName.FullName)
			Assert.AreSame(ResolveType(compileUnit, "Foo"), getName.DeclaringType)
			Assert.AreEqual(0, getName.GetParameters().Length)

	def ResolveType(compileUnit as ICompileUnit, typeName as string) as IType:
		return ResolveQualifiedName(compileUnit, typeName)

	def ResolveQualifiedName(compileUnit as ICompileUnit, typeName as string):
		return my(NameResolutionService).ResolveQualifiedName(compileUnit.RootNamespace, typeName)

	def GenerateTempJarWith(code as Module):
		jar = Path.GetTempFileName()
		compile(CompileUnit(code))
		GenerateJar(jar, "${type.FullName.Replace('.', '/')}.class" for type in code.Members)
		return jar


fixed position of high score input in final exe

import UnityEngine

class HighScoreInput (MonoBehaviour):

	public playerName as string
	def Start ():
		playerName = ""

	def Update ():
		pass

	def OnGUI():
		textureFont as GUIStyle = GUIStyle()
		backTexture = Texture2D(128, 128) as Texture2D
		for i in range(128):
			for j in range(128):
				backTexture.SetPixel(i, j, Color.gray)
		backTexture.Apply()
		textureFont.normal.background = backTexture
		textureFont.fontSize = 30
		textureFont.normal.textColor = Color.red

		GUI.Box(Rect(100, 200, 250, 150), "")
		font as GUIStyle = GUIStyle()
		font.fontSize = 30
		font.normal.textColor = Color.red

		#GUI.Label(Rect(310, 220, 200, 40), "High Score!", font)
		playerName = GUI.TextField(Rect(210,300,170,40), playerName, textureFont)
		if(GUI.Button(Rect(390, 300, 40, 40), "Go")):
			highScores as (int) = (0, 0, 0, 0, 0)
			highScoreNames as List = ["", "", "", "", ""]
			pos as int = -1
			for i in range(0,5):
				highScores[i] = PlayerPrefs.GetInt("highScore-" + i.ToString(), 0)
				highScoreNames[i] = PlayerPrefs.GetString("highScoreName-" + i.ToString(), "")
				if(highScores[i] < StaticStuff.score):
					pos = i
					break
			Debug.Log("pos : " + pos.ToString())
			for i in range(4, pos, -1):
				highScores[i] = highScores[i-1]
				highScoreNames[i] = highScoreNames[i-1]
			highScores[pos] = StaticStuff.score
			highScoreNames[pos] = playerName
			for i in range(0,5):
				PlayerPrefs.SetInt("highScore-" + i.ToString(), highScores[i])
				PlayerPrefs.SetString("highScoreName-" + i.ToString(), highScoreNames[i])
			Application.LoadLevel("HighScore")

import UnityEngine

class HighScoreInput (MonoBehaviour):

	public playerName as string
	def Start ():
		playerName = ""

	def Update ():
		pass

	def OnGUI():
		textureFont as GUIStyle = GUIStyle()
		backTexture = Texture2D(128, 128) as Texture2D
		for i in range(128):
			for j in range(128):
				backTexture.SetPixel(i, j, Color.gray)
		backTexture.Apply()
		textureFont.normal.background = backTexture
		textureFont.fontSize = 30
		textureFont.normal.textColor = Color.red

		GUI.Box(Rect(100, 200, 250, 150), "")
		font as GUIStyle = GUIStyle()
		font.fontSize = 30
		font.normal.textColor = Color.red

		#GUI.Label(Rect(310, 220, 200, 40), "High Score!", font)
		playerName = GUI.TextField(Rect(310,300,170,40), playerName, textureFont)
		if(GUI.Button(Rect(490, 300, 40, 40), "Go")):
			highScores as (int) = (0, 0, 0, 0, 0)
			highScoreNames as List = ["", "", "", "", ""]
			pos as int = -1
			for i in range(0,5):
				highScores[i] = PlayerPrefs.GetInt("highScore-" + i.ToString(), 0)
				highScoreNames[i] = PlayerPrefs.GetString("highScoreName-" + i.ToString(), "")
				if(highScores[i] < StaticStuff.score):
					pos = i
					break
			Debug.Log("pos : " + pos.ToString())
			for i in range(4, pos, -1):
				highScores[i] = highScores[i-1]
				highScoreNames[i] = highScoreNames[i-1]
			highScores[pos] = StaticStuff.score
			highScoreNames[pos] = playerName
			for i in range(0,5):
				PlayerPrefs.SetInt("highScore-" + i.ToString(), highScores[i])
				PlayerPrefs.SetString("highScoreName-" + i.ToString(), highScoreNames[i])
			Application.LoadLevel("HighScore")


implement significant whitespace rules using the last match operator (@); use context subclass instead of generics

namespace miniboo

import Boo.Pegs
import Boo.Lang.Compiler
import Boo.Lang.Compiler.MetaProgramming

//class BooPegContext(PegDebugContext):
class BooPegContext(PegContext):

	[getter(Stack)]
	_stack = []

	def constructor(text as string):
		super(text)

def push(ctx as BooPegContext):
	push(ctx, text(ctx))

def push(ctx as BooPegContext, value):
	ctx.Stack.Push(value)

def pop(ctx as BooPegContext):
	return ctx.Stack.Pop()

def peek(ctx as BooPegContext):
	return ctx.Stack[-1]

def currentType(ctx as BooPegContext):
	return peek(ctx) as Ast.TypeDefinition

def currentBlock(ctx as BooPegContext):
	return peek(ctx) as Ast.Block

keywords = "class", "def", "end"

IsNotKeyword = FunctionExpression() do (ctx as PegContext):
	identifier = text(ctx)
	return identifier not in keywords

peg miniboo:
	Module = EnterModule, AnySpace, ++Member, EndOfFile
	Class = CLASS, Identifier, EnterClass, ClassBody, LeaveClass
	ClassBody = Begin, Space, Member, --(@Space, Member), End
	Member = [Class, Method]
	Method = DEF, Identifier, EnterMethod, LPAREN, RPAREN, Block, LeaveMethod
	Block = Begin, Space, Statement, --(@Space, Statement), End
	Eol = ~NEWLINE
	Statement = ExpressionStatement, NEWLINE
	ExpressionStatement = Invocation, OnExpressionStatement
	Invocation = Expression, EnterInvocation, Argument
	Argument = Expression, OnArgument
	Expression = [Reference, String]
	Reference = Identifier, OnReference
	String = "'", ++(not "'", any()), "'", { $push(Ast.StringLiteralExpression(Value: $text[1:-1])) }, OptSpace
	Identifier = ++[a-z, A-Z], IsNotKeyword, { $push }, OptSpace
	Begin = ":", OptSpace, Eol
	End = --(OptSpace, NEWLINE)
	OptSpace = ~Space
	Space = ++[' ', '\t']
	AnySpace = --whitespace()
	CLASS = "class", Space
	DEF = "def", Space
	LPAREN = "(", AnySpace
	RPAREN = ")", AnySpace
	NEWLINE = ++"\n"
	EndOfFile = not any()

	# actions
	EnterModule = do:
		$push(Ast.Module())

	EnterClass = do:
		type = Ast.ClassDefinition(Name: $pop)
		$currentType.Members.Add(type)
		$push(type)

	LeaveClass = do:
		$pop

	EnterMethod = do:
		method = Ast.Method(Name: $pop)
		$currentType.Members.Add(method)
		$push(method.Body)

	LeaveMethod = do:
		$pop

	OnExpressionStatement = do:
		e = $pop
		$currentBlock.Add(Ast.ExpressionStatement(Expression: e))

	OnReference = do:
		$push(Ast.ReferenceExpression(Name: $pop))

	EnterInvocation = do:
		$push(Ast.MethodInvocationExpression(Target: $pop))

	OnArgument = do:
		arg = $pop
		($peek as Ast.MethodInvocationExpression).Arguments.Add(arg)

code = """
class Foo:
	class Nested:
		def bar():
			print 'yahoo'

	def run():
		print 'Hello, world!'

def baz():
	print 'Hello, again'
"""
ctx = BooPegContext(code)
assert ctx.Match(Module),  "Error at " + ctx.Input.Position

module as Ast.Module = pop(ctx)
module.Name = "code"

print module.ToCodeString()

foo as duck = compile(module).GetType("Foo")()
foo.run()

namespace miniboo

import Boo.Pegs
import Boo.Lang.Compiler
import Boo.Lang.Compiler.MetaProgramming

def push(ctx as PegContextWithPayload[of List]):
	push(ctx, text(ctx))

def push(ctx as PegContextWithPayload[of List], value):
	ctx.Payload.Push(value)

def pop(ctx as PegContextWithPayload[of List]):
	return ctx.Payload.Pop()

def peek(ctx as PegContextWithPayload[of List]):
	return ctx.Payload[-1]

def currentType(ctx as PegContextWithPayload[of List]):
	return peek(ctx) as Ast.TypeDefinition

def currentBlock(ctx as PegContextWithPayload[of List]):
	return peek(ctx) as Ast.Block

keywords = "class", "def", "end"

IsNotKeyword = FunctionExpression() do (ctx as PegContext):
	identifier = text(ctx)
	return identifier not in keywords

peg miniboo:
	Module = EnterModule, OptionalSpacing, ++Member, EndOfFile
	Class = CLASS, Identifier, EnterClass, Begin, ++Member, End, LeaveClass
	Member = [Class, Method]
	Method = DEF, Identifier, EnterMethod, LPAREN, RPAREN, Block, LeaveMethod
	Block = Begin, ++Statement, End
	Statement = ExpressionStatement
	ExpressionStatement = Invocation, OnExpressionStatement
	Invocation = Expression, EnterInvocation, Argument
	Argument = Expression, OnArgument
	Expression = [Reference, String]
	Reference = Identifier, OnReference
	String = "'", ++(not "'"), "'", { $push(Ast.StringLiteralExpression(Value: $text[1:-1])) }, Spacing
	Identifier = ++[a-z, A-Z], IsNotKeyword, { $push }, OptionalSpacing
	Begin = ":", OptionalSpacing
	End = "end", Spacing
	Spacing = ++[' ', '\t', '\r', '\n']
	OptionalSpacing = ~Spacing
	CLASS = "class", Spacing
	DEF = "def", Spacing
	LPAREN = "(", OptionalSpacing
	RPAREN = ")", OptionalSpacing
	EndOfFile = not any()

	# actions
	EnterModule = do:
		$push(Ast.Module())

	EnterClass = do:
		type = Ast.ClassDefinition(Name: $pop)
		$currentType.Members.Add(type)
		$push(type)

	LeaveClass = do:
		$pop

	EnterMethod = do:
		method = Ast.Method(Name: $pop)
		$currentType.Members.Add(method)
		$push(method.Body)

	LeaveMethod = do:
		$pop

	OnExpressionStatement = do:
		e = $pop
		$currentBlock.Add(Ast.ExpressionStatement(Expression: e))

	OnReference = do:
		$push(Ast.ReferenceExpression(Name: $pop))

	EnterInvocation = do:
		$push(Ast.MethodInvocationExpression(Target: $pop))

	OnArgument = do:
		arg = $pop
		($peek as Ast.MethodInvocationExpression).Arguments.Add(arg)

code = """
class Foo:
	class Nested:
		def bar():
			print 'yahoo'
		end
	end
	def run():
		print 'Hello, world!'
	end
end
"""
ctx = PegContextWithPayload[of List](code, [])
assert ctx.Match(Module),  "Error at " + ctx.Input.Position

module as Ast.Module = pop(ctx)
module.Name = "code"

print module.ToCodeString()

foo as duck = compile(module).GetType("Foo")()
foo.run()


prefer "$symbol" over "${symbol}"

prefer "$symbol" over "${symbol}"

namespace Boo.OMeta

import System.Collections.Specialized

class OMetaGrammarBase(OMetaGrammar):

	_rules = HybridDictionary()

	def InstallRule(ruleName as string, rule as OMetaRule):
		_rules[ruleName] = rule

	def Apply(context as OMetaEvaluationContext, rule as string, input as OMetaInput):
		found as OMetaRule = _rules[rule]
		if found is not null:
			return found(context, input)
		return RuleMissing(context, rule, input)

	virtual def RuleMissing(context as OMetaEvaluationContext, rule as string, input as OMetaInput) as OMetaMatch:
		raise "Rule '$rule' missing!"

namespace Boo.OMeta

import System.Collections.Specialized

class OMetaGrammarBase(OMetaGrammar):

	_rules = HybridDictionary()

	def InstallRule(ruleName as string, rule as OMetaRule):
		_rules[ruleName] = rule

	def Apply(context as OMetaEvaluationContext, rule as string, input as OMetaInput):
		found as OMetaRule = _rules[rule]
		if found is not null:
			return found(context, input)
		return RuleMissing(context, rule, input)

	virtual def RuleMissing(context as OMetaEvaluationContext, rule as string, input as OMetaInput) as OMetaMatch:
		raise "Rule '${rule}' missing!"


test uint -> long and ulong -> int conversions as well

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

import NUnit.Framework
import BooCompiler.Tests from BooCompiler.Tests

i0 as int = Constants.UnsignedInt
i1 as int = Constants.UnsignedLong
l0 as long = Constants.UnsignedLong
l1 as long = Constants.UnsignedInt

Assert.AreEqual(Constants.UnsignedInt, i0)
Assert.AreEqual(Constants.UnsignedLong, i1)
Assert.AreEqual(Constants.UnsignedLong, l0)
Assert.AreEqual(Constants.UnsignedInt, l1)

import NUnit.Framework
import BooCompiler.Tests from BooCompiler.Tests

i as int = Constants.UnsignedInt
l as long = Constants.UnsignedLong

Assert.AreEqual(Constants.UnsignedInt, i)
Assert.AreEqual(Constants.UnsignedLong, l)


ExecuteAssembly instead of StartProcess because it doesn't require execution permission on the file

namespace Boo.MonoDevelop.ProjectModel

import MonoDevelop.Core
import MonoDevelop.Projects

import System.IO

import Boo.Lang.PatternMatching

class BooCompiler:

	_config as DotNetProjectConfiguration
	_selector as ConfigurationSelector
	_projectItems as ProjectItemCollection
	_compilationParameters as BooCompilationParameters
	_projectParameters as BooProjectParameters

	def constructor(
		config as DotNetProjectConfiguration,
		selector as ConfigurationSelector,
		projectItems as ProjectItemCollection,
		progressMonitor as IProgressMonitor):

		_config = config
		_selector = selector
		_projectItems = projectItems
		_compilationParameters = config.CompilationParameters or BooCompilationParameters()
		_projectParameters = config.ProjectParameters or BooProjectParameters()

	def Run() as BuildResult:
		responseFileName = Path.GetTempFileName()
		try:
			WriteOptionsToResponseFile(responseFileName)
			compilerOutput = ExecuteProcess(BoocPath(), "@${responseFileName}")
			return ParseBuildResult(compilerOutput)
		ensure:
			FileService.DeleteFile(responseFileName)

	private def BoocPath():
		return PathCombine(AssemblyPath(), "boo", "booc.exe")

	private def AssemblyPath():
		return Path.GetDirectoryName(GetType().Assembly.ManifestModule.FullyQualifiedName)

	private def WriteOptionsToResponseFile(responseFileName as string):
		options = StringWriter()

		options.WriteLine("-t:${OutputType()}")
		options.WriteLine("-out:${_config.CompiledOutputName}")

		options.WriteLine("-debug" + ("+" if _config.DebugMode else "-"))

		if _compilationParameters.Ducky: options.WriteLine("-ducky")

		projectFiles = item as ProjectFile for item in _projectItems if item isa ProjectFile
		for file in projectFiles:
			continue if file.Subtype == Subtype.Directory

			match file.BuildAction:
				case BuildAction.Compile:
					options.WriteLine("\"${file.Name}\"")
				case BuildAction.EmbeddedResource:
					options.WriteLine("-embedres:${file.FilePath},${file.ResourceId}")
				otherwise:
					print "Unrecognized build action for file", file, "-", file.BuildAction

		references = item as ProjectReference for item in _projectItems if item isa ProjectReference
		for reference in references:
			for fileName in reference.GetReferencedFileNames(_selector):
				options.WriteLine("-reference:${fileName}")

		optionsString = options.ToString()
		print optionsString
		File.WriteAllText(responseFileName, optionsString)

	private def OutputType():
		return _config.CompileTarget.ToString().ToLower()

	private def ExecuteProcess(executable as string, commandLine as string):
		startInfo = System.Diagnostics.ProcessStartInfo(executable, commandLine,
						UseShellExecute: false,
						RedirectStandardOutput: true,
						RedirectStandardError: true)

		using process = Runtime.SystemAssemblyService.CurrentRuntime.ExecuteAssembly(startInfo, _config.TargetFramework):
			process.WaitForExit()
			return process.StandardOutput.ReadToEnd() + System.Environment.NewLine + process.StandardError.ReadToEnd()

	private def ParseBuildResult(stdout as string):

		result = BuildResult()

		for line in StringReader(stdout):
			match line:
				case @/^(?<fileName>.+)\((?<lineNumber>\d+),(?<column>\d+)\):\s+(?<code>.+?):\s+(?<message>.+)$/:
					result.Append(BuildError(
								FileName: fileName[0].Value,
								Line: int.Parse(lineNumber[0].Value),
								Column: int.Parse(column[0].Value),
								IsWarning: code[0].Value.StartsWith("BCW"),
								ErrorNumber: code[0].Value,
								ErrorText: message[0].Value))

				case @/^(?<code>.+):\s+(?<message>.+)$/:
					result.Append(
						BuildError(
								ErrorNumber: code[0].Value,
								ErrorText: message[0].Value))

				otherwise:
					if len(line) > 0: print "Unrecognized compiler output:", line

		return result

namespace Boo.MonoDevelop.ProjectModel

import MonoDevelop.Core
import MonoDevelop.Projects

import System.IO

import Boo.Lang.PatternMatching

class BooCompiler:

	_config as DotNetProjectConfiguration
	_selector as ConfigurationSelector
	_projectItems as ProjectItemCollection
	_compilationParameters as BooCompilationParameters
	_projectParameters as BooProjectParameters

	def constructor(
		config as DotNetProjectConfiguration,
		selector as ConfigurationSelector,
		projectItems as ProjectItemCollection,
		progressMonitor as IProgressMonitor):

		_config = config
		_selector = selector
		_projectItems = projectItems
		_compilationParameters = config.CompilationParameters or BooCompilationParameters()
		_projectParameters = config.ProjectParameters or BooProjectParameters()

	def Run() as BuildResult:
		responseFileName = Path.GetTempFileName()
		try:
			WriteOptionsToResponseFile(responseFileName)
			compilerOutput = ExecuteProcess(BoocPath(), "@${responseFileName}")
			return ParseBuildResult(compilerOutput)
		ensure:
			FileService.DeleteFile(responseFileName)

	private def BoocPath():
		return PathCombine(AssemblyPath(), "boo", "booc.exe")

	private def AssemblyPath():
		return Path.GetDirectoryName(GetType().Assembly.ManifestModule.FullyQualifiedName)

	private def WriteOptionsToResponseFile(responseFileName as string):
		options = StringWriter()

		options.WriteLine("-t:${OutputType()}")
		options.WriteLine("-out:${_config.CompiledOutputName}")

		options.WriteLine("-debug" + ("+" if _config.DebugMode else "-"))

		if _compilationParameters.Ducky: options.WriteLine("-ducky")

		projectFiles = item as ProjectFile for item in _projectItems if item isa ProjectFile
		for file in projectFiles:
			continue if file.Subtype == Subtype.Directory

			match file.BuildAction:
				case BuildAction.Compile:
					options.WriteLine("\"${file.Name}\"")
				case BuildAction.EmbeddedResource:
					options.WriteLine("-embedres:${file.FilePath},${file.ResourceId}")
				otherwise:
					print "Unrecognized build action for file", file, "-", file.BuildAction

		references = item as ProjectReference for item in _projectItems if item isa ProjectReference
		for reference in references:
			for fileName in reference.GetReferencedFileNames(_selector):
				options.WriteLine("-reference:${fileName}")

		optionsString = options.ToString()
		print optionsString
		File.WriteAllText(responseFileName, optionsString)

	private def OutputType():
		return _config.CompileTarget.ToString().ToLower()

	private def ExecuteProcess(executable as string, commandLine as string):
		startInfo = System.Diagnostics.ProcessStartInfo(executable, commandLine,
						UseShellExecute: false,
						RedirectStandardOutput: true,
						RedirectStandardError: true)

		stdout = StringWriter()
		stderr = StringWriter()
		using processWrapper = Runtime.ProcessService.StartProcess(startInfo, stdout, stderr, null):
			processWrapper.WaitForOutput()
			return stdout.ToString() + System.Environment.NewLine + stderr.ToString()

	private def ParseBuildResult(stdout as string):

		result = BuildResult()

		for line in StringReader(stdout):
			match line:
				case @/^(?<fileName>.+)\((?<lineNumber>\d+),(?<column>\d+)\):\s+(?<code>.+?):\s+(?<message>.+)$/:
					result.Append(BuildError(
								FileName: fileName[0].Value,
								Line: int.Parse(lineNumber[0].Value),
								Column: int.Parse(column[0].Value),
								IsWarning: code[0].Value.StartsWith("BCW"),
								ErrorNumber: code[0].Value,
								ErrorText: message[0].Value))

				case @/^(?<code>.+):\s+(?<message>.+)$/:
					result.Append(
						BuildError(
								ErrorNumber: code[0].Value,
								ErrorText: message[0].Value))

				otherwise:
					if len(line) > 0: print "Unrecognized compiler output:", line

		return result


Issue a warning if the await macro is used without async

namespace BooJs.Lang.Async

import System
import Boo.Lang.Environments
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast

import BooJs.Lang.Extensions

[Transform( __value )]
def __value() as object:
    pass
[Transform( __value )]
def __valuelist() as (object):
    pass

macro await:
    # await foo()
    # await foo(), bar()  <==>  (foo(), bar())
    # await data = foo()
    # await data = foo(), bar()
    # await data, data2 = foo(), bar()

    # TODO: Support type definitions

    # Check if the macro is used with async
    has_async = false
    parent = await.ParentNode
    while parent:
        if mie = parent as MethodInvocationExpression:
            target = mie.Target as ReferenceExpression
            if target and target.Name == 'async':
                has_async = true
                break

        parent = parent.ParentNode

    if not has_async:
        warning = CompilerWarningFactory.CustomWarning(await, 'await macro is being used in a method without the async attribute')
        my(CompilerContext).Warnings.Add(warning)

    decls = ExpressionCollection()
    exprs = ExpressionCollection()
    list = decls
    for arg in await.Arguments:
        if be = arg as BinaryExpression:
            if be.Operator != BinaryOperatorType.Assign:
                raise 'Invalid operator, only simple assigns are allowed'
            decls.Add(be.Left)
            exprs.Add(be.Right)
            list = exprs
            continue

        list.Add(arg)

    # No expressions mean we are not handling an assignment operation
    if len(exprs) == 0:
        exprs, decls = decls, exprs

    if len(exprs) == 1:
        yield [| yield $(exprs[0]) |]
    else:
        yield [| yield $( ArrayLiteralExpression(Items: exprs) ) |]

    if len(decls) == 1:
        yield [| $(decls[0]) = BooJs.Lang.Async.__value() |]
    elif len(decls) > 1:
        unpack = UnpackStatement()
        for decl as ReferenceExpression in decls:
            unpack.Declarations.Add(Declaration(Name: decl.Name))
        unpack.Expression = [| BooJs.Lang.Async.__valuelist() |]
        yield unpack

[AttributeUsage(AttributeTargets.Method)]
class AsyncAttribute(AbstractAstAttribute):

    def Apply(node as Node):
        method = node as Method
        method.Body = [|
            return async(): $(method.Body)
        |].ToBlock()

interface IPromise:
    def _then(okHandler as callable, errorHandler as callable, progressHandler as callable) as IPromise

internal class Promise(IPromise):

    def constructor(defer as Deferred):
        pass

    def done(fn as callable(object)) as Promise:
        pass

    def fail(fn as callable(object)) as Promise:
        pass

    def always(fn as callable(object)) as Promise:
        pass

    [Transform( then($1, $2, $3) )]
    virtual def _then(okHandler as callable, errorHandler as callable, progressHandler as callable) as IPromise:
        pass

    virtual def cancel():
        pass

enum DeferredState:
    Unresolved
    Resolved
    Rejected
    Cancelled

class Deferred:

    public promise = Promise(self)

    def constructor():
        pass

    def constructor(cancel as callable):
        pass

    def getState() as DeferredState:
        pass

    def resolve(value):
        pass

    def reject(error):
        pass

    def progress(update):
        pass

    [Transform( then($1, $2, $3) )]
    def _then(okHandler as callable, errorHandler as callable, progressHandler as callable) as IPromise:
        pass

    def cancel():
        pass

def async(fn as callable) as IPromise:
    pass

def when(*promises as (IPromise)) as IPromise:
    pass

def sleep(ms as int) as IPromise:
    pass

namespace BooJs.Lang.Async

import BooJs.Lang.Extensions

import System
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast

[Transform( __value )]
def __value() as object:
    pass
[Transform( __value )]
def __valuelist() as (object):
    pass

macro await:
    # await foo()
    # await foo(), bar()  <==>  (foo(), bar())
    # await data = foo()
    # await data = foo(), bar()
    # await data, data2 = foo(), bar()

    # TODO: Support type definitions

    decls = ExpressionCollection()
    exprs = ExpressionCollection()
    list = decls
    for arg in await.Arguments:
        if be = arg as BinaryExpression:
            if be.Operator != BinaryOperatorType.Assign:
                raise 'Invalid operator, only simple assigns are allowed'
            decls.Add(be.Left)
            exprs.Add(be.Right)
            list = exprs
            continue

        list.Add(arg)

    if len(exprs) == 1:
        yield [| yield $(exprs[0]) |]
    else:
        yield [| yield $( ArrayLiteralExpression(Items: exprs) ) |]

    if len(decls) == 1:
        yield [| $(decls[0]) = BooJs.Lang.Async.__value() |]
    elif len(decls) > 1:
        unpack = UnpackStatement()
        for decl as ReferenceExpression in decls:
            unpack.Declarations.Add(Declaration(Name: decl.Name))
        unpack.Expression = [| BooJs.Lang.Async.__valuelist() |]
        yield unpack

[AttributeUsage(AttributeTargets.Method)]
class AsyncAttribute(AbstractAstAttribute):

    def Apply(node as Node):
        method = node as Method
        method.Body = [|
            return async(): $(method.Body)
        |].ToBlock()

interface IPromise:
    def _then(okHandler as callable, errorHandler as callable, progressHandler as callable) as IPromise

class Promise(IPromise):

    def constructor(defer as Deferred):
        pass

    def done(fn as callable(object)) as Promise:
        pass

    def fail(fn as callable(object)) as Promise:
        pass

    def always(fn as callable(object)) as Promise:
        pass

    [Transform( then($1, $2, $3) )]
    virtual def _then(okHandler as callable, errorHandler as callable, progressHandler as callable) as IPromise:
        pass

    virtual def cancel():
        pass

enum DeferredState:
    Unresolved
    Resolved
    Rejected
    Cancelled

class Deferred:

    public promise = Promise(self)

    def constructor():
        pass

    def constructor(cancel as callable):
        pass

    def getState() as DeferredState:
        pass

    def resolve(value):
        pass

    def reject(error):
        pass

    def progress(update):
        pass

    [Transform( then($1, $2, $3) )]
    def _then(okHandler as callable, errorHandler as callable, progressHandler as callable) as IPromise:
        pass

    def cancel():
        pass

def async(fn as callable) as IPromise:
    pass

def when(*promises as (IPromise)) as IPromise:
    pass

def sleep(ms as int) as IPromise:
    pass


simplified test case a bit

simplified test case a bit

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

#region license
// Copyright (c) 2004, 2005, 2006 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.Compiler.Tests

import System
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.TypeSystem
import NUnit.Framework

[TestFixture]
class CallableResolutionServiceTestFixture:

	_context as CompilerContext
	_crs as CallableResolutionService

	[SetUp]
	def SetUp():
		_context = CompilerContext(
			TypeSystemServices: Boo.Lang.Compiler.TypeSystem.TypeSystemServices())
		_crs = CallableResolutionService()
		_crs.Initialize(_context)

	[Test]
	def TestGetLogicalTypeDepth():
		Assert.AreEqual(0, GetLogicalTypeDepth(object))
		Assert.AreEqual(0, _crs.GetLogicalTypeDepth(TypeSystemServices.DuckType))
		Assert.AreEqual(1, GetLogicalTypeDepth(System.ValueType))
		Assert.AreEqual(1, GetLogicalTypeDepth(int))
		Assert.AreEqual(1, GetLogicalTypeDepth(string))

	[Test]
	def TestResolveAmbiguousCallable():
		entity = ResolveCallableReference(
			NewExpressionCollection(NewObjectInvocationExpression()),
			GetMethod("foo", E), GetMethod("foo", string))
		Assert.AreEqual(2, _crs.ValidCandidates.Count, _crs.ValidCandidates.ToString())
		assert entity is null, entity.ToString()

	[Test]
	def CloserMemberWins():
		entity = ResolveCallableReference(
			ExpressionCollection(),
			intMethod = GetMethod(int, "ToString"),
			GetMethod(System.ValueType, "ToString"),
			GetMethod(object, "ToString"))
		Assert.AreSame(intMethod, entity)

	[Test]
	def UpcastPlusMatchBetterThanMatchPlusDowncast():
		entity = ResolveCallableReference(
			NewExpressionCollection(
				CodeBuilder.CreateIntegerLiteral(42),
				NewObjectInvocationExpression()),
			objectMethod = GetMethod("bar", object, object),
			GetMethod("bar", int, int))
		Assert.AreSame(objectMethod, entity)

	def ResolveCallableReference(args as ExpressionCollection, *candidates as (IMethod)):
		return _crs.ResolveCallableReference(args, candidates)

	def GetLogicalTypeDepth(type as System.Type):
		return _crs.GetLogicalTypeDepth(TypeSystemServices.Map(type))

	def NewExpressionCollection(*items as (Expression)):
		return ExpressionCollection.FromArray(*items)

	def NewObjectInvocationExpression():
		return CodeBuilder.CreateConstructorInvocation(
			TypeSystemServices.Map(typeof(object).GetConstructors()[0]))

	def GetMethod(methodName as string, *types as (System.Type)):
		return GetMethod(GetType(), methodName, *types)

	def GetMethod(type as System.Type, methodName as string, *types as (System.Type)):
		return TypeSystemServices.Map(type.GetMethod(methodName, types))

	CodeBuilder:
		get:
			return _context.CodeBuilder

	TypeSystemServices:
		get:
			return _context.TypeSystemServices

	enum E:
		A
		B
		C

	static def foo(i as E):
		pass

	static def foo(s as string):
		pass

	static def bar(x as int, y as int):
		pass

	static def bar(x as object, y as object):
		pass

#region license
// Copyright (c) 2004, 2005, 2006 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.Compiler.Tests

import System
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.TypeSystem
import NUnit.Framework

[TestFixture]
class CallableResolutionServiceTestFixture:

	_context as CompilerContext
	_crs as CallableResolutionService

	[SetUp]
	def SetUp():
		_context = CompilerContext(
			TypeSystemServices: Boo.Lang.Compiler.TypeSystem.TypeSystemServices())
		_crs = CallableResolutionService()
		_crs.Initialize(_context)

	[Test]
	def TestGetLogicalTypeDepth():
		Assert.AreEqual(0, GetLogicalTypeDepth(object))
		Assert.AreEqual(0, _crs.GetLogicalTypeDepth(TypeSystemServices.DuckType))
		Assert.AreEqual(1, GetLogicalTypeDepth(System.ValueType))
		Assert.AreEqual(1, GetLogicalTypeDepth(int))
		Assert.AreEqual(1, GetLogicalTypeDepth(string))

	[Test]
	def TestResolveAmbiguousCallable():
		entity = _crs.ResolveCallableReference(
			NewExpressionCollection(NewObjectInvocationExpression()),
			(GetMethod("foo", E), GetMethod("foo", string)))
		Assert.AreEqual(2, _crs.ValidCandidates.Count, _crs.ValidCandidates.ToString())
		assert entity is null, entity.ToString()

	[Test]
	def CloserMemberWins():
		entity = _crs.ResolveCallableReference(
			ExpressionCollection(),
			(intMethod = GetMethod(int, "ToString"),
			GetMethod(System.ValueType, "ToString"),
			GetMethod(object, "ToString")))
		Assert.AreSame(intMethod, entity)

	[Test]
	def UpcastPlusMatchBetterThanMatchPlusDowncast():
		entity = _crs.ResolveCallableReference(
			NewExpressionCollection(
				CodeBuilder.CreateIntegerLiteral(42),
				NewObjectInvocationExpression()),
			(objectMethod = GetMethod("bar", object, object),
			GetMethod("bar", int, int)))
		Assert.AreSame(objectMethod, entity)

	def GetLogicalTypeDepth(type as System.Type):
		return _crs.GetLogicalTypeDepth(TypeSystemServices.Map(type))

	def NewExpressionCollection(*items as (Expression)):
		e = ExpressionCollection()
		e.Extend(items)
		return e

	def NewObjectInvocationExpression():
		return CodeBuilder.CreateConstructorInvocation(
			TypeSystemServices.Map(typeof(object).GetConstructors()[0]))

	def GetMethod(methodName as string, *types as (System.Type)):
		return GetMethod(GetType(), methodName, *types)

	def GetMethod(type as System.Type, methodName as string, *types as (System.Type)):
		return TypeSystemServices.Map(type.GetMethod(methodName, types))

	CodeBuilder:
		get:
			return _context.CodeBuilder

	TypeSystemServices:
		get:
			return _context.TypeSystemServices

	enum E:
		A
		B
		C

	static def foo(i as E):
		pass

	static def foo(s as string):
		pass

	static def bar(x as int, y as int):
		pass

	static def bar(x as object, y as object):
		pass


booish welcome message

booish welcome message

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

#region license
// Copyright (c) 2004, 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

import System
import System.Diagnostics
import Boo.Lang.Compiler.Steps
import Boo.Lang.Interpreter

interpreter = InteractiveInterpreter(RememberLastValue: true)

if "--print-modules" in argv:
	interpreter.Pipeline.Add(PrintBoo())

if "--debug" in argv:
	Debug.Listeners.Add(TextWriterTraceListener(Console.Out))

print """Welcome to booish, an interpreter for the boo programming language.

Running boo ${BooVersion}.

The following builtin functions are available:
    dir(Type): lists the members of a type
    help(Type): prints detailed information about a type
    load(string): evals an external boo file
    globals(): returns the names of all variables known to the interpreter

Enter boo code in the prompt below."""

interpreter.ConsoleLoopEval()

#region license
// Copyright (c) 2004, 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

import System
import System.Diagnostics
import Boo.Lang.Compiler.Steps
import Boo.Lang.Interpreter

interpreter = InteractiveInterpreter(RememberLastValue: true)

if "--print-modules" in argv:
	interpreter.Pipeline.Add(PrintBoo())

if "--debug" in argv:
	Debug.Listeners.Add(TextWriterTraceListener(Console.Out))

interpreter.ConsoleLoopEval()


workaround for gtk# bug #61703

workaround for gtk# bug #61703

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

import System
import GLib from "glib-sharp" as GLib
import Gtk from "gtk-sharp"
import GtkSourceView from "gtksourceview-sharp"

class BooEditor(ScrolledWindow):

	static _booSourceLanguage = SourceLanguagesManager().GetLanguageFromMimeType("text/x-boo")

	_buffer = SourceBuffer(_booSourceLanguage, Highlight: true)
	_view = SourceView(_buffer, ShowLineNumbers: true, AutoIndent: true)

	def constructor():
		self.SetPolicy(PolicyType.Automatic, PolicyType.Automatic)
		self.Add(_view)

	Text:
		get:
			return _buffer.Text

class MainWindow(Window):

	_status = Statusbar(HasResizeGrip: false)
	_notebook = Notebook(TabPos: PositionType.Top, Scrollable: true)
	_accelGroup = AccelGroup()
	_editors = [] # workaround for gtk# bug #61703

	def constructor():
		super("Boo Explorer")

		self.AddAccelGroup(_accelGroup)
		self.SetDefaultSize(600, 400)
		self.DeleteEvent += OnDelete

		vbox = VBox(false, 1)
		vbox.PackStart(CreateMenuBar(), false, false, 0)
		vbox.PackStart(_notebook, true, true, 0)
		vbox.PackStart(_status, false, false, 0)

		self.Add(vbox)

		self.NewDocument()

	def NewDocument():
		editor = BooEditor()
		_notebook.AppendPage(editor, Label("unnamed.boo"))
		_editors.Add(editor)
		editor.ShowAll()

	private def CreateMenuBar():
		mb = MenuBar()

		file = Menu()
		file.Append(ImageMenuItem(Stock.New, _accelGroup, Activated: _menuItemNew_Activated))
		file.Append(ImageMenuItem(Stock.Open, _accelGroup, Activated: _menuItemOpen_Activated))
		file.Append(ImageMenuItem(Stock.Save, _accelGroup, Activated: _menuItemSave_Activated))
		file.Append(SeparatorMenuItem())
		file.Append(ImageMenuItem(Stock.Quit, _accelGroup, Activated: _menuItemExit_Activated))

		edit = Menu()
		edit.Append(ImageMenuItem(Stock.Undo, _accelGroup))
		edit.Append(ImageMenuItem(Stock.Redo, _accelGroup))
		edit.Append(SeparatorMenuItem())
		edit.Append(ImageMenuItem(Stock.Cut, _accelGroup))
		edit.Append(ImageMenuItem(Stock.Copy, _accelGroup))
		edit.Append(ImageMenuItem(Stock.Paste, _accelGroup))
		edit.Append(ImageMenuItem(Stock.Delete, _accelGroup))
		edit.Append(SeparatorMenuItem())
		edit.Append(ImageMenuItem(Stock.Preferences, _accelGroup))

		tools = Menu()
		tools.Append(ImageMenuItem(Stock.Execute, _accelGroup, Activated: _menuItemExecute_Activated))

		mb.Append(MenuItem("File", Submenu: file))
		mb.Append(MenuItem("Edit", Submenu: edit))
		mb.Append(MenuItem("Tools", Submenu: tools))
		return mb

	private def _menuItemExecute_Activated(sender, args as EventArgs):
		// can't do the simpler:
		// editor as BooEditor = _notebook.CurrentPageWidget
		// because of gtk# bug #61703

		editor as BooEditor = _editors[_notebook.CurrentPage]

		compiler = Boo.Lang.Compiler.BooCompiler()
		compiler.Parameters.Input.Add(Boo.Lang.Compiler.IO.StringInput("<script>", editor.Text))
		compiler.Parameters.Pipeline = Boo.Lang.Compiler.Pipelines.Run()

		result = compiler.Run()
		print(result.Errors.ToString()) if len(result.Errors)

	private def _menuItemNew_Activated(sender, args as EventArgs):
		self.NewDocument()

	private def _menuItemOpen_Activated(sender, args as EventArgs):
		pass

	private def _menuItemSave_Activated(sender, args as EventArgs):
		pass

	private def _menuItemExit_Activated(sender, args as EventArgs):
		Application.Quit()

	def OnDelete(sender, args as DeleteEventArgs):
		Application.Quit()
		args.RetVal = true

Application.Init()

MainWindow().ShowAll()

Application.Run()

import System
import Gtk from "gtk-sharp"
import GtkSourceView from "gtksourceview-sharp"

class BooEditor(ScrolledWindow):

	static _booSourceLanguage = SourceLanguagesManager().GetLanguageFromMimeType("text/x-boo")

	_buffer = SourceBuffer(_booSourceLanguage, Highlight: true)
	_view = SourceView(_buffer, ShowLineNumbers: true, AutoIndent: true)

	def constructor():
		super(Adjustment(IntPtr.Zero), Adjustment(IntPtr.Zero))
		self.SetPolicy(PolicyType.Automatic, PolicyType.Automatic)
		self.Add(_view)

	Text:
		get:
			return _buffer.Text

class MainWindow(Window):

	_status = Statusbar(HasResizeGrip: false)
	_notebook = Notebook(TabPos: PositionType.Top, Scrollable: true)
	_accelGroup = AccelGroup()

	def constructor():
		super("Boo Explorer")

		self.AddAccelGroup(_accelGroup)
		self.SetDefaultSize(600, 400)
		self.DeleteEvent += OnDelete

		vbox = VBox(false, 1)
		vbox.PackStart(CreateMenuBar(), false, false, 0)
		vbox.PackStart(_notebook, true, true, 0)
		vbox.PackStart(_status, false, false, 0)

		self.Add(vbox)

		self.NewDocument()

	def NewDocument():
		editor = BooEditor()
		_notebook.AppendPage(editor, Label("unnamed.boo"))
		editor.ShowAll()

	private def CreateMenuBar():
		mb = MenuBar()

		file = Menu()
		file.Append(ImageMenuItem(Stock.New, _accelGroup, Activated: _menuItemNew_Activated))
		file.Append(ImageMenuItem(Stock.Open, _accelGroup, Activated: _menuItemOpen_Activated))
		file.Append(ImageMenuItem(Stock.Save, _accelGroup, Activated: _menuItemSave_Activated))
		file.Append(SeparatorMenuItem())
		file.Append(ImageMenuItem(Stock.Quit, _accelGroup, Activated: _menuItemExit_Activated))

		edit = Menu()
		edit.Append(ImageMenuItem(Stock.Undo, _accelGroup))
		edit.Append(ImageMenuItem(Stock.Redo, _accelGroup))
		edit.Append(SeparatorMenuItem())
		edit.Append(ImageMenuItem(Stock.Cut, _accelGroup))
		edit.Append(ImageMenuItem(Stock.Copy, _accelGroup))
		edit.Append(ImageMenuItem(Stock.Paste, _accelGroup))
		edit.Append(ImageMenuItem(Stock.Delete, _accelGroup))
		edit.Append(SeparatorMenuItem())
		edit.Append(ImageMenuItem(Stock.Preferences, _accelGroup))

		tools = Menu()
		tools.Append(ImageMenuItem(Stock.Execute, _accelGroup, Activated: _menuItemExecute_Activated))

		mb.Append(MenuItem("File", Submenu: file))
		mb.Append(MenuItem("Edit", Submenu: edit))
		mb.Append(MenuItem("Tools", Submenu: tools))
		return mb

	private def _menuItemExecute_Activated(sender, args as EventArgs):
		// trying to track down a gtk-sharp bug
		// after a few executions (garbage collection?)
		// CurrentPageWidget will start to return a simple
		// ScrolledWindow (no longer a BooEditor)
		print(_notebook.CurrentPage)
		print(_notebook.CurrentPageWidget)
		editor = _notebook.CurrentPageWidget as BooEditor
		return if editor is null

		compiler = Boo.Lang.Compiler.BooCompiler()
		compiler.Parameters.Input.Add(Boo.Lang.Compiler.IO.StringInput("<script>", editor.Text))
		compiler.Parameters.Pipeline = Boo.Lang.Compiler.Pipelines.Run()

		result = compiler.Run()
		print(result.Errors.ToString()) if len(result.Errors)

	private def _menuItemNew_Activated(sender, args as EventArgs):
		self.NewDocument()

	private def _menuItemOpen_Activated(sender, args as EventArgs):
		pass

	private def _menuItemSave_Activated(sender, args as EventArgs):
		pass

	private def _menuItemExit_Activated(sender, args as EventArgs):
		Application.Quit()

	def OnDelete(sender, args as DeleteEventArgs):
		Application.Quit()
		args.RetVal = true

Application.Init()

MainWindow().ShowAll()

Application.Run()


a bit of documentation

a bit of documentation

#!/usr/bin/env booi
"""
Generates test fixtures from files under tests/

First line of test case can specify a nunit attribute to go with it:
	* "// ignore reason" for [Ignore("reason")]
	* "// category name" for [Category("name")]
"""
import System
import System.IO
import Boo.Lang.PatternMatching

//def MapPath(path):
//	return Path.Combine(Project.BaseDirectory, path)

def GetTestCaseName(fname as string):
	return Path.GetFileNameWithoutExtension(fname).Replace("-", "_")

def WriteTestCases(writer as TextWriter, baseDir as string):
	count = 0
	for fname in Directory.GetFiles(baseDir):
		continue unless fname.EndsWith(".js")
		++count
		categoryAttribute = CategoryAttributeFor(fname)
		writer.Write("""
	${categoryAttribute}
	[Test] def ${GetTestCaseName(fname)}():
		RunTestCase("${fname.Replace('\\', '/')}")
		""")
	print("${count} test cases found in ${baseDir}.")

def CategoryAttributeFor(testFile as string):
"""
If the first line of the test case file starts with // category CategoryName
then return a suitable [CategoryName()] attribute.
"""
	match FirstLineOf(testFile):
		case /\/\/\s*ignore\s+(?<reason>.*)/:
			return "[Ignore(\"${reason[0].Value.Trim()}\")]"
		case /\/\/\s*category\s+(?<name>.*)/:
			return "[Category(\"${name[0].Value.Trim()}\")]"
		otherwise:
			return ""

def FirstLineOf(fname as string):
	using reader=File.OpenText(fname):
		return reader.ReadLine()

def GenerateTestFixture(srcDir as string, targetFile as string, header as string):
	contents = GenerateTestFixtureSource(srcDir, header)
	if ShouldReplaceContent(targetFile, contents):
		WriteAllText(targetFile, contents)

def ShouldReplaceContent(fname as string, contents as string):
	if not File.Exists(fname): return true
	return ns(ReadAllText(fname)) != ns(contents)

def ReadAllText(fname as string):
	using reader=File.OpenText(fname):
		return reader.ReadToEnd()

def WriteAllText(fname as string, contents as string):
	using writer=StreamWriter(fname):
		writer.Write(contents)

def ns(s as string):
"""
Normalize string.
"""
	return s.Trim().Replace("\r\n", Environment.NewLine)

def GenerateTestFixtureSource(srcDir as string, header as string):
	writer=StringWriter()
	writer.Write(header)
	WriteTestCases(writer, srcDir)
	return writer.ToString()

GenerateTestFixture("tests/parser", "src/UnityScript.Tests/ParserTestFixture.Generated.boo", """
namespace UnityScript.Tests

import NUnit.Framework

partial class ParserTestFixture:
""")

GenerateTestFixture("tests/semantics", "src/UnityScript.Tests/SemanticsTestFixture.boo", """
namespace UnityScript.Tests

import NUnit.Framework

[TestFixture]
class SemanticsTestFixture(AbstractSemanticsTestFixture):
""")

GenerateTestFixture("tests/integration", "src/UnityScript.Tests/IntegrationTestFixture.boo", """
namespace UnityScript.Tests

import NUnit.Framework

[TestFixture]
class IntegrationTestFixture(AbstractIntegrationTestFixture):
""")

GenerateTestFixture("tests/pragma", "src/UnityScript.Tests/PragmaTestFixture.boo", """
namespace UnityScript.Tests

import NUnit.Framework

[TestFixture]
class PragmaTestFixture(AbstractIntegrationTestFixture):
""")

GenerateTestFixture("tests/generics", "src/UnityScript.Tests/GenericsTestFixture.Generated.boo", """
namespace UnityScript.Tests

import NUnit.Framework

[TestFixture]
class GenericsTestFixture(AbstractIntegrationTestFixture):
""")

GenerateTestFixture("tests/eval", "src/UnityScript.Tests/EvalTestFixture.boo", """
namespace UnityScript.Tests

import NUnit.Framework

[TestFixture]
class EvalTestFixture(AbstractIntegrationTestFixture):
""")

GenerateTestFixture("tests/expando", "src/UnityScript.Tests/ExpandoTestFixture.boo", """
namespace UnityScript.Tests

import NUnit.Framework

[TestFixture]
class ExpandoTestFixture(AbstractIntegrationTestFixture):

	override def CreateCompiler():
		compiler = super()
		compiler.Parameters.Expando = true
		return compiler
""")

GenerateTestFixture("tests/error-messages", "src/UnityScript.Tests/ErrorMessagesTestFixture.Generated.boo", """
namespace UnityScript.Tests

import NUnit.Framework

partial class ErrorMessagesTestFixture:
""")

GenerateTestFixture("tests/stacktrace", "src/UnityScript.Tests/StackTraceTestFixture.Generated.boo", """
namespace UnityScript.Tests

import NUnit.Framework

partial class StackTraceTestFixture:
""")

#!/usr/bin/env booi
"""
Generates test fixtures from files under tests/
"""
import System
import System.IO
import Boo.Lang.PatternMatching

//def MapPath(path):
//	return Path.Combine(Project.BaseDirectory, path)

def GetTestCaseName(fname as string):
	return Path.GetFileNameWithoutExtension(fname).Replace("-", "_")

def WriteTestCases(writer as TextWriter, baseDir as string):
	count = 0
	for fname in Directory.GetFiles(baseDir):
		continue unless fname.EndsWith(".js")
		++count
		categoryAttribute = CategoryAttributeFor(fname)
		writer.Write("""
	${categoryAttribute}
	[Test] def ${GetTestCaseName(fname)}():
		RunTestCase("${fname.Replace('\\', '/')}")
		""")
	print("${count} test cases found in ${baseDir}.")

def CategoryAttributeFor(testFile as string):
"""
If the first line of the test case file starts with // category CategoryName
then return a suitable [CategoryName()] attribute.
"""
	match FirstLineOf(testFile):
		case /\/\/\s*ignore\s+(?<reason>.*)/:
			return "[Ignore(\"${reason[0].Value.Trim()}\")]"
		case /\/\/\s*category\s+(?<name>.*)/:
			return "[Category(\"${name[0].Value.Trim()}\")]"
		otherwise:
			return ""

def FirstLineOf(fname as string):
	using reader=File.OpenText(fname):
		return reader.ReadLine()

def GenerateTestFixture(srcDir as string, targetFile as string, header as string):
	contents = GenerateTestFixtureSource(srcDir, header)
	if ShouldReplaceContent(targetFile, contents):
		WriteAllText(targetFile, contents)

def ShouldReplaceContent(fname as string, contents as string):
	if not File.Exists(fname): return true
	return ns(ReadAllText(fname)) != ns(contents)

def ReadAllText(fname as string):
	using reader=File.OpenText(fname):
		return reader.ReadToEnd()

def WriteAllText(fname as string, contents as string):
	using writer=StreamWriter(fname):
		writer.Write(contents)

def ns(s as string):
"""
Normalize string.
"""
	return s.Trim().Replace("\r\n", Environment.NewLine)

def GenerateTestFixtureSource(srcDir as string, header as string):
	writer=StringWriter()
	writer.Write(header)
	WriteTestCases(writer, srcDir)
	return writer.ToString()

GenerateTestFixture("tests/parser", "src/UnityScript.Tests/ParserTestFixture.Generated.boo", """
namespace UnityScript.Tests

import NUnit.Framework

partial class ParserTestFixture:
""")

GenerateTestFixture("tests/semantics", "src/UnityScript.Tests/SemanticsTestFixture.boo", """
namespace UnityScript.Tests

import NUnit.Framework

[TestFixture]
class SemanticsTestFixture(AbstractSemanticsTestFixture):
""")

GenerateTestFixture("tests/integration", "src/UnityScript.Tests/IntegrationTestFixture.boo", """
namespace UnityScript.Tests

import NUnit.Framework

[TestFixture]
class IntegrationTestFixture(AbstractIntegrationTestFixture):
""")

GenerateTestFixture("tests/pragma", "src/UnityScript.Tests/PragmaTestFixture.boo", """
namespace UnityScript.Tests

import NUnit.Framework

[TestFixture]
class PragmaTestFixture(AbstractIntegrationTestFixture):
""")

GenerateTestFixture("tests/generics", "src/UnityScript.Tests/GenericsTestFixture.Generated.boo", """
namespace UnityScript.Tests

import NUnit.Framework

[TestFixture]
class GenericsTestFixture(AbstractIntegrationTestFixture):
""")

GenerateTestFixture("tests/eval", "src/UnityScript.Tests/EvalTestFixture.boo", """
namespace UnityScript.Tests

import NUnit.Framework

[TestFixture]
class EvalTestFixture(AbstractIntegrationTestFixture):
""")

GenerateTestFixture("tests/expando", "src/UnityScript.Tests/ExpandoTestFixture.boo", """
namespace UnityScript.Tests

import NUnit.Framework

[TestFixture]
class ExpandoTestFixture(AbstractIntegrationTestFixture):

	override def CreateCompiler():
		compiler = super()
		compiler.Parameters.Expando = true
		return compiler
""")

GenerateTestFixture("tests/error-messages", "src/UnityScript.Tests/ErrorMessagesTestFixture.Generated.boo", """
namespace UnityScript.Tests

import NUnit.Framework

partial class ErrorMessagesTestFixture:
""")

GenerateTestFixture("tests/stacktrace", "src/UnityScript.Tests/StackTraceTestFixture.Generated.boo", """
namespace UnityScript.Tests

import NUnit.Framework

partial class StackTraceTestFixture:
""")


Fixed BooParserTestFixture.dsl_1

Fixed BooParserTestFixture.dsl_1

namespace Boo.OMeta.Parser

import Boo.OMeta
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast

import System.Globalization

macro infix:

	l, op, r = infix.Arguments

	return ExpressionStatement([| $l = ((($l >> l, $op >> op, $r >> r) ^ newInfixExpression(op, l, r)) | $r) |])

macro infixr:

	l, op, r = infixr.Arguments

	return ExpressionStatement([| $l = ((($r >> l, $op >> op, $l >> r) ^ newInfixExpression(op, l, r)) | $r) |])

macro prefix:

	rule, op, next = prefix.Arguments

	return ExpressionStatement([| $rule = ($op >> op, $rule >> e) ^ newPrefixExpression(op, e) | $next |])

macro list_of:
"""
Generates rules for lists of the given expression.

	list_of expression

Expands to something that matches:

	expression (COMMA expression)+
"""

	if len(list_of.Arguments) == 2:
		rule, separator = list_of.Arguments
	else:
		rule, separator = list_of.Arguments[0], [| COMMA |]

	block as Block = list_of.ParentNode

	listRuleName = ReferenceExpression(Name: "${rule}_list")
	listRule = [| $listRuleName = ((($rule >> first), ++(($separator, $rule >> e) ^ e) >> rest) ^ prepend(first, rest)) | ($rule >> v ^ [v]) |]
	block.Add(listRule)

	optionalRuleName = ReferenceExpression(Name: "optional_${rule}_list")
	optionalListRule = [| $optionalRuleName = $listRuleName | ("" ^ []) |]
	block.Add(optionalListRule)

ometa BooParser < WhitespaceSensitiveTokenizer:

	tokens:
		qq_begin = "[|"
		qq_end = "|]"
		equality = "=="
		inequality = "!="
		assign = "="
		assign_inplace = "+=" | "-=" | "*=" | "/=" | "%=" | "^=" | "&=" | "|="
		xor = "^"
		increment = "++"
		decrement = "--"
		plus = "+"
		minus = "-"
		exponentiation = "**"
		star = "*"
		division = "/"
		modulus = "%"
		ones_complement = "~"
		bitwise_shift_left = "<<"
		bitwise_shift_right = ">>"
		greater_than_eq = ">="
		greater_than = ">"
		less_than_eq = "<="
		less_than = "<"
		semicolon = ";"
		bitwise_and = "&"
		bitwise_or = "|"
		hexnum = ("0x", ++(hex_digit | digit) >> ds) ^ makeString(ds)
		num = ++digit
		colon = ":"
		dot = "."
		comma = ","
		lparen = "(", enterWhitespaceAgnosticRegion
		rparen = ")", leaveWhitespaceAgnosticRegion
		lbrack = "[", enterWhitespaceAgnosticRegion
		rbrack = "]", leaveWhitespaceAgnosticRegion
		lbrace = "{", enterWhitespaceAgnosticRegion
		rbrace = "}", leaveWhitespaceAgnosticRegion

		kw = (keywords >> value, ~(letter | digit | '_')) ^ value
		tdq = '"""'
		dq = '"'
		sqs = ("'", ++(~"'", _) >> s, "'") ^ s
		id = ((letter | '_') >> p, --(letter | digit | '_') >> s) ^ makeString(p, s)

	space = line_continuation | multi_line_comment | line_comment | super

	line_continuation = "\\", newline

	multi_line_comment = "/*", --(~"*/", (multi_line_comment | _)), "*/"

	line_comment = ('#' | "//"), --(~newline, _)

	hex_digit = _ >> c as char and ((c >= char('a') and c <= char('f')) or (c >= char('A') and c <= char('Z')))

	keywords "class", "def", "do", "import", "pass", "return", "true", \
		"false", "and", "or", "as", "not", "if", "is", "null", \
		"for", "interface", "internal", "in", "yield", "self", "super", "of", \
		"event", "private", "protected", "public", "enum", \
		"callable", "unless", "static", "final", "virtual", "override", "abstract", \
		"transient", "raise", "else", "typeof"

	keyword[expected] = ((KW >> t) and (expected is tokenValue(t))) ^ t

	module = (
		--EOL,
		(docstring >> s | ""),
		--import_declaration >> ids,
		--module_member >> members,
		--stmt >> stmts,
		--EOL
	) ^ newModule(s, ids, members, stmts)

	docstring = (TDQ, ++(~tdq, string_char) >> s, TDQ, eol) ^ makeString(s)

	import_declaration = (IMPORT, qualified_name >> qn, eol) ^ newImport(qn)

	qualified_name = (ID >> qualifier, --((DOT, ID >> n) ^ n) >> suffix)^ buildQName(qualifier, suffix)

	module_member = assembly_attribute | type_def | method

	type_def = class_def | interface_def | enum_def | callable_def

	callable_def = (CALLABLE, ID >> name, method_parameters >> parameters, optional_type >> type, eol) ^ newCallable(name, parameters, type)

	class_def = (
		attributes >> attrs,
		member_modifiers >> mod,
		CLASS, ID >> className, super_types >> superTypes, begin_block, class_body >> body, end_block
	) ^ newClass(attrs, mod, className, superTypes, body)

	interface_def = (
		attributes >> attrs,
		member_modifiers >> mod,
		INTERFACE, ID >> name, super_types >> superTypes, begin_block, interface_body >> body, end_block
	) ^ newInterface(attrs, mod, name, superTypes, body)

	enum_def = (
		attributes >> attrs,
		member_modifiers >> mod,
		ENUM, ID >> name, begin_block, enum_body >> body, end_block
	) ^ newEnum(attrs, mod, name, body)

	enum_body = ++enum_field >> fields ^ fields

	enum_field = (attributes >> attrs, ID >> name, ((ASSIGN, expression >> e) | ""), eol) ^ newEnumField(attrs, name, e)

	super_types = ((LPAREN, optional_type_reference_list >> types, RPAREN) ^ types) | ""

	class_body = no_member | (++class_member >> members ^ members)

	interface_body = no_member

	no_member = (PASS, eol) ^ null

	class_member = type_def | property_def | method | field | event_def

	event_def = (
		attributes >> attrs,
		member_modifiers >> mod,
		EVENT, ID >> name, optional_type >> type, eol
	) ^ newEvent(attrs, mod, name, type)

	property_def = (
		attributes >> attrs,
		member_modifiers >> mod,
		ID >> name, property_parameters >> parameters, optional_type >> type,
		begin_block,
		(
			(property_getter >> pg, property_setter >> ps)
			| (property_setter >> ps, property_getter >> pg)
			| (property_setter >> ps)
			| (property_getter >> pg)
		),
		end_block
	) ^ newProperty(attrs, mod, name, parameters, type, pg, ps)

	property_parameters = ((LBRACK, parameter_list >> parameters, RBRACK) | "") ^ parameters

	property_getter = accessor["get"]

	property_setter = accessor["set"]

	accessor[key] = (
		attributes >> attrs,
		member_modifiers >> mod,
		(ID >> name and (tokenValue(name) == key)),
		block >> body
	) ^ newMethod(attrs, mod, name, null, null, null, body)

	field = (
		attributes >> attrs,
		member_modifiers >> mod,
		ID >> name, optional_type >> type, field_initializer >> initializer
	) ^ newField(attrs, mod, name, type, initializer)

	field_initializer = (ASSIGN, block_expression) | ((ASSIGN, rvalue >> v, eol) ^ v) | eol

	member_modifiers = --(
		(PRIVATE ^ TypeMemberModifiers.Private)
		| (PUBLIC ^ TypeMemberModifiers.Public)
		| (INTERNAL ^ TypeMemberModifiers.Internal)
		| (PROTECTED ^ TypeMemberModifiers.Protected)
		| (FINAL ^ TypeMemberModifiers.Final)
		| (STATIC ^ TypeMemberModifiers.Static)
		| (VIRTUAL ^ TypeMemberModifiers.Virtual)
		| (OVERRIDE ^ TypeMemberModifiers.Override)
		| (TRANSIENT ^ TypeMemberModifiers.Transient)
		| (ABSTRACT ^ TypeMemberModifiers.Abstract)
	) >> all ^ all

	method = (
		attributes >> attrs,
		member_modifiers >> mod,
		DEF, ID >> name,
		optional_generic_parameters >> genericParameters,
		method_parameters >> parameters,
		attributes >> returnTypeAttributes, optional_type >> type,
		block >> body
	) ^ newGenericMethod(attrs, mod, name, genericParameters, parameters, returnTypeAttributes, type, body)

	method_parameters = (LPAREN, optional_parameter_list >> parameters, RPAREN) ^ parameters

	optional_generic_parameters = generic_parameters | ""

	generic_parameters = (LBRACK, OF, generic_parameter_list >> parameters, RBRACK) ^ parameters

	generic_parameter = (ID >> name) ^ newGenericParameterDeclaration(name)

	list_of generic_parameter

	list_of parameter

	assembly_attribute = (
		LBRACK, (ID >> name and (tokenValue(name) == "assembly")), COLON,
		attribute_list >> value,
		RBRACK, eol) ^ value

	attributes = --((LBRACK, attribute_list >> value, RBRACK, --EOL) ^ value) >> all ^ all

	attribute = (ID >> name, attribute_arguments >> args) ^ newAttribute(name, args)

	attribute_arguments = invocation_arguments | ""

	list_of attribute

	parameter = (attributes >> attrs, ID >> name, optional_type >> type) ^ newParameterDeclaration(attrs, name, type)

	optional_type = (AS, type_reference) | ""

	block = empty_block | multi_line_block | single_line_block

	empty_block = (begin_block, (PASS, eol), end_block) ^ Block()

	multi_line_block = (begin_block, ++stmt >> stmts, end_block)  ^ newBlock(stmts)

	single_line_block = (COLON, stmt_line >> line) ^ newBlock(line)

	begin_block = COLON, INDENT

	end_block = DEDENT

	stmt = stmt_block | stmt_line

	stmt_line = (~~(ID, AS), stmt_declaration) \
		| stmt_expression \
		| stmt_macro \
		| stmt_return \
		| stmt_yield \
		| stmt_raise \
		| stmt_unpack

	stmt_unpack = (declaration_list >> declarations, ASSIGN, rvalue >> e, stmt_modifier >> m) ^ newUnpackStatement(declarations, e, m)

	stmt_raise = (RAISE, expression >> e, stmt_modifier >> m) ^ RaiseStatement(Exception: e, Modifier: m)

	stmt_macro = (ID >> name, assignment_list >> args, ((block >> b) | (stmt_modifier >> m))) ^ newMacro(name, args, b, m)

	stmt_yield = (YIELD, assignment >> e, stmt_modifier >> m) ^ YieldStatement(Expression: e, Modifier: m)

	stmt_modifier = ((stmt_modifier_node >> value, eol) ^ value) | eol

	stmt_modifier_node = (
		stmt_modifier_type >> t,
		assignment >> e
	) ^ newStatementModifier(t, e)

	stmt_modifier_type = (IF ^ StatementModifierType.If) | (UNLESS ^ StatementModifierType.Unless)

	stmt_declaration = (declaration >> d,
			(ASSIGN, block_expression >> e)
			| ((ASSIGN, rvalue >> e), eol)
			| eol
		) ^ newDeclarationStatement(d, e)

	declaration = (ID >> name, optional_type >> typeRef) ^ newDeclaration(name, typeRef)

	stmt_block = stmt_if | stmt_for

	stmt_for = (FOR, declaration_list >> dl, IN, rvalue >> e, block >> body) ^ newForStatement(dl, e, body)

	stmt_if = (IF, assignment >> e, block >> trueBlock) ^ newIfStatement(e, trueBlock)

	stmt_return = (
		RETURN, ((optional_assignment >> e, stmt_modifier >> m) | (block_expression >> e))
		) ^ ReturnStatement(Expression: e, Modifier: m)

	optional_assignment = assignment | ""

	stmt_expression_block = (expression >> l, (ASSIGN | ASSIGN_INPLACE) >> op, block_expression >> r) ^ ExpressionStatement(newInfixExpression(op, l, r))

	block_expression = invocation_with_block | closure_block | dsl_friendly_invocation

	invocation_with_block = (member_reference >> e and (e isa MethodInvocationExpression), (closure_block) >> c) ^ newInvocationWithBlock(e, c)

	dsl_friendly_invocation = (member_reference >> e and ((e isa MemberReferenceExpression) or (e isa ReferenceExpression)), (block) >> c) ^ newInvocation(e, [BlockExpression(Body: c)])

	closure_block = ((DEF | DO), optional_parameters >> parameters, block >> body) ^ newBlockExpression(parameters, body)

	optional_parameters = method_parameters | ("" ^ [])

	stmt_expression = stmt_expression_block \
		| ((dsl_friendly_invocation >> e) ^ ExpressionStatement(Expression: e)) | (((multi_assignment | assignment) >> e, stmt_modifier >> m) ^ ExpressionStatement(Expression: e, Modifier: m))

	multi_assignment = (expression >> l, ASSIGN >> op, rvalue >> r) ^ newInfixExpression(op, l, r)

	rvalue = assignment_list >> items ^ newRValue(items)

	list_of assignment

	infixr assignment, (ASSIGN | ASSIGN_INPLACE), expression

	expression = generator_expression | conditional_expression

	generator_expression = (
		or_expression >> projection,
		++generator_expression_body >> body
	) ^ newGeneratorExpression(projection, body)

	generator_expression_body = (FOR, declaration_list >> dl, IN, conditional_expression >> e, optional_filter >> f) ^ newGeneratorExpressionBody(dl, e, f)

	optional_filter = ((stmt_modifier_type >> t, or_expression >> e) ^ newStatementModifier(t, e)) | ""

	conditional_expression = (
		(or_expression >> trueValue, IF, conditional_expression >> condition, ELSE, conditional_expression >> falseValue) ^  newConditionalExpression(condition, trueValue, falseValue)
	) | or_expression

	infix or_expression, OR, and_expression

	infix and_expression, AND, not_expression

	prefix not_expression, NOT, membership_expression

	infix membership_expression, (IN | ((NOT, IN) ^ makeToken("not in"))), identity_test_expression

	infix identity_test_expression, (((IS, NOT) ^ makeToken("is not")) | IS), comparison

	infix comparison, (EQUALITY | INEQUALITY | GREATER_THAN | GREATER_THAN_EQ | LESS_THAN | LESS_THAN_EQ), bitwise_or_expression

	infix bitwise_or_expression, BITWISE_OR, bitwise_xor_expression

	infix bitwise_xor_expression, XOR, bitwise_and_expression

	infix bitwise_and_expression, BITWISE_AND, bitwise_shift_expression

	infix bitwise_shift_expression, (BITWISE_SHIFT_LEFT | BITWISE_SHIFT_RIGHT), term

	infix term, (PLUS | MINUS), factor

	infix factor, (STAR | DIVISION | MODULUS), signalled_expression

	prefix signalled_expression, (MINUS | INCREMENT | DECREMENT), ones_complement_expression

	prefix ones_complement_expression, ONES_COMPLEMENT, exponentiation_expression

	infix exponentiation_expression, EXPONENTIATION, try_cast

	try_cast = ((try_cast >> e, AS, type_reference >> typeRef) ^ TryCastExpression(Target: e, Type: typeRef)) | member_reference

	member_reference = ((member_reference >> e, DOT, ID >> name) ^ newMemberReference(e, name)) | slicing

	slicing = ((member_reference >> e, LBRACK, slice_list >> indices, RBRACK) ^ newSlicing(e, indices)) | invocation

	slice = (
			(
				(COLON ^ OmittedExpression.Default) >> begin,
				(expression | ("" ^ OmittedExpression.Default)) >> end,
				(omitted_expression | "") >> step
			)
			|
			(
				expression >> begin,
				((omitted_expression >> end,
					((omitted_expression >> step) | ""))
				| "")
			)
		) ^ newSlice(begin, end, step)

	list_of expression

	list_of declaration

	list_of type_reference

	list_of slice

	omitted_expression = (COLON, expression) | (COLON ^ OmittedExpression.Default)

	invocation = invocation_expression | atom

	invocation_expression = (member_reference >> target, invocation_arguments >> args) ^ newInvocation(target, args)

	invocation_arguments = (LPAREN, optional_invocation_argument_list >> args, RPAREN) ^ args

	invocation_argument = named_argument | assignment

	list_of invocation_argument

	named_argument = (ID >> name, COLON, assignment >> value) ^ newNamedArgument(name, value)

	type_reference = type_reference_simple \
		| type_reference_array \
		| type_reference_callable \
		| type_reference_generic

	type_reference_generic = (qualified_name >> qname, generic_arguments >> args) ^ newGenericTypeReference(qname, args)

	generic_arguments = (LBRACK, OF, type_reference_list >> args, RBRACK) ^ args \
		| (OF, type_reference_list >> args) ^ args

	type_reference_callable = (
		CALLABLE, LPAREN, optional_type_reference_list >> params, RPAREN, optional_type >> type
	) ^ newCallableTypeReference(params, type) | ((CALLABLE)^ SimpleTypeReference("callable"))

	type_reference_array = (LPAREN, ranked_type_reference >> tr, RPAREN) ^ tr

	type_reference_simple = (qualified_name >> qname) ^ SimpleTypeReference(Name: qname)

	atom = float | integer | boolean | reference | array_literal | list_literal \
		| string_interpolation | string_literal | null_literal | parenthesized_expression  \
		| self_literal | super_literal | quasi_quote | closure | hash_literal \
		| type_literal

	type_literal = (TYPEOF, LPAREN, type_reference >> type, RPAREN) ^ newTypeofExpression(type)

	closure = (LBRACE, closure_parameters >> parameters, closure_stmt_list >> body, RBRACE) ^ newBlockExpression(parameters, newBlock(body))

	closure_parameters = ((optional_parameter_list >> parameters, BITWISE_OR) ^ parameters) | ("" ^ [])

	list_of closure_stmt, SEMICOLON

	closure_stmt = closure_stmt_expression | closure_stmt_macro | closure_stmt_return | closure_stmt_raise | closure_stmt_unpack

	closure_stmt_macro = (ID >> name, assignment_list >> args, closure_stmt_modifier >> m) ^ newMacro(name, args, null, m)

	closure_stmt_modifier = stmt_modifier_node | ~~(RBRACE | SEMICOLON)

	closure_stmt_return = (RETURN, rvalue >> e, closure_stmt_modifier >> m) ^ ReturnStatement(Expression: e, Modifier: m)

	closure_stmt_raise = (RAISE, expression >> e, closure_stmt_modifier >> m) ^ RaiseStatement(Exception: e, Modifier: m)

	closure_stmt_expression = (assignment >> e, closure_stmt_modifier >> m) ^ ExpressionStatement(Expression: e, Modifier: m)

	closure_stmt_unpack = (declaration_list >> declarations, ASSIGN, rvalue >> e, closure_stmt_modifier >> m) ^ newUnpackStatement(declarations, e, m)

	optional_stmt_modifier_node = stmt_modifier_node | ""

	quasi_quote = quasi_quote_member | quasi_quote_module | quasi_quote_expression | quasi_quote_stmt

	quasi_quote_module = (QQ_BEGIN, INDENT, module >> m, DEDENT, QQ_END) ^ newQuasiquoteBlock(m)

	quasi_quote_member = (QQ_BEGIN, INDENT, class_member >> m, DEDENT, QQ_END) ^ newQuasiquoteBlock(m)

	quasi_quote_expression = (QQ_BEGIN, rvalue >> s, QQ_END) ^ newQuasiquoteExpression(s)

	quasi_quote_stmt = (QQ_BEGIN, (qq_return | qq_macro) >> s, QQ_END) ^ newQuasiquoteExpression(s)

	qq_return = (RETURN, optional_assignment >> e, optional_stmt_modifier_node >> m) ^ ReturnStatement(Expression: e, Modifier: m)

	qq_macro = (ID >> name, assignment_list >> args, optional_stmt_modifier_node >> m) ^ newMacro(name, args, null, m)

	parenthesized_expression = (LPAREN, assignment >> e, RPAREN) ^ e

	null_literal = NULL ^ [| null |]

	super_literal = SUPER ^ [| super |]

	self_literal = SELF ^ [| self |]

	string_literal = (SQS >> s) ^ newStringLiteral(s)

	string_interpolation = (
		DQ,
		--(
			((++(~('"' | '$'), string_char) >> s) ^ StringLiteralExpression(makeString(s)))
			| (('${', expression >> v, --space, '}') ^ v)
			| ('$', atom)
			) >> items,
		DQ) ^ newStringInterpolation(items)

	string_char = ('\\', ('\\' | '$')) | (~'\\', _)

	array_literal = array_literal_empty | array_literal_single | array_literal_multi

	array_literal_empty = (LPAREN, array_literal_type >> type, COMMA, RPAREN) ^ newArrayLiteral(type, [])

	array_literal_single = (LPAREN, array_literal_type >> type, assignment >> e, COMMA, RPAREN) ^ newArrayLiteral(type, [e])

	array_literal_multi = (LPAREN, array_literal_type >> type, assignment >> e, ++(COMMA, assignment) >> tail, (COMMA | ""), RPAREN) ^ newArrayLiteral(type, prepend(e, tail))

	array_literal_type = ((OF, ranked_type_reference >> type, COLON) | "") ^ type

	ranked_type_reference = ((type_reference >> type), ((COMMA,  integer >> rank) | "")) ^ ArrayTypeReference(ElementType: type, Rank: rank)

	list_literal = (LBRACK, optional_expression_list >> items, optional_comma, RBRACK) ^ newListLiteral(items)

	hash_literal = (LBRACE, optional_expression_pair_list >> items, optional_comma, RBRACE) ^ newHashLiteral(items)

	optional_comma = COMMA | ""

	expression_pair = (assignment >> first, COLON, assignment >> second) ^ ExpressionPair(First: first, Second: second)

	list_of expression_pair

	reference = ID >> r ^ newReference(r)

	integer = (NUM >> n ^ newInteger(n, NumberStyles.None)) \
		| (HEXNUM >> n ^ newInteger(n, NumberStyles.HexNumber))

	float = ( (fractional_constant >> n, (exponent_part | "") >> e , floating_suffix ) ^ newFloat(makeString(n,e))) | ((NUM >> n, exponent_part >> e, floating_suffix)  ^ newFloat(makeString(tokenValue(n),e)))

	fractional_constant = ((NUM >> a , DOT , NUM >> b) ^ makeString(tokenValue(a),".",tokenValue(b))) | ( (DOT , NUM >> b) ^ makeString(".",tokenValue(b)) ) | ( (NUM >> a , DOT) ^ makeString(tokenValue(a), ".") )

	exponent_part = ( ("e" | "E") , exposignopt >> e , NUM >> d ) ^ makeString("e", e, tokenValue(d))

	exposignopt = ( (PLUS | MINUS) >> e ^ makeString(tokenValue(e)) ) | ""

	floating_suffix = "f" | "l" | "F" | "L" | ""

	boolean = true_literal | false_literal

	true_literal = TRUE ^ [| true |]

	false_literal = FALSE ^ [| false |]

	eol = (++EOL | ~_) ^ null

namespace Boo.OMeta.Parser

import Boo.OMeta
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast

import System.Globalization

macro infix:

	l, op, r = infix.Arguments

	return ExpressionStatement([| $l = ((($l >> l, $op >> op, $r >> r) ^ newInfixExpression(op, l, r)) | $r) |])

macro infixr:

	l, op, r = infixr.Arguments

	return ExpressionStatement([| $l = ((($r >> l, $op >> op, $l >> r) ^ newInfixExpression(op, l, r)) | $r) |])

macro prefix:

	rule, op, next = prefix.Arguments

	return ExpressionStatement([| $rule = ($op >> op, $rule >> e) ^ newPrefixExpression(op, e) | $next |])

macro list_of:
"""
Generates rules for lists of the given expression.

	list_of expression

Expands to something that matches:

	expression (COMMA expression)+
"""

	if len(list_of.Arguments) == 2:
		rule, separator = list_of.Arguments
	else:
		rule, separator = list_of.Arguments[0], [| COMMA |]

	block as Block = list_of.ParentNode

	listRuleName = ReferenceExpression(Name: "${rule}_list")
	listRule = [| $listRuleName = ((($rule >> first), ++(($separator, $rule >> e) ^ e) >> rest) ^ prepend(first, rest)) | ($rule >> v ^ [v]) |]
	block.Add(listRule)

	optionalRuleName = ReferenceExpression(Name: "optional_${rule}_list")
	optionalListRule = [| $optionalRuleName = $listRuleName | ("" ^ []) |]
	block.Add(optionalListRule)

ometa BooParser < WhitespaceSensitiveTokenizer:

	tokens:
		qq_begin = "[|"
		qq_end = "|]"
		equality = "=="
		inequality = "!="
		assign = "="
		assign_inplace = "+=" | "-=" | "*=" | "/=" | "%=" | "^=" | "&=" | "|="
		xor = "^"
		increment = "++"
		decrement = "--"
		plus = "+"
		minus = "-"
		exponentiation = "**"
		star = "*"
		division = "/"
		modulus = "%"
		ones_complement = "~"
		bitwise_shift_left = "<<"
		bitwise_shift_right = ">>"
		greater_than_eq = ">="
		greater_than = ">"
		less_than_eq = "<="
		less_than = "<"
		semicolon = ";"
		bitwise_and = "&"
		bitwise_or = "|"
		hexnum = ("0x", ++(hex_digit | digit) >> ds) ^ makeString(ds)
		num = ++digit
		colon = ":"
		dot = "."
		comma = ","
		lparen = "(", enterWhitespaceAgnosticRegion
		rparen = ")", leaveWhitespaceAgnosticRegion
		lbrack = "[", enterWhitespaceAgnosticRegion
		rbrack = "]", leaveWhitespaceAgnosticRegion
		lbrace = "{", enterWhitespaceAgnosticRegion
		rbrace = "}", leaveWhitespaceAgnosticRegion

		kw = (keywords >> value, ~(letter | digit | '_')) ^ value
		tdq = '"""'
		dq = '"'
		sqs = ("'", ++(~"'", _) >> s, "'") ^ s
		id = ((letter | '_') >> p, --(letter | digit | '_') >> s) ^ makeString(p, s)

	space = line_continuation | multi_line_comment | line_comment | super

	line_continuation = "\\", newline

	multi_line_comment = "/*", --(~"*/", (multi_line_comment | _)), "*/"

	line_comment = ('#' | "//"), --(~newline, _)

	hex_digit = _ >> c as char and ((c >= char('a') and c <= char('f')) or (c >= char('A') and c <= char('Z')))

	keywords "class", "def", "do", "import", "pass", "return", "true", \
		"false", "and", "or", "as", "not", "if", "is", "null", \
		"for", "interface", "internal", "in", "yield", "self", "super", "of", \
		"event", "private", "protected", "public", "enum", \
		"callable", "unless", "static", "final", "virtual", "override", "abstract", \
		"transient", "raise", "else", "typeof"

	keyword[expected] = ((KW >> t) and (expected is tokenValue(t))) ^ t

	module = (
		--EOL,
		(docstring >> s | ""),
		--import_declaration >> ids,
		--module_member >> members,
		--stmt >> stmts,
		--EOL
	) ^ newModule(s, ids, members, stmts)

	docstring = (TDQ, ++(~tdq, string_char) >> s, TDQ, eol) ^ makeString(s)

	import_declaration = (IMPORT, qualified_name >> qn, eol) ^ newImport(qn)

	qualified_name = (ID >> qualifier, --((DOT, ID >> n) ^ n) >> suffix)^ buildQName(qualifier, suffix)

	module_member = assembly_attribute | type_def | method

	type_def = class_def | interface_def | enum_def | callable_def

	callable_def = (CALLABLE, ID >> name, method_parameters >> parameters, optional_type >> type, eol) ^ newCallable(name, parameters, type)

	class_def = (
		attributes >> attrs,
		member_modifiers >> mod,
		CLASS, ID >> className, super_types >> superTypes, begin_block, class_body >> body, end_block
	) ^ newClass(attrs, mod, className, superTypes, body)

	interface_def = (
		attributes >> attrs,
		member_modifiers >> mod,
		INTERFACE, ID >> name, super_types >> superTypes, begin_block, interface_body >> body, end_block
	) ^ newInterface(attrs, mod, name, superTypes, body)

	enum_def = (
		attributes >> attrs,
		member_modifiers >> mod,
		ENUM, ID >> name, begin_block, enum_body >> body, end_block
	) ^ newEnum(attrs, mod, name, body)

	enum_body = ++enum_field >> fields ^ fields

	enum_field = (attributes >> attrs, ID >> name, ((ASSIGN, expression >> e) | ""), eol) ^ newEnumField(attrs, name, e)

	super_types = ((LPAREN, optional_type_reference_list >> types, RPAREN) ^ types) | ""

	class_body = no_member | (++class_member >> members ^ members)

	interface_body = no_member

	no_member = (PASS, eol) ^ null

	class_member = type_def | property_def | method | field | event_def

	event_def = (
		attributes >> attrs,
		member_modifiers >> mod,
		EVENT, ID >> name, optional_type >> type, eol
	) ^ newEvent(attrs, mod, name, type)

	property_def = (
		attributes >> attrs,
		member_modifiers >> mod,
		ID >> name, property_parameters >> parameters, optional_type >> type,
		begin_block,
		(
			(property_getter >> pg, property_setter >> ps)
			| (property_setter >> ps, property_getter >> pg)
			| (property_setter >> ps)
			| (property_getter >> pg)
		),
		end_block
	) ^ newProperty(attrs, mod, name, parameters, type, pg, ps)

	property_parameters = ((LBRACK, parameter_list >> parameters, RBRACK) | "") ^ parameters

	property_getter = accessor["get"]

	property_setter = accessor["set"]

	accessor[key] = (
		attributes >> attrs,
		member_modifiers >> mod,
		(ID >> name and (tokenValue(name) == key)),
		block >> body
	) ^ newMethod(attrs, mod, name, null, null, null, body)

	field = (
		attributes >> attrs,
		member_modifiers >> mod,
		ID >> name, optional_type >> type, field_initializer >> initializer
	) ^ newField(attrs, mod, name, type, initializer)

	field_initializer = (ASSIGN, block_expression) | ((ASSIGN, rvalue >> v, eol) ^ v) | eol

	member_modifiers = --(
		(PRIVATE ^ TypeMemberModifiers.Private)
		| (PUBLIC ^ TypeMemberModifiers.Public)
		| (INTERNAL ^ TypeMemberModifiers.Internal)
		| (PROTECTED ^ TypeMemberModifiers.Protected)
		| (FINAL ^ TypeMemberModifiers.Final)
		| (STATIC ^ TypeMemberModifiers.Static)
		| (VIRTUAL ^ TypeMemberModifiers.Virtual)
		| (OVERRIDE ^ TypeMemberModifiers.Override)
		| (TRANSIENT ^ TypeMemberModifiers.Transient)
		| (ABSTRACT ^ TypeMemberModifiers.Abstract)
	) >> all ^ all

	method = (
		attributes >> attrs,
		member_modifiers >> mod,
		DEF, ID >> name,
		optional_generic_parameters >> genericParameters,
		method_parameters >> parameters,
		attributes >> returnTypeAttributes, optional_type >> type,
		block >> body
	) ^ newGenericMethod(attrs, mod, name, genericParameters, parameters, returnTypeAttributes, type, body)

	method_parameters = (LPAREN, optional_parameter_list >> parameters, RPAREN) ^ parameters

	optional_generic_parameters = generic_parameters | ""

	generic_parameters = (LBRACK, OF, generic_parameter_list >> parameters, RBRACK) ^ parameters

	generic_parameter = (ID >> name) ^ newGenericParameterDeclaration(name)

	list_of generic_parameter

	list_of parameter

	assembly_attribute = (
		LBRACK, (ID >> name and (tokenValue(name) == "assembly")), COLON,
		attribute_list >> value,
		RBRACK, eol) ^ value

	attributes = --((LBRACK, attribute_list >> value, RBRACK, --EOL) ^ value) >> all ^ all

	attribute = (ID >> name, attribute_arguments >> args) ^ newAttribute(name, args)

	attribute_arguments = invocation_arguments | ""

	list_of attribute

	parameter = (attributes >> attrs, ID >> name, optional_type >> type) ^ newParameterDeclaration(attrs, name, type)

	optional_type = (AS, type_reference) | ""

	block = empty_block | multi_line_block | single_line_block

	empty_block = (begin_block, (PASS, eol), end_block) ^ Block()

	multi_line_block = (begin_block, ++stmt >> stmts, end_block)  ^ newBlock(stmts)

	single_line_block = (COLON, stmt_line >> line) ^ newBlock(line)

	begin_block = COLON, INDENT

	end_block = DEDENT

	stmt = stmt_block | stmt_line

	stmt_line = (~~(ID, AS), stmt_declaration) \
		| stmt_expression \
		| stmt_macro \
		| stmt_return \
		| stmt_yield \
		| stmt_raise \
		| stmt_unpack

	stmt_unpack = (declaration_list >> declarations, ASSIGN, rvalue >> e, stmt_modifier >> m) ^ newUnpackStatement(declarations, e, m)

	stmt_raise = (RAISE, expression >> e, stmt_modifier >> m) ^ RaiseStatement(Exception: e, Modifier: m)

	stmt_macro = (ID >> name, assignment_list >> args, ((block >> b) | (stmt_modifier >> m))) ^ newMacro(name, args, b, m)

	stmt_yield = (YIELD, assignment >> e, stmt_modifier >> m) ^ YieldStatement(Expression: e, Modifier: m)

	stmt_modifier = ((stmt_modifier_node >> value, eol) ^ value) | eol

	stmt_modifier_node = (
		stmt_modifier_type >> t,
		assignment >> e
	) ^ newStatementModifier(t, e)

	stmt_modifier_type = (IF ^ StatementModifierType.If) | (UNLESS ^ StatementModifierType.Unless)

	stmt_declaration = (declaration >> d,
			(ASSIGN, block_expression >> e)
			| ((ASSIGN, rvalue >> e), eol)
			| eol
		) ^ newDeclarationStatement(d, e)

	declaration = (ID >> name, optional_type >> typeRef) ^ newDeclaration(name, typeRef)

	stmt_block = stmt_if | stmt_for

	stmt_for = (FOR, declaration_list >> dl, IN, rvalue >> e, block >> body) ^ newForStatement(dl, e, body)

	stmt_if = (IF, assignment >> e, block >> trueBlock) ^ newIfStatement(e, trueBlock)

	stmt_return = (
		RETURN, ((optional_assignment >> e, stmt_modifier >> m) | (block_expression >> e))
		) ^ ReturnStatement(Expression: e, Modifier: m)

	optional_assignment = assignment | ""

	stmt_expression_block = (expression >> l, (ASSIGN | ASSIGN_INPLACE) >> op, block_expression >> r) ^ ExpressionStatement(newInfixExpression(op, l, r))

	block_expression = invocation_with_block | closure_block

	invocation_with_block = (member_reference >> e and (e isa MethodInvocationExpression), closure_block >> c) ^ newInvocationWithBlock(e, c)

	closure_block = ((DEF | DO), optional_parameters >> parameters, block >> body) ^ newBlockExpression(parameters, body)

	optional_parameters = method_parameters | ("" ^ [])

	stmt_expression = stmt_expression_block \
		| (((multi_assignment | assignment) >> e, stmt_modifier >> m) ^ ExpressionStatement(Expression: e, Modifier: m))

	multi_assignment = (expression >> l, ASSIGN >> op, rvalue >> r) ^ newInfixExpression(op, l, r)

	rvalue = assignment_list >> items ^ newRValue(items)

	list_of assignment

	infixr assignment, (ASSIGN | ASSIGN_INPLACE), expression

	expression = generator_expression | conditional_expression

	generator_expression = (
		or_expression >> projection,
		++generator_expression_body >> body
	) ^ newGeneratorExpression(projection, body)

	generator_expression_body = (FOR, declaration_list >> dl, IN, conditional_expression >> e, optional_filter >> f) ^ newGeneratorExpressionBody(dl, e, f)

	optional_filter = ((stmt_modifier_type >> t, or_expression >> e) ^ newStatementModifier(t, e)) | ""

	conditional_expression = (
		(or_expression >> trueValue, IF, conditional_expression >> condition, ELSE, conditional_expression >> falseValue) ^  newConditionalExpression(condition, trueValue, falseValue)
	) | or_expression

	infix or_expression, OR, and_expression

	infix and_expression, AND, not_expression

	prefix not_expression, NOT, membership_expression

	infix membership_expression, (IN | ((NOT, IN) ^ makeToken("not in"))), identity_test_expression

	infix identity_test_expression, (((IS, NOT) ^ makeToken("is not")) | IS), comparison

	infix comparison, (EQUALITY | INEQUALITY | GREATER_THAN | GREATER_THAN_EQ | LESS_THAN | LESS_THAN_EQ), bitwise_or_expression

	infix bitwise_or_expression, BITWISE_OR, bitwise_xor_expression

	infix bitwise_xor_expression, XOR, bitwise_and_expression

	infix bitwise_and_expression, BITWISE_AND, bitwise_shift_expression

	infix bitwise_shift_expression, (BITWISE_SHIFT_LEFT | BITWISE_SHIFT_RIGHT), term

	infix term, (PLUS | MINUS), factor

	infix factor, (STAR | DIVISION | MODULUS), signalled_expression

	prefix signalled_expression, (MINUS | INCREMENT | DECREMENT), ones_complement_expression

	prefix ones_complement_expression, ONES_COMPLEMENT, exponentiation_expression

	infix exponentiation_expression, EXPONENTIATION, try_cast

	try_cast = ((try_cast >> e, AS, type_reference >> typeRef) ^ TryCastExpression(Target: e, Type: typeRef)) | member_reference

	member_reference = ((member_reference >> e, DOT, ID >> name) ^ newMemberReference(e, name)) | slicing

	slicing = ((member_reference >> e, LBRACK, slice_list >> indices, RBRACK) ^ newSlicing(e, indices)) | invocation

	slice = (
			(
				(COLON ^ OmittedExpression.Default) >> begin,
				(expression | ("" ^ OmittedExpression.Default)) >> end,
				(omitted_expression | "") >> step
			)
			|
			(
				expression >> begin,
				((omitted_expression >> end,
					((omitted_expression >> step) | ""))
				| "")
			)
		) ^ newSlice(begin, end, step)

	list_of expression

	list_of declaration

	list_of type_reference

	list_of slice

	omitted_expression = (COLON, expression) | (COLON ^ OmittedExpression.Default)

	invocation = invocation_expression | atom

	invocation_expression = (member_reference >> target, invocation_arguments >> args) ^ newInvocation(target, args)

	invocation_arguments = (LPAREN, optional_invocation_argument_list >> args, RPAREN) ^ args

	invocation_argument = named_argument | assignment

	list_of invocation_argument

	named_argument = (ID >> name, COLON, assignment >> value) ^ newNamedArgument(name, value)

	type_reference = type_reference_simple \
		| type_reference_array \
		| type_reference_callable \
		| type_reference_generic

	type_reference_generic = (qualified_name >> qname, generic_arguments >> args) ^ newGenericTypeReference(qname, args)

	generic_arguments = (LBRACK, OF, type_reference_list >> args, RBRACK) ^ args \
		| (OF, type_reference_list >> args) ^ args

	type_reference_callable = (
		CALLABLE, LPAREN, optional_type_reference_list >> params, RPAREN, optional_type >> type
	) ^ newCallableTypeReference(params, type) | ((CALLABLE)^ SimpleTypeReference("callable"))

	type_reference_array = (LPAREN, ranked_type_reference >> tr, RPAREN) ^ tr

	type_reference_simple = (qualified_name >> qname) ^ SimpleTypeReference(Name: qname)

	atom = float | integer | boolean | reference | array_literal | list_literal \
		| string_interpolation | string_literal | null_literal | parenthesized_expression  \
		| self_literal | super_literal | quasi_quote | closure | hash_literal \
		| type_literal

	type_literal = (TYPEOF, LPAREN, type_reference >> type, RPAREN) ^ newTypeofExpression(type)

	closure = (LBRACE, closure_parameters >> parameters, closure_stmt_list >> body, RBRACE) ^ newBlockExpression(parameters, newBlock(body))

	closure_parameters = ((optional_parameter_list >> parameters, BITWISE_OR) ^ parameters) | ("" ^ [])

	list_of closure_stmt, SEMICOLON

	closure_stmt = closure_stmt_expression | closure_stmt_macro | closure_stmt_return | closure_stmt_raise | closure_stmt_unpack

	closure_stmt_macro = (ID >> name, assignment_list >> args, closure_stmt_modifier >> m) ^ newMacro(name, args, null, m)

	closure_stmt_modifier = stmt_modifier_node | ~~(RBRACE | SEMICOLON)

	closure_stmt_return = (RETURN, rvalue >> e, closure_stmt_modifier >> m) ^ ReturnStatement(Expression: e, Modifier: m)

	closure_stmt_raise = (RAISE, expression >> e, closure_stmt_modifier >> m) ^ RaiseStatement(Exception: e, Modifier: m)

	closure_stmt_expression = (assignment >> e, closure_stmt_modifier >> m) ^ ExpressionStatement(Expression: e, Modifier: m)

	closure_stmt_unpack = (declaration_list >> declarations, ASSIGN, rvalue >> e, closure_stmt_modifier >> m) ^ newUnpackStatement(declarations, e, m)

	optional_stmt_modifier_node = stmt_modifier_node | ""

	quasi_quote = quasi_quote_member | quasi_quote_module | quasi_quote_expression | quasi_quote_stmt

	quasi_quote_module = (QQ_BEGIN, INDENT, module >> m, DEDENT, QQ_END) ^ newQuasiquoteBlock(m)

	quasi_quote_member = (QQ_BEGIN, INDENT, class_member >> m, DEDENT, QQ_END) ^ newQuasiquoteBlock(m)

	quasi_quote_expression = (QQ_BEGIN, rvalue >> s, QQ_END) ^ newQuasiquoteExpression(s)

	quasi_quote_stmt = (QQ_BEGIN, (qq_return | qq_macro) >> s, QQ_END) ^ newQuasiquoteExpression(s)

	qq_return = (RETURN, optional_assignment >> e, optional_stmt_modifier_node >> m) ^ ReturnStatement(Expression: e, Modifier: m)

	qq_macro = (ID >> name, assignment_list >> args, optional_stmt_modifier_node >> m) ^ newMacro(name, args, null, m)

	parenthesized_expression = (LPAREN, assignment >> e, RPAREN) ^ e

	null_literal = NULL ^ [| null |]

	super_literal = SUPER ^ [| super |]

	self_literal = SELF ^ [| self |]

	string_literal = (SQS >> s) ^ newStringLiteral(s)

	string_interpolation = (
		DQ,
		--(
			((++(~('"' | '$'), string_char) >> s) ^ StringLiteralExpression(makeString(s)))
			| (('${', expression >> v, --space, '}') ^ v)
			| ('$', atom)
			) >> items,
		DQ) ^ newStringInterpolation(items)

	string_char = ('\\', ('\\' | '$')) | (~'\\', _)

	array_literal = array_literal_empty | array_literal_single | array_literal_multi

	array_literal_empty = (LPAREN, array_literal_type >> type, COMMA, RPAREN) ^ newArrayLiteral(type, [])

	array_literal_single = (LPAREN, array_literal_type >> type, assignment >> e, COMMA, RPAREN) ^ newArrayLiteral(type, [e])

	array_literal_multi = (LPAREN, array_literal_type >> type, assignment >> e, ++(COMMA, assignment) >> tail, (COMMA | ""), RPAREN) ^ newArrayLiteral(type, prepend(e, tail))

	array_literal_type = ((OF, ranked_type_reference >> type, COLON) | "") ^ type

	ranked_type_reference = ((type_reference >> type), ((COMMA,  integer >> rank) | "")) ^ ArrayTypeReference(ElementType: type, Rank: rank)

	list_literal = (LBRACK, optional_expression_list >> items, optional_comma, RBRACK) ^ newListLiteral(items)

	hash_literal = (LBRACE, optional_expression_pair_list >> items, optional_comma, RBRACE) ^ newHashLiteral(items)

	optional_comma = COMMA | ""

	expression_pair = (assignment >> first, COLON, assignment >> second) ^ ExpressionPair(First: first, Second: second)

	list_of expression_pair

	reference = ID >> r ^ newReference(r)

	integer = (NUM >> n ^ newInteger(n, NumberStyles.None)) \
		| (HEXNUM >> n ^ newInteger(n, NumberStyles.HexNumber))

	float = ( (fractional_constant >> n, (exponent_part | "") >> e , floating_suffix ) ^ newFloat(makeString(n,e))) | ((NUM >> n, exponent_part >> e, floating_suffix)  ^ newFloat(makeString(tokenValue(n),e)))

	fractional_constant = ((NUM >> a , DOT , NUM >> b) ^ makeString(tokenValue(a),".",tokenValue(b))) | ( (DOT , NUM >> b) ^ makeString(".",tokenValue(b)) ) | ( (NUM >> a , DOT) ^ makeString(tokenValue(a), ".") )

	exponent_part = ( ("e" | "E") , exposignopt >> e , NUM >> d ) ^ makeString("e", e, tokenValue(d))

	exposignopt = ( (PLUS | MINUS) >> e ^ makeString(tokenValue(e)) ) | ""

	floating_suffix = "f" | "l" | "F" | "L" | ""

	boolean = true_literal | false_literal

	true_literal = TRUE ^ [| true |]

	false_literal = FALSE ^ [| false |]

	eol = (++EOL | ~_) ^ null