<commit_before>namespace Boojay.Compilation.Steps

import System.IO

import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.Steps
import Boo.Lang.Compiler.TypeSystem

import Boo.Lang.PatternMatching

import org.objectweb.asm
import org.objectweb.asm.Type

class BoojayEmitter(AbstractVisitorCompilerStep):
		
	_classWriter as ClassWriter
	_code as MethodVisitor
	_currentMethod as Method
	_typeMappings as Hash
	_primitiveMappings as Hash
	
	override def Initialize(context as CompilerContext):
		super(context)		
		initializeTypeMappings()

	def Run():
		if len(Errors) > 0:
			return
		Visit(CompileUnit)
		
	def initializeTypeMappings():
		_typeMappings = {
			typeSystem.ObjectType: "java/lang/Object",
			Null.Default: "java/lang/Object",
			typeSystem.StringType: "java/lang/String",
			typeSystem.ICallableType: "Boojay/Lang/Callable",
			typeSystem.TypeType: "java/lang/Class",
			typeSystem.IEnumerableType: "Boojay/Lang/Enumerable",
			typeSystem.IEnumerableGenericType: "Boojay/Lang/Enumerable",
			typeSystem.IEnumeratorType: "Boojay/Lang/Enumerator",
			typeSystem.IEnumeratorGenericType: "Boojay/Lang/Enumerator",
			typeSystem.Map(typeof(Boo.Lang.GenericGenerator[of*])): "Boojay/Lang/Generator",
			typeSystem.Map(typeof(Boo.Lang.GenericGeneratorEnumerator[of*])): "Boojay/Lang/GeneratorEnumerator",
			typeSystem.RuntimeServicesType: "Boojay/Lang/RuntimeServices",
			typeSystem.Map(System.Exception): "java/lang/Exception",
			typeSystem.Map(System.NotImplementedException): "Boojay/Lang/NotImplementedException",
			typeSystem.Map(System.IDisposable): "Boojay/Lang/Disposable",
			typeSystem.Map(System.ICloneable): "java/lang/Cloneable",
		}
		
		_primitiveMappings = {
			typeSystem.CharType: CHAR_TYPE.getDescriptor(),
			typeSystem.BoolType: BOOLEAN_TYPE.getDescriptor(),
			typeSystem.IntType: INT_TYPE.getDescriptor(),
			typeSystem.VoidType: VOID_TYPE.getDescriptor(),
		}
		
	override def OnInterfaceDefinition(node as InterfaceDefinition):
		emitTypeDefinition node
	
	override def OnClassDefinition(node as ClassDefinition):
		emitTypeDefinition node
		
	def emitTypeDefinition(node as TypeDefinition):
		_classWriter = ClassWriter(ClassWriter.COMPUTE_MAXS)
		_classWriter.visit(
			Opcodes.V1_5,
			typeAttributes(node),
			javaType(bindingFor(node)), 
			null,
			javaType(baseType(node)),
			implementedInterfaces(node))
			
		if node.ParentNode isa ClassDefinition:
			_classWriter.visitInnerClass(javaType(bindingFor(node)), javaType(bindingFor(node.ParentNode)), node.Name, Opcodes.ACC_STATIC)
		
		preservingClassWriter:
			emitSourceInformationFor node
			emitFieldsFrom node
			emitNonFieldsFrom node
		
		_classWriter.visitEnd()
		
		writeClassFile node
		
	def emitSourceInformationFor(node as Node):
		sourceFile = node.LexicalInfo.FileName
		if string.IsNullOrEmpty(sourceFile):
			return
			
		_classWriter.visitSource(sourceFile, null)
		
	def emitFieldsFrom(node as TypeDefinition):
		for member in node.Members:
			emit member if member.NodeType == NodeType.Field
			
	def emitNonFieldsFrom(node as TypeDefinition):
		for member in node.Members:
			emit member if member.NodeType != NodeType.Field
		
	def preservingClassWriter(code as callable()):
		previousClassWriter = _classWriter
		code()
		_classWriter = previousClassWriter
		
	def implementedInterfaces(node as TypeDefinition):
		interfaces = array(
				javaType(itf)
				for itf in node.BaseTypes
				if isInterface(itf))
		if len(interfaces) == 0: return null
		return interfaces
		
	def isInterface(typeRef as TypeReference):
		return typeBinding(typeRef).IsInterface
		
	def typeBinding(node as Node) as IType:
		return bindingFor(node)
		
	def typeAttributes(node as TypeDefinition):
		attrs = 0
		match node.NodeType:
			case NodeType.ClassDefinition:
				attrs += Opcodes.ACC_SUPER
				if node.IsAbstract: attrs += Opcodes.ACC_ABSTRACT
			case NodeType.InterfaceDefinition:
				attrs += (Opcodes.ACC_INTERFACE + Opcodes.ACC_ABSTRACT)
		if node.IsPublic:
			attrs += Opcodes.ACC_PUBLIC
		return attrs
		
	def writeClassFile(node as TypeDefinition):
		fname = Path.Combine(outputDirectory(), classFullFileName(node))
		ensurePath(fname)
		File.WriteAllBytes(fname, _classWriter.toByteArray())
		
	def outputDirectory():
		return Parameters.OutputAssembly
		
	override def OnLabelStatement(node as LabelStatement):
		
		emitDebuggingInfoFor node
		
		mark labelFor(node)
		
	override def OnGotoStatement(node as GotoStatement):
		
		emitDebuggingInfoFor node
		
		GOTO labelFor(node.Label)
		
	override def OnIfStatement(node as IfStatement):
		
		emitDebuggingInfoFor node
		
		elseLabel = Label()
		afterElseLabel = Label()
		
		emitBranchFalse node.Condition, elseLabel
		emit node.TrueBlock
		if node.FalseBlock is not null:
			GOTO afterElseLabel				
		mark elseLabel
		if node.FalseBlock is not null:		
			emit node.FalseBlock		
			mark afterElseLabel

	def emitBranchFalse(e as Expression, label as Label):
		match e:
			case [| not $condition |]:
				emitBranchTrue condition, label
			otherwise:
				emitCondition e
				IFEQ label
				
	def emitBranchTrue(e as Expression, label as Label):
		match e:
			case [| not $condition |]:
				emitBranchFalse condition, label
				
			case [| $l < $r |]:
				emit l
				emit r
				IF_ICMPLT label
				
			otherwise:
				emitCondition e
				IFNE label
				
	def emitCondition(e as Expression):
		emit e
		ensureBool typeOf(e)
		
	override def OnModule(node as Module):
		emit node.Members
	
	override def OnWhileStatement(node as WhileStatement):
		
		emitDebuggingInfoFor node
		
		testLabel = Label()
		bodyLabel = Label()
		GOTO testLabel
		mark bodyLabel
		emit node.Block
		mark testLabel
		emitBranchTrue node.Condition, bodyLabel
		
	override def OnField(node as Field):
		field = _classWriter.visitField(
					memberAttributes(node),
					node.Name,
					typeDescriptor(bindingFor(node.Type)),
					null,
					null)
		field.visitEnd() 
		
	override def OnConstructor(node as Constructor):
		emitMethod "<init>", node
		
	_methodMappings = {
		".ctor": "<init>",
		"constructor": "<init>",
		"Main": "main",
		"ToString": "toString",
		"Equals": "equals",
		"GetType": "getClass"
	}
	
	override def OnMethod(node as Method):
		
		if isBlockedMethod(node):
			return
		
		emitMethod methodName(node.Name), node
		
	def isBlockedMethod(node as Method):
		m = bindingFor(node) as IMethod
		return node.Name == "get_Current" and hasReturnValue(m) and not isJavaLangObject(m.ReturnType)
		
	def methodName(name as string):
		return _methodMappings[name] or name
		
	def emitMethod(methodName as string, node as Method):
		_code = _classWriter.visitMethod(
					memberAttributes(node),
					methodName,
					javaSignature(node),
					null,
					null)
					
		if not node.IsAbstract:
			_currentMethod = node
			emitMethodBody node
			
		_code.visitEnd()
		
	def emitMethodBody(node as Method):
		prepareLocalVariables node
		
		_code.visitCode()
		
		emit node.Body
		if node.Body.Statements.Count == 0 or not node.Body.Statements[-1] isa ReturnStatement:
			emitEmptyReturn
		RETURN
	
		_code.visitMaxs(0, 0)
		
	def currentReturnType() as IType:
		returnType = _currentMethod.ReturnType
		if returnType is null: return null
		return bindingFor(returnType)
		
	def emitEmptyReturn():
		returnType = currentReturnType()
		if returnType is null: return
		if returnType is typeSystem().VoidType: return
		
		if returnType.IsValueType:
			ICONST_0
			IRETURN
		else:
			ACONST_NULL
			ARETURN
		
	def memberAttributes(node as TypeMember):
		attributes = Opcodes.ACC_PUBLIC
		if node.IsStatic: attributes += Opcodes.ACC_STATIC
		if node.IsAbstract: attributes += Opcodes.ACC_ABSTRACT
		return attributes
		
	def prepareLocalVariables(node as Method):
		i = firstLocalIndex(node)
		for local in node.Locals:
			index(local, i)
			++i
			
	def firstLocalIndex(node as Method):
		if 0 == len(node.Parameters):
			if node.IsStatic: return 0
			return 1
		return lastParameterIndex(node) + 1
		
	def lastParameterIndex(node as Method):
		param as InternalParameter = bindingFor(node.Parameters[-1])
		return param.Index
		
	def newTemp(type as IType):
		i = nextLocalIndex()
		local = CodeBuilder.DeclareTempLocal(self._currentMethod, type)
		index local.Local, i
		return local
		
	def nextLocalIndex():
		locals = _currentMethod.Locals
		if len(locals) == 0: return firstLocalIndex(_currentMethod)
		return index(bindingFor(locals[-1])) + 1
			
	def index(node as Local, index as int):
		node["index"] = index
		
	def index(bindingFor as InternalLocal) as int:
		return bindingFor.Local["index"]
		
	override def EnterExpressionStatement(node as ExpressionStatement):
		emitDebuggingInfoFor node
		return true
		
	override def LeaveExpressionStatement(node as ExpressionStatement):
		discardValueOnStack node.Expression
		
	def emitDebuggingInfoFor(node as Node):
		if not node.LexicalInfo.IsValid:
			return
			
		label = Label()
		mark label
		_code.visitLineNumber(node.LexicalInfo.Line, label)
		
	def discardValueOnStack(node as Expression):
		mie = node as MethodInvocationExpression
		if mie is null: return
		
		m = bindingFor(mie.Target) as IMethod
		if m is null: return
		
		if hasReturnValue(m): POP
		
	def hasReturnValue(m as IMethod):
		return m.ReturnType is not TypeSystemServices.VoidType
		
	override def OnNullLiteralExpression(node as NullLiteralExpression):
		ACONST_NULL
		
	override def OnReturnStatement(node as ReturnStatement):

		emitDebuggingInfoFor node
		
		if node.Expression is null:
			emitEmptyReturn
		else:
			emit node.Expression
			if isReferenceType(node.Expression):
				ARETURN
			else:
				IRETURN
				
	def isReferenceType(e as Expression):
		return not typeOf(e).IsValueType
		
	override def OnMethodInvocationExpression(node as MethodInvocationExpression):
		match bindingFor(node.Target):
			case ctor = IConstructor():
				emitConstructorInvocation ctor, node
			case method = IMethod():
				emitMethodInvocation method, node
			case builtin = BuiltinFunction():
				emitBuiltinInvocation builtin, node
				
	def emitSuperMethodInvocation(method as InternalMethod, node as MethodInvocationExpression):
		ALOAD 0
		emit node.Arguments
		INVOKESPECIAL method.Overriden
				
	def emitConstructorInvocation(ctor as IConstructor, node as MethodInvocationExpression):
		match node.Target:
			case SuperLiteralExpression():
				ALOAD 0
				emit node.Arguments
				INVOKESPECIAL ctor
			otherwise:
				emitObjectCreation ctor, node
				
	def emitBuiltinInvocation(builtin as BuiltinFunction, node as MethodInvocationExpression):
		match builtin.FunctionType:
			case BuiltinFunctionType.Eval:
				emitEval node
			case BuiltinFunctionType.Switch:
				emitSwitch node
				
	def emitSwitch(node as MethodInvocationExpression):
		targetLabels = array(labelFor(arg) for arg in node.Arguments.ToArray()[1:])
		defaultLabel = Label()
		
		emit node.Arguments[0]
		TABLESWITCH 0, len(targetLabels)-1, defaultLabel, targetLabels
		
		mark defaultLabel
		emitObjectCreation defaultConstructorFor(java.lang.IllegalStateException), MethodInvocationExpression()
		ATHROW
		
	def labelFor(e as Expression):
		labelBinding as InternalLabel = bindingFor(e)
		return labelFor(labelBinding.LabelStatement)
		
	def labelFor(stmt as LabelStatement):
		label as Label = stmt["label"]
		if label is null:
			label = Label()
			stmt["label"] = label
		return label
		
	def defaultConstructorFor(type as System.Type):
		return typeSystem().GetDefaultConstructor(typeSystem().Map(type))
				
	def emitEval(node as MethodInvocationExpression):
		for e in node.Arguments.ToArray()[:-1]:
			match e:
				case [| $l = $r |]:
					emitAssignmentStatement e
				otherwise:
					emit e
					discardValueOnStack e
		emit node.Arguments[-1]
				
	def emitMethodInvocation(method as IMethod, node as MethodInvocationExpression):
		match node.Target:
			case SuperLiteralExpression():
				emitSuperMethodInvocation method, node<commit_msg>debugging info for local variables<commit_after>namespace Boojay.Compilation.Steps

import System.IO

import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.Steps
import Boo.Lang.Compiler.TypeSystem

import Boo.Lang.PatternMatching

import org.objectweb.asm
import org.objectweb.asm.Type

class BoojayEmitter(AbstractVisitorCompilerStep):
		
	_classWriter as ClassWriter
	_code as MethodVisitor
	_currentMethod as Method
	_typeMappings as Hash
	_primitiveMappings as Hash
	
	override def Initialize(context as CompilerContext):
		super(context)		
		initializeTypeMappings()

	def Run():
		if len(Errors) > 0:
			return
		Visit(CompileUnit)
		
	def initializeTypeMappings():
		_typeMappings = {
			typeSystem.ObjectType: "java/lang/Object",
			Null.Default: "java/lang/Object",
			typeSystem.StringType: "java/lang/String",
			typeSystem.ICallableType: "Boojay/Lang/Callable",
			typeSystem.TypeType: "java/lang/Class",
			typeSystem.IEnumerableType: "Boojay/Lang/Enumerable",
			typeSystem.IEnumerableGenericType: "Boojay/Lang/Enumerable",
			typeSystem.IEnumeratorType: "Boojay/Lang/Enumerator",
			typeSystem.IEnumeratorGenericType: "Boojay/Lang/Enumerator",
			typeSystem.Map(typeof(Boo.Lang.GenericGenerator[of*])): "Boojay/Lang/Generator",
			typeSystem.Map(typeof(Boo.Lang.GenericGeneratorEnumerator[of*])): "Boojay/Lang/GeneratorEnumerator",
			typeSystem.RuntimeServicesType: "Boojay/Lang/RuntimeServices",
			typeSystem.Map(System.Exception): "java/lang/Exception",
			typeSystem.Map(System.NotImplementedException): "Boojay/Lang/NotImplementedException",
			typeSystem.Map(System.IDisposable): "Boojay/Lang/Disposable",
			typeSystem.Map(System.ICloneable): "java/lang/Cloneable",
		}
		
		_primitiveMappings = {
			typeSystem.CharType: CHAR_TYPE.getDescriptor(),
			typeSystem.BoolType: BOOLEAN_TYPE.getDescriptor(),
			typeSystem.IntType: INT_TYPE.getDescriptor(),
			typeSystem.VoidType: VOID_TYPE.getDescriptor(),
		}
		
	override def OnInterfaceDefinition(node as InterfaceDefinition):
		emitTypeDefinition node
	
	override def OnClassDefinition(node as ClassDefinition):
		emitTypeDefinition node
		
	def emitTypeDefinition(node as TypeDefinition):
		_classWriter = ClassWriter(ClassWriter.COMPUTE_MAXS)
		_classWriter.visit(
			Opcodes.V1_5,
			typeAttributes(node),
			javaType(bindingFor(node)), 
			null,
			javaType(baseType(node)),
			implementedInterfaces(node))
			
		if node.ParentNode isa ClassDefinition:
			_classWriter.visitInnerClass(javaType(bindingFor(node)), javaType(bindingFor(node.ParentNode)), node.Name, Opcodes.ACC_STATIC)
		
		preservingClassWriter:
			emitSourceInformationFor node
			emitFieldsFrom node
			emitNonFieldsFrom node
		
		_classWriter.visitEnd()
		
		writeClassFile node
		
	def emitSourceInformationFor(node as Node):
		sourceFile = node.LexicalInfo.FileName
		if string.IsNullOrEmpty(sourceFile):
			return
			
		_classWriter.visitSource(sourceFile, null)
		
	def emitFieldsFrom(node as TypeDefinition):
		for member in node.Members:
			emit member if member.NodeType == NodeType.Field
			
	def emitNonFieldsFrom(node as TypeDefinition):
		for member in node.Members:
			emit member if member.NodeType != NodeType.Field
		
	def preservingClassWriter(code as callable()):
		previousClassWriter = _classWriter
		code()
		_classWriter = previousClassWriter
		
	def implementedInterfaces(node as TypeDefinition):
		interfaces = array(
				javaType(itf)
				for itf in node.BaseTypes
				if isInterface(itf))
		if len(interfaces) == 0: return null
		return interfaces
		
	def isInterface(typeRef as TypeReference):
		return typeBinding(typeRef).IsInterface
		
	def typeBinding(node as Node) as IType:
		return bindingFor(node)
		
	def typeAttributes(node as TypeDefinition):
		attrs = 0
		match node.NodeType:
			case NodeType.ClassDefinition:
				attrs += Opcodes.ACC_SUPER
				if node.IsAbstract: attrs += Opcodes.ACC_ABSTRACT
			case NodeType.InterfaceDefinition:
				attrs += (Opcodes.ACC_INTERFACE + Opcodes.ACC_ABSTRACT)
		if node.IsPublic:
			attrs += Opcodes.ACC_PUBLIC
		return attrs
		
	def writeClassFile(node as TypeDefinition):
		fname = Path.Combine(outputDirectory(), classFullFileName(node))
		ensurePath(fname)
		File.WriteAllBytes(fname, _classWriter.toByteArray())
		
	def outputDirectory():
		return Parameters.OutputAssembly
		
	override def OnLabelStatement(node as LabelStatement):
		
		emitDebuggingInfoFor node
		
		mark labelFor(node)
		
	override def OnGotoStatement(node as GotoStatement):
		
		emitDebuggingInfoFor node
		
		GOTO labelFor(node.Label)
		
	override def OnIfStatement(node as IfStatement):
		
		emitDebuggingInfoFor node
		
		elseLabel = Label()
		afterElseLabel = Label()
		
		emitBranchFalse node.Condition, elseLabel
		emit node.TrueBlock
		if node.FalseBlock is not null:
			GOTO afterElseLabel				
		mark elseLabel
		if node.FalseBlock is not null:		
			emit node.FalseBlock		
			mark afterElseLabel

	def emitBranchFalse(e as Expression, label as Label):
		match e:
			case [| not $condition |]:
				emitBranchTrue condition, label
			otherwise:
				emitCondition e
				IFEQ label
				
	def emitBranchTrue(e as Expression, label as Label):
		match e:
			case [| not $condition |]:
				emitBranchFalse condition, label
				
			case [| $l < $r |]:
				emit l
				emit r
				IF_ICMPLT label
				
			otherwise:
				emitCondition e
				IFNE label
				
	def emitCondition(e as Expression):
		emit e
		ensureBool typeOf(e)
		
	override def OnModule(node as Module):
		emit node.Members
	
	override def OnWhileStatement(node as WhileStatement):
		
		emitDebuggingInfoFor node
		
		testLabel = Label()
		bodyLabel = Label()
		GOTO testLabel
		mark bodyLabel
		emit node.Block
		mark testLabel
		emitBranchTrue node.Condition, bodyLabel
		
	override def OnField(node as Field):
		field = _classWriter.visitField(
					memberAttributes(node),
					node.Name,
					typeDescriptor(bindingFor(node.Type)),
					null,
					null)
		field.visitEnd() 
		
	override def OnConstructor(node as Constructor):
		emitMethod "<init>", node
		
	_methodMappings = {
		".ctor": "<init>",
		"constructor": "<init>",
		"Main": "main",
		"ToString": "toString",
		"Equals": "equals",
		"GetType": "getClass"
	}
	
	override def OnMethod(node as Method):
		
		if isBlockedMethod(node):
			return
		
		emitMethod methodName(node.Name), node
		
	def isBlockedMethod(node as Method):
		m = bindingFor(node) as IMethod
		return node.Name == "get_Current" and hasReturnValue(m) and not isJavaLangObject(m.ReturnType)
		
	def methodName(name as string):
		return _methodMappings[name] or name
		
	def emitMethod(methodName as string, node as Method):
		_code = _classWriter.visitMethod(
					memberAttributes(node),
					methodName,
					javaSignature(node),
					null,
					null)
					
		if not node.IsAbstract:
			_currentMethod = node
			emitMethodBody node
			
		_code.visitEnd()
		
	def emitMethodBody(node as Method):
		prepareLocalVariables node
		
		_code.visitCode()
		
		beginLabel = Label()
		mark beginLabel
		
		emit node.Body
		if node.Body.Statements.Count == 0 or not node.Body.Statements[-1] isa ReturnStatement:
			emitEmptyReturn
		RETURN
		
		endLabel = Label()
		mark endLabel

		emitDebuggingInfoForLocalVariablesOf node, beginLabel, endLabel
		_code.visitMaxs(0, 0)
		
	def emitDebuggingInfoForLocalVariablesOf(node as Method, beginLabel as Label, endLabel as Label):
		emitDebuggingInfoForImplicitSelfVariable node, beginLabel, endLabel
		for param in node.Parameters:
			paramBinding as InternalParameter = bindingFor(param)
			_code.visitLocalVariable(paramBinding.Name, typeDescriptor(paramBinding.Type), null, beginLabel, endLabel, paramBinding.Index)
		for local in node.Locals:
			binding as ILocalEntity = bindingFor(local)
			_code.visitLocalVariable(binding.Name, typeDescriptor(binding.Type), null, beginLabel, endLabel, index(binding))
		
	def emitDebuggingInfoForImplicitSelfVariable(node as Method, beginLabel, endLabel):
		if node.IsStatic: return
		_code.visitLocalVariable("self", typeDescriptor(bindingFor(node.DeclaringType)), null, beginLabel, endLabel, 0)
		
	def currentReturnType() as IType:
		returnType = _currentMethod.ReturnType
		if returnType is null: return typeSystem().VoidType
		return bindingFor(returnType)
		
	def emitEmptyReturn():
		returnType = currentReturnType()
		if returnType is typeSystem().VoidType:
			return
		
		if returnType.IsValueType:
			ICONST_0
			IRETURN
		else:
			ACONST_NULL
			ARETURN
		
	def memberAttributes(node as TypeMember):
		attributes = Opcodes.ACC_PUBLIC
		if node.IsStatic: attributes += Opcodes.ACC_STATIC
		if node.IsAbstract: attributes += Opcodes.ACC_ABSTRACT
		return attributes
		
	def prepareLocalVariables(node as Method):
		i = firstLocalIndex(node)
		for local in node.Locals:
			index(local, i)
			++i
			
	def firstLocalIndex(node as Method):
		if 0 == len(node.Parameters):
			if node.IsStatic: return 0
			return 1
		return lastParameterIndex(node) + 1
		
	def lastParameterIndex(node as Method):
		param as InternalParameter = bindingFor(node.Parameters[-1])
		return param.Index
		
	def newTemp(type as IType):
		localIndex = nextLocalIndex()
		local = CodeBuilder.DeclareTempLocal(self._currentMethod, type)
		index local.Local, localIndex
		return local
		
	def nextLocalIndex():
		locals = _currentMethod.Locals
		if len(locals) == 0: return firstLocalIndex(_currentMethod)
		return index(bindingFor(locals[-1])) + 1
			
	def index(node as Local, index as int):
		node["index"] = index
		
	def index(bindingFor as InternalLocal) as int:
		return bindingFor.Local["index"]
		
	override def EnterExpressionStatement(node as ExpressionStatement):
		emitDebuggingInfoFor node
		return true
		
	override def LeaveExpressionStatement(node as ExpressionStatement):
		discardValueOnStack node.Expression
		
	def emitDebuggingInfoFor(node as Node):
		if not node.LexicalInfo.IsValid:
			return
			
		label = Label()
		mark label
		_code.visitLineNumber(node.LexicalInfo.Line, label)
		
	def discardValueOnStack(node as Expression):
		mie = node as MethodInvocationExpression
		if mie is null: return
		
		m = bindingFor(mie.Target) as IMethod
		if m is null: return
		
		if hasReturnValue(m): POP
		
	def hasReturnValue(m as IMethod):
		return m.ReturnType is not TypeSystemServices.VoidType
		
	override def OnNullLiteralExpression(node as NullLiteralExpression):
		ACONST_NULL
		
	override def OnReturnStatement(node as ReturnStatement):

		emitDebuggingInfoFor node
		
		if node.Expression is null:
			emitEmptyReturn
		else:
			emit node.Expression
			if isReferenceType(node.Expression):
				ARETURN
			else:
				IRETURN
				
	def isReferenceType(e as Expression):
		return not typeOf(e).IsValueType
		
	override def OnMethodInvocationExpression(node as MethodInvocationExpression):
		match bindingFor(node.Target):
			case ctor = IConstructor():
				emitConstructorInvocation ctor, node
			case method = IMethod():
				emitMethodInvocation method, node
			case builtin = BuiltinFunction():
				emitBuiltinInvocation builtin, node
				
	def emitSuperMethodInvocation(method as InternalMethod, node as MethodInvocationExpression):
		ALOAD 0
		emit node.Arguments
		INVOKESPECIAL method.Overriden
				
	def emitConstructorInvocation(ctor as IConstructor, node as MethodInvocationExpression):
		match node.Target:
			case SuperLiteralExpression():
				ALOAD 0
				emit node.Arguments
				INVOKESPECIAL ctor
			otherwise:
				emitObjectCreation ctor, node
				
	def emitBuiltinInvocation(builtin as BuiltinFunction, node as MethodInvocationExpression):
		match builtin.FunctionType:
			case BuiltinFunctionType.Eval:
				emitEval node
			case BuiltinFunctionType.Switch:
				emitSwitch node
				
	def emitSwitch(node as MethodInvocationExpression):
		targetLabels = array(labelFor(arg) for arg in node.Arguments.ToArray()[1:])
		defaultLabel = Label()
		
		emit node.Arguments[0]
		TABLESWITCH 0, len(targetLabels)-1, defaultLabel, targetLabels
		
		mark defaultLabel
		emitObjectCreation defaultConstructorFor(java.lang.IllegalStateException), MethodInvocationExpression()
		ATHROW
		
	def labelFor(e as Expression):
		labelBinding as InternalLabel = bindingFor(e)
		return labelFor(labelBinding.LabelStatement)
		
	def labelFor(stmt as LabelStatement):
		label as Label = stmt["label"]
		if label is null:
			label = Label()
			stmt["label"] = label
		return label
		
	def defaultConstructorFor(type as System.Type):
		return typeSystem().GetDefaultConstructor(typeSystem().Map(type))
				
	def emitEval(node as MethodInvocationExpression):
		for e in node.Arguments.ToArray()[:-1]:
			match e:
				case [| $l = $r |]:
					assert l is not null and r is not null
					emitAssignmentStatement e
				otherwise:
					emit e
					discardValueOnStack e
		emit node.Arguments[-1]
				
	def emitMethodInvocation(method as IMethod, node as MethodInvocationExpression):
		match node.Target:
			case SuperLiteralExpression():
				emitSuperMethodInvocation method, node
{'fraction_non_alphanumeric': 0.08154075027140043, 'fraction_numerical': 0.0021309959390454747, 'mean_word_length': 4.2975505857295, 'pattern_counts': {'":': 12, '<': 11, '<?xml version=': 0, '>': 11, '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': '2886662', 'n_tokens_mistral': 8884, 'n_tokens_neox': 7434, 'n_words': 1897}