<commit_before>namespace Boo.Adt

import System.Linq
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.PatternMatching

macro data:
"""
Produces a complete data type hierarchy from a declaration.

All the types produced are immutable (unless instructed otherwise) and have
meaningful implementations for Equals, GetHashCode and ToString.

Usage:

	data Expression = Const(Value as int) | Add(Left, Right) // omitted types assumed to be Expression
	
	
	data SingleValue(Value as int)
	
	
	data TypeWithMutableField(@MutableValue as int) // @ makes the field mutable
"""
	
	DataMacroExpansion(data)

class DataMacroExpansion:
	
	_module as TypeDefinition
	_superType as TypeDefinition
	_superTypeRef as TypeReference
	_defaultTypeRef as TypeReference
	
	def constructor(node as MacroStatement):
		
		assert 1 == len(node.Arguments)
		_module = enclosingModule(node)
		
		match node.Arguments[0]:
			case [| $left = $right |]:
				assert node.Body.IsEmpty
				_superType = createBaseType(left)
				expandDataConstructors(right)
				
			case [| $(ctor=MethodInvocationExpression()) < $(superCtor=MethodInvocationExpression()) |]:
				_defaultTypeRef = SimpleTypeReference("object")
				_superType = ClassDefinition()
				_superTypeRef = TypeReference.Lift(superCtor.Target)
				expandDataConstructorWithSuperCtor(ctor, superCtor, node.Body)
				
			case [| $(ctor=MethodInvocationExpression()) < $superType |]:
				_superTypeRef = TypeReference.Lift(superType)
				_superType = ClassDefinition()
				expandDataConstructorWithBody(ctor, node.Body)
				
			case ctor=MethodInvocationExpression():
				_superType = [|
					class object:
						pass
				|]
				expandDataConstructorWithBody(ctor, node.Body)
				
	def createBaseType(node as Expression):
		type = superTypeForExpression(node)
		type.LexicalInfo = node.LexicalInfo
		registerType(type)
		return type
		
	def abstractType(name as string):
		type = [|
			partial abstract class $name:
				pass
		|]
		return type
		
	def superTypeForExpression(node as Expression):
		match node:
			case ReferenceExpression(Name: name):
				return abstractType(name)
				
			case [| $(ReferenceExpression(Name: name)) < $(ReferenceExpression(Name: superType)) |]:
				type = [|
					partial abstract class $name($superType):
						pass
				|]
				return type
				
			case mie=MethodInvocationExpression(Target: ReferenceExpression(Name: name)):
				type = abstractType(name)
				fields = fieldsFrom(mie)
				type.Members.Extend(fields)
				type.Members.Add(constructorForFields(fields))
				return type
				
			case gre=SlicingExpression(
						Target: ReferenceExpression(Name: name)):
				type = [|
					partial abstract class $name[of T]:
						pass
				|]
				type.GenericParameters.Clear()
				for index in gre.Indices:
					match index:
						case Slice(
							Begin: ReferenceExpression(Name: name),
							End: null,
							Step: null):
							type.GenericParameters.Add(
								GenericParameterDeclaration(Name: name))
				return type
			
		
	def expandDataConstructors(node as Expression):
		match node:
			case [| $left | $right |]:
				expandDataConstructors(left)
				expandDataConstructors(right)
			case MethodInvocationExpression():
				expandDataConstructor(node)
				
	def expandDataConstructorWithBody(ctor as Expression, body as Block):
		expandDataConstructor(ctor).Members.Extend(TypeMember.Lift(body))
		
	def expandDataConstructorWithSuperCtor(ctor as Expression, superCtor as Expression, body as Block):
		superFields = fieldsFrom(superCtor)
		superFieldNames = array(f.Name for f in superFields)
		ctorFields = fieldsFrom(ctor)
		fields = array(f for f in ctorFields if f.Name not in superFieldNames)
		expandDataConstructorWithFields(ctor, ctorFields, fields, superFields).Members.Extend(TypeMember.Lift(body))
				
	def expandDataConstructor(node as MethodInvocationExpression):
		fields = fieldsFrom(node)
		superFields = fieldsOf(_superType).ToArray()
		ctorFields = superFields + fields
		return expandDataConstructorWithFields(node, ctorFields, fields, superFields)
		
	def expandDataConstructorWithFields(node as MethodInvocationExpression, ctorFields as (Field), fields as (Field), superFields as Field*):
		type = dataConstructorTypeForExpression(node.Target)
		type.LexicalInfo = node.LexicalInfo
		type.Members.Extend(fields)
		type.Members.Add(toStringForType(type))
		type.Members.Add(equalsForType(type)) 
		
		ctor = constructorDeclarationFor(ctorFields)
		for field in fields: ctor.Body.Add([| self.$(field.Name) = $field |])
		addSuperInvocationTo ctor, superFields
		
		type.Members.Add(ctor)
		for ctor in constructorsWithDefaultValues(fields):
			type.Members.Add(ctor)
		
		registerType(type)
		return type
		
	def addSuperInvocationTo(ctor as Constructor, superFields as Field*):
		superInvocation = [| super() |]
		for field in superFields:
			superInvocation.Arguments.Add(ReferenceExpression(field.Name))
		ctor.Body.Insert(0, superInvocation)
		<commit_msg>Extend => AddRange<commit_after>namespace Boo.Adt

import System.Linq
import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.PatternMatching

macro data:
"""
Produces a complete data type hierarchy from a declaration.

All the types produced are immutable (unless instructed otherwise) and have
meaningful implementations for Equals, GetHashCode and ToString.

Usage:

	data Expression = Const(Value as int) | Add(Left, Right) // omitted types assumed to be Expression
	
	
	data SingleValue(Value as int)
	
	
	data TypeWithMutableField(@MutableValue as int) // @ makes the field mutable
"""
	
	DataMacroExpansion(data)

class DataMacroExpansion:
	
	_module as TypeDefinition
	_superType as TypeDefinition
	_superTypeRef as TypeReference
	_defaultTypeRef as TypeReference
	
	def constructor(node as MacroStatement):
		
		assert 1 == len(node.Arguments)
		_module = enclosingModule(node)
		
		match node.Arguments[0]:
			case [| $left = $right |]:
				assert node.Body.IsEmpty
				_superType = createBaseType(left)
				expandDataConstructors(right)
				
			case [| $(ctor=MethodInvocationExpression()) < $(superCtor=MethodInvocationExpression()) |]:
				_defaultTypeRef = SimpleTypeReference("object")
				_superType = ClassDefinition()
				_superTypeRef = TypeReference.Lift(superCtor.Target)
				expandDataConstructorWithSuperCtor(ctor, superCtor, node.Body)
				
			case [| $(ctor=MethodInvocationExpression()) < $superType |]:
				_superTypeRef = TypeReference.Lift(superType)
				_superType = ClassDefinition()
				expandDataConstructorWithBody(ctor, node.Body)
				
			case ctor=MethodInvocationExpression():
				_superType = [|
					class object:
						pass
				|]
				expandDataConstructorWithBody(ctor, node.Body)
				
	def createBaseType(node as Expression):
		type = superTypeForExpression(node)
		type.LexicalInfo = node.LexicalInfo
		registerType(type)
		return type
		
	def abstractType(name as string):
		type = [|
			partial abstract class $name:
				pass
		|]
		return type
		
	def superTypeForExpression(node as Expression):
		match node:
			case ReferenceExpression(Name: name):
				return abstractType(name)
				
			case [| $(ReferenceExpression(Name: name)) < $(ReferenceExpression(Name: superType)) |]:
				type = [|
					partial abstract class $name($superType):
						pass
				|]
				return type
				
			case mie=MethodInvocationExpression(Target: ReferenceExpression(Name: name)):
				type = abstractType(name)
				fields = fieldsFrom(mie)
				type.Members.AddRange(fields)
				type.Members.Add(constructorForFields(fields))
				return type
				
			case gre=SlicingExpression(
						Target: ReferenceExpression(Name: name)):
				type = [|
					partial abstract class $name[of T]:
						pass
				|]
				type.GenericParameters.Clear()
				for index in gre.Indices:
					match index:
						case Slice(
							Begin: ReferenceExpression(Name: name),
							End: null,
							Step: null):
							type.GenericParameters.Add(
								GenericParameterDeclaration(Name: name))
				return type
			
		
	def expandDataConstructors(node as Expression):
		match node:
			case [| $left | $right |]:
				expandDataConstructors(left)
				expandDataConstructors(right)
			case MethodInvocationExpression():
				expandDataConstructor(node)
				
	def expandDataConstructorWithBody(ctor as Expression, body as Block):
		expandDataConstructor(ctor).Members.AddRange(TypeMember.Lift(body))
		
	def expandDataConstructorWithSuperCtor(ctor as Expression, superCtor as Expression, body as Block):
		superFields = fieldsFrom(superCtor)
		superFieldNames = array(f.Name for f in superFields)
		ctorFields = fieldsFrom(ctor)
		fields = array(f for f in ctorFields if f.Name not in superFieldNames)
		expandDataConstructorWithFields(ctor, ctorFields, fields, superFields).Members.AddRange(TypeMember.Lift(body))
				
	def expandDataConstructor(node as MethodInvocationExpression):
		fields = fieldsFrom(node)
		superFields = fieldsOf(_superType).ToArray()
		ctorFields = superFields + fields
		return expandDataConstructorWithFields(node, ctorFields, fields, superFields)
		
	def expandDataConstructorWithFields(node as MethodInvocationExpression, ctorFields as (Field), fields as (Field), superFields as Field*):
		type = dataConstructorTypeForExpression(node.Target)
		type.LexicalInfo = node.LexicalInfo
		type.Members.AddRange(fields)
		type.Members.Add(toStringForType(type))
		type.Members.Add(equalsForType(type)) 
		
		ctor = constructorDeclarationFor(ctorFields)
		for field in fields: ctor.Body.Add([| self.$(field.Name) = $field |])
		addSuperInvocationTo ctor, superFields
		
		type.Members.Add(ctor)
		for ctor in constructorsWithDefaultValues(fields):
			type.Members.Add(ctor)
		
		registerType(type)
		return type
		
	def addSuperInvocationTo(ctor as Constructor, superFields as Field*):
		superInvocation = [| super() |]
		for field in superFields:
			superInvocation.Arguments.Add(ReferenceExpression(field.Name))
		ctor.Body.Insert(0, superInvocation)
		
{'fraction_non_alphanumeric': 0.09066237812845512, 'fraction_numerical': 0.0006030756859985928, 'mean_word_length': 4.369670804101457, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1277081', 'n_tokens_mistral': 3479, 'n_tokens_neox': 2833, 'n_words': 701}