1// Copyright 2020 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package strconv
6
7import "internal/stringslite"
8
9const fnParseComplex = "ParseComplex"
10
11// convErr splits an error returned by parseFloatPrefix
12// into a syntax or range error for ParseComplex.
13func convErr(err error, s string) (syntax, range_ error) {
14	if x, ok := err.(*NumError); ok {
15		x.Func = fnParseComplex
16		x.Num = stringslite.Clone(s)
17		if x.Err == ErrRange {
18			return nil, x
19		}
20	}
21	return err, nil
22}
23
24// ParseComplex converts the string s to a complex number
25// with the precision specified by bitSize: 64 for complex64, or 128 for complex128.
26// When bitSize=64, the result still has type complex128, but it will be
27// convertible to complex64 without changing its value.
28//
29// The number represented by s must be of the form N, Ni, or N±Ni, where N stands
30// for a floating-point number as recognized by [ParseFloat], and i is the imaginary
31// component. If the second N is unsigned, a + sign is required between the two components
32// as indicated by the ±. If the second N is NaN, only a + sign is accepted.
33// The form may be parenthesized and cannot contain any spaces.
34// The resulting complex number consists of the two components converted by ParseFloat.
35//
36// The errors that ParseComplex returns have concrete type [*NumError]
37// and include err.Num = s.
38//
39// If s is not syntactically well-formed, ParseComplex returns err.Err = ErrSyntax.
40//
41// If s is syntactically well-formed but either component is more than 1/2 ULP
42// away from the largest floating point number of the given component's size,
43// ParseComplex returns err.Err = ErrRange and c = ±Inf for the respective component.
44func ParseComplex(s string, bitSize int) (complex128, error) {
45	size := 64
46	if bitSize == 64 {
47		size = 32 // complex64 uses float32 parts
48	}
49
50	orig := s
51
52	// Remove parentheses, if any.
53	if len(s) >= 2 && s[0] == '(' && s[len(s)-1] == ')' {
54		s = s[1 : len(s)-1]
55	}
56
57	var pending error // pending range error, or nil
58
59	// Read real part (possibly imaginary part if followed by 'i').
60	re, n, err := parseFloatPrefix(s, size)
61	if err != nil {
62		err, pending = convErr(err, orig)
63		if err != nil {
64			return 0, err
65		}
66	}
67	s = s[n:]
68
69	// If we have nothing left, we're done.
70	if len(s) == 0 {
71		return complex(re, 0), pending
72	}
73
74	// Otherwise, look at the next character.
75	switch s[0] {
76	case '+':
77		// Consume the '+' to avoid an error if we have "+NaNi", but
78		// do this only if we don't have a "++" (don't hide that error).
79		if len(s) > 1 && s[1] != '+' {
80			s = s[1:]
81		}
82	case '-':
83		// ok
84	case 'i':
85		// If 'i' is the last character, we only have an imaginary part.
86		if len(s) == 1 {
87			return complex(0, re), pending
88		}
89		fallthrough
90	default:
91		return 0, syntaxError(fnParseComplex, orig)
92	}
93
94	// Read imaginary part.
95	im, n, err := parseFloatPrefix(s, size)
96	if err != nil {
97		err, pending = convErr(err, orig)
98		if err != nil {
99			return 0, err
100		}
101	}
102	s = s[n:]
103	if s != "i" {
104		return 0, syntaxError(fnParseComplex, orig)
105	}
106	return complex(re, im), pending
107}
108