1package main
2
3import (
4	"bytes"
5	"errors"
6	"fmt"
7	"go/ast"
8	"go/token"
9	"strconv"
10	"text/scanner"
11)
12
13//-------------------------------------------------------------------------
14// gc_parser
15//
16// The following part of the code may contain portions of the code from the Go
17// standard library, which tells me to retain their copyright notice:
18//
19// Copyright (c) 2009 The Go Authors. All rights reserved.
20//
21// Redistribution and use in source and binary forms, with or without
22// modification, are permitted provided that the following conditions are
23// met:
24//
25//    * Redistributions of source code must retain the above copyright
26// notice, this list of conditions and the following disclaimer.
27//    * Redistributions in binary form must reproduce the above
28// copyright notice, this list of conditions and the following disclaimer
29// in the documentation and/or other materials provided with the
30// distribution.
31//    * Neither the name of Google Inc. nor the names of its
32// contributors may be used to endorse or promote products derived from
33// this software without specific prior written permission.
34//
35// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46//-------------------------------------------------------------------------
47
48type gc_parser struct {
49	scanner      scanner.Scanner
50	tok          rune
51	lit          string
52	path_to_name map[string]string
53	beautify     bool
54	pfc          *package_file_cache
55}
56
57func (p *gc_parser) init(data []byte, pfc *package_file_cache) {
58	p.scanner.Init(bytes.NewReader(data))
59	p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) }
60	p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanStrings |
61		scanner.ScanComments | scanner.ScanChars | scanner.SkipComments
62	p.scanner.Whitespace = 1<<'\t' | 1<<' ' | 1<<'\r' | 1<<'\v' | 1<<'\f'
63	p.scanner.Filename = "package.go"
64	p.next()
65	// and the built-in "unsafe" package to the path_to_name map
66	p.path_to_name = map[string]string{"unsafe": "unsafe"}
67	p.pfc = pfc
68}
69
70func (p *gc_parser) next() {
71	p.tok = p.scanner.Scan()
72	switch p.tok {
73	case scanner.Ident, scanner.Int, scanner.String:
74		p.lit = p.scanner.TokenText()
75	default:
76		p.lit = ""
77	}
78}
79
80func (p *gc_parser) error(msg string) {
81	panic(errors.New(msg))
82}
83
84func (p *gc_parser) errorf(format string, args ...interface{}) {
85	p.error(fmt.Sprintf(format, args...))
86}
87
88func (p *gc_parser) expect(tok rune) string {
89	lit := p.lit
90	if p.tok != tok {
91		p.errorf("expected %s, got %s (%q)", scanner.TokenString(tok),
92			scanner.TokenString(p.tok), lit)
93	}
94	p.next()
95	return lit
96}
97
98func (p *gc_parser) expect_keyword(keyword string) {
99	lit := p.expect(scanner.Ident)
100	if lit != keyword {
101		p.errorf("expected keyword: %s, got: %q", keyword, lit)
102	}
103}
104
105func (p *gc_parser) expect_special(what string) {
106	i := 0
107	for i < len(what) {
108		if p.tok != rune(what[i]) {
109			break
110		}
111
112		nc := p.scanner.Peek()
113		if i != len(what)-1 && nc <= ' ' {
114			break
115		}
116
117		p.next()
118		i++
119	}
120
121	if i < len(what) {
122		p.errorf("expected: %q, got: %q", what, what[0:i])
123	}
124}
125
126// dotIdentifier = "?" | ( ident | '·' ) { ident | int | '·' } .
127// we're doing lexer job here, kind of
128func (p *gc_parser) parse_dot_ident() string {
129	if p.tok == '?' {
130		p.next()
131		return "?"
132	}
133
134	ident := ""
135	sep := 'x'
136	i, j := 0, -1
137	for (p.tok == scanner.Ident || p.tok == scanner.Int || p.tok == '·') && sep > ' ' {
138		ident += p.lit
139		if p.tok == '·' {
140			ident += "·"
141			j = i
142			i++
143		}
144		i += len(p.lit)
145		sep = p.scanner.Peek()
146		p.next()
147	}
148	// middot = \xc2\xb7
149	if j != -1 && i > j+1 {
150		c := ident[j+2]
151		if c >= '0' && c <= '9' {
152			ident = ident[0:j]
153		}
154	}
155	return ident
156}
157
158// ImportPath = string_lit .
159// quoted name of the path, but we return it as an identifier, taking an alias
160// from 'pathToAlias' map, it is filled by import statements
161func (p *gc_parser) parse_package() *ast.Ident {
162	path, err := strconv.Unquote(p.expect(scanner.String))
163	if err != nil {
164		panic(err)
165	}
166
167	return ast.NewIdent(path)
168}
169
170// ExportedName = "@" ImportPath "." dotIdentifier .
171func (p *gc_parser) parse_exported_name() *ast.SelectorExpr {
172	p.expect('@')
173	pkg := p.parse_package()
174	if pkg.Name == "" {
175		pkg.Name = "!" + p.pfc.name + "!" + p.pfc.defalias
176	} else {
177		pkg.Name = p.path_to_name[pkg.Name]
178	}
179	p.expect('.')
180	name := ast.NewIdent(p.parse_dot_ident())
181	return &ast.SelectorExpr{X: pkg, Sel: name}
182}
183
184// Name = identifier | "?" | ExportedName .
185func (p *gc_parser) parse_name() (string, ast.Expr) {
186	switch p.tok {
187	case scanner.Ident:
188		name := p.lit
189		p.next()
190		return name, ast.NewIdent(name)
191	case '?':
192		p.next()
193		return "?", ast.NewIdent("?")
194	case '@':
195		en := p.parse_exported_name()
196		return en.Sel.Name, en
197	}
198	p.error("name expected")
199	return "", nil
200}
201
202// Field = Name Type [ string_lit ] .
203func (p *gc_parser) parse_field() *ast.Field {
204	var tag string
205	name, _ := p.parse_name()
206	typ := p.parse_type()
207	if p.tok == scanner.String {
208		tag = p.expect(scanner.String)
209	}
210
211	var names []*ast.Ident
212	if name != "?" {
213		names = []*ast.Ident{ast.NewIdent(name)}
214	}
215
216	return &ast.Field{
217		Names: names,
218		Type:  typ,
219		Tag:   &ast.BasicLit{Kind: token.STRING, Value: tag},
220	}
221}
222
223// Parameter = ( identifier | "?" ) [ "..." ] Type [ string_lit ] .
224func (p *gc_parser) parse_parameter() *ast.Field {
225	// name
226	name, _ := p.parse_name()
227
228	// type
229	var typ ast.Expr
230	if p.tok == '.' {
231		p.expect_special("...")
232		typ = &ast.Ellipsis{Elt: p.parse_type()}
233	} else {
234		typ = p.parse_type()
235	}
236
237	var tag string
238	if p.tok == scanner.String {
239		tag = p.expect(scanner.String)
240	}
241
242	return &ast.Field{
243		Names: []*ast.Ident{ast.NewIdent(name)},
244		Type:  typ,
245		Tag:   &ast.BasicLit{Kind: token.STRING, Value: tag},
246	}
247}
248
249// Parameters = "(" [ ParameterList ] ")" .
250// ParameterList = { Parameter "," } Parameter .
251func (p *gc_parser) parse_parameters() *ast.FieldList {
252	flds := []*ast.Field{}
253	parse_parameter := func() {
254		par := p.parse_parameter()
255		flds = append(flds, par)
256	}
257
258	p.expect('(')
259	if p.tok != ')' {
260		parse_parameter()
261		for p.tok == ',' {
262			p.next()
263			parse_parameter()
264		}
265	}
266	p.expect(')')
267	return &ast.FieldList{List: flds}
268}
269
270// Signature = Parameters [ Result ] .
271// Result = Type | Parameters .
272func (p *gc_parser) parse_signature() *ast.FuncType {
273	var params *ast.FieldList
274	var results *ast.FieldList
275
276	params = p.parse_parameters()
277	switch p.tok {
278	case scanner.Ident, '[', '*', '<', '@':
279		fld := &ast.Field{Type: p.parse_type()}
280		results = &ast.FieldList{List: []*ast.Field{fld}}
281	case '(':
282		results = p.parse_parameters()
283	}
284	return &ast.FuncType{Params: params, Results: results}
285}
286
287// MethodOrEmbedSpec = Name [ Signature ] .
288func (p *gc_parser) parse_method_or_embed_spec() *ast.Field {
289	name, nameexpr := p.parse_name()
290	if p.tok == '(' {
291		typ := p.parse_signature()
292		return &ast.Field{
293			Names: []*ast.Ident{ast.NewIdent(name)},
294			Type:  typ,
295		}
296	}
297
298	return &ast.Field{
299		Type: nameexpr,
300	}
301}
302
303// int_lit = [ "-" | "+" ] { "0" ... "9" } .
304func (p *gc_parser) parse_int() {
305	switch p.tok {
306	case '-', '+':
307		p.next()
308	}
309	p.expect(scanner.Int)
310}
311
312// number = int_lit [ "p" int_lit ] .
313func (p *gc_parser) parse_number() {
314	p.parse_int()
315	if p.lit == "p" {
316		p.next()
317		p.parse_int()
318	}
319}
320
321//-------------------------------------------------------------------------------
322// gc_parser.types
323//-------------------------------------------------------------------------------
324
325// InterfaceType = "interface" "{" [ MethodOrEmbedList ] "}" .
326// MethodOrEmbedList = MethodOrEmbedSpec { ";" MethodOrEmbedSpec } .
327func (p *gc_parser) parse_interface_type() ast.Expr {
328	var methods []*ast.Field
329	parse_method := func() {
330		meth := p.parse_method_or_embed_spec()
331		methods = append(methods, meth)
332	}
333
334	p.expect_keyword("interface")
335	p.expect('{')
336	if p.tok != '}' {
337		parse_method()
338		for p.tok == ';' {
339			p.next()
340			parse_method()
341		}
342	}
343	p.expect('}')
344	return &ast.InterfaceType{Methods: &ast.FieldList{List: methods}}
345}
346
347// StructType = "struct" "{" [ FieldList ] "}" .
348// FieldList = Field { ";" Field } .
349func (p *gc_parser) parse_struct_type() ast.Expr {
350	var fields []*ast.Field
351	parse_field := func() {
352		fld := p.parse_field()
353		fields = append(fields, fld)
354	}
355
356	p.expect_keyword("struct")
357	p.expect('{')
358	if p.tok != '}' {
359		parse_field()
360		for p.tok == ';' {
361			p.next()
362			parse_field()
363		}
364	}
365	p.expect('}')
366	return &ast.StructType{Fields: &ast.FieldList{List: fields}}
367}
368
369// MapType = "map" "[" Type "]" Type .
370func (p *gc_parser) parse_map_type() ast.Expr {
371	p.expect_keyword("map")
372	p.expect('[')
373	key := p.parse_type()
374	p.expect(']')
375	elt := p.parse_type()
376	return &ast.MapType{Key: key, Value: elt}
377}
378
379// ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type .
380func (p *gc_parser) parse_chan_type() ast.Expr {
381	dir := ast.SEND | ast.RECV
382	if p.tok == scanner.Ident {
383		p.expect_keyword("chan")
384		if p.tok == '<' {
385			p.expect_special("<-")
386			dir = ast.SEND
387		}
388	} else {
389		p.expect_special("<-")
390		p.expect_keyword("chan")
391		dir = ast.RECV
392	}
393
394	elt := p.parse_type()
395	return &ast.ChanType{Dir: dir, Value: elt}
396}
397
398// ArrayOrSliceType = ArrayType | SliceType .
399// ArrayType = "[" int_lit "]" Type .
400// SliceType = "[" "]" Type .
401func (p *gc_parser) parse_array_or_slice_type() ast.Expr {
402	p.expect('[')
403	if p.tok == ']' {
404		// SliceType
405		p.next() // skip ']'
406		return &ast.ArrayType{Len: nil, Elt: p.parse_type()}
407	}
408
409	// ArrayType
410	lit := p.expect(scanner.Int)
411	p.expect(']')
412	return &ast.ArrayType{
413		Len: &ast.BasicLit{Kind: token.INT, Value: lit},
414		Elt: p.parse_type(),
415	}
416}
417
418// Type =
419//	BasicType | TypeName | ArrayType | SliceType | StructType |
420//      PointerType | FuncType | InterfaceType | MapType | ChanType |
421//      "(" Type ")" .
422// BasicType = ident .
423// TypeName = ExportedName .
424// SliceType = "[" "]" Type .
425// PointerType = "*" Type .
426// FuncType = "func" Signature .
427func (p *gc_parser) parse_type() ast.Expr {
428	switch p.tok {
429	case scanner.Ident:
430		switch p.lit {
431		case "struct":
432			return p.parse_struct_type()
433		case "func":
434			p.next()
435			return p.parse_signature()
436		case "interface":
437			return p.parse_interface_type()
438		case "map":
439			return p.parse_map_type()
440		case "chan":
441			return p.parse_chan_type()
442		default:
443			lit := p.lit
444			p.next()
445			return ast.NewIdent(lit)
446		}
447	case '@':
448		return p.parse_exported_name()
449	case '[':
450		return p.parse_array_or_slice_type()
451	case '*':
452		p.next()
453		return &ast.StarExpr{X: p.parse_type()}
454	case '<':
455		return p.parse_chan_type()
456	case '(':
457		p.next()
458		typ := p.parse_type()
459		p.expect(')')
460		return typ
461	}
462	p.errorf("unexpected token: %s", scanner.TokenString(p.tok))
463	return nil
464}
465
466//-------------------------------------------------------------------------------
467// gc_parser.declarations
468//-------------------------------------------------------------------------------
469
470// ImportDecl = "import" identifier string_lit .
471func (p *gc_parser) parse_import_decl() {
472	p.expect_keyword("import")
473	alias := p.expect(scanner.Ident)
474	path := p.parse_package()
475	fullName := "!" + path.Name + "!" + alias
476	p.path_to_name[path.Name] = fullName
477	p.pfc.add_package_to_scope(fullName, path.Name)
478}
479
480// ConstDecl   = "const" ExportedName [ Type ] "=" Literal .
481// Literal     = bool_lit | int_lit | float_lit | complex_lit | string_lit .
482// bool_lit    = "true" | "false" .
483// complex_lit = "(" float_lit "+" float_lit ")" .
484// rune_lit    = "(" int_lit "+" int_lit ")" .
485// string_lit  = `"` { unicode_char } `"` .
486func (p *gc_parser) parse_const_decl() (string, *ast.GenDecl) {
487	// TODO: do we really need actual const value? gocode doesn't use this
488	p.expect_keyword("const")
489	name := p.parse_exported_name()
490
491	var typ ast.Expr
492	if p.tok != '=' {
493		typ = p.parse_type()
494	}
495
496	p.expect('=')
497
498	// skip the value
499	switch p.tok {
500	case scanner.Ident:
501		// must be bool, true or false
502		p.next()
503	case '-', '+', scanner.Int:
504		// number
505		p.parse_number()
506	case '(':
507		// complex_lit or rune_lit
508		p.next() // skip '('
509		if p.tok == scanner.Char {
510			p.next()
511		} else {
512			p.parse_number()
513		}
514		p.expect('+')
515		p.parse_number()
516		p.expect(')')
517	case scanner.Char:
518		p.next()
519	case scanner.String:
520		p.next()
521	default:
522		p.error("expected literal")
523	}
524
525	return name.X.(*ast.Ident).Name, &ast.GenDecl{
526		Tok: token.CONST,
527		Specs: []ast.Spec{
528			&ast.ValueSpec{
529				Names:  []*ast.Ident{name.Sel},
530				Type:   typ,
531				Values: []ast.Expr{&ast.BasicLit{Kind: token.INT, Value: "0"}},
532			},
533		},
534	}
535}
536
537// TypeDecl = "type" ExportedName Type .
538func (p *gc_parser) parse_type_decl() (string, *ast.GenDecl) {
539	p.expect_keyword("type")
540	name := p.parse_exported_name()
541	typ := p.parse_type()
542	return name.X.(*ast.Ident).Name, &ast.GenDecl{
543		Tok: token.TYPE,
544		Specs: []ast.Spec{
545			&ast.TypeSpec{
546				Name: name.Sel,
547				Type: typ,
548			},
549		},
550	}
551}
552
553// VarDecl = "var" ExportedName Type .
554func (p *gc_parser) parse_var_decl() (string, *ast.GenDecl) {
555	p.expect_keyword("var")
556	name := p.parse_exported_name()
557	typ := p.parse_type()
558	return name.X.(*ast.Ident).Name, &ast.GenDecl{
559		Tok: token.VAR,
560		Specs: []ast.Spec{
561			&ast.ValueSpec{
562				Names: []*ast.Ident{name.Sel},
563				Type:  typ,
564			},
565		},
566	}
567}
568
569// FuncBody = "{" ... "}" .
570func (p *gc_parser) parse_func_body() {
571	p.expect('{')
572	for i := 1; i > 0; p.next() {
573		switch p.tok {
574		case '{':
575			i++
576		case '}':
577			i--
578		}
579	}
580}
581
582// FuncDecl = "func" ExportedName Signature [ FuncBody ] .
583func (p *gc_parser) parse_func_decl() (string, *ast.FuncDecl) {
584	// "func" was already consumed by lookahead
585	name := p.parse_exported_name()
586	typ := p.parse_signature()
587	if p.tok == '{' {
588		p.parse_func_body()
589	}
590	return name.X.(*ast.Ident).Name, &ast.FuncDecl{
591		Name: name.Sel,
592		Type: typ,
593	}
594}
595
596func strip_method_receiver(recv *ast.FieldList) string {
597	var sel *ast.SelectorExpr
598
599	// find selector expression
600	typ := recv.List[0].Type
601	switch t := typ.(type) {
602	case *ast.StarExpr:
603		sel = t.X.(*ast.SelectorExpr)
604	case *ast.SelectorExpr:
605		sel = t
606	}
607
608	// extract package path
609	pkg := sel.X.(*ast.Ident).Name
610
611	// write back stripped type
612	switch t := typ.(type) {
613	case *ast.StarExpr:
614		t.X = sel.Sel
615	case *ast.SelectorExpr:
616		recv.List[0].Type = sel.Sel
617	}
618
619	return pkg
620}
621
622// MethodDecl = "func" Receiver Name Signature .
623// Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" [ FuncBody ] .
624func (p *gc_parser) parse_method_decl() (string, *ast.FuncDecl) {
625	recv := p.parse_parameters()
626	pkg := strip_method_receiver(recv)
627	name, _ := p.parse_name()
628	typ := p.parse_signature()
629	if p.tok == '{' {
630		p.parse_func_body()
631	}
632	return pkg, &ast.FuncDecl{
633		Recv: recv,
634		Name: ast.NewIdent(name),
635		Type: typ,
636	}
637}
638
639// Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" .
640func (p *gc_parser) parse_decl() (pkg string, decl ast.Decl) {
641	switch p.lit {
642	case "import":
643		p.parse_import_decl()
644	case "const":
645		pkg, decl = p.parse_const_decl()
646	case "type":
647		pkg, decl = p.parse_type_decl()
648	case "var":
649		pkg, decl = p.parse_var_decl()
650	case "func":
651		p.next()
652		if p.tok == '(' {
653			pkg, decl = p.parse_method_decl()
654		} else {
655			pkg, decl = p.parse_func_decl()
656		}
657	}
658	p.expect('\n')
659	return
660}
661
662// Export = PackageClause { Decl } "$$" .
663// PackageClause = "package" identifier [ "safe" ] "\n" .
664func (p *gc_parser) parse_export(callback func(string, ast.Decl)) {
665	p.expect_keyword("package")
666	p.pfc.defalias = p.expect(scanner.Ident)
667	if p.tok != '\n' {
668		p.expect_keyword("safe")
669	}
670	p.expect('\n')
671
672	for p.tok != '$' && p.tok != scanner.EOF {
673		pkg, decl := p.parse_decl()
674		if decl != nil {
675			callback(pkg, decl)
676		}
677	}
678}
679