all: byte.str() => byte.ascii_str()
parent
fdb6f1ab50
commit
5a70eba8e1
|
@ -5,7 +5,7 @@ fn test_clone() {
|
|||
assert b[0] == 0
|
||||
assert b[1] == 1
|
||||
assert b[2] == 2
|
||||
println(b[1].str() )
|
||||
println(b[1].ascii_str())
|
||||
println(typeof(`A`))
|
||||
x := rune(`A`)
|
||||
assert x.str() == 'A'
|
||||
|
@ -15,5 +15,4 @@ fn test_clone() {
|
|||
assert typeof(y) == 'rune'
|
||||
assert y.str() == 'Z'
|
||||
// assert b[1].str() == '1' TODO
|
||||
|
||||
}
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
module csv
|
||||
|
||||
// Once interfaces are further along the idea would be to have something similar to
|
||||
// go's io.reader & bufio.reader rather than reading the whole file into string, this
|
||||
// would then satisfy that interface. I designed it this way to be easily adapted.
|
||||
|
||||
const (
|
||||
err_comment_is_delim = error('encoding.csv: comment cannot be the same as delimiter')
|
||||
err_invalid_delim = error('encoding.csv: invalid delimiter')
|
||||
|
@ -15,8 +13,7 @@ const (
|
|||
err_invalid_le = error('encoding.csv: could not find any valid line endings')
|
||||
)
|
||||
|
||||
|
||||
struct Reader {
|
||||
struct Reader {
|
||||
// not used yet
|
||||
// has_header bool
|
||||
// headings []string
|
||||
|
@ -31,8 +28,8 @@ pub mut:
|
|||
// new_reader initializes a Reader with string data to parse
|
||||
pub fn new_reader(data string) &Reader {
|
||||
return &Reader{
|
||||
delimiter: `,`,
|
||||
comment: `#`,
|
||||
delimiter: `,`
|
||||
comment: `#`
|
||||
data: data
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +37,7 @@ pub fn new_reader(data string) &Reader {
|
|||
// read reads a row from the CSV data.
|
||||
// If successful, the result holds an array of each column's data.
|
||||
pub fn (mut r Reader) read() ?[]string {
|
||||
l := r.read_record()?
|
||||
l := r.read_record() ?
|
||||
return l
|
||||
}
|
||||
|
||||
|
@ -59,7 +56,6 @@ pub fn (mut r Reader) read() ?[]string {
|
|||
// }
|
||||
// return records
|
||||
// }
|
||||
|
||||
fn (mut r Reader) read_line() ?string {
|
||||
// last record
|
||||
if r.row_pos == r.data.len {
|
||||
|
@ -79,14 +75,14 @@ fn (mut r Reader) read_line() ?string {
|
|||
}
|
||||
} else {
|
||||
// No line ending on file
|
||||
i = r.data.len-1
|
||||
i = r.data.len - 1
|
||||
}
|
||||
}
|
||||
mut line := r.data[r.row_pos..i]
|
||||
r.row_pos = i+1
|
||||
r.row_pos = i + 1
|
||||
// normalize win line endings (remove extra \r)
|
||||
if !r.is_mac_pre_osx_le && (line.len >= 1 && line[line.len-1] == `\r`) {
|
||||
line = line[..line.len-1]
|
||||
if !r.is_mac_pre_osx_le && (line.len >= 1 && line[line.len - 1] == `\r`) {
|
||||
line = line[..line.len - 1]
|
||||
}
|
||||
return line
|
||||
}
|
||||
|
@ -103,47 +99,51 @@ fn (mut r Reader) read_record() ?[]string {
|
|||
mut line := ''
|
||||
mut fields := []string{}
|
||||
mut i := -1
|
||||
|
||||
for {
|
||||
if need_read {
|
||||
l := r.read_line()?
|
||||
l := r.read_line() ?
|
||||
if l.len <= 0 {
|
||||
if keep_raw { line += '\n'}
|
||||
if keep_raw {
|
||||
line += '\n'
|
||||
}
|
||||
continue
|
||||
} else if l[0] == r.comment {
|
||||
if keep_raw { line += '\n' + l }
|
||||
if keep_raw {
|
||||
line += '\n' + l
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
if keep_raw { line += '\n'}
|
||||
if keep_raw {
|
||||
line += '\n'
|
||||
}
|
||||
line += l
|
||||
}
|
||||
need_read = false
|
||||
keep_raw = false
|
||||
}
|
||||
|
||||
if line[0] != `"` { // not quoted
|
||||
j := line.index(r.delimiter.str()) or {
|
||||
if line[0] != `"` { // not quoted
|
||||
j := line.index(r.delimiter.ascii_str()) or {
|
||||
// last
|
||||
fields << line[..line.len]
|
||||
break
|
||||
}
|
||||
i = j
|
||||
fields << line[..i]
|
||||
line = line[i+1..]
|
||||
line = line[i + 1..]
|
||||
continue
|
||||
} else { // quoted
|
||||
} else { // quoted
|
||||
j := line[1..].index('"') or {
|
||||
need_read = true
|
||||
keep_raw = true
|
||||
continue
|
||||
}
|
||||
line = line[1..]
|
||||
if j+1 == line.len {
|
||||
if j + 1 == line.len {
|
||||
// last record
|
||||
fields << line[..j]
|
||||
break
|
||||
}
|
||||
next := line[j+1]
|
||||
next := line[j + 1]
|
||||
if next == r.delimiter {
|
||||
fields << line[..j]
|
||||
line = line[j..]
|
||||
|
@ -159,8 +159,5 @@ fn (mut r Reader) read_record() ?[]string {
|
|||
}
|
||||
|
||||
fn valid_delim(b byte) bool {
|
||||
return b != 0 &&
|
||||
b != `"` &&
|
||||
b != `\r` &&
|
||||
b != `\n`
|
||||
return b != 0 && b != `"` && b != `\r` && b != `\n`
|
||||
}
|
||||
|
|
|
@ -1,22 +1,21 @@
|
|||
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
module csv
|
||||
|
||||
import strings
|
||||
|
||||
struct Writer {
|
||||
mut:
|
||||
sb strings.Builder
|
||||
sb strings.Builder
|
||||
pub mut:
|
||||
use_crlf bool
|
||||
use_crlf bool
|
||||
delimiter byte
|
||||
}
|
||||
|
||||
pub fn new_writer() &Writer {
|
||||
return &Writer{
|
||||
delimiter: `,`,
|
||||
delimiter: `,`
|
||||
sb: strings.new_builder(200)
|
||||
}
|
||||
}
|
||||
|
@ -30,34 +29,25 @@ pub fn (mut w Writer) write(record []string) ?bool {
|
|||
for n, field_ in record {
|
||||
mut field := field_
|
||||
if n > 0 {
|
||||
w.sb.write(w.delimiter.str())
|
||||
w.sb.write(w.delimiter.ascii_str())
|
||||
}
|
||||
|
||||
if !w.field_needs_quotes(field) {
|
||||
w.sb.write(field)
|
||||
continue
|
||||
}
|
||||
|
||||
w.sb.write('"')
|
||||
|
||||
for field.len > 0 {
|
||||
mut i := field.index_any('"\r\n')
|
||||
if i < 0 {
|
||||
i = field.len
|
||||
}
|
||||
|
||||
w.sb.write(field[..i])
|
||||
field = field[i..]
|
||||
|
||||
if field.len > 0 {
|
||||
z := field[0]
|
||||
match z {
|
||||
`"` {
|
||||
w.sb.write('""')
|
||||
}
|
||||
`\r`, `\n` {
|
||||
w.sb.write(le)
|
||||
}
|
||||
`"` { w.sb.write('""') }
|
||||
`\r`, `\n` { w.sb.write(le) }
|
||||
else {}
|
||||
}
|
||||
field = field[1..]
|
||||
|
@ -65,7 +55,6 @@ pub fn (mut w Writer) write(record []string) ?bool {
|
|||
}
|
||||
w.sb.write('"')
|
||||
}
|
||||
|
||||
w.sb.write(le)
|
||||
return true
|
||||
}
|
||||
|
@ -76,12 +65,11 @@ pub fn (mut w Writer) write(record []string) ?bool {
|
|||
// w.write(record)
|
||||
// }
|
||||
// }
|
||||
|
||||
fn (w &Writer) field_needs_quotes(field string) bool {
|
||||
if field == '' {
|
||||
return false
|
||||
}
|
||||
if field.contains(w.delimiter.str()) || (field.index_any('"\r\n') != -1) {
|
||||
if field.contains(w.delimiter.ascii_str()) || (field.index_any('"\r\n') != -1) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
|
|
@ -210,7 +210,7 @@ fn unescape(s_ string, mode EncodingMode) ?string {
|
|||
x := s[i]
|
||||
match x {
|
||||
`%` {
|
||||
t.write(((unhex(s[i + 1]) << byte(4)) | unhex(s[i + 2])).str())
|
||||
t.write(((unhex(s[i + 1]) << byte(4)) | unhex(s[i + 2])).ascii_str())
|
||||
i += 2
|
||||
}
|
||||
`+` {
|
||||
|
@ -221,7 +221,7 @@ fn unescape(s_ string, mode EncodingMode) ?string {
|
|||
}
|
||||
}
|
||||
else {
|
||||
t.write(s[i].str())
|
||||
t.write(s[i].ascii_str())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -315,14 +315,14 @@ fn escape(s string, mode EncodingMode) string {
|
|||
pub struct URL {
|
||||
pub mut:
|
||||
scheme string
|
||||
opaque string // encoded opaque data
|
||||
opaque string // encoded opaque data
|
||||
user &Userinfo // username and password information
|
||||
host string // host or host:port
|
||||
path string // path (relative paths may omit leading slash)
|
||||
raw_path string // encoded path hint (see escaped_path method)
|
||||
force_query bool // append a query ('?') even if raw_query is empty
|
||||
raw_query string // encoded query values, without '?'
|
||||
fragment string // fragment for references, without '#'
|
||||
host string // host or host:port
|
||||
path string // path (relative paths may omit leading slash)
|
||||
raw_path string // encoded path hint (see escaped_path method)
|
||||
force_query bool // append a query ('?') even if raw_query is empty
|
||||
raw_query string // encoded query values, without '?'
|
||||
fragment string // fragment for references, without '#'
|
||||
}
|
||||
|
||||
// user returns a Userinfo containing the provided username
|
||||
|
@ -402,9 +402,7 @@ fn split_by_scheme(rawurl string) ?[]string {
|
|||
}
|
||||
|
||||
fn get_scheme(rawurl string) ?string {
|
||||
split := split_by_scheme(rawurl) or {
|
||||
return err
|
||||
}
|
||||
split := split_by_scheme(rawurl) or { return err }
|
||||
return split[0]
|
||||
}
|
||||
|
||||
|
@ -431,15 +429,11 @@ fn split(s string, sep byte, cutc bool) (string, string) {
|
|||
pub fn parse(rawurl string) ?URL {
|
||||
// Cut off #frag
|
||||
u, frag := split(rawurl, `#`, true)
|
||||
mut url := parse_url(u, false) or {
|
||||
return error(error_msg(err_msg_parse, u))
|
||||
}
|
||||
mut url := parse_url(u, false) or { return error(error_msg(err_msg_parse, u)) }
|
||||
if frag == '' {
|
||||
return url
|
||||
}
|
||||
f := unescape(frag, .encode_fragment) or {
|
||||
return error(error_msg(err_msg_parse, u))
|
||||
}
|
||||
f := unescape(frag, .encode_fragment) or { return error(error_msg(err_msg_parse, u)) }
|
||||
url.fragment = f
|
||||
return url
|
||||
}
|
||||
|
@ -501,12 +495,8 @@ fn parse_url(rawurl string, via_request bool) ?URL {
|
|||
// RFC 3986, §3.3:
|
||||
// In addition, a URI reference (Section 4.1) may be a relative-path reference,
|
||||
// in which case the first path segment cannot contain a colon (':') character.
|
||||
colon := rest.index(':') or {
|
||||
return error('there should be a : in the URL')
|
||||
}
|
||||
slash := rest.index('/') or {
|
||||
return error('there should be a / in the URL')
|
||||
}
|
||||
colon := rest.index(':') or { return error('there should be a : in the URL') }
|
||||
slash := rest.index('/') or { return error('there should be a / in the URL') }
|
||||
if colon >= 0 && (slash < 0 || colon < slash) {
|
||||
// First path segment has colon. Not allowed in relative URL.
|
||||
return error(error_msg('parse_url: first path segment in URL cannot contain colon',
|
||||
|
@ -534,9 +524,7 @@ struct ParseAuthorityRes {
|
|||
}
|
||||
|
||||
fn parse_authority(authority string) ?ParseAuthorityRes {
|
||||
i := authority.last_index('@') or {
|
||||
-1
|
||||
}
|
||||
i := authority.last_index('@') or { -1 }
|
||||
mut host := ''
|
||||
mut zuser := user('')
|
||||
if i < 0 {
|
||||
|
@ -595,15 +583,9 @@ fn parse_host(host string) ?string {
|
|||
// We do impose some restrictions on the zone, to avoid stupidity
|
||||
// like newlines.
|
||||
if zone := host[..i].index('%25') {
|
||||
host1 := unescape(host[..zone], .encode_host) or {
|
||||
return err
|
||||
}
|
||||
host2 := unescape(host[zone..i], .encode_zone) or {
|
||||
return err
|
||||
}
|
||||
host3 := unescape(host[i..], .encode_host) or {
|
||||
return err
|
||||
}
|
||||
host1 := unescape(host[..zone], .encode_host) or { return err }
|
||||
host2 := unescape(host[zone..i], .encode_zone) or { return err }
|
||||
host3 := unescape(host[i..], .encode_host) or { return err }
|
||||
return host1 + host2 + host3
|
||||
}
|
||||
if idx := host.last_index(':') {
|
||||
|
@ -614,9 +596,7 @@ fn parse_host(host string) ?string {
|
|||
}
|
||||
}
|
||||
}
|
||||
h := unescape(host, .encode_host) or {
|
||||
return err
|
||||
}
|
||||
h := unescape(host, .encode_host) or { return err }
|
||||
return h
|
||||
// host = h
|
||||
// return host
|
||||
|
@ -654,9 +634,7 @@ pub fn (mut u URL) set_path(p string) ?bool {
|
|||
// reading u.raw_path directly.
|
||||
fn (u &URL) escaped_path() string {
|
||||
if u.raw_path != '' && valid_encoded_path(u.raw_path) {
|
||||
unescape(u.raw_path, .encode_path) or {
|
||||
return ''
|
||||
}
|
||||
unescape(u.raw_path, .encode_path) or { return '' }
|
||||
return u.raw_path
|
||||
}
|
||||
if u.path == '*' {
|
||||
|
@ -883,9 +861,7 @@ fn resolve_path(base string, ref string) string {
|
|||
if ref == '' {
|
||||
full = base
|
||||
} else if ref[0] != `/` {
|
||||
i := base.last_index('/') or {
|
||||
-1
|
||||
}
|
||||
i := base.last_index('/') or { -1 }
|
||||
full = base[..i + 1] + ref
|
||||
} else {
|
||||
full = ref
|
||||
|
@ -1050,8 +1026,12 @@ pub fn valid_userinfo(s string) bool {
|
|||
continue
|
||||
}
|
||||
match r {
|
||||
`-`, `.`, `_`, `:`, `~`, `!`, `$`, `&`, `\\`, `(`, `)`, `*`, `+`, `,`, `;`, `=`, `%`, `@` { continue }
|
||||
else { return false }
|
||||
`-`, `.`, `_`, `:`, `~`, `!`, `$`, `&`, `\\`, `(`, `)`, `*`, `+`, `,`, `;`, `=`, `%`, `@` {
|
||||
continue
|
||||
}
|
||||
else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
|
|
@ -1224,7 +1224,7 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
|
|||
}
|
||||
/*
|
||||
if left_type == table.byte_type && method_name == 'str' {
|
||||
c.warn('byte str', call_expr.pos)
|
||||
c.error('byte str', call_expr.pos)
|
||||
}
|
||||
*/
|
||||
// TODO: remove this for actual methods, use only for compiler magic
|
||||
|
|
Loading…
Reference in New Issue