From a1b7c32b295c71083f46aab9997f4b127cd6f441 Mon Sep 17 00:00:00 2001
From: David Anderson <dvander@alliedmods.net>
Date: Thu, 28 Aug 2014 14:02:08 -0700
Subject: [PATCH] Add a "union" keyword to replace funcenum.

---
 plugins/include/console.inc        |  6 ++--
 plugins/include/events.inc         |  6 ++--
 plugins/include/sdkhooks.inc       | 48 +++++++++++++++---------------
 plugins/include/sdktools_trace.inc |  8 ++---
 plugins/include/sorting.inc        |  6 ++--
 plugins/include/timers.inc         |  8 ++---
 sourcepawn/compiler/sc.h           |  1 +
 sourcepawn/compiler/sc1.cpp        | 25 ++++++++++++++++
 sourcepawn/compiler/sc2.cpp        |  1 +
 9 files changed, 68 insertions(+), 41 deletions(-)

diff --git a/plugins/include/console.inc b/plugins/include/console.inc
index 6323102e..91c03222 100644
--- a/plugins/include/console.inc
+++ b/plugins/include/console.inc
@@ -669,7 +669,7 @@ native SetConVarBounds(Handle:convar, ConVarBounds:type, bool:set, Float:value=0
  */
 native GetConVarName(Handle:convar, String:name[], maxlength);
 
-funcenum ConVarQueryFinished
+union ConVarQueryFinished
 {	
 	/**
 	 * Called when a query to retrieve a client's console variable has finished.
@@ -683,7 +683,7 @@ funcenum ConVarQueryFinished
 	 * @param value			Value that was passed when query was started.
 	 * @noreturn
 	 */
-	public(QueryCookie:cookie, client, ConVarQueryResult:result, const String:cvarName[], const String:cvarValue[], any:value),
+	function void (QueryCookie cookie, int client, ConVarQueryResult result, const char[] cvarName, const char[] cvarValue, any value);
 	
 	/**
 	 * Called when a query to retrieve a client's console variable has finished.
@@ -696,7 +696,7 @@ funcenum ConVarQueryFinished
 	 * @param convarValue	Value of client convar that was queried if successful. This will be "" if it was not.
 	 * @noreturn
 	 */
-	public(QueryCookie:cookie, client, ConVarQueryResult:result, const String:cvarName[], const String:cvarValue[])
+	function void (QueryCookie cookie, int client, ConVarQueryResult result, const char[] cvarName, const char[] cvarValue);
 };
 
 /**
diff --git a/plugins/include/events.inc b/plugins/include/events.inc
index be3f2d46..771d1578 100644
--- a/plugins/include/events.inc
+++ b/plugins/include/events.inc
@@ -48,7 +48,7 @@ enum EventHookMode
 /**
  * Hook function types for events.
  */
-funcenum EventHook
+union EventHook
 {
 	/**
 	 * Called when a game event is fired.
@@ -59,7 +59,7 @@ funcenum EventHook
 	 * @param dontBroadcast	True if event was not broadcast to clients, false otherwise.
 	 * @return				Ignored for post hooks. Plugin_Handled will block event if hooked as pre.
 	 */
-	Action:public(Handle:event, const String:name[], bool:dontBroadcast),
+	function Action (Handle event, const char[] name, bool dontBroadcast);
 	/**
 	 * Called when a game event is fired.
 	 *
@@ -69,7 +69,7 @@ funcenum EventHook
 	 * @param dontBroadcast	True if event was not broadcast to clients, false otherwise.
 	 * @noreturn
 	 */
-	public(Handle:event, const String:name[], bool:dontBroadcast),
+	function void (Handle event, const char[] name, bool dontBroadcast);
 };
 
 /**
diff --git a/plugins/include/sdkhooks.inc b/plugins/include/sdkhooks.inc
index 2b255044..a58f59a4 100644
--- a/plugins/include/sdkhooks.inc
+++ b/plugins/include/sdkhooks.inc
@@ -192,90 +192,90 @@ enum UseType
 	Use_Toggle
 };
 
-funcenum SDKHookCB
+union SDKHookCB
 {
 	// PreThink/Post
 	// PostThink/Post
-	public(client),
+	function void (int client);
 	
 	// Spawn
-	Action:public(entity),
+	function Action (int entity);
 	
 	// GroundEntChanged
 	// SpawnPost
 	// Think/Post
 	// VPhysicsUpdate/Post
-	public(entity),
+	function void (int entity);
 	
 	// EndTouch
 	// StartTouch
 	// Touch
-	Action:public(entity, other),
+	function Action (int entity, int other);
 	
 	// EndTouchPost
 	// StartTouchPost
 	// TouchPost
-	public(entity, other),
+	function void (int entity, int other);
 	
 	// SetTransmit
-	Action:public(entity, client),
+	function Action (int entity, int client);
 	
 	// WeaponCanSwitchTo
 	// WeaponCanUse
 	// WeaponDrop
 	// WeaponEquip
 	// WeaponSwitch
-	Action:public(client, weapon),
+	function Action (int client, int weapon);
 	
 	// WeaponCanSwitchToPost
 	// WeaponCanUsePost
 	// WeaponDropPost
 	// WeaponEquipPost
 	// WeaponSwitchPost
-	public(client, weapon),
+	function void (int client, int weapon);
 	
 	// GetMaxHealth (ep2v and later)
-	Action:public(entity, &maxhealth),
+	function Action (int entity, int &maxhealth);
 	
 	// OnTakeDamage
 	// Note: The weapon parameter is not used by all games and damage sources.
 	// Note: Force application is dependent on game and damage type(s)
 	// SDKHooks 1.0+
-	Action:public(victim, &attacker, &inflictor, &Float:damage, &damagetype),
+	function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype),
 	// SDKHooks 2.0+
-	Action:public(victim, &attacker, &inflictor, &Float:damage, &damagetype, &weapon, Float:damageForce[3], Float:damagePosition[3]),
+	function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon, float[3] damageForce, float[3] damagePosition);
 	// SDKHooks 2.1+  (can check for support at runtime using GetFeatureStatus on SDKHook_DmgCustomInOTD capability.
 	// DON'T attempt to access 'damagecustom' var if feature status != available
-	Action:public(victim, &attacker, &inflictor, &Float:damage, &damagetype, &weapon,
-		Float:damageForce[3], Float:damagePosition[3], damagecustom),
+	function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon,
+		float[3] damageForce, float[3] damagePosition, int damagecustom);
 	
 	// OnTakeDamagePost
-	public(victim, attacker, inflictor, Float:damage, damagetype),
-	public(victim, attacker, inflictor, Float:damage, damagetype, weapon, const Float:damageForce[3], const Float:damagePosition[3]),
+	function void (int victim, int attacker, int inflictor, float damage, int damagetype);
+	function void (int victim, int attacker, int inflictor, float damage, int damagetype, const float[3] damageForce, const float[3] damagePosition);
 	
 	// FireBulletsPost
-	public(client, shots, const String:weaponname[]),
+	function void (int client, int shots, const char[] weaponname);
 	
 	// TraceAttack
-	Action:public(victim, &attacker, &inflictor, &Float:damage, &damagetype, &ammotype, hitbox, hitgroup),
+	function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &ammotype, int hitbox, int hitgroup);
 	
 	// TraceAttackPost
-	public(victim, attacker, inflictor, Float:damage, damagetype, ammotype, hitbox, hitgroup),
+	function void (int victim, int attacker, int inflictor, float damage, int damagetype, int ammotype, int hitbox, int hitgroup);
 	
 	// ShouldCollide
-	bool:public(entity, collisiongroup, contentsmask, bool:originalResult),
+	function bool (int entity, int collisiongroup, int contentsmask, bool originalResult);
 	
 	// Use
-	Action:public(entity, activator, caller, UseType:type, Float:value),
+	function Action (int entity, int activator, int caller, UseType type, float value);
 	
 	// UsePost
-	public(entity, activator, caller, UseType:type, Float:value),
+	function void (int entity, int activator, int caller, UseType type, float value);
 	
 	// Reload
-	Action:public(weapon),
+	function Action (int weapon);
 	
 	// Reload post
-	public(weapon, bool:bSuccessful)
+	function void (int weapon, bool bSuccessful);
 };
 
 
diff --git a/plugins/include/sdktools_trace.inc b/plugins/include/sdktools_trace.inc
index 27de9201..ce493547 100644
--- a/plugins/include/sdktools_trace.inc
+++ b/plugins/include/sdktools_trace.inc
@@ -110,7 +110,7 @@ enum RayType
 	RayType_Infinite	/**< The trace ray will go from the start position to infinity using a direction vector. */
 };
 
-funcenum TraceEntityFilter
+union TraceEntityFilter
 {
 	/**
 	 * Called on entity filtering.
@@ -119,7 +119,7 @@ funcenum TraceEntityFilter
  	 * @param contentsMask	Contents Mask.
  	 * @return				True to allow the current entity to be hit, otherwise false.
  	 */
-	bool:public(entity, contentsMask),
+	function bool (int entity, int contentsMask);
 	
 	/**
 	 * Called on entity filtering.
@@ -129,7 +129,7 @@ funcenum TraceEntityFilter
  	 * @param data			Data value, if used.
  	 * @return				True to allow the current entity to be hit, otherwise false.
  	 */
-	bool:public(entity, contentsMask, any:data),
+	function bool (int entity, int contentsMask, any data);
 };
 
 /**
@@ -371,4 +371,4 @@ native TR_GetPlaneNormal(Handle:hndl, Float:normal[3]);
  * @param pos		Vector buffer to store data in.
  * @return		True if outside world, otherwise false.
  */
-native TR_PointOutsideWorld(Float:pos[3]);
\ No newline at end of file
+native TR_PointOutsideWorld(Float:pos[3]);
diff --git a/plugins/include/sorting.inc b/plugins/include/sorting.inc
index 161aff00..e60bcd6e 100644
--- a/plugins/include/sorting.inc
+++ b/plugins/include/sorting.inc
@@ -123,10 +123,10 @@ native SortCustom1D(array[], array_size, SortFunc1D:sortfunc, Handle:hndl=INVALI
  *						0 if first is equal to second
  *						1 if first should go after second
  */
-funcenum SortFunc2D
+union SortFunc2D
 {
-	public(elem1[], elem2[], const array[][], Handle:hndl),
-	public(String:elem1[], String:elem2[], const String:array[][], Handle:hndl),
+	function int (int[] elem1, int[] elem2, const int[][] array, Handle hndl);
+	function int (char[] elem1, char[] elem2, const char[][] array, Handle hndl);
 };
 
 /** 
diff --git a/plugins/include/timers.inc b/plugins/include/timers.inc
index d0a9ed09..8da9696b 100644
--- a/plugins/include/timers.inc
+++ b/plugins/include/timers.inc
@@ -45,7 +45,7 @@
 /**
  * Any of the following prototypes will work for a timed function.
  */
-funcenum Timer
+union Timer
 {
 	/**
  	 * Called when the timer interval has elapsed.
@@ -55,7 +55,7 @@ funcenum Timer
  	 * @return				Plugin_Stop to stop a repeating timer, any other value for
  	 *						default behavior.
  	 */
-	Action:public(Handle:timer, Handle:hndl),
+	function Action(Handle timer, Handle hndl);
 	
 	/**
  	 * Called when the timer interval has elapsed.
@@ -65,7 +65,7 @@ funcenum Timer
  	 * @return				Plugin_Stop to stop a repeating timer, any other value for
  	 *						default behavior.
  	 */
-	Action:public(Handle:timer, any:data),
+	function Action(Handle timer, any data);
 	
 	/**
  	 * Called when the timer interval has elapsed.
@@ -74,7 +74,7 @@ funcenum Timer
  	 * @return				Plugin_Stop to stop a repeating timer, any other value for
  	 *						default behavior.
  	 */
-	Action:public(Handle:timer),
+	function Action(Handle timer);
 };
 
 /**
diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h
index aaab83c3..42020bca 100644
--- a/sourcepawn/compiler/sc.h
+++ b/sourcepawn/compiler/sc.h
@@ -432,6 +432,7 @@ enum TokenKind {
   tTAGOF,
   tTHEN,
   tTYPEDEF,
+  tUNION,
   tVOID,
   tWHILE,
   /* compiler directives */
diff --git a/sourcepawn/compiler/sc1.cpp b/sourcepawn/compiler/sc1.cpp
index 4baca471..ecd002f2 100644
--- a/sourcepawn/compiler/sc1.cpp
+++ b/sourcepawn/compiler/sc1.cpp
@@ -144,6 +144,7 @@ static void dolabel(void);
 static void doreturn(void);
 static void dofuncenum(int listmode);
 static void dotypedef();
+static void dounion();
 static void domethodmap(LayoutSpec spec);
 static void dobreak(void);
 static void docont(void);
@@ -1535,6 +1536,9 @@ static void parse(void)
     case tTYPEDEF:
       dotypedef();
       break;
+    case tUNION:
+      dounion();
+      break;
     case tSTRUCT:
       declstruct();
       break;
@@ -4247,6 +4251,27 @@ static void dotypedef()
   functags_add(def, &type);
 }
 
+// Unsafe union - only supports function types. This is a transition hack for SP2.
+static void dounion()
+{
+  token_ident_t ident;
+  if (!needsymbol(&ident))
+    return;
+
+  int prev_tag = pc_findtag(ident.name);
+  if (prev_tag != -1 && !(prev_tag & FUNCTAG))
+    error(94);
+
+  funcenum_t *def = funcenums_add(ident.name);
+  needtoken('{');
+  while (!matchtoken('}')) {
+    functag_t type;
+    parse_function_type(&type);
+    functags_add(def, &type);
+  }
+
+  require_newline(TRUE);
+}
 
 /**
  * dofuncenum - declare function enumerations
diff --git a/sourcepawn/compiler/sc2.cpp b/sourcepawn/compiler/sc2.cpp
index b03d6929..7b5f25cd 100644
--- a/sourcepawn/compiler/sc2.cpp
+++ b/sourcepawn/compiler/sc2.cpp
@@ -1963,6 +1963,7 @@ const char *sc_tokens[] = {
          "return",
          "sizeof", "sleep", "static", "stock", "struct", "switch",
          "tagof", "*then", "typedef",
+         "union",
          "void",
          "while",
          "#assert", "#define", "#else", "#elseif", "#emit", "#endif", "#endinput",