Subject: bug#22370: [PATCH] Initial support for Go Language in 'etags'

From: lu4nx <[email-masked]>
Date: Thu, 14 Jan 2016 13:27:48 +0800

* lib-src/etags.c <Go_suffixes>: New variable.
(lang_names): Add an entry for Go
(Go_functions): Add new function.
* test/manual/etags/ETAGS.good_6: Add TAGS content for Go
* test/manual/etags/Makefile:
(GOSRC): Add new variable.
(SRCS): Add an entry for Go.
---
 lib-src/etags.c                   | 73 +++++++++++++++++++++++++++++++++++++++
 test/manual/etags/ETAGS.good_6    | 15 ++++++++
 test/manual/etags/Makefile        |  3 +-
 test/manual/etags/go-src/test.go  | 11 ++++++
 test/manual/etags/go-src/test1.go | 34 ++++++++++++++++++
 5 files changed, 135 insertions(+), 1 deletion(-)
 create mode 100644 test/manual/etags/go-src/test.go
 create mode 100644 test/manual/etags/go-src/test1.go

diff --git a/lib-src/etags.c b/lib-src/etags.c
index 2192627..5320686 100644
--- a/lib-src/etags.c
+++ b/lib-src/etags.c
@@ -354,6 +354,7 @@ static void Cstar_entries (FILE *);
 static void Erlang_functions (FILE *);
 static void Forth_words (FILE *);
 static void Fortran_functions (FILE *);
+static void Go_functions (FILE *);
 static void HTML_labels (FILE *);
 static void Lisp_functions (FILE *);
 static void Lua_functions (FILE *);
@@ -641,6 +642,10 @@ static const char *Fortran_suffixes [] =
 static const char Fortran_help [] =
 "In Fortran code, functions, subroutines and block data are tags.";
 
+static const char *Go_suffixes [] = {"go", NULL};
+static const char Go_help [] =
+  "In Go code, functions, interfaces and packages.";
+
 static const char *HTML_suffixes [] =
   { "htm", "html", "shtml", NULL };
 static const char HTML_help [] =
@@ -794,6 +799,7 @@ static language lang_names [] =
   { "erlang",    Erlang_help,    Erlang_functions,  Erlang_suffixes    },
   { "forth",     Forth_help,     Forth_words,       Forth_suffixes     },
   { "fortran",   Fortran_help,   Fortran_functions, Fortran_suffixes   },
+  { "go",        Go_help,        Go_functions,      Go_suffixes        },
   { "html",      HTML_help,      HTML_labels,       HTML_suffixes      },
   { "java",      Cjava_help,     Cjava_entries,     Cjava_suffixes     },
   { "lisp",      Lisp_help,      Lisp_functions,    Lisp_suffixes      },
@@ -4210,6 +4216,73 @@ Fortran_functions (FILE *inf)
 
 
 /*
+ * Go language support
+ * Idea by Xi Lu <[email-masked]>. (2016)
+ */
+static void
+Go_functions(FILE *inf)
+{
+  char *cp, *name;
+
+  LOOP_ON_INPUT_LINES(inf, lb, cp)
+    {
+      cp = skip_spaces (cp);
+
+      if (LOOKING_AT (cp, "package"))
+	{
+	  name = cp;
+	  while (!notinname (*cp) && *cp != '\0')
+	    cp++;
+	  make_tag (name, cp - name, false, lb.buffer,
+		    cp - lb.buffer + 1, lineno, linecharno);
+	}
+      else if (LOOKING_AT (cp, "func"))
+	{
+	  /* Go implementation of interface, such as:
+	     func (n *Integer) Add(m Integer) ...
+	     skip `(n *Integer)` part.
+	  */
+	  if (*cp == '(')
+	    {
+	      while (*cp != ')')
+		cp++;
+	      cp = skip_spaces (cp+1);
+	    }
+
+	  if (*cp)
+	    {
+	      name = cp;
+
+	      while (!notinname (*cp))
+		cp++;
+
+	      make_tag (name, cp - name, true, lb.buffer,
+			cp - lb.buffer + 1, lineno, linecharno);
+	    }
+	}
+      else if (members && LOOKING_AT (cp, "type"))
+	{
+	  name = cp;
+
+	  /* Ignore similar to the following:
+	     type (
+	            A
+	     )
+	   */
+	  if (*cp == '(')
+	    return;
+
+	  while (!notinname (*cp) && *cp != '\0')
+	    cp++;
+
+	  make_tag (name, cp - name, false, lb.buffer,
+		    cp - lb.buffer + 1, lineno, linecharno);
+	}
+    }
+}
+
+
+/*
  * Ada parsing
  * Original code by
  * Philippe Waroquiers (1998)
diff --git a/test/manual/etags/ETAGS.good_6 b/test/manual/etags/ETAGS.good_6
index 39522db..3c53a8b 100644
--- a/test/manual/etags/ETAGS.good_6
+++ b/test/manual/etags/ETAGS.good_6
@@ -5406,3 +5406,18 @@ tex-src/nonewline.tex,0
 php-src/sendmail.php,0
 
 a-src/empty.zz,0
+
+test.go,48
+package main1,0
+func say(5,28
+func main(9,72
+
+test1.go,172
+package main1,0
+type plus 5,28
+type str 9,65
+type intNumber 13,99
+func (s str) PrintAdd(17,136
+func (n intNumber) PrintAdd(21,189
+func test(25,248
+func main(29,285
diff --git a/test/manual/etags/Makefile b/test/manual/etags/Makefile
index 4d9f358..81ee7a7 100644
--- a/test/manual/etags/Makefile
+++ b/test/manual/etags/Makefile
@@ -11,6 +11,7 @@ ELSRC=$(addprefix ./el-src/,TAGTEST.EL emacs/lisp/progmodes/etags.el)
 ERLSRC=$(addprefix ./erl-src/,gs_dialog.erl)
 FORTHSRC=$(addprefix ./forth-src/,test-forth.fth)
 FSRC=$(addprefix ./f-src/,entry.for entry.strange_suffix entry.strange)
+GOSRC=$(addprefix ./go-src/,test.go test1.go)
 HTMLSRC=$(addprefix ./html-src/,softwarelibero.html index.shtml algrthms.html software.html)
 #JAVASRC=$(addprefix ./java-src/, )
 LUASRC=$(addprefix ./lua-src/,allegro.lua test.lua)
@@ -27,7 +28,7 @@ RBSRC=$(addprefix ./ruby-src/,test.rb test1.ruby)
 TEXSRC=$(addprefix ./tex-src/,testenv.tex gzip.texi texinfo.tex nonewline.tex)
 YSRC=$(addprefix ./y-src/,parse.y parse.c atest.y cccp.c cccp.y)
 SRCS=${ADASRC} ${ASRC} ${CSRC} ${CPSRC} ${ELSRC} ${ERLSRC} ${FSRC}\
-     ${FORTHSRC} ${HTMLSRC} ${JAVASRC} ${LUASRC} ${MAKESRC} ${OBJCSRC}\
+     ${FORTHSRC} ${GOSRC} ${HTMLSRC} ${JAVASRC} ${LUASRC} ${MAKESRC} ${OBJCSRC}\
      ${OBJCPPSRC} ${PASSRC} ${PHPSRC} ${PERLSRC} ${PSSRC} ${PROLSRC} ${PYTSRC}\
      ${RBSRC} ${TEXSRC} ${YSRC}
 NONSRCS=./f-src/entry.strange ./erl-src/lists.erl ./cp-src/clheir.hpp.gz
diff --git a/test/manual/etags/go-src/test.go b/test/manual/etags/go-src/test.go
new file mode 100644
index 0000000..6aea26e
--- /dev/null
+++ b/test/manual/etags/go-src/test.go
@@ -0,0 +1,11 @@
+package main
+
+import "fmt"
+
+func say(msg string) {
+	fmt.Println(msg)
+}
+
+func main() {
+	say("Hello, Emacs!")
+}
diff --git a/test/manual/etags/go-src/test1.go b/test/manual/etags/go-src/test1.go
new file mode 100644
index 0000000..6d1efaa
--- /dev/null
+++ b/test/manual/etags/go-src/test1.go
@@ -0,0 +1,34 @@
+package main
+
+import "fmt"
+
+type plus interface {
+	PrintAdd()
+}
+
+type str struct {
+	a, b string
+}
+
+type intNumber struct {
+	a, b int
+}
+
+func (s str) PrintAdd() {
+	fmt.Println(s.a + s.b)
+}
+
+func (n intNumber) PrintAdd() {
+	fmt.Println(n.a + n.b)
+}
+
+func test(p plus) {
+	p.PrintAdd()
+}
+
+func main() {
+	s := str{a: "Hello,", b: "Emacs!"}
+	number := intNumber{a: 1, b: 2}
+	test(number)
+	test(s)
+}
-- 
2.5.0