/* © 2012 David Given
 * This file is made available under the terms of the two-clause BSD
 * license. See the file COPYING.BSD in the distribution directory for the
 * full license text.
 */

package com.cowlark.cowbel.parser.parsers;

import com.cowlark.cowbel.ast.nodes.AbstractExpressionNode;
import com.cowlark.cowbel.ast.nodes.DirectFunctionCallExpressionNode;
import com.cowlark.cowbel.ast.nodes.ExpressionListNode;
import com.cowlark.cowbel.ast.nodes.IdentifierNode;
import com.cowlark.cowbel.ast.nodes.IndirectFunctionCallExpressionNode;
import com.cowlark.cowbel.ast.nodes.MethodCallExpressionNode;
import com.cowlark.cowbel.ast.nodes.TypeListNode;
import com.cowlark.cowbel.parser.core.Location;
import com.cowlark.cowbel.parser.core.ParseResult;

public class ExpressionHighParser extends Parser
{
	private ParseResult parseMethodCall(ParseResult seed, Location location)
	{
		ParseResult methodpr = MethodNameParser.parse(location);
		if (methodpr.failed())
			return methodpr;
		
		ParseResult typeargspr = TypeListParser.parse(methodpr.end());
		if (typeargspr.failed())
			return typeargspr;
		
		ParseResult arguments = ArgumentListParser.parse(typeargspr.end());
		if (arguments.failed())
			return arguments;
		
		return new MethodCallExpressionNode(location, arguments.end(),
				(AbstractExpressionNode) seed, (IdentifierNode) methodpr,
				(TypeListNode) typeargspr,
				(ExpressionListNode) arguments);
	}
	
	private ParseResult parseFunctionCall(ParseResult seed, Location location)
	{
		ParseResult typeargspr = TypeListParser.parse(location);
		if (typeargspr.failed())
			return typeargspr;
		
		ParseResult argumentspr = ArgumentListParser.parse(typeargspr.end());
		if (argumentspr.failed())
			return argumentspr;
		
		return new IndirectFunctionCallExpressionNode(location, argumentspr.end(),
				(AbstractExpressionNode)seed, (ExpressionListNode) argumentspr);
	}
	
	private ParseResult parseDirectFunctionCall(Location location)
	{
		ParseResult identifierpr = IdentifierParser.parse(location);
		if (identifierpr.failed())
			return identifierpr;
		
		ParseResult typeargspr = TypeListParser.parse(identifierpr.end());
		if (typeargspr.failed())
			return typeargspr;
		
		ParseResult argumentspr = ArgumentListParser.parse(typeargspr.end());
		if (argumentspr.failed())
			return argumentspr;
		
		return new DirectFunctionCallExpressionNode(location, argumentspr.end(),
				(IdentifierNode) identifierpr,
				(TypeListNode) typeargspr,
				(ExpressionListNode) argumentspr);
	}
	
	@Override
	protected ParseResult parseImpl(Location location)
	{
		ParseResult seed = parseDirectFunctionCall(location);
		if (seed.failed())
			seed = ExpressionLeafParser.parse(location);
		if (seed.failed())
			return seed;
		
		for (;;)
		{
			ParseResult pr = DotParser.parse(seed.end());
			if (pr.success())
			{
				seed = parseMethodCall(seed, pr.end());
				if (seed.failed())
					return seed;
				continue;
			}
			
			pr = OpenAngleBracketParser.parse(seed.end());
			if (pr.success())
			{
				seed = parseFunctionCall(seed, pr.end());
				if (seed.failed())
					return seed;
				continue;
			}
			
			pr = OpenParenthesisParser.parse(seed.end());
			if (pr.success())
			{
				seed = parseFunctionCall(seed, pr.end());
				if (seed.failed())
					return seed;
				continue;
			}
			
			break;
		}
		
		return seed;
	}
}

@@ -3010,36 +3010,50 @@
 ess())%0A%09%09%09%7B%0A%09%09%09%09
-seed
+ParseResult funcpr
  = parseFunction
@@ -3074,36 +3074,38 @@
 end());%0A%09%09%09%09if (
-seed
+funcpr
 .failed())%0A%09%09%09%09%09
@@ -3099,36 +3099,231 @@
 iled())%0A%09%09%09%09
-%09return seed
+%7B%0A%09%09%09%09%09/* Ambiguity! We will fail here on expressons like a %3C b.%0A%09%09%09%09%09 * We want the a to be parsed, so instead of returning an%0A%09%09%09%09%09 * error, we return the seed. */%0A%09%09%09%09%09return seed;%0A%09%09%09%09%7D%0A%09%09%09%09seed = funcpr
 ;%0A%09%09%09%09contin

Fix an ambiguity that was causing 'a < b' to get parsed by the 'a<b>(...)' parser instead.