1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

strconv,v.gen.js: proper optionals returns, strconv compiles to the JS backend (#11364)

This commit is contained in:
playX 2021-09-03 12:16:07 +03:00 committed by GitHub
parent 227d12f1ac
commit 08c517c966
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 432 additions and 388 deletions

View File

@ -57,5 +57,9 @@ pub fn unwrap(opt string) string {
if o.state != 0 {
js_throw(o.err)
}
return opt
mut res := ''
#res = opt.data
return res
}

View File

@ -0,0 +1,9 @@
module builtin
pub fn utf8_str_visible_length(s string) int {
// todo: proper implementation
res := 0
#res.val = s.str.length;
return res
}

9
vlib/strconv/atof.js.v Normal file
View File

@ -0,0 +1,9 @@
module strconv
// atof64 return a f64 from a string doing a parsing operation
pub fn atof64(s string) f64 {
res := 0.0
#res.val = Number(s.str)
return res
}

1
vlib/strconv/atoi.js.v Normal file
View File

@ -0,0 +1 @@
module atoi

View File

@ -86,6 +86,7 @@ pub fn common_parse_uint2(s string, _base int, _bit_size int) (u64, int) {
for i in start_index .. s.len {
c := s[i]
cl := byte_to_lower(c)
mut d := byte(0)
if c == `_` && base0 {
// underscore_ok already called

384
vlib/strconv/utilities.c.v Normal file
View File

@ -0,0 +1,384 @@
module strconv
// import math
/*
f32/f64 to string utilities
Copyright (c) 2019-2021 Dario Deledda. All rights reserved.
Use of this source code is governed by an MIT license
that can be found in the LICENSE file.
This file contains the f32/f64 to string utilities functions
These functions are based on the work of:
Publication:PLDI 2018: Proceedings of the 39th ACM SIGPLAN
Conference on Programming Language Design and ImplementationJune 2018
Pages 270282 https://doi.org/10.1145/3192366.3192369
inspired by the Go version here:
https://github.com/cespare/ryu/tree/ba56a33f39e3bbbfa409095d0f9ae168a595feea
*/
/*
f64 to string with string format
*/
// TODO: Investigate precision issues
// f32_to_str_l return a string with the f32 converted in a string in decimal notation
[manualfree]
pub fn f32_to_str_l(f f32) string {
s := f32_to_str(f, 6)
res := fxx_to_str_l_parse(s)
unsafe { s.free() }
return res
}
[manualfree]
pub fn f32_to_str_l_no_dot(f f32) string {
s := f32_to_str(f, 6)
res := fxx_to_str_l_parse_no_dot(s)
unsafe { s.free() }
return res
}
[manualfree]
pub fn f64_to_str_l(f f64) string {
s := f64_to_str(f, 18)
res := fxx_to_str_l_parse(s)
unsafe { s.free() }
return res
}
[manualfree]
pub fn f64_to_str_l_no_dot(f f64) string {
s := f64_to_str(f, 18)
res := fxx_to_str_l_parse_no_dot(s)
unsafe { s.free() }
return res
}
// f64_to_str_l return a string with the f64 converted in a string in decimal notation
[manualfree]
pub fn fxx_to_str_l_parse(s string) string {
// check for +inf -inf Nan
if s.len > 2 && (s[0] == `n` || s[1] == `i`) {
return s.clone()
}
m_sgn_flag := false
mut sgn := 1
mut b := [26]byte{}
mut d_pos := 1
mut i := 0
mut i1 := 0
mut exp := 0
mut exp_sgn := 1
// get sign and decimal parts
for c in s {
if c == `-` {
sgn = -1
i++
} else if c == `+` {
sgn = 1
i++
} else if c >= `0` && c <= `9` {
b[i1] = c
i1++
i++
} else if c == `.` {
if sgn > 0 {
d_pos = i
} else {
d_pos = i - 1
}
i++
} else if c == `e` {
i++
break
} else {
return 'Float conversion error!!'
}
}
b[i1] = 0
// get exponent
if s[i] == `-` {
exp_sgn = -1
i++
} else if s[i] == `+` {
exp_sgn = 1
i++
}
mut c := i
for c < s.len {
exp = exp * 10 + int(s[c] - `0`)
c++
}
// allocate exp+32 chars for the return string
mut res := []byte{len: exp + 32, init: 0}
mut r_i := 0 // result string buffer index
// println("s:${sgn} b:${b[0]} es:${exp_sgn} exp:${exp}")
if sgn == 1 {
if m_sgn_flag {
res[r_i] = `+`
r_i++
}
} else {
res[r_i] = `-`
r_i++
}
i = 0
if exp_sgn >= 0 {
for b[i] != 0 {
res[r_i] = b[i]
r_i++
i++
if i >= d_pos && exp >= 0 {
if exp == 0 {
res[r_i] = `.`
r_i++
}
exp--
}
}
for exp >= 0 {
res[r_i] = `0`
r_i++
exp--
}
} else {
mut dot_p := true
for exp > 0 {
res[r_i] = `0`
r_i++
exp--
if dot_p {
res[r_i] = `.`
r_i++
dot_p = false
}
}
for b[i] != 0 {
res[r_i] = b[i]
r_i++
i++
}
}
/*
// remove the dot form the numbers like 2.
if r_i > 1 && res[r_i-1] == `.` {
r_i--
}
*/
res[r_i] = 0
return unsafe { tos(res.data, r_i) }
}
// f64_to_str_l return a string with the f64 converted in a string in decimal notation
[manualfree]
pub fn fxx_to_str_l_parse_no_dot(s string) string {
// check for +inf -inf Nan
if s.len > 2 && (s[0] == `n` || s[1] == `i`) {
return s.clone()
}
m_sgn_flag := false
mut sgn := 1
mut b := [26]byte{}
mut d_pos := 1
mut i := 0
mut i1 := 0
mut exp := 0
mut exp_sgn := 1
// get sign and decimal parts
for c in s {
if c == `-` {
sgn = -1
i++
} else if c == `+` {
sgn = 1
i++
} else if c >= `0` && c <= `9` {
b[i1] = c
i1++
i++
} else if c == `.` {
if sgn > 0 {
d_pos = i
} else {
d_pos = i - 1
}
i++
} else if c == `e` {
i++
break
} else {
return 'Float conversion error!!'
}
}
b[i1] = 0
// get exponent
if s[i] == `-` {
exp_sgn = -1
i++
} else if s[i] == `+` {
exp_sgn = 1
i++
}
mut c := i
for c < s.len {
exp = exp * 10 + int(s[c] - `0`)
c++
}
// allocate exp+32 chars for the return string
mut res := []byte{len: exp + 32, init: 0}
mut r_i := 0 // result string buffer index
// println("s:${sgn} b:${b[0]} es:${exp_sgn} exp:${exp}")
if sgn == 1 {
if m_sgn_flag {
res[r_i] = `+`
r_i++
}
} else {
res[r_i] = `-`
r_i++
}
i = 0
if exp_sgn >= 0 {
for b[i] != 0 {
res[r_i] = b[i]
r_i++
i++
if i >= d_pos && exp >= 0 {
if exp == 0 {
res[r_i] = `.`
r_i++
}
exp--
}
}
for exp >= 0 {
res[r_i] = `0`
r_i++
exp--
}
} else {
mut dot_p := true
for exp > 0 {
res[r_i] = `0`
r_i++
exp--
if dot_p {
res[r_i] = `.`
r_i++
dot_p = false
}
}
for b[i] != 0 {
res[r_i] = b[i]
r_i++
i++
}
}
// remove the dot form the numbers like 2.
if r_i > 1 && res[r_i - 1] == `.` {
r_i--
}
res[r_i] = 0
return unsafe { tos(res.data, r_i) }
}
// dec_digits return the number of decimal digit of an u64
pub fn dec_digits(n u64) int {
if n <= 9_999_999_999 { // 1-10
if n <= 99_999 { // 5
if n <= 99 { // 2
if n <= 9 { // 1
return 1
} else {
return 2
}
} else {
if n <= 999 { // 3
return 3
} else {
if n <= 9999 { // 4
return 4
} else {
return 5
}
}
}
} else {
if n <= 9_999_999 { // 7
if n <= 999_999 { // 6
return 6
} else {
return 7
}
} else {
if n <= 99_999_999 { // 8
return 8
} else {
if n <= 999_999_999 { // 9
return 9
}
return 10
}
}
}
} else {
if n <= 999_999_999_999_999 { // 5
if n <= 999_999_999_999 { // 2
if n <= 99_999_999_999 { // 1
return 11
} else {
return 12
}
} else {
if n <= 9_999_999_999_999 { // 3
return 13
} else {
if n <= 99_999_999_999_999 { // 4
return 14
} else {
return 15
}
}
}
} else {
if n <= 99_999_999_999_999_999 { // 7
if n <= 9_999_999_999_999_999 { // 6
return 16
} else {
return 17
}
} else {
if n <= 999_999_999_999_999_999 { // 8
return 18
} else {
if n <= 9_999_999_999_999_999_999 { // 9
return 19
}
return 20
}
}
}
}
}

View File

@ -1,25 +1,8 @@
module strconv
import math.bits
// import math
/*
f32/f64 to string utilities
Copyright (c) 2019-2021 Dario Deledda. All rights reserved.
Use of this source code is governed by an MIT license
that can be found in the LICENSE file.
This file contains the f32/f64 to string utilities functions
These functions are based on the work of:
Publication:PLDI 2018: Proceedings of the 39th ACM SIGPLAN
Conference on Programming Language Design and ImplementationJune 2018
Pages 270282 https://doi.org/10.1145/3192366.3192369
inspired by the Go version here:
https://github.com/cespare/ryu/tree/ba56a33f39e3bbbfa409095d0f9ae168a595feea
*/
// general utilities
// General Utilities
[if debug_strconv ?]
@ -191,366 +174,3 @@ fn multiple_of_power_of_five_64(v u64, p u32) bool {
fn multiple_of_power_of_two_64(v u64, p u32) bool {
return u32(bits.trailing_zeros_64(v)) >= p
}
/*
f64 to string with string format
*/
// TODO: Investigate precision issues
// f32_to_str_l return a string with the f32 converted in a string in decimal notation
[manualfree]
pub fn f32_to_str_l(f f32) string {
s := f32_to_str(f, 6)
res := fxx_to_str_l_parse(s)
unsafe { s.free() }
return res
}
[manualfree]
pub fn f32_to_str_l_no_dot(f f32) string {
s := f32_to_str(f, 6)
res := fxx_to_str_l_parse_no_dot(s)
unsafe { s.free() }
return res
}
[manualfree]
pub fn f64_to_str_l(f f64) string {
s := f64_to_str(f, 18)
res := fxx_to_str_l_parse(s)
unsafe { s.free() }
return res
}
[manualfree]
pub fn f64_to_str_l_no_dot(f f64) string {
s := f64_to_str(f, 18)
res := fxx_to_str_l_parse_no_dot(s)
unsafe { s.free() }
return res
}
// f64_to_str_l return a string with the f64 converted in a string in decimal notation
[manualfree]
pub fn fxx_to_str_l_parse(s string) string {
// check for +inf -inf Nan
if s.len > 2 && (s[0] == `n` || s[1] == `i`) {
return s.clone()
}
m_sgn_flag := false
mut sgn := 1
mut b := [26]byte{}
mut d_pos := 1
mut i := 0
mut i1 := 0
mut exp := 0
mut exp_sgn := 1
// get sign and decimal parts
for c in s {
if c == `-` {
sgn = -1
i++
} else if c == `+` {
sgn = 1
i++
} else if c >= `0` && c <= `9` {
b[i1] = c
i1++
i++
} else if c == `.` {
if sgn > 0 {
d_pos = i
} else {
d_pos = i - 1
}
i++
} else if c == `e` {
i++
break
} else {
return 'Float conversion error!!'
}
}
b[i1] = 0
// get exponent
if s[i] == `-` {
exp_sgn = -1
i++
} else if s[i] == `+` {
exp_sgn = 1
i++
}
mut c := i
for c < s.len {
exp = exp * 10 + int(s[c] - `0`)
c++
}
// allocate exp+32 chars for the return string
mut res := []byte{len: exp + 32, init: 0}
mut r_i := 0 // result string buffer index
// println("s:${sgn} b:${b[0]} es:${exp_sgn} exp:${exp}")
if sgn == 1 {
if m_sgn_flag {
res[r_i] = `+`
r_i++
}
} else {
res[r_i] = `-`
r_i++
}
i = 0
if exp_sgn >= 0 {
for b[i] != 0 {
res[r_i] = b[i]
r_i++
i++
if i >= d_pos && exp >= 0 {
if exp == 0 {
res[r_i] = `.`
r_i++
}
exp--
}
}
for exp >= 0 {
res[r_i] = `0`
r_i++
exp--
}
} else {
mut dot_p := true
for exp > 0 {
res[r_i] = `0`
r_i++
exp--
if dot_p {
res[r_i] = `.`
r_i++
dot_p = false
}
}
for b[i] != 0 {
res[r_i] = b[i]
r_i++
i++
}
}
/*
// remove the dot form the numbers like 2.
if r_i > 1 && res[r_i-1] == `.` {
r_i--
}
*/
res[r_i] = 0
return unsafe { tos(res.data, r_i) }
}
// f64_to_str_l return a string with the f64 converted in a string in decimal notation
[manualfree]
pub fn fxx_to_str_l_parse_no_dot(s string) string {
// check for +inf -inf Nan
if s.len > 2 && (s[0] == `n` || s[1] == `i`) {
return s.clone()
}
m_sgn_flag := false
mut sgn := 1
mut b := [26]byte{}
mut d_pos := 1
mut i := 0
mut i1 := 0
mut exp := 0
mut exp_sgn := 1
// get sign and decimal parts
for c in s {
if c == `-` {
sgn = -1
i++
} else if c == `+` {
sgn = 1
i++
} else if c >= `0` && c <= `9` {
b[i1] = c
i1++
i++
} else if c == `.` {
if sgn > 0 {
d_pos = i
} else {
d_pos = i - 1
}
i++
} else if c == `e` {
i++
break
} else {
return 'Float conversion error!!'
}
}
b[i1] = 0
// get exponent
if s[i] == `-` {
exp_sgn = -1
i++
} else if s[i] == `+` {
exp_sgn = 1
i++
}
mut c := i
for c < s.len {
exp = exp * 10 + int(s[c] - `0`)
c++
}
// allocate exp+32 chars for the return string
mut res := []byte{len: exp + 32, init: 0}
mut r_i := 0 // result string buffer index
// println("s:${sgn} b:${b[0]} es:${exp_sgn} exp:${exp}")
if sgn == 1 {
if m_sgn_flag {
res[r_i] = `+`
r_i++
}
} else {
res[r_i] = `-`
r_i++
}
i = 0
if exp_sgn >= 0 {
for b[i] != 0 {
res[r_i] = b[i]
r_i++
i++
if i >= d_pos && exp >= 0 {
if exp == 0 {
res[r_i] = `.`
r_i++
}
exp--
}
}
for exp >= 0 {
res[r_i] = `0`
r_i++
exp--
}
} else {
mut dot_p := true
for exp > 0 {
res[r_i] = `0`
r_i++
exp--
if dot_p {
res[r_i] = `.`
r_i++
dot_p = false
}
}
for b[i] != 0 {
res[r_i] = b[i]
r_i++
i++
}
}
// remove the dot form the numbers like 2.
if r_i > 1 && res[r_i - 1] == `.` {
r_i--
}
res[r_i] = 0
return unsafe { tos(res.data, r_i) }
}
// dec_digits return the number of decimal digit of an u64
pub fn dec_digits(n u64) int {
if n <= 9_999_999_999 { // 1-10
if n <= 99_999 { // 5
if n <= 99 { // 2
if n <= 9 { // 1
return 1
} else {
return 2
}
} else {
if n <= 999 { // 3
return 3
} else {
if n <= 9999 { // 4
return 4
} else {
return 5
}
}
}
} else {
if n <= 9_999_999 { // 7
if n <= 999_999 { // 6
return 6
} else {
return 7
}
} else {
if n <= 99_999_999 { // 8
return 8
} else {
if n <= 999_999_999 { // 9
return 9
}
return 10
}
}
}
} else {
if n <= 999_999_999_999_999 { // 5
if n <= 999_999_999_999 { // 2
if n <= 99_999_999_999 { // 1
return 11
} else {
return 12
}
} else {
if n <= 9_999_999_999_999 { // 3
return 13
} else {
if n <= 99_999_999_999_999 { // 4
return 14
} else {
return 15
}
}
}
} else {
if n <= 99_999_999_999_999_999 { // 7
if n <= 9_999_999_999_999_999 { // 6
return 16
} else {
return 17
}
} else {
if n <= 999_999_999_999_999_999 { // 8
return 18
} else {
if n <= 9_999_999_999_999_999_999 { // 9
return 19
}
return 20
}
}
}
}
}

View File

@ -856,8 +856,7 @@ fn (mut g JsGen) expr(node ast.Expr) {
g.gen_type_cast_expr(node)
}
ast.CharLiteral {
// todo(playX): char type?
g.write("new builtin.string('$node.val')")
g.write("new builtin.byte('$node.val')")
}
ast.Comment {}
ast.ConcatExpr {
@ -1673,7 +1672,23 @@ fn (mut g JsGen) gen_return_stmt(it ast.Return) {
return
}
}
if fn_return_is_optional {
tmp := g.new_tmp_var()
g.write('const $tmp = new ')
if g.ns.name != 'builtin' {
g.write('builtin.')
}
g.writeln('Option({});')
g.write('${tmp}.data = ')
if it.exprs.len == 1 {
g.expr(it.exprs[0])
} else { // Multi return
g.gen_array_init_values(it.exprs)
}
g.writeln('')
g.write('return $tmp;')
return
}
g.write('return ')
if it.exprs.len == 1 {
g.expr(it.exprs[0])

View File

@ -135,8 +135,8 @@ true
0
2
-1
1
2
-1
-1
-1
2
3
@ -226,7 +226,7 @@ true
true
[1, 3, 5, hi]
[-3, 7, 42, 67, 108]
[a, b, c, d, e, f]
[97, 98, 99, 100, 101, 102]
0
1
79

View File

@ -542,6 +542,7 @@ pub fn parse_args(known_external_commands []string, args []string) (&Preferences
res.out_name = cmdline.option(current_args, arg, '')
if res.out_name.ends_with('.js') {
res.backend = .js_node
res.output_cross_c = true
}
if !os.is_abs_path(res.out_name) {
res.out_name = os.join_path(os.getwd(), res.out_name)