~ubuntu-branches/ubuntu/saucy/exuberant-ctags/saucy

« back to all changes in this revision

Viewing changes to debian/patches/go.patch

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson
  • Date: 2011-07-20 14:24:17 UTC
  • Revision ID: james.westby@ubuntu.com-20110720142417-tt3bxbzn17cy1yzo
Tags: 1:5.9~svn20110310-2
Add Go support, from a patch by Alexey Marinichev (closes: #634166).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
Description: Add Go support
 
2
Bug-Debian: http://bugs.debian.org/634166
 
3
Author: Alexey Marinichev <amarinichev@chromium.org>
 
4
Origin: other, https://github.com/lyosha/ctags-go/commit/ca097bd639e35470a9abccbf348016b7cc44f811
 
5
Last-Update: 2011-07-20
 
6
 
 
7
Index: b/go.c
 
8
===================================================================
 
9
--- /dev/null
 
10
+++ b/go.c
 
11
@@ -0,0 +1,670 @@
 
12
+/*
 
13
+*   INCLUDE FILES
 
14
+*/
 
15
+#include "general.h"        /* must always come first */
 
16
+#include <setjmp.h>
 
17
+
 
18
+#include "debug.h"
 
19
+#include "entry.h"
 
20
+#include "keyword.h"
 
21
+#include "read.h"
 
22
+#include "main.h"
 
23
+#include "routines.h"
 
24
+#include "vstring.h"
 
25
+#include "options.h"
 
26
+
 
27
+/*
 
28
+ *      MACROS
 
29
+ */
 
30
+#define isType(token,t) (boolean) ((token)->type == (t))
 
31
+#define isKeyword(token,k) (boolean) ((token)->keyword == (k))
 
32
+
 
33
+/*
 
34
+ *      DATA DECLARATIONS
 
35
+ */
 
36
+
 
37
+typedef enum eException { ExceptionNone, ExceptionEOF } exception_t;
 
38
+
 
39
+typedef enum eKeywordId {
 
40
+       KEYWORD_NONE = -1,
 
41
+       KEYWORD_package,
 
42
+       KEYWORD_import,
 
43
+       KEYWORD_const,
 
44
+       KEYWORD_type,
 
45
+       KEYWORD_var,
 
46
+       KEYWORD_func,
 
47
+       KEYWORD_struct,
 
48
+       KEYWORD_interface,
 
49
+       KEYWORD_map,
 
50
+       KEYWORD_chan
 
51
+} keywordId;
 
52
+
 
53
+/*  Used to determine whether keyword is valid for the current language and
 
54
+ *  what its ID is.
 
55
+ */
 
56
+typedef struct sKeywordDesc {
 
57
+       const char *name;
 
58
+       keywordId id;
 
59
+} keywordDesc;
 
60
+
 
61
+typedef enum eTokenType {
 
62
+       TOKEN_NONE = -1,
 
63
+       TOKEN_CHARACTER,
 
64
+       // Don't need TOKEN_FORWARD_SLASH
 
65
+       TOKEN_FORWARD_SLASH,
 
66
+       TOKEN_KEYWORD,
 
67
+       TOKEN_IDENTIFIER,
 
68
+       TOKEN_STRING,
 
69
+       TOKEN_OPEN_PAREN,
 
70
+       TOKEN_CLOSE_PAREN,
 
71
+       TOKEN_OPEN_CURLY,
 
72
+       TOKEN_CLOSE_CURLY,
 
73
+       TOKEN_OPEN_SQUARE,
 
74
+       TOKEN_CLOSE_SQUARE,
 
75
+       TOKEN_SEMICOLON,
 
76
+       TOKEN_STAR,
 
77
+       TOKEN_LEFT_ARROW,
 
78
+       TOKEN_DOT,
 
79
+       TOKEN_COMMA
 
80
+} tokenType;
 
81
+
 
82
+typedef struct sTokenInfo {
 
83
+       tokenType type;
 
84
+       keywordId keyword;
 
85
+       vString *string;                /* the name of the token */
 
86
+       unsigned long lineNumber;       /* line number of tag */
 
87
+       fpos_t filePosition;            /* file position of line containing name */
 
88
+} tokenInfo;
 
89
+
 
90
+/*
 
91
+*   DATA DEFINITIONS
 
92
+*/
 
93
+
 
94
+static int Lang_go;
 
95
+static jmp_buf Exception;
 
96
+static vString *scope;
 
97
+
 
98
+typedef enum {
 
99
+       GOTAG_UNDEFINED = -1,
 
100
+       GOTAG_PACKAGE,
 
101
+       GOTAG_FUNCTION,
 
102
+       GOTAG_CONST,
 
103
+       GOTAG_TYPE,
 
104
+       GOTAG_VAR,
 
105
+} goKind;
 
106
+
 
107
+static kindOption GoKinds[] = {
 
108
+       {TRUE, 'p', "package", "packages"},
 
109
+       {TRUE, 'f', "func", "functions"},
 
110
+       {TRUE, 'c', "const", "constants"},
 
111
+       {TRUE, 't', "type", "types"},
 
112
+       {TRUE, 'v', "var", "variables"}
 
113
+};
 
114
+
 
115
+static keywordDesc GoKeywordTable[] = {
 
116
+       {"package", KEYWORD_package},
 
117
+       {"import", KEYWORD_import},
 
118
+       {"const", KEYWORD_const},
 
119
+       {"type", KEYWORD_type},
 
120
+       {"var", KEYWORD_var},
 
121
+       {"func", KEYWORD_func},
 
122
+       {"struct", KEYWORD_struct},
 
123
+       {"interface", KEYWORD_interface},
 
124
+       {"map", KEYWORD_map},
 
125
+       {"chan", KEYWORD_chan}
 
126
+};
 
127
+
 
128
+/*
 
129
+*   FUNCTION DEFINITIONS
 
130
+*/
 
131
+
 
132
+// XXX UTF-8
 
133
+static boolean isIdentChar (const int c)
 
134
+{
 
135
+       return (boolean)
 
136
+               (isalpha (c) || isdigit (c) || c == '$' ||
 
137
+                c == '@' || c == '_' || c == '#' || c > 128);
 
138
+}
 
139
+
 
140
+static void initialize (const langType language)
 
141
+{
 
142
+       size_t i;
 
143
+       const size_t count =
 
144
+               sizeof (GoKeywordTable) / sizeof (GoKeywordTable[0]);
 
145
+       Lang_go = language;
 
146
+       for (i = 0; i < count; ++i)
 
147
+       {
 
148
+               const keywordDesc *const p = &GoKeywordTable[i];
 
149
+               addKeyword (p->name, language, (int) p->id);
 
150
+       }
 
151
+}
 
152
+
 
153
+static tokenInfo *newToken (void)
 
154
+{
 
155
+       tokenInfo *const token = xMalloc (1, tokenInfo);
 
156
+       token->type = TOKEN_NONE;
 
157
+       token->keyword = KEYWORD_NONE;
 
158
+       token->string = vStringNew ();
 
159
+       token->lineNumber = getSourceLineNumber ();
 
160
+       token->filePosition = getInputFilePosition ();
 
161
+       return token;
 
162
+}
 
163
+
 
164
+static void deleteToken (tokenInfo * const token)
 
165
+{
 
166
+       if (token != NULL)
 
167
+       {
 
168
+               vStringDelete (token->string);
 
169
+               eFree (token);
 
170
+       }
 
171
+}
 
172
+
 
173
+/*
 
174
+ *   Parsing functions
 
175
+ */
 
176
+
 
177
+static void parseString (vString *const string, const int delimiter)
 
178
+{
 
179
+       boolean end = FALSE;
 
180
+       while (!end)
 
181
+       {
 
182
+               int c = fileGetc ();
 
183
+               if (c == EOF)
 
184
+                       end = TRUE;
 
185
+               else if (c == '\\' && delimiter != '`')
 
186
+               {
 
187
+                       c = fileGetc ();        /* This maybe a ' or ". */
 
188
+                       vStringPut (string, c);
 
189
+               }
 
190
+               else if (c == delimiter)
 
191
+                       end = TRUE;
 
192
+               else
 
193
+                       vStringPut (string, c);
 
194
+       }
 
195
+       vStringTerminate (string);
 
196
+}
 
197
+
 
198
+static void parseIdentifier (vString *const string, const int firstChar)
 
199
+{
 
200
+       int c = firstChar;
 
201
+       //Assert (isIdentChar (c));
 
202
+       do
 
203
+       {
 
204
+               vStringPut (string, c);
 
205
+               c = fileGetc ();
 
206
+       } while (isIdentChar (c));
 
207
+       vStringTerminate (string);
 
208
+       fileUngetc (c);         /* always unget, LF might add a semicolon */
 
209
+}
 
210
+
 
211
+static void readToken (tokenInfo *const token)
 
212
+{
 
213
+       int c;
 
214
+       static tokenType lastTokenType = TOKEN_NONE;
 
215
+
 
216
+       token->type = TOKEN_NONE;
 
217
+       token->keyword = KEYWORD_NONE;
 
218
+       vStringClear (token->string);
 
219
+
 
220
+getNextChar:
 
221
+       do
 
222
+       {
 
223
+               c = fileGetc ();
 
224
+               token->lineNumber = getSourceLineNumber ();
 
225
+               token->filePosition = getInputFilePosition ();
 
226
+               if (c == '\n' && (lastTokenType == TOKEN_IDENTIFIER ||
 
227
+                                                 lastTokenType == TOKEN_STRING ||
 
228
+                                                 lastTokenType == TOKEN_CLOSE_PAREN ||
 
229
+                                                 lastTokenType == TOKEN_CLOSE_CURLY ||
 
230
+                                                 lastTokenType == TOKEN_CLOSE_SQUARE))
 
231
+               {
 
232
+                       token->type = TOKEN_SEMICOLON;
 
233
+                       goto done;
 
234
+               }
 
235
+       }
 
236
+       while (c == '\t'  ||  c == ' ' ||  c == '\r' || c == '\n');
 
237
+
 
238
+       switch (c)
 
239
+       {
 
240
+               case EOF:
 
241
+                       longjmp (Exception, (int)ExceptionEOF);
 
242
+                       break;
 
243
+
 
244
+               case '/':
 
245
+                       {
 
246
+                               boolean hasNewline = FALSE;
 
247
+                               int d = fileGetc ();
 
248
+                               switch (d)
 
249
+                               {
 
250
+                                       case '/':
 
251
+                                               fileSkipToCharacter ('\n');
 
252
+                                               /* Line comments start with the
 
253
+                                                * character sequence // and
 
254
+                                                * continue through the next
 
255
+                                                * newline. A line comment acts
 
256
+                                                * like a newline.  */
 
257
+                                               fileUngetc ('\n');
 
258
+                                               goto getNextChar;
 
259
+                                       case '*':
 
260
+                                               do
 
261
+                                               {
 
262
+                                                       int d;
 
263
+                                                       do
 
264
+                                                       {
 
265
+                                                               d = fileGetc ();
 
266
+                                                               if (d == '\n')
 
267
+                                                               {
 
268
+                                                                       hasNewline = TRUE;
 
269
+                                                               }
 
270
+                                                       } while (d != EOF && d != '*');
 
271
+
 
272
+                                                       c = fileGetc ();
 
273
+                                                       if (c == '/')
 
274
+                                                               break;
 
275
+                                                       else
 
276
+                                                               fileUngetc (c);
 
277
+                                               } while (c != EOF && c != '\0');
 
278
+
 
279
+                                               fileUngetc (hasNewline ? '\n' : ' ');
 
280
+                                               goto getNextChar;
 
281
+                                       default:
 
282
+                                               token->type = TOKEN_FORWARD_SLASH;
 
283
+                                               fileUngetc (d);
 
284
+                                               break;
 
285
+                               }
 
286
+                       }
 
287
+                       break;
 
288
+
 
289
+               case '"':
 
290
+               case '\'':
 
291
+               case '`':
 
292
+                       token->type = TOKEN_STRING;
 
293
+                       parseString (token->string, c);
 
294
+                       token->lineNumber = getSourceLineNumber ();
 
295
+                       token->filePosition = getInputFilePosition ();
 
296
+                       break;
 
297
+
 
298
+               case '<':
 
299
+                       {
 
300
+                               int d = fileGetc ();
 
301
+                               if (d == '-')
 
302
+                               {
 
303
+                                       token->type = TOKEN_LEFT_ARROW;
 
304
+                                       break;
 
305
+                               }
 
306
+                               else
 
307
+                                       goto getNextChar;
 
308
+                       }
 
309
+
 
310
+               case '(':
 
311
+                       token->type = TOKEN_OPEN_PAREN;
 
312
+                       break;
 
313
+
 
314
+               case ')':
 
315
+                       token->type = TOKEN_CLOSE_PAREN;
 
316
+                       break;
 
317
+
 
318
+               case '{':
 
319
+                       token->type = TOKEN_OPEN_CURLY;
 
320
+                       break;
 
321
+
 
322
+               case '}':
 
323
+                       token->type = TOKEN_CLOSE_CURLY;
 
324
+                       break;
 
325
+
 
326
+               case '[':
 
327
+                       token->type = TOKEN_OPEN_SQUARE;
 
328
+                       break;
 
329
+
 
330
+               case ']':
 
331
+                       token->type = TOKEN_CLOSE_SQUARE;
 
332
+                       break;
 
333
+
 
334
+               case '*':
 
335
+                       token->type = TOKEN_STAR;
 
336
+                       break;
 
337
+
 
338
+               case '.':
 
339
+                       token->type = TOKEN_DOT;
 
340
+                       break;
 
341
+
 
342
+               case ',':
 
343
+                       token->type = TOKEN_COMMA;
 
344
+                       break;
 
345
+
 
346
+               default:
 
347
+                       parseIdentifier (token->string, c);
 
348
+                       token->lineNumber = getSourceLineNumber ();
 
349
+                       token->filePosition = getInputFilePosition ();
 
350
+                       token->keyword = lookupKeyword (vStringValue (token->string), Lang_go);
 
351
+                       if (isKeyword (token, KEYWORD_NONE))
 
352
+                               token->type = TOKEN_IDENTIFIER;
 
353
+                       else
 
354
+                               token->type = TOKEN_KEYWORD;
 
355
+                       break;
 
356
+       }
 
357
+
 
358
+done:
 
359
+       lastTokenType = token->type;
 
360
+}
 
361
+
 
362
+static void skipToMatched (tokenInfo *const token)
 
363
+{
 
364
+       int nest_level = 0;
 
365
+       tokenType open_token;
 
366
+       tokenType close_token;
 
367
+
 
368
+       switch (token->type)
 
369
+       {
 
370
+               case TOKEN_OPEN_PAREN:
 
371
+                       open_token = TOKEN_OPEN_PAREN;
 
372
+                       close_token = TOKEN_CLOSE_PAREN;
 
373
+                       break;
 
374
+               case TOKEN_OPEN_CURLY:
 
375
+                       open_token = TOKEN_OPEN_CURLY;
 
376
+                       close_token = TOKEN_CLOSE_CURLY;
 
377
+                       break;
 
378
+               case TOKEN_OPEN_SQUARE:
 
379
+                       open_token = TOKEN_OPEN_SQUARE;
 
380
+                       close_token = TOKEN_CLOSE_SQUARE;
 
381
+                       break;
 
382
+               default:
 
383
+                       return;
 
384
+       }
 
385
+
 
386
+       /*
 
387
+        * This routine will skip to a matching closing token.
 
388
+        * It will also handle nested tokens like the (, ) below.
 
389
+        *   (  name varchar(30), text binary(10)  )
 
390
+        */
 
391
+       if (isType (token, open_token))
 
392
+       {
 
393
+               nest_level++;
 
394
+               while (!(isType (token, close_token) && (nest_level == 0)))
 
395
+               {
 
396
+                       readToken (token);
 
397
+                       if (isType (token, open_token))
 
398
+                       {
 
399
+                               nest_level++;
 
400
+                       }
 
401
+                       if (isType (token, close_token))
 
402
+                       {
 
403
+                               if (nest_level > 0)
 
404
+                               {
 
405
+                                       nest_level--;
 
406
+                               }
 
407
+                       }
 
408
+               }
 
409
+               readToken (token);
 
410
+       }
 
411
+}
 
412
+
 
413
+static void skipType (tokenInfo *const token)
 
414
+{
 
415
+again:
 
416
+       // Type      = TypeName | TypeLit | "(" Type ")" .
 
417
+       if (isType (token, TOKEN_OPEN_PAREN))
 
418
+       {
 
419
+               skipToMatched (token);
 
420
+               return;
 
421
+       }
 
422
+
 
423
+       // TypeName  = QualifiedIdent.
 
424
+       // QualifiedIdent = [ PackageName "." ] identifier .
 
425
+       // PackageName    = identifier .
 
426
+       if (isType (token, TOKEN_IDENTIFIER))
 
427
+       {
 
428
+               readToken (token);
 
429
+               if (isType (token, TOKEN_DOT))
 
430
+               {
 
431
+                       readToken (token);
 
432
+                       Assert (isType (token, TOKEN_IDENTIFIER));
 
433
+                       readToken (token);
 
434
+               }
 
435
+               return;
 
436
+       }
 
437
+
 
438
+       // StructType     = "struct" "{" { FieldDecl ";" } "}"
 
439
+       // InterfaceType      = "interface" "{" { MethodSpec ";" } "}" .
 
440
+       if (isKeyword (token, KEYWORD_struct) || isKeyword (token, KEYWORD_interface))
 
441
+       {
 
442
+               readToken (token);
 
443
+               Assert (isType (token, TOKEN_OPEN_CURLY));
 
444
+               skipToMatched (token);
 
445
+               return;
 
446
+       }
 
447
+
 
448
+       // ArrayType   = "[" ArrayLength "]" ElementType .
 
449
+       // SliceType = "[" "]" ElementType .
 
450
+       // ElementType = Type .
 
451
+       if (isType (token, TOKEN_OPEN_SQUARE))
 
452
+       {
 
453
+               skipToMatched (token);
 
454
+               goto again;
 
455
+       }
 
456
+
 
457
+       // PointerType = "*" BaseType .
 
458
+       // BaseType = Type .
 
459
+       // ChannelType = ( "chan" [ "<-" ] | "<-" "chan" ) ElementType .
 
460
+       if (isType (token, TOKEN_STAR) || isKeyword (token, KEYWORD_chan) || isType (token, TOKEN_LEFT_ARROW))
 
461
+       {
 
462
+               readToken (token);
 
463
+               goto again;
 
464
+       }
 
465
+
 
466
+       // MapType     = "map" "[" KeyType "]" ElementType .
 
467
+       // KeyType     = Type .
 
468
+       if (isKeyword (token, KEYWORD_map))
 
469
+       {
 
470
+               readToken (token);
 
471
+               Assert (isType (token, TOKEN_OPEN_SQUARE));
 
472
+               skipToMatched (token);
 
473
+               goto again;
 
474
+       }
 
475
+
 
476
+       // FunctionType   = "func" Signature .
 
477
+       // Signature      = Parameters [ Result ] .
 
478
+       // Result         = Parameters | Type .
 
479
+       // Parameters     = "(" [ ParameterList [ "," ] ] ")" .
 
480
+       if (isKeyword (token, KEYWORD_func))
 
481
+       {
 
482
+               readToken (token);
 
483
+               Assert (isType (token, TOKEN_OPEN_PAREN));
 
484
+               // Parameters
 
485
+               skipToMatched (token);
 
486
+               // Result is parameters or type or nothing.  skipType treats anything
 
487
+               // surrounded by parentheses as a type, and does nothing if what
 
488
+               // follows is not a type.
 
489
+               goto again;
 
490
+       }
 
491
+}
 
492
+
 
493
+// Skip to the next semicolon, skipping over matching brackets.
 
494
+static void skipToTopLevelSemicolon (tokenInfo *const token)
 
495
+{
 
496
+       while (!isType (token, TOKEN_SEMICOLON))
 
497
+       {
 
498
+               readToken (token);
 
499
+               skipToMatched (token);
 
500
+       }
 
501
+}
 
502
+
 
503
+static void makeTag (tokenInfo *const token, const goKind kind)
 
504
+{
 
505
+       const char *const name = vStringValue (token->string);
 
506
+
 
507
+       tagEntryInfo e;
 
508
+       initTagEntry (&e, name);
 
509
+
 
510
+       if (!GoKinds [kind].enabled)
 
511
+               return;
 
512
+
 
513
+       e.lineNumber = token->lineNumber;
 
514
+       e.filePosition = token->filePosition;
 
515
+       e.kindName = GoKinds [kind].name;
 
516
+       e.kind = GoKinds [kind].letter;
 
517
+
 
518
+       makeTagEntry (&e);
 
519
+
 
520
+       if (scope && Option.include.qualifiedTags)
 
521
+       {
 
522
+               vString *qualifiedName = vStringNew ();
 
523
+               vStringCopy (qualifiedName, scope);
 
524
+               vStringCatS (qualifiedName, ".");
 
525
+               vStringCat (qualifiedName, token->string);
 
526
+               e.name = vStringValue (qualifiedName);
 
527
+               makeTagEntry (&e);
 
528
+               vStringDelete (qualifiedName);
 
529
+       }
 
530
+}
 
531
+
 
532
+static void parsePackage (tokenInfo *const token)
 
533
+{
 
534
+       tokenInfo *const name = newToken ();
 
535
+
 
536
+       readToken (name);
 
537
+       Assert (isType (name, TOKEN_IDENTIFIER));
 
538
+       makeTag (name, GOTAG_PACKAGE);
 
539
+       if (!scope && Option.include.qualifiedTags)
 
540
+       {
 
541
+               scope = vStringNew ();
 
542
+               vStringCopy (scope, name->string);
 
543
+       }
 
544
+
 
545
+       deleteToken (name);
 
546
+}
 
547
+
 
548
+static void parseFunctionOrMethod (tokenInfo *const token)
 
549
+{
 
550
+       // FunctionDecl = "func" identifier Signature [ Body ] .
 
551
+       // Body         = Block.
 
552
+       //
 
553
+       // MethodDecl   = "func" Receiver MethodName Signature [ Body ] .
 
554
+       // Receiver     = "(" [ identifier ] [ "*" ] BaseTypeName ")" .
 
555
+       // BaseTypeName = identifier .
 
556
+       tokenInfo *const name = newToken ();
 
557
+
 
558
+       // Skip over receiver.
 
559
+       readToken (name);
 
560
+       if (isType (name, TOKEN_OPEN_PAREN))
 
561
+               skipToMatched (name);
 
562
+
 
563
+       Assert (isType (name, TOKEN_IDENTIFIER));
 
564
+
 
565
+       // Skip over parameters.
 
566
+       readToken (token);
 
567
+       skipToMatched (token);
 
568
+
 
569
+       // Skip over result.
 
570
+       skipType (token);
 
571
+
 
572
+       // Skip over function body.
 
573
+       if (isType (token, TOKEN_OPEN_CURLY))
 
574
+               skipToMatched (token);
 
575
+
 
576
+       makeTag (name, GOTAG_FUNCTION);
 
577
+
 
578
+       deleteToken (name);
 
579
+}
 
580
+
 
581
+static void parseConstTypeVar (tokenInfo *const token, goKind kind)
 
582
+{
 
583
+       // ConstDecl      = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) .
 
584
+       // ConstSpec      = IdentifierList [ [ Type ] "=" ExpressionList ] .
 
585
+       // IdentifierList = identifier { "," identifier } .
 
586
+       // ExpressionList = Expression { "," Expression } .
 
587
+       // TypeDecl     = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) .
 
588
+       // TypeSpec     = identifier Type .
 
589
+       // VarDecl     = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
 
590
+       // VarSpec     = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
 
591
+       tokenInfo *const name = newToken ();
 
592
+       boolean usesParens = FALSE;
 
593
+
 
594
+       readToken (name);
 
595
+
 
596
+       if (isType (name, TOKEN_OPEN_PAREN))
 
597
+       {
 
598
+               usesParens = TRUE;
 
599
+               readToken (name);
 
600
+       }
 
601
+
 
602
+again:
 
603
+       while (1)
 
604
+       {
 
605
+               makeTag (name, kind);
 
606
+               readToken (token);
 
607
+               if (!isType (token, TOKEN_COMMA) && !isType (token, TOKEN_CLOSE_PAREN))
 
608
+                       break;
 
609
+               readToken (name);
 
610
+       }
 
611
+
 
612
+       skipType (token);
 
613
+       skipToTopLevelSemicolon (token);
 
614
+
 
615
+       if (usesParens)
 
616
+       {
 
617
+               readToken (name);
 
618
+               if (!isType (name, TOKEN_CLOSE_PAREN))
 
619
+                       goto again;
 
620
+       }
 
621
+
 
622
+       deleteToken (name);
 
623
+}
 
624
+
 
625
+static void parseGoFile (tokenInfo *const token)
 
626
+{
 
627
+       do
 
628
+       {
 
629
+               readToken (token);
 
630
+
 
631
+               if (isType (token, TOKEN_KEYWORD))
 
632
+               {
 
633
+                       switch (token->keyword)
 
634
+                       {
 
635
+                               case KEYWORD_package:
 
636
+                                       parsePackage (token);
 
637
+                                       break;
 
638
+                               case KEYWORD_func:
 
639
+                                       parseFunctionOrMethod (token);
 
640
+                                       break;
 
641
+                               case KEYWORD_const:
 
642
+                                       parseConstTypeVar (token, GOTAG_CONST);
 
643
+                                       break;
 
644
+                               case KEYWORD_type:
 
645
+                                       parseConstTypeVar (token, GOTAG_TYPE);
 
646
+                                       break;
 
647
+                               case KEYWORD_var:
 
648
+                                       parseConstTypeVar (token, GOTAG_VAR);
 
649
+                                       break;
 
650
+                               default:
 
651
+                                       break;
 
652
+                       }
 
653
+               }
 
654
+       } while (TRUE);
 
655
+}
 
656
+
 
657
+static void findGoTags (void)
 
658
+{
 
659
+       tokenInfo *const token = newToken ();
 
660
+       exception_t exception;
 
661
+
 
662
+       exception = (exception_t) (setjmp (Exception));
 
663
+       while (exception == ExceptionNone)
 
664
+               parseGoFile (token);
 
665
+
 
666
+       deleteToken (token);
 
667
+       vStringDelete (scope);
 
668
+       scope = NULL;
 
669
+}
 
670
+
 
671
+extern parserDefinition *GoParser (void)
 
672
+{
 
673
+       static const char *const extensions[] = { "go", NULL };
 
674
+       parserDefinition *def = parserNew ("Go");
 
675
+       def->kinds = GoKinds;
 
676
+       def->kindCount = KIND_COUNT (GoKinds);
 
677
+       def->extensions = extensions;
 
678
+       def->parser = findGoTags;
 
679
+       def->initialize = initialize;
 
680
+       return def;
 
681
+}
 
682
Index: b/parsers.h
 
683
===================================================================
 
684
--- a/parsers.h
 
685
+++ b/parsers.h
 
686
@@ -31,6 +31,7 @@
 
687
        ErlangParser, \
 
688
        FlexParser, \
 
689
        FortranParser, \
 
690
+       GoParser, \
 
691
        HtmlParser, \
 
692
        JavaParser, \
 
693
        JavaScriptParser, \
 
694
Index: b/source.mak
 
695
===================================================================
 
696
--- a/source.mak
 
697
+++ b/source.mak
 
698
@@ -24,6 +24,7 @@
 
699
        flex.c \
 
700
        fortran.c \
 
701
        get.c \
 
702
+       go.c \
 
703
        html.c \
 
704
        jscript.c \
 
705
        keyword.c \
 
706
@@ -87,6 +88,7 @@
 
707
        flex.$(OBJEXT) \
 
708
        fortran.$(OBJEXT) \
 
709
        get.$(OBJEXT) \
 
710
+       go.$(OBJEXT) \
 
711
        html.$(OBJEXT) \
 
712
        jscript.$(OBJEXT) \
 
713
        keyword.$(OBJEXT) \