github.com/goplus/llgo@v0.8.3/xtool/clang/types/parser/parser.go (about)

     1  /*
     2   * Copyright (c) 2022 The GoPlus Authors (goplus.org). All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package parser
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"go/token"
    23  	"go/types"
    24  	"io"
    25  	"log"
    26  	"strconv"
    27  
    28  	"github.com/goplus/gogen"
    29  	"github.com/goplus/llgo/xtool/clang/types/scanner"
    30  
    31  	ctypes "github.com/goplus/llgo/xtool/clang/types"
    32  )
    33  
    34  const (
    35  	emsgDefArrWithoutLen = "define array without length"
    36  )
    37  
    38  var (
    39  	ErrInvalidType = errors.New("invalid type")
    40  )
    41  
    42  type TypeNotFound struct {
    43  	Literal       string
    44  	StructOrUnion bool
    45  }
    46  
    47  func (p *TypeNotFound) Error() string {
    48  	return fmt.Sprintf("type %s not found", p.Literal)
    49  }
    50  
    51  type ParseTypeError struct {
    52  	QualType string
    53  	ErrMsg   string
    54  }
    55  
    56  func (p *ParseTypeError) Error() string {
    57  	return p.ErrMsg // TODO
    58  }
    59  
    60  func IsArrayWithoutLen(err error) bool {
    61  	if e, ok := err.(*ParseTypeError); ok {
    62  		return e.ErrMsg == emsgDefArrWithoutLen
    63  	}
    64  	return false
    65  }
    66  
    67  // -----------------------------------------------------------------------------
    68  
    69  const (
    70  	FlagIsParam = 1 << iota
    71  	FlagIsStructField
    72  	FlagIsExtern
    73  	FlagIsTypedef
    74  	FlagGetRetType
    75  )
    76  
    77  func getRetType(flags int) bool {
    78  	return (flags & FlagGetRetType) != 0
    79  }
    80  
    81  type ParseEnv interface {
    82  	Pkg() *types.Package
    83  	Int128() types.Type
    84  	Uint128() types.Type
    85  }
    86  
    87  type Config struct {
    88  	ParseEnv
    89  	Scope  *types.Scope
    90  	Anonym types.Type
    91  	Flags  int
    92  }
    93  
    94  const (
    95  	KindFConst = 1 << iota
    96  	KindFVolatile
    97  	KindFAnonymous
    98  	KindFVariadic
    99  )
   100  
   101  // qualType can be:
   102  //   - unsigned int
   103  //   - struct ConstantString
   104  //   - volatile uint32_t
   105  //   - int (*)(void *, int, char **, char **)
   106  //   - int (*)(const char *, ...)
   107  //   - int (*)(void)
   108  //   - void (*(int, void (*)(int)))(int)
   109  //   - const char *restrict
   110  //   - const char [7]
   111  //   - char *
   112  //   - void
   113  //   - ...
   114  func ParseType(qualType string, conf *Config) (t types.Type, kind int, err error) {
   115  	p := newParser(qualType, conf)
   116  	if t, kind, err = p.parse(conf.Flags); err != nil {
   117  		return
   118  	}
   119  	if p.tok != token.EOF {
   120  		err = p.newError("unexpect token " + p.tok.String())
   121  	}
   122  	return
   123  }
   124  
   125  // -----------------------------------------------------------------------------
   126  
   127  type parser struct {
   128  	s     scanner.Scanner
   129  	scope *types.Scope
   130  	conf  *Config
   131  
   132  	tok token.Token
   133  	lit string
   134  	old struct {
   135  		tok token.Token
   136  		lit string
   137  	}
   138  }
   139  
   140  const (
   141  	invalidTok token.Token = -1
   142  )
   143  
   144  func newParser(qualType string, conf *Config) *parser {
   145  	p := &parser{scope: conf.Scope, conf: conf}
   146  	p.old.tok = invalidTok
   147  	p.s.Init(qualType)
   148  	return p
   149  }
   150  
   151  func (p *parser) peek() token.Token {
   152  	if p.old.tok == invalidTok {
   153  		p.old.tok, p.old.lit = p.s.Scan()
   154  	}
   155  	return p.old.tok
   156  }
   157  
   158  func (p *parser) next() {
   159  	if p.old.tok != invalidTok { // support unget
   160  		p.tok, p.lit = p.old.tok, p.old.lit
   161  		p.old.tok = invalidTok
   162  		return
   163  	}
   164  	p.tok, p.lit = p.s.Scan()
   165  }
   166  
   167  func (p *parser) unget(tok token.Token, lit string) {
   168  	p.old.tok, p.old.lit = p.tok, p.lit
   169  	p.tok, p.lit = tok, lit
   170  }
   171  
   172  func (p *parser) skipUntil(tok token.Token) bool {
   173  	for {
   174  		p.next()
   175  		switch p.tok {
   176  		case tok:
   177  			return true
   178  		case token.EOF:
   179  			return false
   180  		}
   181  	}
   182  }
   183  
   184  func (p *parser) newErrorf(format string, args ...interface{}) *ParseTypeError {
   185  	return p.newError(fmt.Sprintf(format, args...))
   186  }
   187  
   188  func (p *parser) newError(errMsg string) *ParseTypeError {
   189  	return &ParseTypeError{QualType: p.s.Source(), ErrMsg: errMsg}
   190  }
   191  
   192  // TODO(xsw): check expect results
   193  func (p *parser) expect(tokExp token.Token) error {
   194  	p.next()
   195  	if p.tok != tokExp {
   196  		return p.newErrorf("expect %v, got %v", tokExp, p.tok)
   197  	}
   198  	return nil
   199  }
   200  
   201  const (
   202  	flagShort = 1 << iota
   203  	flagLong
   204  	flagLongLong
   205  	flagUnsigned
   206  	flagSigned
   207  	flagComplex
   208  	flagStructOrUnion
   209  )
   210  
   211  func (p *parser) lookupType(tylit string, flags int) (t types.Type, err error) {
   212  	structOrUnion := (flags & flagStructOrUnion) != 0
   213  	_, o := gogen.LookupParent(p.scope, tylit, token.NoPos)
   214  	if o == nil {
   215  		return nil, &TypeNotFound{Literal: tylit, StructOrUnion: structOrUnion}
   216  	}
   217  	t = o.Type()
   218  	if !structOrUnion && flags != 0 {
   219  		tt, ok := t.(*types.Basic)
   220  		if !ok {
   221  			tyInt128 := p.conf.Int128()
   222  			if t == tyInt128 {
   223  				switch flags {
   224  				case flagSigned:
   225  					return tyInt128, nil
   226  				case flagUnsigned:
   227  					return p.conf.Uint128(), nil
   228  				}
   229  			}
   230  		} else if (flags & flagComplex) != 0 {
   231  			switch tt.Kind() {
   232  			case types.Float32:
   233  				return types.Typ[types.Complex64], nil
   234  			case types.Float64:
   235  				return types.Typ[types.Complex128], nil
   236  			case types.Int:
   237  				return types.Typ[types.Complex128], nil
   238  			}
   239  		} else {
   240  			switch tt.Kind() {
   241  			case types.Int:
   242  				if t = intTypes[flags&^flagSigned]; t != nil {
   243  					return
   244  				}
   245  			case types.Int8:
   246  				switch flags {
   247  				case flagUnsigned:
   248  					return types.Typ[types.Uint8], nil
   249  				case flagSigned:
   250  					return types.Typ[types.Int8], nil
   251  				}
   252  			case types.Float64:
   253  				switch flags {
   254  				case flagLong:
   255  					return ctypes.LongDouble, nil
   256  				}
   257  			}
   258  		}
   259  		log.Panicln("lookupType: TODO - invalid type")
   260  		return nil, ErrInvalidType
   261  	}
   262  	if t == types.Typ[types.Int] {
   263  		return ctypes.Int, nil
   264  	}
   265  	return
   266  }
   267  
   268  var intTypes = [...]types.Type{
   269  	0:                                      ctypes.Int,
   270  	flagShort:                              types.Typ[types.Int16],
   271  	flagLong:                               ctypes.Long,
   272  	flagLong | flagLongLong:                types.Typ[types.Int64],
   273  	flagUnsigned:                           ctypes.Uint,
   274  	flagShort | flagUnsigned:               types.Typ[types.Uint16],
   275  	flagLong | flagUnsigned:                ctypes.Ulong,
   276  	flagLong | flagLongLong | flagUnsigned: types.Typ[types.Uint64],
   277  	flagShort | flagLong | flagLongLong | flagUnsigned: nil,
   278  }
   279  
   280  func (p *parser) parseArray(t types.Type, inFlags int) (types.Type, error) {
   281  	var n int64
   282  	var err error
   283  	p.next()
   284  	switch p.tok {
   285  	case token.RBRACK: // ]
   286  		if (inFlags & FlagIsStructField) != 0 {
   287  			n = 0
   288  		} else {
   289  			n = -1
   290  		}
   291  	case token.INT:
   292  		if n, err = strconv.ParseInt(p.lit, 10, 64); err != nil {
   293  			return nil, p.newError(err.Error())
   294  		}
   295  		if err = p.expect(token.RBRACK); err != nil { // ]
   296  			return nil, err
   297  		}
   298  	default:
   299  		return nil, p.newError("array length not an integer")
   300  	}
   301  	if n >= 0 || (inFlags&(FlagIsExtern|FlagIsTypedef|FlagIsParam)) != 0 {
   302  		t = types.NewArray(t, n)
   303  	} else {
   304  		return nil, p.newError(emsgDefArrWithoutLen)
   305  	}
   306  	return t, nil
   307  }
   308  
   309  func (p *parser) parseArrays(t types.Type, inFlags int) (ret types.Type, err error) {
   310  	if t == nil {
   311  		return nil, p.newError("array to nil")
   312  	}
   313  	var tyArr types.Type
   314  	for {
   315  		if tyArr, err = p.parseArray(tyArr, inFlags); err != nil {
   316  			return
   317  		}
   318  		if p.peek() != token.LBRACK {
   319  			return newArraysEx(t, tyArr, inFlags), nil
   320  		}
   321  		p.next()
   322  	}
   323  }
   324  
   325  func (p *parser) parseFunc(pkg *types.Package, t types.Type, inFlags int) (ret types.Type, err error) {
   326  	var results *types.Tuple
   327  	if ctypes.NotVoid(t) {
   328  		results = types.NewTuple(types.NewParam(token.NoPos, pkg, "", t))
   329  	}
   330  	args, variadic, err := p.parseArgs(pkg)
   331  	if err != nil {
   332  		return
   333  	}
   334  	_ = inFlags
   335  	return ctypes.NewFunc(types.NewTuple(args...), results, variadic), nil
   336  }
   337  
   338  func (p *parser) parseArgs(pkg *types.Package) (args []*types.Var, variadic bool, err error) {
   339  	for {
   340  		arg, kind, e := p.parse(FlagIsParam)
   341  		if e != nil {
   342  			return nil, false, e
   343  		}
   344  		if ctypes.NotVoid(arg) {
   345  			args = append(args, types.NewParam(token.NoPos, pkg, "", arg))
   346  		}
   347  		if p.tok != token.COMMA {
   348  			variadic = (kind & KindFVariadic) != 0
   349  			break
   350  		}
   351  	}
   352  	if p.tok != token.RPAREN { // )
   353  		return nil, false, p.newError("expect )")
   354  	}
   355  	return
   356  }
   357  
   358  func (p *parser) parseStars() (nstar int) {
   359  	for isPtr(p.peek()) {
   360  		p.next()
   361  		nstar++
   362  	}
   363  	return
   364  }
   365  
   366  func (p *parser) parse(inFlags int) (t types.Type, kind int, err error) {
   367  	flags := 0
   368  	for {
   369  		p.next()
   370  	retry:
   371  		switch p.tok {
   372  		case token.IDENT:
   373  		ident:
   374  			switch lit := p.lit; lit {
   375  			case "unsigned":
   376  				flags |= flagUnsigned
   377  			case "short":
   378  				flags |= flagShort
   379  			case "long":
   380  				if (flags & flagLong) != 0 {
   381  					flags |= flagLongLong
   382  				} else {
   383  					flags |= flagLong
   384  				}
   385  			case "signed":
   386  				flags |= flagSigned
   387  			case "const":
   388  				kind |= KindFConst
   389  			case "volatile":
   390  				kind |= KindFVolatile
   391  			case "_Complex":
   392  				flags |= flagComplex
   393  			case "restrict", "_Nullable", "_Nonnull":
   394  			case "enum":
   395  				if err = p.expect(token.IDENT); err != nil {
   396  					return
   397  				}
   398  				if t != nil {
   399  					return nil, 0, p.newError("illegal syntax: multiple types?")
   400  				}
   401  				t = ctypes.Int
   402  				continue
   403  			case "struct", "union":
   404  				p.next()
   405  				switch p.tok {
   406  				case token.IDENT:
   407  				case token.LPAREN:
   408  					if t == nil && p.conf.Anonym != nil {
   409  						p.skipUntil(token.RPAREN)
   410  						t = p.conf.Anonym
   411  						kind |= KindFAnonymous
   412  						continue
   413  					}
   414  					fallthrough
   415  				default:
   416  					log.Panicln("c.types.ParseType: struct/union - TODO:", p.lit)
   417  				}
   418  				lit = ctypes.MangledName(lit, p.lit)
   419  				flags |= flagStructOrUnion
   420  				fallthrough
   421  			default:
   422  				if t != nil {
   423  					return nil, 0, p.newError("illegal syntax: multiple types?")
   424  				}
   425  				if t, err = p.lookupType(lit, flags); err != nil {
   426  					return
   427  				}
   428  				flags = 0
   429  			}
   430  			if flags != 0 {
   431  				p.next()
   432  				if p.tok == token.IDENT {
   433  					goto ident
   434  				}
   435  				if t != nil {
   436  					return nil, 0, p.newError("illegal syntax: multiple types?")
   437  				}
   438  				if t, err = p.lookupType("int", flags); err != nil {
   439  					return
   440  				}
   441  				flags = 0
   442  				goto retry
   443  			}
   444  		case token.MUL: // *
   445  			if t == nil {
   446  				return nil, 0, p.newError("pointer to nil")
   447  			}
   448  			t = ctypes.NewPointer(t)
   449  		case token.LBRACK: // [
   450  			if t, err = p.parseArrays(t, inFlags); err != nil {
   451  				return
   452  			}
   453  		case token.LPAREN: // (
   454  			if t == nil {
   455  				log.Panicln("TODO")
   456  				return nil, 0, p.newError("no function return type")
   457  			}
   458  			var nstar = p.parseStars()
   459  			var nstarRet int
   460  			var tyArr types.Type
   461  			var pkg, isFn = p.conf.Pkg(), false
   462  			var args []*types.Var
   463  			var variadic bool
   464  			if nstar == 0 {
   465  				if getRetType(inFlags) {
   466  					err = nil
   467  					p.tok = token.EOF
   468  					return
   469  				}
   470  				if args, variadic, err = p.parseArgs(pkg); err != nil {
   471  					return
   472  				}
   473  				isFn = true
   474  			} else {
   475  			nextTok:
   476  				p.next()
   477  				switch p.tok {
   478  				case token.RPAREN: // )
   479  				case token.LPAREN: // (
   480  					if !isFn {
   481  						nstar, nstarRet = p.parseStars(), nstar
   482  						if nstar != 0 {
   483  							p.expect(token.RPAREN) // )
   484  							p.expect(token.LPAREN) // (
   485  						}
   486  						if args, variadic, err = p.parseArgs(pkg); err != nil {
   487  							return
   488  						}
   489  						isFn = true
   490  						goto nextTok
   491  					}
   492  					return nil, 0, p.newError("expect )")
   493  				case token.LBRACK:
   494  					if tyArr, err = p.parseArrays(ctypes.Void, 0); err != nil {
   495  						return
   496  					}
   497  					p.expect(token.RPAREN) // )
   498  				case token.IDENT:
   499  					switch p.lit {
   500  					case "_Nullable", "_Nonnull", "const", "volatile":
   501  						goto nextTok
   502  					}
   503  					fallthrough
   504  				default:
   505  					return nil, 0, p.newError("expect )")
   506  				}
   507  			}
   508  			p.next()
   509  			switch p.tok {
   510  			case token.LPAREN: // (
   511  				if t, err = p.parseFunc(pkg, t, inFlags); err != nil {
   512  					return
   513  				}
   514  			case token.LBRACK: // [
   515  				if t, err = p.parseArrays(t, 0); err != nil {
   516  					return
   517  				}
   518  			case token.EOF:
   519  			case token.IDENT:
   520  				if p.lit == "__attribute__" {
   521  					p.tok, p.lit = token.EOF, ""
   522  					p.unget(token.EOF, "")
   523  					break
   524  				}
   525  				fallthrough
   526  			default:
   527  				return nil, 0, p.newError("unexpected " + p.tok.String())
   528  			}
   529  			t = newPointers(t, nstarRet)
   530  			if isFn {
   531  				if getRetType(inFlags) {
   532  					p.tok = token.EOF
   533  					return
   534  				}
   535  				var results *types.Tuple
   536  				if ctypes.NotVoid(t) {
   537  					results = types.NewTuple(types.NewParam(token.NoPos, pkg, "", t))
   538  				}
   539  				t = ctypes.NewFunc(types.NewTuple(args...), results, variadic)
   540  			}
   541  			t = newPointers(t, nstar)
   542  			t = newArrays(t, tyArr)
   543  		case token.RPAREN:
   544  			if t == nil {
   545  				t = ctypes.Void
   546  			}
   547  			return
   548  		case token.COMMA, token.EOF:
   549  			if t == nil {
   550  				err = io.ErrUnexpectedEOF
   551  			}
   552  			return
   553  		case token.ELLIPSIS:
   554  			if t != nil {
   555  				return nil, 0, p.newError("illegal syntax: multiple types?")
   556  			}
   557  			t = ctypes.Valist
   558  			kind |= KindFVariadic
   559  		default:
   560  			log.Panicln("c.types.ParseType: unknown -", p.tok, p.lit)
   561  		}
   562  	}
   563  }
   564  
   565  func newPointers(t types.Type, nstar int) types.Type {
   566  	for nstar > 0 {
   567  		t = ctypes.NewPointer(t)
   568  		nstar--
   569  	}
   570  	return t
   571  }
   572  
   573  func isPtr(tok token.Token) bool {
   574  	return tok == token.MUL || tok == token.XOR // * or ^
   575  }
   576  
   577  func newArrays(t types.Type, tyArr types.Type) types.Type {
   578  retry:
   579  	if arr, ok := tyArr.(*types.Array); ok {
   580  		t = types.NewArray(t, arr.Len())
   581  		tyArr = arr.Elem()
   582  		goto retry
   583  	}
   584  	return t
   585  }
   586  
   587  func newArraysEx(t types.Type, tyArr types.Type, inFlags int) types.Type {
   588  	t = newArrays(t, tyArr)
   589  	if arr, ok := t.(*types.Array); ok {
   590  		if (inFlags & FlagIsParam) != 0 {
   591  			t = ctypes.NewPointer(arr.Elem())
   592  		}
   593  	}
   594  	return t
   595  }
   596  
   597  // -----------------------------------------------------------------------------