Skip to content

Commit fff175c

Browse files
authored
builtin: Implement builtin_ascii (#66)
1 parent bd0985b commit fff175c

File tree

3 files changed

+77
-49
lines changed

3 files changed

+77
-49
lines changed

builtin/builtin.go

+14-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ func init() {
2424
py.MustNewMethod("abs", builtin_abs, 0, abs_doc),
2525
py.MustNewMethod("all", builtin_all, 0, all_doc),
2626
py.MustNewMethod("any", builtin_any, 0, any_doc),
27-
// py.MustNewMethod("ascii", builtin_ascii, 0, ascii_doc),
27+
py.MustNewMethod("ascii", builtin_ascii, 0, ascii_doc),
2828
// py.MustNewMethod("bin", builtin_bin, 0, bin_doc),
2929
// py.MustNewMethod("callable", builtin_callable, 0, callable_doc),
3030
py.MustNewMethod("chr", builtin_chr, 0, chr_doc),
@@ -309,6 +309,19 @@ func builtin_any(self, seq py.Object) (py.Object, error) {
309309
return py.False, nil
310310
}
311311

312+
const ascii_doc = `
313+
`
314+
315+
func builtin_ascii(self, o py.Object) (py.Object, error) {
316+
reprObj, err := py.Repr(o)
317+
if err != nil {
318+
return nil, err
319+
}
320+
repr := reprObj.(py.String)
321+
out := py.StringEscape(repr, true)
322+
return py.String(out), err
323+
}
324+
312325
const round_doc = `round(number[, ndigits]) -> number
313326
314327
Round a number to a given precision in decimal digits (default 0 digits).

builtin/tests/builtin.py

+6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919
assert any(["hello", "world"]) == True
2020
assert any([]) == False
2121

22+
doc="ascii"
23+
assert ascii('hello world') == "'hello world'"
24+
assert ascii('안녕 세상') == "'\\uc548\\ub155 \\uc138\\uc0c1'"
25+
assert ascii(chr(0x10001)) == "'\\U00010001'"
26+
assert ascii('안녕 gpython') == "'\\uc548\\ub155 gpython'"
27+
2228
doc="chr"
2329
assert chr(65) == "A"
2430
assert chr(163) == "£"

py/string.go

+57-48
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,61 @@ or repr(object).
3535
encoding defaults to sys.getdefaultencoding().
3636
errors defaults to 'strict'.`, StrNew, nil)
3737

38+
// Escape the py.String
39+
func StringEscape(a String, ascii bool) string {
40+
s := string(a)
41+
var out bytes.Buffer
42+
quote := '\''
43+
if strings.ContainsRune(s, '\'') && !strings.ContainsRune(s, '"') {
44+
quote = '"'
45+
}
46+
if !ascii {
47+
out.WriteRune(quote)
48+
}
49+
for _, c := range s {
50+
switch {
51+
case c < 0x20:
52+
switch c {
53+
case '\t':
54+
out.WriteString(`\t`)
55+
case '\n':
56+
out.WriteString(`\n`)
57+
case '\r':
58+
out.WriteString(`\r`)
59+
default:
60+
fmt.Fprintf(&out, `\x%02x`, c)
61+
}
62+
case !ascii && c < 0x7F:
63+
if c == '\\' || (quote == '\'' && c == '\'') || (quote == '"' && c == '"') {
64+
out.WriteRune('\\')
65+
}
66+
out.WriteRune(c)
67+
case c < 0x100:
68+
if ascii || strconv.IsPrint(c) {
69+
out.WriteRune(c)
70+
} else {
71+
fmt.Fprintf(&out, "\\x%02x", c)
72+
}
73+
case c < 0x10000:
74+
if !ascii && strconv.IsPrint(c) {
75+
out.WriteRune(c)
76+
} else {
77+
fmt.Fprintf(&out, "\\u%04x", c)
78+
}
79+
default:
80+
if !ascii && strconv.IsPrint(c) {
81+
out.WriteRune(c)
82+
} else {
83+
fmt.Fprintf(&out, "\\U%08x", c)
84+
}
85+
}
86+
}
87+
if !ascii {
88+
out.WriteRune(quote)
89+
}
90+
return out.String()
91+
}
92+
3893
// standard golang strings.Fields doesn't have a 'first N' argument
3994
func fieldsN(s string, n int) []string {
4095
out := []string{}
@@ -194,54 +249,8 @@ func (a String) M__str__() (Object, error) {
194249
}
195250

196251
func (a String) M__repr__() (Object, error) {
197-
// FIXME combine this with parser/stringescape.go into file in py?
198-
s := string(a)
199-
var out bytes.Buffer
200-
quote := '\''
201-
if strings.ContainsRune(s, '\'') && !strings.ContainsRune(s, '"') {
202-
quote = '"'
203-
}
204-
out.WriteRune(quote)
205-
for _, c := range s {
206-
switch {
207-
case c < 0x20:
208-
switch c {
209-
case '\t':
210-
out.WriteString(`\t`)
211-
case '\n':
212-
out.WriteString(`\n`)
213-
case '\r':
214-
out.WriteString(`\r`)
215-
default:
216-
fmt.Fprintf(&out, `\x%02x`, c)
217-
}
218-
case c < 0x7F:
219-
if c == '\\' || (quote == '\'' && c == '\'') || (quote == '"' && c == '"') {
220-
out.WriteRune('\\')
221-
}
222-
out.WriteRune(c)
223-
case c < 0x100:
224-
if strconv.IsPrint(c) {
225-
out.WriteRune(c)
226-
} else {
227-
fmt.Fprintf(&out, "\\x%02x", c)
228-
}
229-
case c < 0x10000:
230-
if strconv.IsPrint(c) {
231-
out.WriteRune(c)
232-
} else {
233-
fmt.Fprintf(&out, "\\u%04x", c)
234-
}
235-
default:
236-
if strconv.IsPrint(c) {
237-
out.WriteRune(c)
238-
} else {
239-
fmt.Fprintf(&out, "\\U%08x", c)
240-
}
241-
}
242-
}
243-
out.WriteRune(quote)
244-
return String(out.String()), nil
252+
out := StringEscape(a, false)
253+
return String(out), nil
245254
}
246255

247256
func (s String) M__bool__() (Object, error) {

0 commit comments

Comments
 (0)