From 039572060e641f2f0a82ae28a48208c0792f8651 Mon Sep 17 00:00:00 2001
From: David Anderson <dvander@alliedmods.net>
Date: Sat, 8 Nov 2014 02:48:13 -0800
Subject: [PATCH] Add new dynamic array syntax.

---
 sourcepawn/compiler/sc1.cpp                   | 40 +++++++++++++++++--
 sourcepawn/compiler/sc5-in.scp                |  1 +
 .../tests/fail-dynamic-array-bad-type.sp      |  4 ++
 .../tests/fail-dynamic-array-bad-type.txt     |  1 +
 .../tests/ok-new-dynamic-array-syntax.sp      | 10 +++++
 5 files changed, 53 insertions(+), 3 deletions(-)
 create mode 100644 sourcepawn/compiler/tests/fail-dynamic-array-bad-type.sp
 create mode 100644 sourcepawn/compiler/tests/fail-dynamic-array-bad-type.txt
 create mode 100644 sourcepawn/compiler/tests/ok-new-dynamic-array-syntax.sp

diff --git a/sourcepawn/compiler/sc1.cpp b/sourcepawn/compiler/sc1.cpp
index 81e121b9..07c9bea1 100644
--- a/sourcepawn/compiler/sc1.cpp
+++ b/sourcepawn/compiler/sc1.cpp
@@ -157,6 +157,7 @@ static void inst_datetime_defines(void);
 static void inst_binary_name(char *binfname);
 static int operatorname(char *name);
 static int parse_new_typename(const token_t *tok);
+static bool parse_new_typename(const token_t *tok, int *outp);
 static int parse_new_decl(declinfo_t *decl, const token_t *first, int flags);
 static int reparse_old_decl(declinfo_t *decl, int flags);
 static int reparse_new_decl(declinfo_t *decl, int flags);
@@ -2184,6 +2185,30 @@ static void declloc(int tokid)
           genarray(1, false);
           ldconst((cur_lit + glb_declared) * sizeof(cell), sPRI);
           copyarray(sym, cells * sizeof(cell));
+        } else if (matchtoken(tNEW)) {
+          int tag = 0;
+          if (parse_new_typename(NULL, &tag)) {
+            if (tag != type->tag)
+              error(164, pc_typename(tag), pc_typename(type->tag));
+          }
+
+          for (int i = 0; i < type->numdim; i++) {
+            if (!needtoken('['))
+              break;
+
+            value val;
+            symbol *child;
+            int ident = doexpr2(
+              TRUE, FALSE, TRUE, FALSE,
+              &type->idxtag[i],
+              &child, 0, &val);
+            pushreg(sPRI);
+
+            if (!needtoken(']'))
+              break;
+          }
+          
+          genarray(type->numdim, true);
         } else if (lexpeek('{')) {
           // Dynamic array with fixed initializer.
           error(160);
@@ -3064,6 +3089,16 @@ static int parse_new_typename(const token_t *tok)
   return -1;
 }
 
+static bool parse_new_typename(const token_t *tok, int *tagp)
+{
+  int tag = parse_new_typename(tok);
+  if (tag >= 0)
+    *tagp = tag;
+  else
+    *tagp = 0;
+  return true;
+}
+
 static int parse_new_typeexpr(typeinfo_t *type, const token_t *first, int flags)
 {
   token_t tok;
@@ -3080,8 +3115,7 @@ static int parse_new_typeexpr(typeinfo_t *type, const token_t *first, int flags)
     lextok(&tok);
   }
 
-  type->tag = parse_new_typename(&tok);
-  if (type->tag == -1)
+  if (!parse_new_typename(&tok, &type->tag))
     goto err_out;
 
   // Note: we could have already filled in the prefix array bits, so we check
@@ -4224,7 +4258,7 @@ static void parse_function_type(functag_t *type)
   int lparen = matchtoken('(');
   needtoken(tFUNCTION);
 
-  type->ret_tag = parse_new_typename(NULL);
+  parse_new_typename(NULL, &type->ret_tag);
   type->usage = uPUBLIC;
 
   needtoken('(');
diff --git a/sourcepawn/compiler/sc5-in.scp b/sourcepawn/compiler/sc5-in.scp
index ddc69650..e099541f 100644
--- a/sourcepawn/compiler/sc5-in.scp
+++ b/sourcepawn/compiler/sc5-in.scp
@@ -207,6 +207,7 @@ static const char *errmsg[] = {
 /*161*/  "brackets after variable name indicate a fixed-size array, but a dynamic size was given - did you mean to use 'new %s[size]' syntax?\n",
 /*162*/  "cannot create dynamic arrays in global scope - did you mean to create a fixed-length array with brackets after the variable name?\n",
 /*163*/  "indeterminate array size in \"sizeof\" expression (symbol \"%s\")\n",
+/*164*/  "allocated array type '%s' doesn't match original type '%s'\n",
 #else
   "\315e\306\227\266k\217:\235\277bu\201fo\220\204\223\012",
   "\202l\224\250s\205g\346\356e\233\201(\243\315\214\267\202) \253 f\255low ea\305 \042c\353e\042\012",
diff --git a/sourcepawn/compiler/tests/fail-dynamic-array-bad-type.sp b/sourcepawn/compiler/tests/fail-dynamic-array-bad-type.sp
new file mode 100644
index 00000000..14a53f54
--- /dev/null
+++ b/sourcepawn/compiler/tests/fail-dynamic-array-bad-type.sp
@@ -0,0 +1,4 @@
+public main()
+{
+  int[] x = new float[3];
+}
diff --git a/sourcepawn/compiler/tests/fail-dynamic-array-bad-type.txt b/sourcepawn/compiler/tests/fail-dynamic-array-bad-type.txt
new file mode 100644
index 00000000..d2e8545a
--- /dev/null
+++ b/sourcepawn/compiler/tests/fail-dynamic-array-bad-type.txt
@@ -0,0 +1 @@
+(3) : error 164: allocated array type 'float' doesn't match original type 'int'
diff --git a/sourcepawn/compiler/tests/ok-new-dynamic-array-syntax.sp b/sourcepawn/compiler/tests/ok-new-dynamic-array-syntax.sp
new file mode 100644
index 00000000..ef3f8ac4
--- /dev/null
+++ b/sourcepawn/compiler/tests/ok-new-dynamic-array-syntax.sp
@@ -0,0 +1,10 @@
+native printnum(num);
+
+public main()
+{
+  new x = 4;
+  new y = 8;
+  int[][] v = new int[4][8];
+  v[2][3] = 9;
+  printnum(v[2][3]);
+}