Adding switch case default keywords

This adds switch/case keywords to glsl.
This makes the shaders that include these
keywords compile, but they don't run
properly yet, partly because the "break"
statement only handles loops currently.

Change-Id: I1f52b445e1124ed3931843c46e27ecc1d9ce3d11
Reviewed-on: https://swiftshader-review.googlesource.com/3400
Reviewed-by: Nicolas Capens <capn@google.com>
Tested-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/OpenGL/compiler/ParseHelper.cpp b/src/OpenGL/compiler/ParseHelper.cpp
index 9f86042..7275d7b 100644
--- a/src/OpenGL/compiler/ParseHelper.cpp
+++ b/src/OpenGL/compiler/ParseHelper.cpp
@@ -11,6 +11,7 @@
 
 #include "glslang.h"
 #include "preprocessor/SourceLocation.h"
+#include "ValidateSwitch.h"
 
 ///////////////////////////////////////////////////////////////////////
 //
@@ -2966,6 +2967,143 @@
 	return true;
 }
 
+TIntermSwitch *TParseContext::addSwitch(TIntermTyped *init, TIntermAggregate *statementList, const TSourceLoc &loc)
+{
+	TBasicType switchType = init->getBasicType();
+	if((switchType != EbtInt && switchType != EbtUInt) ||
+	   init->isMatrix() ||
+	   init->isArray() ||
+	   init->isVector())
+	{
+		error(init->getLine(), "init-expression in a switch statement must be a scalar integer", "switch");
+		recover();
+		return nullptr;
+	}
+
+	if(statementList)
+	{
+		if(!ValidateSwitch::validate(switchType, this, statementList, loc))
+		{
+			recover();
+			return nullptr;
+		}
+	}
+
+	TIntermSwitch *node = intermediate.addSwitch(init, statementList, loc);
+	if(node == nullptr)
+	{
+		error(loc, "erroneous switch statement", "switch");
+		recover();
+		return nullptr;
+	}
+	return node;
+}
+
+TIntermCase *TParseContext::addCase(TIntermTyped *condition, const TSourceLoc &loc)
+{
+	if(switchNestingLevel == 0)
+	{
+		error(loc, "case labels need to be inside switch statements", "case");
+		recover();
+		return nullptr;
+	}
+	if(condition == nullptr)
+	{
+		error(loc, "case label must have a condition", "case");
+		recover();
+		return nullptr;
+	}
+	if((condition->getBasicType() != EbtInt && condition->getBasicType() != EbtUInt) ||
+	   condition->isMatrix() ||
+	   condition->isArray() ||
+	   condition->isVector())
+	{
+		error(condition->getLine(), "case label must be a scalar integer", "case");
+		recover();
+	}
+	TIntermConstantUnion *conditionConst = condition->getAsConstantUnion();
+	if(conditionConst == nullptr)
+	{
+		error(condition->getLine(), "case label must be constant", "case");
+		recover();
+	}
+	TIntermCase *node = intermediate.addCase(condition, loc);
+	if(node == nullptr)
+	{
+		error(loc, "erroneous case statement", "case");
+		recover();
+		return nullptr;
+	}
+	return node;
+}
+
+TIntermCase *TParseContext::addDefault(const TSourceLoc &loc)
+{
+	if(switchNestingLevel == 0)
+	{
+		error(loc, "default labels need to be inside switch statements", "default");
+		recover();
+		return nullptr;
+	}
+	TIntermCase *node = intermediate.addCase(nullptr, loc);
+	if(node == nullptr)
+	{
+		error(loc, "erroneous default statement", "default");
+		recover();
+		return nullptr;
+	}
+	return node;
+}
+
+TIntermBranch *TParseContext::addBranch(TOperator op, const TSourceLoc &loc)
+{
+	switch(op)
+	{
+	case EOpContinue:
+		if(loopNestingLevel <= 0)
+		{
+			error(loc, "continue statement only allowed in loops", "");
+			recover();
+		}
+		break;
+	case EOpBreak:
+		if(loopNestingLevel <= 0 && switchNestingLevel <= 0)
+		{
+			error(loc, "break statement only allowed in loops and switch statements", "");
+			recover();
+		}
+		break;
+	case EOpReturn:
+		if(currentFunctionType->getBasicType() != EbtVoid)
+		{
+			error(loc, "non-void function must return a value", "return");
+			recover();
+		}
+		break;
+	default:
+		// No checks for discard
+		break;
+	}
+	return intermediate.addBranch(op, loc);
+}
+
+TIntermBranch *TParseContext::addBranch(TOperator op, TIntermTyped *returnValue, const TSourceLoc &loc)
+{
+	ASSERT(op == EOpReturn);
+	functionReturnsValue = true;
+	if(currentFunctionType->getBasicType() == EbtVoid)
+	{
+		error(loc, "void function cannot return a value", "return");
+		recover();
+	}
+	else if(*currentFunctionType != returnValue->getType())
+	{
+		error(loc, "function return is not matching type:", "return");
+		recover();
+	}
+	return intermediate.addBranch(op, returnValue, loc);
+}
+
 //
 // Parse an array of strings using yyparse.
 //