<commit_before>namespace Boo.Adt

import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.PatternMatching

class DataMacro(AbstractAstMacro):
	
	override def Expand(node as MacroStatement):
		DataMacroExpansion(node)
		
class DataMacroExpansion:
	
	_module as Module
	_baseType as TypeReference
	
	def constructor(node as MacroStatement):
		match node.Arguments[0]:
			case BinaryExpression(
					Operator: BinaryOperatorType.Assign,
					Left: left,
					Right: right):
				_module = enclosingModule(node)
				_baseType = createBaseType(left)
				expandDataConstructors(right)
				
	def enclosingModule(node as Node):
		return node.GetAncestor(NodeType.Module)
		
	def createBaseType(node as ReferenceExpression):
		type = [|
			abstract class $node:
				pass
		|]
		registerType(type)
		return SimpleTypeReference(LexicalInfo: node.LexicalInfo, Name: node.Name)
		
	def expandDataConstructors(node as Expression):
		match node:
			case BinaryExpression(Operator: BinaryOperatorType.BitwiseOr,
								Left: left,
								Right: right):
				expandDataConstructors(left)
				expandDataConstructors(right)
			case MethodInvocationExpression():
				expandDataConstructor(node)
				
	def expandDataConstructor(node as MethodInvocationExpression):
		match node.Target:
			case ReferenceExpression(Name: name):
				type = [|
					class $name($_baseType):
						pass
				|]
		type.LexicalInfo = node.LexicalInfo
		for member in membersForArgs(node):
			type.Members.Add(member)	
		type.Members.Add(toStringForType(type))
		type.Members.Add(equalsForType(type))
		type.Members.Add(constructorForInvocation(node))	
		registerType(type)
		
	def equalsForType(type as TypeDefinition):
			
		method = [|
			override def Equals(o):
				if o is null: return false
				if GetType() != o.GetType(): return false
				other as $(type.Name) = o
		|]
		
		for field in fields(type):
			comparison = [|
				if self.$(field.Name) != other.$(field.Name):
					return false
			|]
			method.Body.Add(comparison)
			
		method.Body.Add([| return true |])
		return method
		
	def toStringForType(type as TypeDefinition):
		expression = ExpressionInterpolationExpression()
		items = expression.Expressions
		items.Add([| $("${type.Name}(") |])
		
		comma = false
		for field in fields(type):
			if comma: items.Add([| ", " |])
			items.Add([| self.$(field.Name) |])
			comma = true
		
		items.Add([| $(")") |])
		return [|
			override def ToString():
				return $expression
		|]
		
	def fields(type as TypeDefinition):
		return f for f as Field in type.Members.Select(NodeType.Field)
		
	def constructorForInvocation(node as MethodInvocationExpression):
		ctor = [|
			def constructor():
				pass
		|]
		for arg in node.Arguments:
			match arg:
				case TryCastExpression(
						Target: ReferenceExpression(Name: name),
						Type: type):
					ctor.Parameters.Add(
						ParameterDeclaration(Name: name, Type: type))
					ctor.Body.Add([|
						self.$name = $(ReferenceExpression(name))
					|])
		return ctor
	
	def membersForArgs(node as MethodInvocationExpression):
		for arg in node.Arguments:
			yield fieldForArg(arg)
		
	def fieldForArg(node as TryCastExpression):
		match node.Target:
			case ReferenceExpression(Name: name):<commit_msg>removed unnecessary indirection (memberForArgs) and added a simple checking to make sure 1 and only argument is passed in<commit_after>namespace Boo.Adt

import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.PatternMatching

class DataMacro(AbstractAstMacro):
	
	override def Expand(node as MacroStatement):
		DataMacroExpansion(node)
		
class DataMacroExpansion:
	
	_module as Module
	_baseType as TypeReference
	
	def constructor(node as MacroStatement):
		
		assert 1 == len(node.Arguments)
		
		match node.Arguments[0]:
			case BinaryExpression(
					Operator: BinaryOperatorType.Assign,
					Left: left,
					Right: right):
				_module = enclosingModule(node)
				_baseType = createBaseType(left)
				expandDataConstructors(right)
				
	def enclosingModule(node as Node):
		return node.GetAncestor(NodeType.Module)
		
	def createBaseType(node as ReferenceExpression):
		type = [|
			abstract class $node:
				pass
		|]
		registerType(type)
		return SimpleTypeReference(LexicalInfo: node.LexicalInfo, Name: node.Name)
		
	def expandDataConstructors(node as Expression):
		match node:
			case BinaryExpression(Operator: BinaryOperatorType.BitwiseOr,
								Left: left,
								Right: right):
				expandDataConstructors(left)
				expandDataConstructors(right)
			case MethodInvocationExpression():
				expandDataConstructor(node)
				
	def expandDataConstructor(node as MethodInvocationExpression):
		match node.Target:
			case ReferenceExpression(Name: name):
				type = [|
					class $name($_baseType):
						pass
				|]
		type.LexicalInfo = node.LexicalInfo
		for arg in node.Arguments:
			type.Members.Add(fieldForArg(arg))	
		type.Members.Add(toStringForType(type))
		type.Members.Add(equalsForType(type))
		type.Members.Add(constructorForInvocation(node))	
		registerType(type)
		
	def equalsForType(type as TypeDefinition):
			
		method = [|
			override def Equals(o):
				if o is null: return false
				if GetType() != o.GetType(): return false
				other as $(type.Name) = o
		|]
		
		for field in fields(type):
			comparison = [|
				if self.$(field.Name) != other.$(field.Name):
					return false
			|]
			method.Body.Add(comparison)
			
		method.Body.Add([| return true |])
		return method
		
	def toStringForType(type as TypeDefinition):
		expression = ExpressionInterpolationExpression()
		items = expression.Expressions
		items.Add([| $("${type.Name}(") |])
		
		comma = false
		for field in fields(type):
			if comma: items.Add([| ", " |])
			items.Add([| self.$(field.Name) |])
			comma = true
		
		items.Add([| $(")") |])
		return [|
			override def ToString():
				return $expression
		|]
		
	def fields(type as TypeDefinition):
		return f for f as Field in type.Members.Select(NodeType.Field)
		
	def constructorForInvocation(node as MethodInvocationExpression):
		ctor = [|
			def constructor():
				pass
		|]
		for arg in node.Arguments:
			match arg:
				case TryCastExpression(
						Target: ReferenceExpression(Name: name),
						Type: type):
					ctor.Parameters.Add(
						ParameterDeclaration(Name: name, Type: type))
					ctor.Body.Add([|
						self.$name = $(ReferenceExpression(name))
					|])
		return ctor
	
	def fieldForArg(node as TryCastExpression):
		match node.Target:
			case ReferenceExpression(Name: name):
{'fraction_non_alphanumeric': 0.10622880049337034, 'fraction_numerical': 0.0006167129201356768, 'mean_word_length': 3.7384952520087653, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '1328458', 'n_tokens_mistral': 2465, 'n_tokens_neox': 1956, 'n_words': 484}