github.com/goplus/llgo@v0.8.3/chore/llpyg/pysig/parse.go (about)

     1  /*
     2   * Copyright (c) 2024 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 pysig
    18  
    19  import (
    20  	"strings"
    21  )
    22  
    23  type Arg struct {
    24  	Name   string
    25  	Type   string
    26  	DefVal string
    27  }
    28  
    29  // Parse parses a Python function signature.
    30  func Parse(sig string) (args []*Arg) {
    31  	sig = strings.TrimPrefix(sig, "(")
    32  	for {
    33  		pos := strings.IndexAny(sig, ",:=)")
    34  		if pos <= 0 {
    35  			return
    36  		}
    37  		arg := &Arg{Name: strings.TrimSpace(sig[:pos])}
    38  		args = append(args, arg)
    39  		c := sig[pos]
    40  		sig = sig[pos+1:]
    41  		switch c {
    42  		case ',':
    43  			continue
    44  		case ':':
    45  			arg.Type, sig = parseType(sig)
    46  			if strings.HasPrefix(sig, "=") {
    47  				arg.DefVal, sig = parseDefVal(sig[1:])
    48  			}
    49  		case '=':
    50  			arg.DefVal, sig = parseDefVal(sig)
    51  		case ')':
    52  			return
    53  		}
    54  		sig = strings.TrimPrefix(sig, ",")
    55  	}
    56  }
    57  
    58  const (
    59  	allSpecials = "([<'\""
    60  )
    61  
    62  var pairStops = map[byte]string{
    63  	'(':  ")" + allSpecials,
    64  	'[':  "]" + allSpecials,
    65  	'<':  ">" + allSpecials,
    66  	'\'': "'" + allSpecials,
    67  	'"':  "\"",
    68  }
    69  
    70  func parseText(sig string, stops string) (left string) {
    71  	for {
    72  		pos := strings.IndexAny(sig, stops)
    73  		if pos < 0 {
    74  			return sig
    75  		}
    76  		if c := sig[pos]; c != stops[0] {
    77  			if pstop, ok := pairStops[c]; ok {
    78  				sig = strings.TrimPrefix(parseText(sig[pos+1:], pstop), pstop[:1])
    79  				continue
    80  			}
    81  		}
    82  		return sig[pos:]
    83  	}
    84  }
    85  
    86  // stops: "=,)"
    87  func parseType(sig string) (string, string) {
    88  	left := parseText(sig, "=,)"+allSpecials)
    89  	return resultOf(sig, left), left
    90  }
    91  
    92  // stops: ",)"
    93  func parseDefVal(sig string) (string, string) {
    94  	left := parseText(sig, ",)"+allSpecials)
    95  	return resultOf(sig, left), left
    96  }
    97  
    98  func resultOf(sig, left string) string {
    99  	return strings.TrimSpace(sig[:len(sig)-len(left)])
   100  }