Enemy AI script causing Unity to crash (Javascript to C#)

I figured it’d be best to ask a new question since the issue is in a different script.

I’ve managed to convert the Enemy AI script to C# and Unity does not show any errors, however when trying to run after attaching the script to anything, the program freezes (both in the editor itself and as a standalone .exe). I can’t shake the feeling that I’m just overlooking something simple (I’m guessing I messed up somewhere and made an infinite loop or something similar), but figured it’d be best to ask in case I’m wrong.

using UnityEngine;
using System.Collections;

//We need a character controller for this script to run.
[RequireComponent(typeof (CharacterController))]

public class EnemyAI:MonoBehaviour
{
	public float speed = 3.0f;
	public float rotationSpeed = 5.0f;
	public float shootRange = 15.0f;
	public float attackRange = 30.0f;
	public float shootAngle = 4.0f;
	public float dontComeCloserRange = 5.0f;
	public float delayShootTime = .35f;
	public float pickNextWaypointDistance = 2.0f;
	public Transform target;
	
	private float lastShot = -10.0f;
	
	void Start ()
	{
		//If we have no target at first, we'll set it to be our player.
		if(target == null && GameObject.FindWithTag("Player"))
		{
			target = GameObject.FindWithTag("Player").transform;
		}
		
		StartCoroutine("Patrol");
	}
	
	IEnumerator Patrol()
	{
		var curWayPoint = AutoWaypoint.FindClosest(transform.position);
		
		while(true)
		{
			var waypointPosition = curWayPoint.transform.position;
			//If we're close to a waypoint, we'll go ahead and pick the next one.
			if(Vector3.Distance(waypointPosition, transform.position) <
				pickNextWaypointDistance)
			{
				curWayPoint = PickNextWaypoint(curWayPoint);
			}
			
			//We'll attack the player if he is in sight.
			if(CanSeeTarget())
			{
				StartCoroutine("AttackPlayer");
			}
			
			//Otherwise we'll just continue moving along the waypoints.
			MoveTowards(waypointPosition);
		}
	}
	
	bool CanSeeTarget()
	{
		//If the target is out of range, we cannot see it.
		if(Vector3.Distance(transform.position, target.position) > attackRange)
		{
			return false;
		}
		
		RaycastHit hit;
		if(Physics.Linecast(transform.position, target.position, out hit))
		{
			return hit.transform == target;
		}
		
		return false;
	}
	
	IEnumerator Shoot()
	{
		//We need to begin the shooting animation.
		animation.CrossFade("shoot", 0.3f);
		
		//We'll wait until half of the animation has played...
		yield return new WaitForSeconds(delayShootTime);
		
		//...fire the gun...
		BroadcastMessage("Fire");
		
		//...and finally, let the rest of the animation finish.
		yield return new WaitForSeconds(animation["shoot"].length - delayShootTime);
	}
	
	IEnumerator AttackPlayer()
	{
		//We'll set up the position the player was last visible.
		var lastVisiblePlayerPosition = target.position;
		while(true)
		{
			if(CanSeeTarget())
			{
				//If our target is dead, we need to quit hunting.
				if(target == null)
				{
					yield return null;
				}
				
				//If the target is too far away, we need to give up the hunt.
				var distance = Vector3.Distance(transform.position, target.position);
				if(distance > shootRange * 3)
				{
					yield return null;
				}
				
				lastVisiblePlayerPosition = target.position;
				//If we aren't in the "Don't come closer range" yet, we'll move toward the last known
				//position.
				if(distance > dontComeCloserRange)
				{
					MoveTowards(lastVisiblePlayerPosition);
				}
				else
				{
					RotateTowards(lastVisiblePlayerPosition);
				}
				
				var forward = transform.TransformDirection(Vector3.forward);
				var targetDirection = lastVisiblePlayerPosition - transform.position;
				targetDirection.y = 0;
				
				var angle = Vector3.Angle(targetDirection, forward);
				
				//We'll start shooting at the player if he's in sight and within range.
				if(distance < shootRange && angle < shootAngle)
				{
					StartCoroutine("Shoot");
				}
				else
				{
					StartCoroutine("SearchPlayer", lastVisiblePlayerPosition);
					
					//If at any point the player leaves visibility, we should stop attacking.
					if(!CanSeeTarget())
					{
						yield return null;
					}
				}
			}
		}
	}
	
	IEnumerator SearchPlayer(Vector3 position)
	{
		//We'll run at the player, however if we can't see him for 3 seconds, we return to our patrol
		//route.
		float timeout = 3.0f;
		while(timeout > 0.0f)
		{
			MoveTowards(position);
			
			//We've found the player!
			if(CanSeeTarget())
			{
				yield return null;
			}
			
			timeout -= Time.deltaTime;
		}
	}
	
	IEnumerator RotateTowards(Vector3 position)
	{
		SendMessage("SetSpeed", 0.0);
		
		var direction = position - transform.position;
		direction.y = 0;
		
		if(direction.magnitude < .1)
		{
			yield return null;
		}
		
		//Otherwise we have a target that we can see. As such, we'll rotate
		//towards our target.
		var targetPoint = target.position;
		var targetRotation = Quaternion.LookRotation(targetPoint -
			transform.position, Vector3.up);
		transform.rotation = Quaternion.Slerp(transform.rotation,
			targetRotation, Time.deltaTime * 2.0f);
	}
	
	IEnumerator MoveTowards(Vector3 position)
	{
		var direction = position - transform.position;
		direction.y = 0;
		
		if(direction.magnitude < .5)
		{
			SendMessage("SetSpeed", 0.0);
			yield return null;
		}
		
			//Otherwise we have a target that we can see. As such, we'll rotate
		//towards our target.
		var targetPoint = target.position;
		var targetRotation = Quaternion.LookRotation(targetPoint -
			transform.position, Vector3.up);
		transform.rotation = Quaternion.Slerp(transform.rotation,
			targetRotation, Time.deltaTime * 2.0f);
		
		//Now we should modify our speed so that we slow down when we aren't facing our target.
		var forward = transform.TransformDirection(Vector3.forward);
		var speedModifier = Vector3.Dot(forward, direction.normalized);
		speedModifier = Mathf.Clamp01(speedModifier);
		
		//Now we actually move our character.
		direction = forward * speed * speedModifier;
		CharacterController controller = GetComponent<CharacterController>();
		controller.SimpleMove(direction * speed);
		
		SendMessage("SetSpeed", speed * speedModifier,
			SendMessageOptions.DontRequireReceiver);
	}
	
	AutoWaypoint PickNextWaypoint(AutoWaypoint currentWaypoint)
	{
		//Let's find the waypoint where our character will have to turn the least.
		
		//This is the direction the character is walking.
		var forward = transform.TransformDirection(Vector3.forward);
		
		//The closer our two vectors are, the larger the dot product shall be.
		var best = currentWaypoint;
		float bestDot = -10.0f;
		
		foreach(AutoWaypoint cur in currentWaypoint.connected)
		{
			var direction = Vector3.Normalize(cur.transform.position - transform.position);
			var dot = Vector3.Dot(direction, forward);
			
			if(dot > bestDot && cur != currentWaypoint)
			{
				bestDot = dot;
				best = cur;
			}
		}
		return best;
	}
}

In AttackPlayer you have this code:

while(true)
{
    if(CanSeeTarget())
    {
        // Other code omitted
    }
}

If CanSeeTarget return false, then it will probably return false again after and lock up.

Also Patrol seems to have a loop that will lock up. Coroutines doesn’t work in C# as they do in JS. To branch into a child coroutine of a function you must yield return StartCoroutine(MoveTowards(waypointPosition)); etc. Just calling the coroutine function will not work.