parent
603e57745f
commit
d8d05e0106
|
@ -24,6 +24,7 @@ const (
|
||||||
'examples/sokol/03_march_tracing_glsl/rt_glsl.v',
|
'examples/sokol/03_march_tracing_glsl/rt_glsl.v',
|
||||||
'examples/sokol/04_multi_shader_glsl/rt_glsl.v',
|
'examples/sokol/04_multi_shader_glsl/rt_glsl.v',
|
||||||
'examples/sokol/05_instancing_glsl/rt_glsl.v',
|
'examples/sokol/05_instancing_glsl/rt_glsl.v',
|
||||||
|
'examples/sokol/06_obj_viewer/show_obj.v',
|
||||||
'vlib/gg/m4/graphic.v',
|
'vlib/gg/m4/graphic.v',
|
||||||
'vlib/gg/m4/m4_test.v',
|
'vlib/gg/m4/m4_test.v',
|
||||||
'vlib/gg/m4/matrix.v',
|
'vlib/gg/m4/matrix.v',
|
||||||
|
|
|
@ -336,4 +336,4 @@ fn main() {
|
||||||
|
|
||||||
app.ticks = time.ticks()
|
app.ticks = time.ticks()
|
||||||
app.gg.run()
|
app.gg.run()
|
||||||
}
|
}
|
|
@ -12,6 +12,17 @@ import strconv
|
||||||
// str return a `f64` as `string` in suitable notation.
|
// str return a `f64` as `string` in suitable notation.
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (x f64) str() string {
|
pub fn (x f64) str() string {
|
||||||
|
unsafe {
|
||||||
|
f := strconv.Float64u{
|
||||||
|
f: x
|
||||||
|
}
|
||||||
|
if f.u == strconv.double_minus_zero {
|
||||||
|
return '-0'
|
||||||
|
}
|
||||||
|
if f.u == strconv.double_plus_zero {
|
||||||
|
return '0'
|
||||||
|
}
|
||||||
|
}
|
||||||
abs_x := f64_abs(x)
|
abs_x := f64_abs(x)
|
||||||
if abs_x >= 0.0001 && abs_x < 1.0e6 {
|
if abs_x >= 0.0001 && abs_x < 1.0e6 {
|
||||||
return strconv.f64_to_str_l(x)
|
return strconv.f64_to_str_l(x)
|
||||||
|
@ -20,6 +31,20 @@ pub fn (x f64) str() string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// strg return a `f64` as `string` in "g" printf format
|
||||||
|
[inline]
|
||||||
|
pub fn (x f64) strg() string {
|
||||||
|
if x == 0 {
|
||||||
|
return '0'
|
||||||
|
}
|
||||||
|
abs_x := f64_abs(x)
|
||||||
|
if abs_x >= 0.0001 && abs_x < 1.0e6 {
|
||||||
|
return strconv.f64_to_str_l_no_dot(x)
|
||||||
|
} else {
|
||||||
|
return strconv.ftoa_64(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// str returns the value of the `float_literal` as a `string`.
|
// str returns the value of the `float_literal` as a `string`.
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (d float_literal) str() string {
|
pub fn (d float_literal) str() string {
|
||||||
|
@ -53,6 +78,17 @@ pub fn (x f64) strlong() string {
|
||||||
// str returns a `f32` as `string` in suitable notation.
|
// str returns a `f32` as `string` in suitable notation.
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (x f32) str() string {
|
pub fn (x f32) str() string {
|
||||||
|
unsafe {
|
||||||
|
f := strconv.Float32u{
|
||||||
|
f: x
|
||||||
|
}
|
||||||
|
if f.u == strconv.single_minus_zero {
|
||||||
|
return '-0'
|
||||||
|
}
|
||||||
|
if f.u == strconv.single_plus_zero {
|
||||||
|
return '0'
|
||||||
|
}
|
||||||
|
}
|
||||||
abs_x := f32_abs(x)
|
abs_x := f32_abs(x)
|
||||||
if abs_x >= 0.0001 && abs_x < 1.0e6 {
|
if abs_x >= 0.0001 && abs_x < 1.0e6 {
|
||||||
return strconv.f32_to_str_l(x)
|
return strconv.f32_to_str_l(x)
|
||||||
|
@ -61,6 +97,20 @@ pub fn (x f32) str() string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// strg return a `f32` as `string` in "g" printf format
|
||||||
|
[inline]
|
||||||
|
pub fn (x f32) strg() string {
|
||||||
|
if x == 0 {
|
||||||
|
return '0'
|
||||||
|
}
|
||||||
|
abs_x := f32_abs(x)
|
||||||
|
if abs_x >= 0.0001 && abs_x < 1.0e6 {
|
||||||
|
return strconv.f32_to_str_l_no_dot(x)
|
||||||
|
} else {
|
||||||
|
return strconv.ftoa_32(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// strsci returns the `f32` as a `string` in scientific notation with `digit_num` deciamals displayed, max 8 digits.
|
// strsci returns the `f32` as a `string` in scientific notation with `digit_num` deciamals displayed, max 8 digits.
|
||||||
// Example: assert f32(1.234).strsci(3) == '1.234e+00'
|
// Example: assert f32(1.234).strsci(3) == '1.234e+00'
|
||||||
[inline]
|
[inline]
|
||||||
|
|
|
@ -0,0 +1,674 @@
|
||||||
|
/*=============================================================================
|
||||||
|
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 string interpolation V functions
|
||||||
|
=============================================================================*/
|
||||||
|
|
||||||
|
module builtin
|
||||||
|
|
||||||
|
import strconv
|
||||||
|
import strings
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// Enum format types max 0x1F => 32 types
|
||||||
|
//=============================================================================
|
||||||
|
pub enum StrIntpType {
|
||||||
|
si_no_str = 0 // no parameter to print only fix string
|
||||||
|
si_c
|
||||||
|
si_u8
|
||||||
|
si_i8
|
||||||
|
si_u16
|
||||||
|
si_i16
|
||||||
|
si_u32
|
||||||
|
si_i32
|
||||||
|
si_u64
|
||||||
|
si_i64
|
||||||
|
si_e32
|
||||||
|
si_e64
|
||||||
|
si_f32
|
||||||
|
si_f64
|
||||||
|
si_g32
|
||||||
|
si_g64
|
||||||
|
si_s
|
||||||
|
si_p
|
||||||
|
si_vp
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (x StrIntpType) str() string {
|
||||||
|
match x {
|
||||||
|
.si_no_str { return 'no_str' }
|
||||||
|
.si_c { return 'c' }
|
||||||
|
.si_u8 { return 'u8' }
|
||||||
|
.si_i8 { return 'i8' }
|
||||||
|
.si_u16 { return 'u16' }
|
||||||
|
.si_i16 { return 'i16' }
|
||||||
|
.si_u32 { return 'u32' }
|
||||||
|
.si_i32 { return 'i32' }
|
||||||
|
.si_u64 { return 'u64' }
|
||||||
|
.si_i64 { return 'i64' }
|
||||||
|
.si_f32 { return 'f32' }
|
||||||
|
.si_f64 { return 'f64' }
|
||||||
|
.si_g32 { return 'f32' } // g32 format use f32 data
|
||||||
|
.si_g64 { return 'f64' } // g64 format use f64 data
|
||||||
|
.si_e32 { return 'f32' } // e32 format use f32 data
|
||||||
|
.si_e64 { return 'f64' } // e64 format use f64 data
|
||||||
|
.si_s { return 's' }
|
||||||
|
.si_p { return 'p' }
|
||||||
|
.si_vp { return 'vp' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
pub fn (x StrIntpType) data_str() string {
|
||||||
|
match x {
|
||||||
|
.si_no_str{ return "no_str" }
|
||||||
|
.si_c { return "d_c" }
|
||||||
|
|
||||||
|
.si_u8 { return "d_u8" }
|
||||||
|
.si_i8 { return "d_i8" }
|
||||||
|
.si_u16 { return "d_u16" }
|
||||||
|
.si_i16 { return "d_i16" }
|
||||||
|
.si_u32 { return "d_u32" }
|
||||||
|
.si_i32 { return "d_i32" }
|
||||||
|
.si_u64 { return "d_u64" }
|
||||||
|
.si_i64 { return "d_i64" }
|
||||||
|
|
||||||
|
.si_f32 { return "d_f32" }
|
||||||
|
.si_f64 { return "d_f64" }
|
||||||
|
.si_g32 { return "d_f32" } // g32 format use f32 data
|
||||||
|
.si_g64 { return "d_f64" } // g64 format use f64 data
|
||||||
|
.si_e32 { return "d_f32" } // e32 format use f32 data
|
||||||
|
.si_e64 { return "d_f64" } // e64 format use f64 data
|
||||||
|
|
||||||
|
.si_s { return "d_s" }
|
||||||
|
.si_p { return "d_p" }
|
||||||
|
.si_vp { return "d_vp" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// Union data
|
||||||
|
//=============================================================================
|
||||||
|
pub union StrIntpMem {
|
||||||
|
pub mut:
|
||||||
|
d_c u32
|
||||||
|
d_u8 byte
|
||||||
|
d_i8 i8
|
||||||
|
d_u16 u16
|
||||||
|
d_i16 i16
|
||||||
|
d_u32 u32
|
||||||
|
d_i32 int
|
||||||
|
d_u64 u64
|
||||||
|
d_i64 i64
|
||||||
|
d_f32 f32
|
||||||
|
d_f64 f64
|
||||||
|
d_s string
|
||||||
|
d_p voidptr
|
||||||
|
d_vp voidptr
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fabs64(x f64) f64 {
|
||||||
|
if x < 0 {
|
||||||
|
return -x
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fabs32(x f32) f32 {
|
||||||
|
if x < 0 {
|
||||||
|
return -x
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn abs64(x i64) u64 {
|
||||||
|
if x < 0 {
|
||||||
|
return u64(-x)
|
||||||
|
}
|
||||||
|
return u64(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================
|
||||||
|
//
|
||||||
|
// u32/u64 bit compact format
|
||||||
|
//
|
||||||
|
//___ 32 24 16 8
|
||||||
|
//___ | | | |
|
||||||
|
//_3333333333222222222211111111110000000000
|
||||||
|
//_9876543210987654321098765432109876543210
|
||||||
|
//_nPPPPPPPPBBBBWWWWWWWWWWTDDDDDDDSUAA=====
|
||||||
|
// = data type 5 bit max 32 data type
|
||||||
|
// A allign 2 bit Note: for now only 1 used!
|
||||||
|
// U uppercase 1 bit 0 do nothing, 1 do to_upper()
|
||||||
|
// S sign 1 bit show the sign if positive
|
||||||
|
// D decimals 7 bit number of decimals digit to show
|
||||||
|
// T tail zeros 1 bit 1 remove tail zeros, 0 do nothing
|
||||||
|
// W Width 10 bit number of char for padding and indentation
|
||||||
|
// B num base 4 bit start from 2, 0 for base 10
|
||||||
|
// P pad char 1/8 bit padding char (in u32 format reduced to 1 bit as flag for `0` padding)
|
||||||
|
// --------------
|
||||||
|
// TOTAL: 39/32 bit
|
||||||
|
//=========================================
|
||||||
|
|
||||||
|
// convert from data format to compact u64
|
||||||
|
pub fn get_str_intp_u64_format(fmt_type StrIntpType, in_width int, in_precision int, in_tail_zeros bool, in_sign bool, in_pad_ch u8, in_base int, in_upper_case bool) u64 {
|
||||||
|
width := if in_width != 0 { abs64(in_width) } else { u64(0) }
|
||||||
|
allign := if in_width > 0 { u64(1 << 5) } else { u64(0) } // two bit 0 .left 1 .rigth, for now we use only one
|
||||||
|
upper_case := if in_upper_case { u64(1 << 7) } else { u64(0) }
|
||||||
|
sign := if in_sign { u64(1 << 8) } else { u64(0) }
|
||||||
|
precision := if in_precision != 987698 {
|
||||||
|
(u64(in_precision & 0x7F) << 9)
|
||||||
|
} else {
|
||||||
|
u64(0x7F) << 9
|
||||||
|
}
|
||||||
|
tail_zeros := if in_tail_zeros { u32(1) << 16 } else { u32(0) }
|
||||||
|
base := u64((in_base & 0xf) << 27)
|
||||||
|
res := u64((u64(fmt_type) & 0x1F) | allign | upper_case | sign | precision | tail_zeros | (u64(width & 0x3FF) << 17) | base | (u64(in_pad_ch) << 31))
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert from data format to compact u32
|
||||||
|
pub fn get_str_intp_u32_format(fmt_type StrIntpType, in_width int, in_precision int, in_tail_zeros bool, in_sign bool, in_pad_ch u8, in_base int, in_upper_case bool) u32 {
|
||||||
|
width := if in_width != 0 { abs64(in_width) } else { u32(0) }
|
||||||
|
allign := if in_width > 0 { u32(1 << 5) } else { u32(0) } // two bit 0 .left 1 .rigth, for now we use only one
|
||||||
|
upper_case := if in_upper_case { u32(1 << 7) } else { u32(0) }
|
||||||
|
sign := if in_sign { u32(1 << 8) } else { u32(0) }
|
||||||
|
precision := if in_precision != 987698 {
|
||||||
|
(u32(in_precision & 0x7F) << 9)
|
||||||
|
} else {
|
||||||
|
u32(0x7F) << 9
|
||||||
|
}
|
||||||
|
tail_zeros := if in_tail_zeros { u32(1) << 16 } else { u32(0) }
|
||||||
|
base := u32((in_base & 0xf) << 27)
|
||||||
|
res := u32((u32(fmt_type) & 0x1F) | allign | upper_case | sign | precision | tail_zeros | (u32(width & 0x3FF) << 17) | base | (u32(in_pad_ch & 1) << 31))
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert from struct to formated string
|
||||||
|
[manualfree]
|
||||||
|
fn (data StrIntpData) get_fmt_format(mut sb strings.Builder) {
|
||||||
|
x := data.fmt
|
||||||
|
typ := StrIntpType(x & 0x1F)
|
||||||
|
allign := int((x >> 5) & 0x01)
|
||||||
|
upper_case := if ((x >> 7) & 0x01) > 0 { true } else { false }
|
||||||
|
sign := int((x >> 8) & 0x01)
|
||||||
|
precision := int((x >> 9) & 0x7F)
|
||||||
|
tail_zeros := if ((x >> 16) & 0x01) > 0 { true } else { false }
|
||||||
|
width := int(i16((x >> 17) & 0x3FF))
|
||||||
|
mut base := int(x >> 27) & 0xF
|
||||||
|
fmt_pad_ch := byte((x >> 31) & 0xFF)
|
||||||
|
|
||||||
|
// no string interpolation is needed, return empty string
|
||||||
|
if typ == .si_no_str {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// if width > 0 { println("${x.hex()} Type: ${x & 0x7F} Width: ${width} Precision: ${precision} allign:${allign}") }
|
||||||
|
|
||||||
|
// manage base if any
|
||||||
|
if base > 0 {
|
||||||
|
base += 2 // we start from 2, 0 == base 10
|
||||||
|
}
|
||||||
|
|
||||||
|
// mange pad char, for now only 0 allowed
|
||||||
|
mut pad_ch := byte(` `)
|
||||||
|
if fmt_pad_ch > 0 {
|
||||||
|
// pad_ch = fmt_pad_ch
|
||||||
|
pad_ch = `0`
|
||||||
|
}
|
||||||
|
|
||||||
|
len0_set := if width > 0 { width } else { -1 }
|
||||||
|
len1_set := if precision == 0x7F { -1 } else { precision }
|
||||||
|
sign_set := if sign == 1 { true } else { false }
|
||||||
|
|
||||||
|
mut bf := strconv.BF_param{
|
||||||
|
pad_ch: pad_ch // padding char
|
||||||
|
len0: len0_set // default len for whole the number or string
|
||||||
|
len1: len1_set // number of decimal digits, if needed
|
||||||
|
positive: true // mandatory: the sign of the number passed
|
||||||
|
sign_flag: sign_set // flag for print sign as prefix in padding
|
||||||
|
allign: .left // alignment of the string
|
||||||
|
rm_tail_zero: tail_zeros // false // remove the tail zeros from floats
|
||||||
|
}
|
||||||
|
|
||||||
|
// allign
|
||||||
|
if fmt_pad_ch == 0 {
|
||||||
|
match allign {
|
||||||
|
0 { bf.allign = .left }
|
||||||
|
1 { bf.allign = .right }
|
||||||
|
// 2 { bf.allign = .center }
|
||||||
|
else { bf.allign = .left }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bf.allign = .right
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
// strings
|
||||||
|
if typ == .si_s {
|
||||||
|
mut s := ''
|
||||||
|
if upper_case {
|
||||||
|
s = data.d.d_s.to_upper()
|
||||||
|
} else {
|
||||||
|
s = data.d.d_s.clone()
|
||||||
|
}
|
||||||
|
if width == 0 {
|
||||||
|
sb.write_string(s)
|
||||||
|
} else {
|
||||||
|
strconv.format_str_sb(s, bf, mut sb)
|
||||||
|
}
|
||||||
|
s.free()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// signed int
|
||||||
|
if typ in [.si_i8, .si_i16, .si_i32, .si_i64] {
|
||||||
|
mut d := data.d.d_i64
|
||||||
|
if typ == .si_i8 {
|
||||||
|
d = i64(data.d.d_i8)
|
||||||
|
} else if typ == .si_i16 {
|
||||||
|
d = i64(data.d.d_i16)
|
||||||
|
} else if typ == .si_i32 {
|
||||||
|
d = i64(data.d.d_i32)
|
||||||
|
}
|
||||||
|
|
||||||
|
if base == 0 {
|
||||||
|
if width == 0 {
|
||||||
|
d_str := d.str()
|
||||||
|
sb.write_string(d_str)
|
||||||
|
d_str.free()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if d < 0 {
|
||||||
|
bf.positive = false
|
||||||
|
}
|
||||||
|
strconv.format_dec_sb(abs64(d), bf, mut sb)
|
||||||
|
} else {
|
||||||
|
mut hx := strconv.format_int(d, base)
|
||||||
|
if upper_case {
|
||||||
|
tmp := hx
|
||||||
|
hx = hx.to_upper()
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
if width == 0 {
|
||||||
|
sb.write_string(hx)
|
||||||
|
} else {
|
||||||
|
strconv.format_str_sb(hx, bf, mut sb)
|
||||||
|
}
|
||||||
|
hx.free()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsigned int and pointers
|
||||||
|
if typ in [.si_u8, .si_u16, .si_u32, .si_u64] {
|
||||||
|
mut d := data.d.d_u64
|
||||||
|
if typ == .si_u8 {
|
||||||
|
d = u64(data.d.d_u8)
|
||||||
|
} else if typ == .si_u16 {
|
||||||
|
d = u64(data.d.d_u16)
|
||||||
|
} else if typ == .si_u32 {
|
||||||
|
d = u64(data.d.d_u32)
|
||||||
|
}
|
||||||
|
if base == 0 {
|
||||||
|
if width == 0 {
|
||||||
|
d_str := d.str()
|
||||||
|
sb.write_string(d_str)
|
||||||
|
d_str.free()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strconv.format_dec_sb(d, bf, mut sb)
|
||||||
|
} else {
|
||||||
|
mut hx := strconv.format_uint(d, base)
|
||||||
|
if upper_case {
|
||||||
|
tmp := hx
|
||||||
|
hx = hx.to_upper()
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
if width == 0 {
|
||||||
|
sb.write_string(hx)
|
||||||
|
} else {
|
||||||
|
strconv.format_str_sb(hx, bf, mut sb)
|
||||||
|
}
|
||||||
|
hx.free()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// pointers
|
||||||
|
if typ == .si_p {
|
||||||
|
mut d := data.d.d_u64
|
||||||
|
base = 16 // TODO: **** decide the behaviour of this flag! ****
|
||||||
|
if base == 0 {
|
||||||
|
if width == 0 {
|
||||||
|
d_str := d.str()
|
||||||
|
sb.write_string(d_str)
|
||||||
|
d_str.free()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strconv.format_dec_sb(d, bf, mut sb)
|
||||||
|
} else {
|
||||||
|
mut hx := strconv.format_uint(d, base)
|
||||||
|
if upper_case {
|
||||||
|
tmp := hx
|
||||||
|
hx = hx.to_upper()
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
if width == 0 {
|
||||||
|
sb.write_string(hx)
|
||||||
|
} else {
|
||||||
|
strconv.format_str_sb(hx, bf, mut sb)
|
||||||
|
}
|
||||||
|
hx.free()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// default settings for floats
|
||||||
|
mut use_default_str := false
|
||||||
|
if width == 0 && precision == 0x7F {
|
||||||
|
bf.len1 = 3
|
||||||
|
use_default_str = true
|
||||||
|
}
|
||||||
|
if bf.len1 < 0 {
|
||||||
|
bf.len1 = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
match typ {
|
||||||
|
// floating point
|
||||||
|
.si_f32 {
|
||||||
|
// println("HERE: f32")
|
||||||
|
if use_default_str {
|
||||||
|
mut f := data.d.d_f32.str()
|
||||||
|
if upper_case {
|
||||||
|
tmp := f
|
||||||
|
f = f.to_upper()
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
sb.write_string(f)
|
||||||
|
f.free()
|
||||||
|
} else {
|
||||||
|
// println("HERE: f32 format")
|
||||||
|
// println(data.d.d_f32)
|
||||||
|
if data.d.d_f32 < 0 {
|
||||||
|
bf.positive = false
|
||||||
|
}
|
||||||
|
mut f := strconv.format_fl(data.d.d_f32, bf)
|
||||||
|
if upper_case {
|
||||||
|
tmp := f
|
||||||
|
f = f.to_upper()
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
sb.write_string(f)
|
||||||
|
f.free()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.si_f64 {
|
||||||
|
// println("HERE: f64")
|
||||||
|
if use_default_str {
|
||||||
|
mut f := data.d.d_f64.str()
|
||||||
|
if upper_case {
|
||||||
|
tmp := f
|
||||||
|
f = f.to_upper()
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
sb.write_string(f)
|
||||||
|
f.free()
|
||||||
|
} else {
|
||||||
|
if data.d.d_f64 < 0 {
|
||||||
|
bf.positive = false
|
||||||
|
}
|
||||||
|
f_union := strconv.Float64u{
|
||||||
|
f: data.d.d_f64
|
||||||
|
}
|
||||||
|
if f_union.u == strconv.double_minus_zero {
|
||||||
|
bf.positive = false
|
||||||
|
}
|
||||||
|
|
||||||
|
mut f := strconv.format_fl(data.d.d_f64, bf)
|
||||||
|
if upper_case {
|
||||||
|
tmp := f
|
||||||
|
f = f.to_upper()
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
sb.write_string(f)
|
||||||
|
f.free()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.si_g32 {
|
||||||
|
// println("HERE: g32")
|
||||||
|
if use_default_str {
|
||||||
|
mut f := data.d.d_f32.strg()
|
||||||
|
if upper_case {
|
||||||
|
tmp := f
|
||||||
|
f = f.to_upper()
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
sb.write_string(f)
|
||||||
|
f.free()
|
||||||
|
} else {
|
||||||
|
if data.d.d_f32 < 0 {
|
||||||
|
bf.positive = false
|
||||||
|
}
|
||||||
|
d := fabs32(data.d.d_f32)
|
||||||
|
if d < 999_999.0 && d >= 0.00001 {
|
||||||
|
mut f := strconv.format_fl(data.d.d_f32, bf)
|
||||||
|
if upper_case {
|
||||||
|
tmp := f
|
||||||
|
f = f.to_upper()
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
sb.write_string(f)
|
||||||
|
f.free()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mut f := strconv.format_es(data.d.d_f32, bf)
|
||||||
|
if upper_case {
|
||||||
|
tmp := f
|
||||||
|
f = f.to_upper()
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
sb.write_string(f)
|
||||||
|
f.free()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.si_g64 {
|
||||||
|
// println("HERE: g64")
|
||||||
|
if use_default_str {
|
||||||
|
mut f := data.d.d_f64.strg()
|
||||||
|
if upper_case {
|
||||||
|
tmp := f
|
||||||
|
f = f.to_upper()
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
sb.write_string(f)
|
||||||
|
f.free()
|
||||||
|
} else {
|
||||||
|
if data.d.d_f64 < 0 {
|
||||||
|
bf.positive = false
|
||||||
|
}
|
||||||
|
d := fabs64(data.d.d_f64)
|
||||||
|
if d < 999_999.0 && d >= 0.00001 {
|
||||||
|
mut f := strconv.format_fl(data.d.d_f64, bf)
|
||||||
|
if upper_case {
|
||||||
|
tmp := f
|
||||||
|
f = f.to_upper()
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
sb.write_string(f)
|
||||||
|
f.free()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mut f := strconv.format_es(data.d.d_f64, bf)
|
||||||
|
if upper_case {
|
||||||
|
tmp := f
|
||||||
|
f = f.to_upper()
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
sb.write_string(f)
|
||||||
|
f.free()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.si_e32 {
|
||||||
|
// println("HERE: e32")
|
||||||
|
bf.len1 = 6
|
||||||
|
if use_default_str {
|
||||||
|
mut f := data.d.d_f32.str()
|
||||||
|
if upper_case {
|
||||||
|
tmp := f
|
||||||
|
f = f.to_upper()
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
sb.write_string(f)
|
||||||
|
f.free()
|
||||||
|
} else {
|
||||||
|
if data.d.d_f32 < 0 {
|
||||||
|
bf.positive = false
|
||||||
|
}
|
||||||
|
mut f := strconv.format_es(data.d.d_f32, bf)
|
||||||
|
if upper_case {
|
||||||
|
tmp := f
|
||||||
|
f = f.to_upper()
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
sb.write_string(f)
|
||||||
|
f.free()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.si_e64 {
|
||||||
|
// println("HERE: e64")
|
||||||
|
bf.len1 = 6
|
||||||
|
if use_default_str {
|
||||||
|
mut f := data.d.d_f64.str()
|
||||||
|
if upper_case {
|
||||||
|
tmp := f
|
||||||
|
f = f.to_upper()
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
sb.write_string(f)
|
||||||
|
f.free()
|
||||||
|
} else {
|
||||||
|
if data.d.d_f64 < 0 {
|
||||||
|
bf.positive = false
|
||||||
|
}
|
||||||
|
mut f := strconv.format_es(data.d.d_f64, bf)
|
||||||
|
if upper_case {
|
||||||
|
tmp := f
|
||||||
|
f = f.to_upper()
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
sb.write_string(f)
|
||||||
|
f.free()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// runes
|
||||||
|
.si_c {
|
||||||
|
sb.write_string(utf32_to_str(data.d.d_c))
|
||||||
|
}
|
||||||
|
// v pointers
|
||||||
|
.si_vp {
|
||||||
|
sb.write_string(u64(data.d.d_vp).hex())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sb.write_string('***ERROR!***')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//====================================================================================
|
||||||
|
|
||||||
|
// storing struct used by cgen
|
||||||
|
pub struct StrIntpCgenData {
|
||||||
|
pub:
|
||||||
|
str string
|
||||||
|
fmt string
|
||||||
|
d string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: LOW LEVEL struct
|
||||||
|
// storing struct passed to V in the C code
|
||||||
|
pub struct StrIntpData {
|
||||||
|
pub:
|
||||||
|
str string
|
||||||
|
// fmt u64 // expanded version for future use, 64 bit
|
||||||
|
fmt u32
|
||||||
|
d StrIntpMem
|
||||||
|
}
|
||||||
|
|
||||||
|
// interpolation function
|
||||||
|
[manualfree]
|
||||||
|
pub fn str_intp(data_len int, in_data voidptr) string {
|
||||||
|
mut res := strings.new_builder(256)
|
||||||
|
unsafe {
|
||||||
|
mut i := 0
|
||||||
|
for i < data_len {
|
||||||
|
data := &StrIntpData(&byte(in_data) + (int(sizeof(StrIntpData)) * i))
|
||||||
|
// avoid empty strings
|
||||||
|
if data.str.len != 0 {
|
||||||
|
res.write_string(data.str)
|
||||||
|
}
|
||||||
|
// skip empty data
|
||||||
|
if data.fmt != 0 {
|
||||||
|
data.get_fmt_format(mut &res)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret := res.str()
|
||||||
|
unsafe { res.free() }
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
//====================================================================================
|
||||||
|
// Utility for the compiler "auto_str_methods.v"
|
||||||
|
//====================================================================================
|
||||||
|
|
||||||
|
// substitute old _STR calls
|
||||||
|
|
||||||
|
pub const (
|
||||||
|
// BUG: this const is not released from the memory! use a const for now
|
||||||
|
// si_s_code = "0x" + int(StrIntpType.si_s).hex() // code for a simple string
|
||||||
|
si_s_code = '0xfe10'
|
||||||
|
si_g32_code = '0xfe0e'
|
||||||
|
si_g64_code = '0xfe0f'
|
||||||
|
)
|
||||||
|
|
||||||
|
// replace _STR("\'%.*s\\000\'", 2, in_str)
|
||||||
|
[inline]
|
||||||
|
pub fn str_intp_sq(in_str string) string {
|
||||||
|
return 'str_intp(2, _MOV((StrIntpData[]){{_SLIT("\'"), $si_s_code, {.d_s = $in_str}},{_SLIT("\'"), 0, {.d_c = 0 }}}))'
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace _STR("\`%.*s\\000\`", 2, in_str)
|
||||||
|
[inline]
|
||||||
|
pub fn str_intp_rune(in_str string) string {
|
||||||
|
return 'str_intp(2, _MOV((StrIntpData[]){{_SLIT("\`"), $si_s_code, {.d_s = $in_str}},{_SLIT("\`"), 0, {.d_c = 0 }}}))'
|
||||||
|
}
|
||||||
|
|
||||||
|
[inline]
|
||||||
|
pub fn str_intp_g32(in_str string) string {
|
||||||
|
return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT(""), $si_g32_code, {.d_f32 = $in_str }}}))'
|
||||||
|
}
|
||||||
|
|
||||||
|
[inline]
|
||||||
|
pub fn str_intp_g64(in_str string) string {
|
||||||
|
return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT(""), $si_g64_code, {.d_f64 = $in_str }}}))'
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace %% with the in_str
|
||||||
|
pub fn str_intp_sub(base_str string, in_str string) string {
|
||||||
|
index := base_str.index('%%') or {
|
||||||
|
eprintln('No strin interpolation %% parameteres')
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
// return base_str[..index] + in_str + base_str[index+2..]
|
||||||
|
if index + 2 < base_str.len {
|
||||||
|
return 'str_intp(2, _MOV((StrIntpData[]){{_SLIT("${base_str[..index]}"), $si_s_code, {.d_s = $in_str }},{_SLIT("${base_str[
|
||||||
|
index + 2..]}"), 0, {.d_c = 0}}}))'
|
||||||
|
}
|
||||||
|
return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT("${base_str[..index]}"), $si_s_code, {.d_s = $in_str }}}))'
|
||||||
|
}
|
|
@ -18,8 +18,8 @@ pub fn complex(re f64, im f64) Complex {
|
||||||
|
|
||||||
// To String method
|
// To String method
|
||||||
pub fn (c Complex) str() string {
|
pub fn (c Complex) str() string {
|
||||||
mut out := '${c.re:f}'
|
mut out := '${c.re:.6f}'
|
||||||
out += if c.im >= 0 { '+${c.im:f}' } else { '${c.im:f}' }
|
out += if c.im >= 0 { '+${c.im:.6f}' } else { '${c.im:.6f}' }
|
||||||
out += 'i'
|
out += 'i'
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,14 @@ fn sub96(s2 u32, s1 u32, s0 u32, d2 u32, d1 u32, d0 u32) (u32, u32, u32) {
|
||||||
Constants
|
Constants
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const (
|
pub const (
|
||||||
|
//
|
||||||
|
// f32 constants
|
||||||
|
//
|
||||||
|
single_plus_zero = u32(0x0000_0000)
|
||||||
|
single_minus_zero = u32(0x8000_0000)
|
||||||
|
single_plus_infinity = u32(0x7F80_0000)
|
||||||
|
single_minus_infinity = u32(0xFF80_0000)
|
||||||
//
|
//
|
||||||
// f64 constants
|
// f64 constants
|
||||||
//
|
//
|
||||||
|
@ -407,6 +414,7 @@ Public functions
|
||||||
|
|
||||||
// atof64 return a f64 from a string doing a parsing operation
|
// atof64 return a f64 from a string doing a parsing operation
|
||||||
pub fn atof64(s string) f64 {
|
pub fn atof64(s string) f64 {
|
||||||
|
|
||||||
mut pn := PrepNumber{}
|
mut pn := PrepNumber{}
|
||||||
mut res_parsing := 0
|
mut res_parsing := 0
|
||||||
mut res := Float64u{}
|
mut res := Float64u{}
|
||||||
|
|
|
@ -164,7 +164,7 @@ fn f32_to_decimal_exact_int(i_mant u32, exp u32) (Dec32,bool) {
|
||||||
return d, true
|
return d, true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn f32_to_decimal(mant u32, exp u32) Dec32 {
|
fn f32_to_decimal(mant u32, exp u32) Dec32 {
|
||||||
mut e2 := 0
|
mut e2 := 0
|
||||||
mut m2 := u32(0)
|
mut m2 := u32(0)
|
||||||
if exp == 0 {
|
if exp == 0 {
|
||||||
|
|
|
@ -25,6 +25,33 @@ pub enum Align_text {
|
||||||
Float conversion utility
|
Float conversion utility
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
const(
|
||||||
|
// rounding value
|
||||||
|
dec_round = [
|
||||||
|
f64(0.5),
|
||||||
|
0.05,
|
||||||
|
0.005,
|
||||||
|
0.0005,
|
||||||
|
0.00005,
|
||||||
|
0.000005,
|
||||||
|
0.0000005,
|
||||||
|
0.00000005,
|
||||||
|
0.000000005,
|
||||||
|
0.0000000005,
|
||||||
|
0.00000000005,
|
||||||
|
0.000000000005,
|
||||||
|
0.0000000000005,
|
||||||
|
0.00000000000005,
|
||||||
|
0.000000000000005,
|
||||||
|
0.0000000000000005,
|
||||||
|
0.00000000000000005,
|
||||||
|
0.000000000000000005,
|
||||||
|
0.0000000000000000005,
|
||||||
|
0.00000000000000000005,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
const(
|
const(
|
||||||
// rounding value
|
// rounding value
|
||||||
dec_round = [
|
dec_round = [
|
||||||
|
@ -50,7 +77,7 @@ const(
|
||||||
0.000000000000000000044,
|
0.000000000000000000044,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
*/
|
||||||
// max float 1.797693134862315708145274237317043567981e+308
|
// max float 1.797693134862315708145274237317043567981e+308
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -0,0 +1,497 @@
|
||||||
|
/*=============================================================================
|
||||||
|
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 string interpolation V functions
|
||||||
|
=============================================================================*/
|
||||||
|
module strconv
|
||||||
|
import strings
|
||||||
|
|
||||||
|
// strings.Builder version of format_str
|
||||||
|
pub fn format_str_sb(s string, p BF_param, mut sb strings.Builder) {
|
||||||
|
if p.len0 <= 0 {
|
||||||
|
sb.write_string(s)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dif := p.len0 - utf8_str_visible_length(s)
|
||||||
|
if dif <= 0 {
|
||||||
|
sb.write_string(s)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.allign == .right {
|
||||||
|
for i1 :=0; i1 < dif; i1++ {
|
||||||
|
sb.write_b(p.pad_ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.write_string(s)
|
||||||
|
if p.allign == .left {
|
||||||
|
for i1 :=0; i1 < dif; i1++ {
|
||||||
|
sb.write_b(p.pad_ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// digit pairs in reverse order
|
||||||
|
digit_pairs = '00102030405060708090011121314151617181910212223242526272829203132333435363738393041424344454647484940515253545556575859506162636465666768696071727374757677787970818283848586878889809192939495969798999'
|
||||||
|
)
|
||||||
|
|
||||||
|
// format_dec_sb format a u64
|
||||||
|
[direct_array_access]
|
||||||
|
pub fn format_dec_sb(d u64, p BF_param, mut res strings.Builder) {
|
||||||
|
mut n_char := dec_digits(d)
|
||||||
|
sign_len := if !p.positive || p.sign_flag { 1 } else { 0 }
|
||||||
|
number_len := sign_len + n_char
|
||||||
|
dif := p.len0 - number_len
|
||||||
|
mut sign_written := false
|
||||||
|
|
||||||
|
if p.allign == .right {
|
||||||
|
if p.pad_ch == `0` {
|
||||||
|
if p.positive {
|
||||||
|
if p.sign_flag {
|
||||||
|
res.write_b(`+`)
|
||||||
|
sign_written = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.write_b(`-`)
|
||||||
|
sign_written = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// write the pad chars
|
||||||
|
for i1 :=0; i1 < dif; i1++ {
|
||||||
|
res.write_b(p.pad_ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !sign_written {
|
||||||
|
// no pad char, write the sign before the number
|
||||||
|
if p.positive {
|
||||||
|
if p.sign_flag {
|
||||||
|
res.write_b(`+`)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.write_b(`-`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Legacy version
|
||||||
|
// max u64 18446744073709551615 => 20 byte
|
||||||
|
mut buf := [32]byte{}
|
||||||
|
mut i := 20
|
||||||
|
mut d1 := d
|
||||||
|
for i >= (21 - n_char) {
|
||||||
|
buf[i] = byte(d1 % 10) + `0`
|
||||||
|
d1 = d1 / 10
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
*/
|
||||||
|
|
||||||
|
//===========================================
|
||||||
|
// Speed version
|
||||||
|
// max u64 18446744073709551615 => 20 byte
|
||||||
|
mut buf := [32]byte{}
|
||||||
|
mut i := 20
|
||||||
|
mut n := d
|
||||||
|
mut d_i := u64(0)
|
||||||
|
if n > 0 {
|
||||||
|
for n > 0 {
|
||||||
|
n1 := n / 100
|
||||||
|
// calculate the digit_pairs start index
|
||||||
|
d_i = (n - (n1 * 100)) << 1
|
||||||
|
n = n1
|
||||||
|
unsafe{ buf[i] = digit_pairs.str[d_i] }
|
||||||
|
i--
|
||||||
|
d_i++
|
||||||
|
unsafe{ buf[i] = digit_pairs.str[d_i] }
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
// remove head zero
|
||||||
|
if d_i < 20 {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
unsafe{ res.write_ptr(&buf[i],n_char) }
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// we have a zero no need of more code!
|
||||||
|
res.write_b(`0`)
|
||||||
|
}
|
||||||
|
//===========================================
|
||||||
|
|
||||||
|
if p.allign == .left {
|
||||||
|
for i1 :=0; i1 < dif; i1++ {
|
||||||
|
res.write_b(p.pad_ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[manualfree]
|
||||||
|
[direct_array_access]
|
||||||
|
pub fn f64_to_str_lnd1(f f64, dec_digit int) string {
|
||||||
|
unsafe{
|
||||||
|
// we add the rounding value
|
||||||
|
s := f64_to_str(f + dec_round[dec_digit], 18)
|
||||||
|
// check for +inf -inf Nan
|
||||||
|
if s.len > 2 && (s[0] == `n` || s[1] == `i`) {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
mut dot_res_sp := -1
|
||||||
|
|
||||||
|
// get sign and deciaml 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 {
|
||||||
|
s.free()
|
||||||
|
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 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}")
|
||||||
|
|
||||||
|
// s no more needed
|
||||||
|
s.free()
|
||||||
|
|
||||||
|
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 {
|
||||||
|
dot_res_sp = r_i
|
||||||
|
res[r_i] = `.`
|
||||||
|
r_i++
|
||||||
|
}
|
||||||
|
exp--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for exp >= 0 {
|
||||||
|
res[r_i] = `0`
|
||||||
|
r_i++
|
||||||
|
exp--
|
||||||
|
}
|
||||||
|
//println("exp: $exp $r_i $dot_res_sp")
|
||||||
|
} else {
|
||||||
|
mut dot_p := true
|
||||||
|
for exp > 0 {
|
||||||
|
res[r_i] = `0`
|
||||||
|
r_i++
|
||||||
|
exp--
|
||||||
|
if dot_p {
|
||||||
|
dot_res_sp = r_i
|
||||||
|
res[r_i] = `.`
|
||||||
|
r_i++
|
||||||
|
dot_p = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for b[i] != 0 {
|
||||||
|
res[r_i] = b[i]
|
||||||
|
r_i++
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no more digits needed, stop here
|
||||||
|
if dec_digit <= 0 {
|
||||||
|
tmp_res := tos(res.data, dot_res_sp).clone()
|
||||||
|
res.free()
|
||||||
|
return tmp_res
|
||||||
|
}
|
||||||
|
|
||||||
|
//println("r_i-d_pos: ${r_i - d_pos}")
|
||||||
|
if dot_res_sp >= 0 {
|
||||||
|
if (r_i - dot_res_sp) > dec_digit {
|
||||||
|
r_i = dot_res_sp + dec_digit + 1
|
||||||
|
}
|
||||||
|
res[r_i] = 0
|
||||||
|
//println("result: [${tos(&res[0],r_i)}]")
|
||||||
|
tmp_res := tos(res.data, r_i).clone()
|
||||||
|
res.free()
|
||||||
|
return tmp_res
|
||||||
|
} else {
|
||||||
|
if dec_digit > 0 {
|
||||||
|
mut c1 := 0
|
||||||
|
res[r_i] = `.`
|
||||||
|
r_i++
|
||||||
|
for c1 < dec_digit {
|
||||||
|
res[r_i] = `0`
|
||||||
|
r_i++
|
||||||
|
c1++
|
||||||
|
}
|
||||||
|
res[r_i] = 0
|
||||||
|
}
|
||||||
|
tmp_res := tos(res.data, r_i).clone()
|
||||||
|
res.free()
|
||||||
|
return tmp_res
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// strings.Builder version of format_fl
|
||||||
|
[manualfree]
|
||||||
|
pub fn format_fl(f f64, p BF_param) string {
|
||||||
|
unsafe{
|
||||||
|
mut s := ""
|
||||||
|
//mut fs := "1.2343"
|
||||||
|
mut fs := f64_to_str_lnd1(if f >= 0.0 {f} else {-f}, p.len1)
|
||||||
|
//println("Dario")
|
||||||
|
//println(fs)
|
||||||
|
|
||||||
|
// error!!
|
||||||
|
if fs[0] == `[` {
|
||||||
|
s.free()
|
||||||
|
return fs
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.rm_tail_zero {
|
||||||
|
tmp := fs
|
||||||
|
fs = remove_tail_zeros(fs)
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
mut res := strings.new_builder( if p.len0 > fs.len { p.len0 } else { fs.len })
|
||||||
|
|
||||||
|
mut sign_len_diff := 0
|
||||||
|
if p.pad_ch == `0` {
|
||||||
|
if p.positive {
|
||||||
|
if p.sign_flag {
|
||||||
|
res.write_b(`+`)
|
||||||
|
sign_len_diff = -1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.write_b(`-`)
|
||||||
|
sign_len_diff = -1
|
||||||
|
}
|
||||||
|
tmp := s
|
||||||
|
s = fs.clone()
|
||||||
|
tmp.free()
|
||||||
|
} else {
|
||||||
|
if p.positive {
|
||||||
|
if p.sign_flag {
|
||||||
|
tmp := s
|
||||||
|
s = "+" + fs
|
||||||
|
tmp.free()
|
||||||
|
} else {
|
||||||
|
tmp := s
|
||||||
|
s = fs.clone()
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tmp := s
|
||||||
|
s = "-" + fs
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dif := p.len0 - s.len + sign_len_diff
|
||||||
|
|
||||||
|
if p.allign == .right {
|
||||||
|
for i1 :=0; i1 < dif; i1++ {
|
||||||
|
res.write_b(p.pad_ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.write_string(s)
|
||||||
|
if p.allign == .left {
|
||||||
|
for i1 :=0; i1 < dif; i1++ {
|
||||||
|
res.write_b(p.pad_ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
s.free()
|
||||||
|
fs.free()
|
||||||
|
tmp_res := res.str()
|
||||||
|
res.free()
|
||||||
|
return tmp_res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[manualfree]
|
||||||
|
pub fn format_es(f f64, p BF_param) string {
|
||||||
|
unsafe{
|
||||||
|
mut s := ""
|
||||||
|
mut fs := f64_to_str_pad(if f> 0 {f} else {-f},p.len1)
|
||||||
|
if p.rm_tail_zero {
|
||||||
|
fs = remove_tail_zeros(fs)
|
||||||
|
}
|
||||||
|
mut res := strings.new_builder( if p.len0 > fs.len { p.len0 } else { fs.len })
|
||||||
|
|
||||||
|
mut sign_len_diff := 0
|
||||||
|
if p.pad_ch == `0` {
|
||||||
|
if p.positive {
|
||||||
|
if p.sign_flag {
|
||||||
|
res.write_b(`+`)
|
||||||
|
sign_len_diff = -1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.write_b(`-`)
|
||||||
|
sign_len_diff = -1
|
||||||
|
}
|
||||||
|
tmp := s
|
||||||
|
s = fs.clone()
|
||||||
|
tmp.free()
|
||||||
|
} else {
|
||||||
|
if p.positive {
|
||||||
|
if p.sign_flag {
|
||||||
|
tmp := s
|
||||||
|
s = "+" + fs
|
||||||
|
tmp.free()
|
||||||
|
} else {
|
||||||
|
tmp := s
|
||||||
|
s = fs.clone()
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tmp := s
|
||||||
|
s = "-" + fs
|
||||||
|
tmp.free()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dif := p.len0 - s.len + sign_len_diff
|
||||||
|
if p.allign == .right {
|
||||||
|
for i1 :=0; i1 < dif; i1++ {
|
||||||
|
res.write_b(p.pad_ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.write_string(s)
|
||||||
|
if p.allign == .left {
|
||||||
|
for i1 :=0; i1 < dif; i1++ {
|
||||||
|
res.write_b(p.pad_ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.free()
|
||||||
|
fs.free()
|
||||||
|
tmp_res := res.str()
|
||||||
|
res.free()
|
||||||
|
return tmp_res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[direct_array_access]
|
||||||
|
pub fn remove_tail_zeros(s string) string {
|
||||||
|
unsafe{
|
||||||
|
mut buf := malloc(s.len + 1)
|
||||||
|
mut i_d := 0
|
||||||
|
mut i_s := 0
|
||||||
|
|
||||||
|
// skip spaces
|
||||||
|
for i_s < s.len && s[i_s] !in [`-`,`+`] && s[i_s] >= `9` && s[i_s] <= `0`{
|
||||||
|
buf[i_d] = s[i_s]
|
||||||
|
i_s++
|
||||||
|
i_d++
|
||||||
|
}
|
||||||
|
// sign
|
||||||
|
if i_s < s.len && s[i_s] in [`-`,`+`] {
|
||||||
|
buf[i_d] = s[i_s]
|
||||||
|
i_s++
|
||||||
|
i_d++
|
||||||
|
}
|
||||||
|
|
||||||
|
// integer part
|
||||||
|
for i_s < s.len && s[i_s] >= `0` && s[i_s] <= `9` {
|
||||||
|
buf[i_d] = s[i_s]
|
||||||
|
i_s++
|
||||||
|
i_d++
|
||||||
|
}
|
||||||
|
|
||||||
|
// check decimals
|
||||||
|
if i_s < s.len && s[i_s] == `.` {
|
||||||
|
mut i_s1 := i_s + 1
|
||||||
|
mut sum := 0
|
||||||
|
for i_s1 < s.len && s[i_s1] >= `0` && s[i_s1] <= `9` {
|
||||||
|
sum += s[i_s1] - byte(`0`)
|
||||||
|
i_s1++
|
||||||
|
}
|
||||||
|
// decimal part must be copied
|
||||||
|
if sum > 0 {
|
||||||
|
for c_i in i_s .. i_s1 {
|
||||||
|
buf[i_d] = s[c_i]
|
||||||
|
i_d++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i_s = i_s1
|
||||||
|
}
|
||||||
|
|
||||||
|
if s[i_s] != `.` {
|
||||||
|
// check exponent
|
||||||
|
for i_s < s.len {
|
||||||
|
buf[i_d] = s[i_s]
|
||||||
|
i_s++
|
||||||
|
i_d++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[i_d] = 0
|
||||||
|
return tos(buf, i_d+1)
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,42 +4,58 @@ const base_digits = '0123456789abcdefghijklmnopqrstuvwxyz'
|
||||||
|
|
||||||
// format_int returns the string representation of the number n in base `radix`
|
// format_int returns the string representation of the number n in base `radix`
|
||||||
// for digit values > 10, this function uses the small latin leters a-z.
|
// for digit values > 10, this function uses the small latin leters a-z.
|
||||||
|
[manualfree]
|
||||||
pub fn format_int(n i64, radix int) string {
|
pub fn format_int(n i64, radix int) string {
|
||||||
if radix < 2 || radix > 36 {
|
unsafe{
|
||||||
panic('invalid radix: $radix . It should be => 2 and <= 36')
|
if radix < 2 || radix > 36 {
|
||||||
|
panic('invalid radix: $radix . It should be => 2 and <= 36')
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
return '0'
|
||||||
|
}
|
||||||
|
mut n_copy := n
|
||||||
|
mut sign := ''
|
||||||
|
if n < 0 {
|
||||||
|
sign = '-'
|
||||||
|
n_copy = -n_copy
|
||||||
|
}
|
||||||
|
mut res := ''
|
||||||
|
for n_copy != 0 {
|
||||||
|
tmp_0 := res
|
||||||
|
tmp_1 := base_digits[n_copy % radix].ascii_str()
|
||||||
|
res = tmp_1 + res
|
||||||
|
tmp_0.free()
|
||||||
|
tmp_1.free()
|
||||||
|
//res = base_digits[n_copy % radix].ascii_str() + res
|
||||||
|
n_copy /= radix
|
||||||
|
}
|
||||||
|
return '$sign$res'
|
||||||
}
|
}
|
||||||
if n == 0 {
|
|
||||||
return '0'
|
|
||||||
}
|
|
||||||
mut n_copy := n
|
|
||||||
mut sign := ''
|
|
||||||
if n < 0 {
|
|
||||||
sign = '-'
|
|
||||||
n_copy = -n_copy
|
|
||||||
}
|
|
||||||
mut res := ''
|
|
||||||
for n_copy != 0 {
|
|
||||||
res = base_digits[n_copy % radix].ascii_str() + res
|
|
||||||
n_copy /= radix
|
|
||||||
}
|
|
||||||
return '$sign$res'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// format_uint returns the string representation of the number n in base `radix`
|
// format_uint returns the string representation of the number n in base `radix`
|
||||||
// for digit values > 10, this function uses the small latin leters a-z.
|
// for digit values > 10, this function uses the small latin leters a-z.
|
||||||
|
[manualfree]
|
||||||
pub fn format_uint(n u64, radix int) string {
|
pub fn format_uint(n u64, radix int) string {
|
||||||
if radix < 2 || radix > 36 {
|
unsafe{
|
||||||
panic('invalid radix: $radix . It should be => 2 and <= 36')
|
if radix < 2 || radix > 36 {
|
||||||
|
panic('invalid radix: $radix . It should be => 2 and <= 36')
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
return '0'
|
||||||
|
}
|
||||||
|
mut n_copy := n
|
||||||
|
mut res := ''
|
||||||
|
uradix := u64(radix)
|
||||||
|
for n_copy != 0 {
|
||||||
|
tmp_0 := res
|
||||||
|
tmp_1 := base_digits[n_copy % uradix].ascii_str()
|
||||||
|
res = tmp_1 + res
|
||||||
|
tmp_0.free()
|
||||||
|
tmp_1.free()
|
||||||
|
//res = base_digits[n_copy % uradix].ascii_str() + res
|
||||||
|
n_copy /= uradix
|
||||||
|
}
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
if n == 0 {
|
|
||||||
return '0'
|
|
||||||
}
|
|
||||||
mut n_copy := n
|
|
||||||
mut res := ''
|
|
||||||
uradix := u64(radix)
|
|
||||||
for n_copy != 0 {
|
|
||||||
res = base_digits[n_copy % uradix].ascii_str() + res
|
|
||||||
n_copy /= uradix
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,8 +42,14 @@ mut:
|
||||||
u u64
|
u u64
|
||||||
}
|
}
|
||||||
|
|
||||||
union Float64u {
|
pub union Float64u {
|
||||||
mut:
|
pub mut:
|
||||||
f f64
|
f f64
|
||||||
u u64
|
u u64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub union Float32u {
|
||||||
|
pub mut:
|
||||||
|
f f32
|
||||||
|
u u32
|
||||||
|
}
|
|
@ -81,7 +81,9 @@ fn get_string_special(neg bool, expZero bool, mantZero bool) string {
|
||||||
32 bit functions
|
32 bit functions
|
||||||
|
|
||||||
*/
|
*/
|
||||||
fn decimal_len_32(u u32) int {
|
// decimal_len_32 return the number of decimal digits of the input
|
||||||
|
[deprecated]
|
||||||
|
pub fn decimal_len_32(u u32) int {
|
||||||
// Function precondition: u is not a 10-digit number.
|
// Function precondition: u is not a 10-digit number.
|
||||||
// (9 digits are sufficient for round-tripping.)
|
// (9 digits are sufficient for round-tripping.)
|
||||||
// This benchmarked faster than the log2 approach used for u64.
|
// This benchmarked faster than the log2 approach used for u64.
|
||||||
|
@ -172,7 +174,9 @@ fn pow5_bits(e int) int {
|
||||||
64 bit functions
|
64 bit functions
|
||||||
|
|
||||||
*/
|
*/
|
||||||
fn decimal_len_64(u u64) int {
|
[deprecated]
|
||||||
|
// decimal_len_64 return the number of decimal digits of the input
|
||||||
|
pub fn decimal_len_64(u u64) int {
|
||||||
// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
|
// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
|
||||||
log2 := 64 - bits.leading_zeros_64(u) - 1
|
log2 := 64 - bits.leading_zeros_64(u) - 1
|
||||||
t := (log2 + 1) * 1233 >> 12
|
t := (log2 + 1) * 1233 >> 12
|
||||||
|
@ -227,15 +231,44 @@ 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
|
// f32_to_str_l return a string with the f32 converted in a string in decimal notation
|
||||||
pub fn f32_to_str_l(f f64) string {
|
[manualfree]
|
||||||
return f64_to_str_l(f32(f))
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// f64_to_str_l return a string with the f64 converted in a string in decimal notation
|
[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 {
|
pub fn f64_to_str_l(f f64) string {
|
||||||
s := f64_to_str(f,18)
|
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
|
// check for +inf -inf Nan
|
||||||
if s.len > 2 && (s[0] == `n` || s[1] == `i`) {
|
if s.len > 2 && (s[0] == `n` || s[1] == `i`) {
|
||||||
return s
|
return s
|
||||||
|
@ -287,8 +320,11 @@ pub fn f64_to_str_l(f f64) string {
|
||||||
exp_sgn = 1
|
exp_sgn = 1
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
for c in s[i..] {
|
|
||||||
exp = exp * 10 + int(c-`0`)
|
mut c := i
|
||||||
|
for c < s.len {
|
||||||
|
exp = exp * 10 + int(s[c]-`0`)
|
||||||
|
c++
|
||||||
}
|
}
|
||||||
|
|
||||||
// allocate exp+32 chars for the return string
|
// allocate exp+32 chars for the return string
|
||||||
|
@ -296,7 +332,7 @@ pub fn f64_to_str_l(f f64) string {
|
||||||
mut r_i := 0 // result string buffer index
|
mut r_i := 0 // result string buffer index
|
||||||
|
|
||||||
//println("s:${sgn} b:${b[0]} es:${exp_sgn} exp:${exp}")
|
//println("s:${sgn} b:${b[0]} es:${exp_sgn} exp:${exp}")
|
||||||
|
|
||||||
if sgn == 1 {
|
if sgn == 1 {
|
||||||
if m_sgn_flag {
|
if m_sgn_flag {
|
||||||
res[r_i] = `+`
|
res[r_i] = `+`
|
||||||
|
@ -344,6 +380,136 @@ pub fn f64_to_str_l(f f64) string {
|
||||||
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
res[r_i] = 0
|
||||||
return unsafe { tos(res.data,r_i) }
|
return unsafe { tos(res.data,r_i) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -455,170 +455,6 @@ fn fabs(x f64) f64 {
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
[manualfree]
|
|
||||||
pub fn f64_to_str_lnd1(f f64, dec_digit int) string {
|
|
||||||
unsafe{
|
|
||||||
// we add the rounding value
|
|
||||||
s := f64_to_str(f + dec_round[dec_digit], 18)
|
|
||||||
// check for +inf -inf Nan
|
|
||||||
if s.len > 2 && (s[0] == `n` || s[1] == `i`) {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
mut dot_res_sp := -1
|
|
||||||
|
|
||||||
// get sign and deciaml 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 {
|
|
||||||
s.free()
|
|
||||||
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 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}")
|
|
||||||
|
|
||||||
// s no more needed
|
|
||||||
s.free()
|
|
||||||
|
|
||||||
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 {
|
|
||||||
dot_res_sp = r_i
|
|
||||||
res[r_i] = `.`
|
|
||||||
r_i++
|
|
||||||
}
|
|
||||||
exp--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for exp >= 0 {
|
|
||||||
res[r_i] = `0`
|
|
||||||
r_i++
|
|
||||||
exp--
|
|
||||||
}
|
|
||||||
//println("exp: $exp $r_i $dot_res_sp")
|
|
||||||
} else {
|
|
||||||
mut dot_p := true
|
|
||||||
for exp > 0 {
|
|
||||||
res[r_i] = `0`
|
|
||||||
r_i++
|
|
||||||
exp--
|
|
||||||
if dot_p {
|
|
||||||
dot_res_sp = r_i
|
|
||||||
res[r_i] = `.`
|
|
||||||
r_i++
|
|
||||||
dot_p = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for b[i] != 0 {
|
|
||||||
res[r_i] = b[i]
|
|
||||||
r_i++
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// no more digits needed, stop here
|
|
||||||
if dec_digit <= 0 {
|
|
||||||
tmp_res := tos(res.data, dot_res_sp).clone()
|
|
||||||
res.free()
|
|
||||||
return tmp_res
|
|
||||||
}
|
|
||||||
|
|
||||||
//println("r_i-d_pos: ${r_i - d_pos}")
|
|
||||||
if dot_res_sp >= 0 {
|
|
||||||
if (r_i - dot_res_sp) > dec_digit {
|
|
||||||
r_i = dot_res_sp + dec_digit + 1
|
|
||||||
}
|
|
||||||
res[r_i] = 0
|
|
||||||
//println("result: [${tos(&res[0],r_i)}]")
|
|
||||||
tmp_res := tos(res.data, r_i).clone()
|
|
||||||
res.free()
|
|
||||||
return tmp_res
|
|
||||||
} else {
|
|
||||||
if dec_digit > 0 {
|
|
||||||
mut c1 := 0
|
|
||||||
res[r_i] = `.`
|
|
||||||
r_i++
|
|
||||||
for c1 < dec_digit {
|
|
||||||
res[r_i] = `0`
|
|
||||||
r_i++
|
|
||||||
c1++
|
|
||||||
}
|
|
||||||
res[r_i] = 0
|
|
||||||
}
|
|
||||||
tmp_res := tos(res.data, r_i).clone()
|
|
||||||
res.free()
|
|
||||||
return tmp_res
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// strings.Builder version of format_fl
|
// strings.Builder version of format_fl
|
||||||
[manualfree]
|
[manualfree]
|
||||||
pub fn format_fl_old(f f64, p BF_param) string {
|
pub fn format_fl_old(f f64, p BF_param) string {
|
||||||
|
|
|
@ -493,7 +493,8 @@ pub fn (node Stmt) str() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn field_to_string(f ConstField) string {
|
fn field_to_string(f ConstField) string {
|
||||||
return '${f.name.trim_prefix(f.mod + '.')} = $f.expr'
|
x := f.name.trim_prefix(f.mod + '.')
|
||||||
|
return '$x = $f.expr'
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (e CompForKind) str() string {
|
pub fn (e CompForKind) str() string {
|
||||||
|
|
|
@ -443,7 +443,9 @@ pub fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) ast.Typ
|
||||||
typ := c.table.unalias_num_type(ftyp)
|
typ := c.table.unalias_num_type(ftyp)
|
||||||
mut fmt := node.fmts[i]
|
mut fmt := node.fmts[i]
|
||||||
// analyze and validate format specifier
|
// analyze and validate format specifier
|
||||||
if fmt !in [`E`, `F`, `G`, `e`, `f`, `g`, `d`, `u`, `x`, `X`, `o`, `c`, `s`, `p`, `_`] {
|
if fmt !in [`E`, `F`, `G`, `e`, `f`, `g`, `d`, `u`, `x`, `X`, `o`, `c`, `s`, `S`, `p`,
|
||||||
|
`_`,
|
||||||
|
] {
|
||||||
c.error('unknown format specifier `${fmt:c}`', node.fmt_poss[i])
|
c.error('unknown format specifier `${fmt:c}`', node.fmt_poss[i])
|
||||||
}
|
}
|
||||||
if fmt == `_` { // set default representation for type if none has been given
|
if fmt == `_` { // set default representation for type if none has been given
|
||||||
|
@ -469,7 +471,7 @@ pub fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) ast.Typ
|
||||||
|| (typ.is_int_literal() && fmt !in [`d`, `c`, `x`, `X`, `o`, `u`, `x`, `X`, `o`])
|
|| (typ.is_int_literal() && fmt !in [`d`, `c`, `x`, `X`, `o`, `u`, `x`, `X`, `o`])
|
||||||
|| (typ.is_float() && fmt !in [`E`, `F`, `G`, `e`, `f`, `g`])
|
|| (typ.is_float() && fmt !in [`E`, `F`, `G`, `e`, `f`, `g`])
|
||||||
|| (typ.is_pointer() && fmt !in [`p`, `x`, `X`])
|
|| (typ.is_pointer() && fmt !in [`p`, `x`, `X`])
|
||||||
|| (typ.is_string() && fmt != `s`)
|
|| (typ.is_string() && fmt !in [`s`, `S`])
|
||||||
|| (typ.idx() in [ast.i64_type_idx, ast.f64_type_idx] && fmt == `c`) {
|
|| (typ.idx() in [ast.i64_type_idx, ast.f64_type_idx] && fmt == `c`) {
|
||||||
c.error('illegal format specifier `${fmt:c}` for type `${c.table.get_type_name(ftyp)}`',
|
c.error('illegal format specifier `${fmt:c}` for type `${c.table.get_type_name(ftyp)}`',
|
||||||
node.fmt_poss[i])
|
node.fmt_poss[i])
|
||||||
|
|
|
@ -0,0 +1,170 @@
|
||||||
|
module c
|
||||||
|
|
||||||
|
// Copyright (c) 2019-2021 Alexander Medvednikov. 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.
|
||||||
|
import v.ast
|
||||||
|
|
||||||
|
fn (mut g Gen) gen_str_for_array(info ast.Array, styp string, str_fn_name string) {
|
||||||
|
mut typ := info.elem_type
|
||||||
|
mut sym := g.table.get_type_symbol(info.elem_type)
|
||||||
|
if mut sym.info is ast.Alias {
|
||||||
|
typ = sym.info.parent_type
|
||||||
|
sym = g.table.get_type_symbol(typ)
|
||||||
|
}
|
||||||
|
field_styp := g.typ(typ)
|
||||||
|
is_elem_ptr := typ.is_ptr()
|
||||||
|
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
|
||||||
|
mut elem_str_fn_name := ''
|
||||||
|
if sym_has_str_method {
|
||||||
|
elem_str_fn_name = if is_elem_ptr {
|
||||||
|
field_styp.replace('*', '') + '_str'
|
||||||
|
} else {
|
||||||
|
field_styp + '_str'
|
||||||
|
}
|
||||||
|
if sym.kind == .byte {
|
||||||
|
elem_str_fn_name = elem_str_fn_name + '_escaped'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
elem_str_fn_name = styp_to_str_fn_name(field_styp)
|
||||||
|
}
|
||||||
|
if !sym_has_str_method {
|
||||||
|
g.gen_str_for_type(typ)
|
||||||
|
}
|
||||||
|
g.type_definitions.writeln('static string ${str_fn_name}($styp a); // auto')
|
||||||
|
g.auto_str_funcs.writeln('static string ${str_fn_name}($styp a) { return indent_${str_fn_name}(a, 0);}')
|
||||||
|
g.type_definitions.writeln('static string indent_${str_fn_name}($styp a, int indent_count); // auto')
|
||||||
|
g.auto_str_funcs.writeln('static string indent_${str_fn_name}($styp a, int indent_count) {')
|
||||||
|
g.auto_str_funcs.writeln('\tstrings__Builder sb = strings__new_builder(a.len * 10);')
|
||||||
|
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("["));')
|
||||||
|
g.auto_str_funcs.writeln('\tfor (int i = 0; i < a.len; ++i) {')
|
||||||
|
if sym.kind == .function {
|
||||||
|
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}();')
|
||||||
|
} else {
|
||||||
|
if sym.kind == .array_fixed {
|
||||||
|
g.auto_str_funcs.writeln('\t\t$field_styp it;')
|
||||||
|
g.auto_str_funcs.writeln('\t\tmemcpy(*($field_styp*)it, (byte*)array_get(a, i), sizeof($field_styp));')
|
||||||
|
} else {
|
||||||
|
g.auto_str_funcs.writeln('\t\t$field_styp it = *($field_styp*)array_get(a, i);')
|
||||||
|
}
|
||||||
|
if should_use_indent_func(sym.kind) && !sym_has_str_method {
|
||||||
|
if is_elem_ptr {
|
||||||
|
g.auto_str_funcs.writeln('\t\tstring x = indent_${elem_str_fn_name}(*it, indent_count);')
|
||||||
|
} else {
|
||||||
|
g.auto_str_funcs.writeln('\t\tstring x = indent_${elem_str_fn_name}(it, indent_count);')
|
||||||
|
}
|
||||||
|
} else if sym.kind in [.f32, .f64] {
|
||||||
|
if sym.kind == .f32 {
|
||||||
|
g.auto_str_funcs.writeln('\t\tstring x = ${str_intp_g32('it')};')
|
||||||
|
} else {
|
||||||
|
g.auto_str_funcs.writeln('\t\tstring x = ${str_intp_g64('it')};')
|
||||||
|
}
|
||||||
|
|
||||||
|
// g.auto_str_funcs.writeln('\t\tstring x = _STR("%g", 1, it);')
|
||||||
|
} else if sym.kind == .rune {
|
||||||
|
// Rune are managed at this level as strings
|
||||||
|
g.auto_str_funcs.writeln('\t\tstring x = str_intp(2, _MOV((StrIntpData[]){{_SLIT("\`"), $si_s_code, {.d_s = ${elem_str_fn_name}(it) }}, {_SLIT("\`"), 0, {.d_c = 0 }}}));\n')
|
||||||
|
|
||||||
|
// g.auto_str_funcs.writeln('\t\tstring x = _STR("`%.*s\\000`", 2, ${elem_str_fn_name}(it));')
|
||||||
|
} else if sym.kind == .string {
|
||||||
|
g.auto_str_funcs.writeln('\t\tstring x = str_intp(2, _MOV((StrIntpData[]){{_SLIT("\'"), $si_s_code, {.d_s = it }}, {_SLIT("\'"), 0, {.d_c = 0 }}}));\n')
|
||||||
|
|
||||||
|
// g.auto_str_funcs.writeln('\t\tstring x = _STR("\'%.*s\\000\'", 2, it);')
|
||||||
|
} else {
|
||||||
|
// There is a custom .str() method, so use it.
|
||||||
|
// NB: we need to take account of whether the user has defined
|
||||||
|
// `fn (x T) str() {` or `fn (x &T) str() {`, and convert accordingly
|
||||||
|
deref, deref_label := deref_kind(str_method_expects_ptr, is_elem_ptr, typ)
|
||||||
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _SLIT("$deref_label"));')
|
||||||
|
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}( $deref it);')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, x);')
|
||||||
|
if g.is_autofree && typ != ast.bool_type {
|
||||||
|
// no need to free "true"/"false" literals
|
||||||
|
g.auto_str_funcs.writeln('\t\tstring_free(&x);')
|
||||||
|
}
|
||||||
|
g.auto_str_funcs.writeln('\t\tif (i < a.len-1) {')
|
||||||
|
g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, _SLIT(", "));')
|
||||||
|
g.auto_str_funcs.writeln('\t\t}')
|
||||||
|
g.auto_str_funcs.writeln('\t}')
|
||||||
|
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("]"));')
|
||||||
|
g.auto_str_funcs.writeln('\tstring res = strings__Builder_str(&sb);')
|
||||||
|
g.auto_str_funcs.writeln('\tstrings__Builder_free(&sb);')
|
||||||
|
g.auto_str_funcs.writeln('\treturn res;')
|
||||||
|
g.auto_str_funcs.writeln('}')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) gen_str_for_array_fixed(info ast.ArrayFixed, styp string, str_fn_name string) {
|
||||||
|
mut typ := info.elem_type
|
||||||
|
mut sym := g.table.get_type_symbol(info.elem_type)
|
||||||
|
if mut sym.info is ast.Alias {
|
||||||
|
typ = sym.info.parent_type
|
||||||
|
sym = g.table.get_type_symbol(typ)
|
||||||
|
}
|
||||||
|
field_styp := g.typ(typ)
|
||||||
|
is_elem_ptr := typ.is_ptr()
|
||||||
|
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
|
||||||
|
mut elem_str_fn_name := ''
|
||||||
|
if sym_has_str_method {
|
||||||
|
elem_str_fn_name = if is_elem_ptr {
|
||||||
|
field_styp.replace('*', '') + '_str'
|
||||||
|
} else {
|
||||||
|
field_styp + '_str'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
elem_str_fn_name = styp_to_str_fn_name(field_styp)
|
||||||
|
}
|
||||||
|
if !sym.has_method('str') {
|
||||||
|
elem_str_fn_name = g.gen_str_for_type(typ)
|
||||||
|
}
|
||||||
|
g.type_definitions.writeln('static string ${str_fn_name}($styp a); // auto')
|
||||||
|
g.auto_str_funcs.writeln('static string ${str_fn_name}($styp a) { return indent_${str_fn_name}(a, 0);}')
|
||||||
|
g.type_definitions.writeln('static string indent_${str_fn_name}($styp a, int indent_count); // auto')
|
||||||
|
g.auto_str_funcs.writeln('static string indent_${str_fn_name}($styp a, int indent_count) {')
|
||||||
|
g.auto_str_funcs.writeln('\tstrings__Builder sb = strings__new_builder($info.size * 10);')
|
||||||
|
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("["));')
|
||||||
|
if sym.kind == .function {
|
||||||
|
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}();')
|
||||||
|
} else {
|
||||||
|
deref, deref_label := deref_kind(str_method_expects_ptr, is_elem_ptr, typ)
|
||||||
|
g.auto_str_funcs.writeln('\tfor (int i = 0; i < $info.size; ++i) {')
|
||||||
|
if should_use_indent_func(sym.kind) && !sym_has_str_method {
|
||||||
|
if is_elem_ptr {
|
||||||
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _SLIT("$deref_label"));')
|
||||||
|
g.auto_str_funcs.writeln('\t\tif ( 0 == a[i] ) {')
|
||||||
|
g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, _SLIT("0"));')
|
||||||
|
g.auto_str_funcs.writeln('\t\t}else{')
|
||||||
|
g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}( $deref a[i]) );')
|
||||||
|
g.auto_str_funcs.writeln('\t\t}')
|
||||||
|
} else {
|
||||||
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}( $deref a[i]) );')
|
||||||
|
}
|
||||||
|
} else if sym.kind in [.f32, .f64] {
|
||||||
|
if sym.kind == .f32 {
|
||||||
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${str_intp_g32('a[i]')} );')
|
||||||
|
} else {
|
||||||
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${str_intp_g64('a[i]')} );')
|
||||||
|
}
|
||||||
|
// g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _STR("%g", 1, a[i]));')
|
||||||
|
} else if sym.kind == .string {
|
||||||
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${str_intp_sq('a[i]')});')
|
||||||
|
// g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _STR("\'%.*s\\000\'", 2, a[i]));')
|
||||||
|
} else if sym.kind == .rune {
|
||||||
|
tmp_str := str_intp_rune('${elem_str_fn_name}( $deref a[i])')
|
||||||
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, $tmp_str);')
|
||||||
|
// g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _STR("`%.*s\\000`", 2, ${elem_str_fn_name}(a[i])));')
|
||||||
|
} else {
|
||||||
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}( $deref a[i]));')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.auto_str_funcs.writeln('\t\tif (i < ${info.size - 1}) {')
|
||||||
|
g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, _SLIT(", "));')
|
||||||
|
g.auto_str_funcs.writeln('\t\t}')
|
||||||
|
g.auto_str_funcs.writeln('\t}')
|
||||||
|
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("]"));')
|
||||||
|
g.auto_str_funcs.writeln('\tstring res = strings__Builder_str(&sb);')
|
||||||
|
g.auto_str_funcs.writeln('\tstrings__Builder_free(&sb);')
|
||||||
|
g.auto_str_funcs.writeln('\treturn res;')
|
||||||
|
g.auto_str_funcs.writeln('}')
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
module c
|
||||||
|
|
||||||
|
// Copyright (c) 2019-2021 Alexander Medvednikov. 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.
|
||||||
|
import v.ast
|
||||||
|
|
||||||
|
fn (mut g Gen) gen_str_for_map(info ast.Map, styp string, str_fn_name string) {
|
||||||
|
mut key_typ := info.key_type
|
||||||
|
mut key_sym := g.table.get_type_symbol(key_typ)
|
||||||
|
if mut key_sym.info is ast.Alias {
|
||||||
|
key_typ = key_sym.info.parent_type
|
||||||
|
key_sym = g.table.get_type_symbol(key_typ)
|
||||||
|
}
|
||||||
|
key_styp := g.typ(key_typ)
|
||||||
|
key_str_fn_name := key_styp.replace('*', '') + '_str'
|
||||||
|
if !key_sym.has_method('str') {
|
||||||
|
g.gen_str_for_type(key_typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
mut val_typ := info.value_type
|
||||||
|
mut val_sym := g.table.get_type_symbol(val_typ)
|
||||||
|
if mut val_sym.info is ast.Alias {
|
||||||
|
val_typ = val_sym.info.parent_type
|
||||||
|
val_sym = g.table.get_type_symbol(val_typ)
|
||||||
|
}
|
||||||
|
val_styp := g.typ(val_typ)
|
||||||
|
elem_str_fn_name := val_styp.replace('*', '') + '_str'
|
||||||
|
if !val_sym.has_method('str') {
|
||||||
|
g.gen_str_for_type(val_typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
g.type_definitions.writeln('static string ${str_fn_name}($styp m); // auto')
|
||||||
|
g.auto_str_funcs.writeln('static string ${str_fn_name}($styp m) { return indent_${str_fn_name}(m, 0);}')
|
||||||
|
g.type_definitions.writeln('static string indent_${str_fn_name}($styp m, int indent_count); // auto')
|
||||||
|
g.auto_str_funcs.writeln('static string indent_${str_fn_name}($styp m, int indent_count) { /* gen_str_for_map */')
|
||||||
|
g.auto_str_funcs.writeln('\tstrings__Builder sb = strings__new_builder(m.key_values.len*10);')
|
||||||
|
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("{"));')
|
||||||
|
g.auto_str_funcs.writeln('\tfor (int i = 0; i < m.key_values.len; ++i) {')
|
||||||
|
g.auto_str_funcs.writeln('\t\tif (!DenseArray_has_index(&m.key_values, i)) { continue; }')
|
||||||
|
|
||||||
|
if key_sym.kind == .string {
|
||||||
|
g.auto_str_funcs.writeln('\t\tstring key = *(string*)DenseArray_key(&m.key_values, i);')
|
||||||
|
} else {
|
||||||
|
g.auto_str_funcs.writeln('\t\t$key_styp key = *($key_styp*)DenseArray_key(&m.key_values, i);')
|
||||||
|
}
|
||||||
|
if key_sym.kind == .string {
|
||||||
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${str_intp_sq('key')});')
|
||||||
|
// g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _STR("\'%.*s\\000\'", 2, key));')
|
||||||
|
} else if key_sym.kind == .rune {
|
||||||
|
tmp_str := str_intp_rune('${key_str_fn_name}(key)')
|
||||||
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, $tmp_str);')
|
||||||
|
// g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _STR("`%.*s\\000`", 2, ${key_str_fn_name}(key)));')
|
||||||
|
} else {
|
||||||
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${key_str_fn_name}(key));')
|
||||||
|
}
|
||||||
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _SLIT(": "));')
|
||||||
|
if val_sym.kind == .function {
|
||||||
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}());')
|
||||||
|
} else if val_sym.kind == .string {
|
||||||
|
tmp_str := str_intp_sq('*($val_styp*)DenseArray_value(&m.key_values, i)')
|
||||||
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, $tmp_str);')
|
||||||
|
// g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _STR("\'%.*s\\000\'", 2, *($val_styp*)DenseArray_value(&m.key_values, i)));')
|
||||||
|
} else if should_use_indent_func(val_sym.kind) && !val_sym.has_method('str') {
|
||||||
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, indent_${elem_str_fn_name}(*($val_styp*)DenseArray_value(&m.key_values, i), indent_count));')
|
||||||
|
} else if val_sym.kind in [.f32, .f64] {
|
||||||
|
tmp_val := '*($val_styp*)DenseArray_value(&m.key_values, i)'
|
||||||
|
if val_sym.kind == .f32 {
|
||||||
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${str_intp_g32(tmp_val)});')
|
||||||
|
} else {
|
||||||
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${str_intp_g64(tmp_val)});')
|
||||||
|
}
|
||||||
|
// g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _STR("%g", 1, *($val_styp*)DenseArray_value(&m.key_values, i)));')
|
||||||
|
} else if val_sym.kind == .rune {
|
||||||
|
tmp_str := str_intp_rune('${elem_str_fn_name}(*($val_styp*)DenseArray_value(&m.key_values, i))')
|
||||||
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, $tmp_str);')
|
||||||
|
// g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _STR("`%.*s\\000`", 2, ${elem_str_fn_name}(*($val_styp*)DenseArray_value(&m.key_values, i))));')
|
||||||
|
} else {
|
||||||
|
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}(*($val_styp*)DenseArray_value(&m.key_values, i)));')
|
||||||
|
}
|
||||||
|
g.auto_str_funcs.writeln('\t\tif (i != m.key_values.len-1) {')
|
||||||
|
g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, _SLIT(", "));')
|
||||||
|
g.auto_str_funcs.writeln('\t\t}')
|
||||||
|
g.auto_str_funcs.writeln('\t}')
|
||||||
|
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("}"));')
|
||||||
|
g.auto_str_funcs.writeln('\tstring res = strings__Builder_str(&sb);')
|
||||||
|
g.auto_str_funcs.writeln('\tstrings__Builder_free(&sb);')
|
||||||
|
g.auto_str_funcs.writeln('\treturn res;')
|
||||||
|
g.auto_str_funcs.writeln('}')
|
||||||
|
}
|
|
@ -5,6 +5,82 @@ module c
|
||||||
import v.ast
|
import v.ast
|
||||||
import v.util
|
import v.util
|
||||||
|
|
||||||
|
pub enum StrIntpType {
|
||||||
|
si_no_str = 0 // no parameter to print only fix string
|
||||||
|
si_c
|
||||||
|
si_u8
|
||||||
|
si_i8
|
||||||
|
si_u16
|
||||||
|
si_i16
|
||||||
|
si_u32
|
||||||
|
si_i32
|
||||||
|
si_u64
|
||||||
|
si_i64
|
||||||
|
si_e32
|
||||||
|
si_e64
|
||||||
|
si_f32
|
||||||
|
si_f64
|
||||||
|
si_g32
|
||||||
|
si_g64
|
||||||
|
si_s
|
||||||
|
si_p
|
||||||
|
si_vp
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_to_str(x StrIntpType) string {
|
||||||
|
match x {
|
||||||
|
.si_no_str { return 'no_str' }
|
||||||
|
.si_c { return 'c' }
|
||||||
|
.si_u8 { return 'u8' }
|
||||||
|
.si_i8 { return 'i8' }
|
||||||
|
.si_u16 { return 'u16' }
|
||||||
|
.si_i16 { return 'i16' }
|
||||||
|
.si_u32 { return 'u32' }
|
||||||
|
.si_i32 { return 'i32' }
|
||||||
|
.si_u64 { return 'u64' }
|
||||||
|
.si_i64 { return 'i64' }
|
||||||
|
.si_f32 { return 'f32' }
|
||||||
|
.si_f64 { return 'f64' }
|
||||||
|
.si_g32 { return 'f32' } // g32 format use f32 data
|
||||||
|
.si_g64 { return 'f64' } // g64 format use f64 data
|
||||||
|
.si_e32 { return 'f32' } // e32 format use f32 data
|
||||||
|
.si_e64 { return 'f64' } // e64 format use f64 data
|
||||||
|
.si_s { return 's' }
|
||||||
|
.si_p { return 'p' }
|
||||||
|
.si_vp { return 'vp' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn data_str(x StrIntpType) string {
|
||||||
|
match x {
|
||||||
|
.si_no_str { return 'no_str' }
|
||||||
|
.si_c { return 'd_c' }
|
||||||
|
.si_u8 { return 'd_u8' }
|
||||||
|
.si_i8 { return 'd_i8' }
|
||||||
|
.si_u16 { return 'd_u16' }
|
||||||
|
.si_i16 { return 'd_i16' }
|
||||||
|
.si_u32 { return 'd_u32' }
|
||||||
|
.si_i32 { return 'd_i32' }
|
||||||
|
.si_u64 { return 'd_u64' }
|
||||||
|
.si_i64 { return 'd_i64' }
|
||||||
|
.si_f32 { return 'd_f32' }
|
||||||
|
.si_f64 { return 'd_f64' }
|
||||||
|
.si_g32 { return 'd_f32' } // g32 format use f32 data
|
||||||
|
.si_g64 { return 'd_f64' } // g64 format use f64 data
|
||||||
|
.si_e32 { return 'd_f32' } // e32 format use f32 data
|
||||||
|
.si_e64 { return 'd_f64' } // e64 format use f64 data
|
||||||
|
.si_s { return 'd_s' }
|
||||||
|
.si_p { return 'd_p' }
|
||||||
|
.si_vp { return 'd_vp' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// BUG: this const is not released from the memory! use a const for now
|
||||||
|
// si_s_code = "0x" + int(StrIntpType.si_s).hex() // code for a simple string
|
||||||
|
si_s_code = '0xfe10'
|
||||||
|
)
|
||||||
|
|
||||||
fn should_use_indent_func(kind ast.Kind) bool {
|
fn should_use_indent_func(kind ast.Kind) bool {
|
||||||
return kind in [.struct_, .alias, .array, .array_fixed, .map, .sum_type, .interface_]
|
return kind in [.struct_, .alias, .array, .array_fixed, .map, .sum_type, .interface_]
|
||||||
}
|
}
|
||||||
|
@ -40,41 +116,6 @@ fn (mut g Gen) gen_str_default(sym ast.TypeSymbol, styp string, str_fn_name stri
|
||||||
g.auto_str_funcs.writeln('}')
|
g.auto_str_funcs.writeln('}')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g &Gen) type_to_fmt(typ ast.Type) string {
|
|
||||||
if typ == ast.byte_type_idx {
|
|
||||||
return '%hhx\\000'
|
|
||||||
}
|
|
||||||
if typ == ast.char_type_idx {
|
|
||||||
return '%c\\000'
|
|
||||||
}
|
|
||||||
if typ == ast.voidptr_type_idx || typ in ast.byteptr_types {
|
|
||||||
return '%p\\000'
|
|
||||||
}
|
|
||||||
if typ in ast.charptr_types {
|
|
||||||
return '%C\\000' // a C string
|
|
||||||
}
|
|
||||||
sym := g.table.get_type_symbol(typ)
|
|
||||||
if typ.is_ptr() && (typ.is_int_valptr() || typ.is_float_valptr()) {
|
|
||||||
return '%.*s\\000'
|
|
||||||
} else if sym.kind in [.struct_, .array, .array_fixed, .map, .bool, .enum_, .interface_,
|
|
||||||
.sum_type, .function, .alias] {
|
|
||||||
return '%.*s\\000'
|
|
||||||
} else if sym.kind == .string {
|
|
||||||
return "'%.*s\\000'"
|
|
||||||
} else if sym.kind in [.f32, .f64] {
|
|
||||||
return '%g\\000' // g removes trailing zeros unlike %f
|
|
||||||
} else if sym.kind == .int {
|
|
||||||
return '%d\\000'
|
|
||||||
} else if sym.kind == .u32 {
|
|
||||||
return '%u\\000'
|
|
||||||
} else if sym.kind == .u64 {
|
|
||||||
return '%llu\\000'
|
|
||||||
} else if sym.kind == .i64 {
|
|
||||||
return '%lld\\000'
|
|
||||||
}
|
|
||||||
return '%d\\000'
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut g Gen) gen_str_for_type(typ ast.Type) string {
|
fn (mut g Gen) gen_str_for_type(typ ast.Type) string {
|
||||||
styp := g.typ(typ).replace('*', '')
|
styp := g.typ(typ).replace('*', '')
|
||||||
mut sym := g.table.get_type_symbol(g.unwrap_generic(typ))
|
mut sym := g.table.get_type_symbol(g.unwrap_generic(typ))
|
||||||
|
@ -158,16 +199,24 @@ fn (mut g Gen) gen_str_for_option(typ ast.Type, styp string, str_fn_name string)
|
||||||
g.auto_str_funcs.writeln('\tstring res;')
|
g.auto_str_funcs.writeln('\tstring res;')
|
||||||
g.auto_str_funcs.writeln('\tif (it.state == 0) {')
|
g.auto_str_funcs.writeln('\tif (it.state == 0) {')
|
||||||
if sym.kind == .string {
|
if sym.kind == .string {
|
||||||
g.auto_str_funcs.writeln('\t\tres = _STR("\'%.*s\\000\'", 2, ${parent_str_fn_name}(*($sym.cname*)it.data));')
|
tmp_res := '${parent_str_fn_name}(*($sym.cname*)it.data)'
|
||||||
|
g.auto_str_funcs.writeln('\t\tres = ${str_intp_sq(tmp_res)};')
|
||||||
|
// g.auto_str_funcs.writeln('\t\tres = _STR("\'%.*s\\000\'", 2, ${parent_str_fn_name}(*($sym.cname*)it.data));')
|
||||||
} else if should_use_indent_func(sym.kind) && !sym_has_str_method {
|
} else if should_use_indent_func(sym.kind) && !sym_has_str_method {
|
||||||
g.auto_str_funcs.writeln('\t\tres = indent_${parent_str_fn_name}(*($sym.cname*)it.data, indent_count);')
|
g.auto_str_funcs.writeln('\t\tres = indent_${parent_str_fn_name}(*($sym.cname*)it.data, indent_count);')
|
||||||
} else {
|
} else {
|
||||||
g.auto_str_funcs.writeln('\t\tres = ${parent_str_fn_name}(*($sym.cname*)it.data);')
|
g.auto_str_funcs.writeln('\t\tres = ${parent_str_fn_name}(*($sym.cname*)it.data);')
|
||||||
}
|
}
|
||||||
g.auto_str_funcs.writeln('\t} else {')
|
g.auto_str_funcs.writeln('\t} else {')
|
||||||
g.auto_str_funcs.writeln('\t\tres = _STR("error: %.*s\\000", 2, IError_str(it.err));')
|
|
||||||
|
tmp_str := str_intp_sub('error: %%', 'IError_str(it.err)')
|
||||||
|
g.auto_str_funcs.writeln('\t\tres = $tmp_str;')
|
||||||
|
// g.auto_str_funcs.writeln('\t\tres = _STR("error: %.*s\\000", 2, IError_str(it.err));')
|
||||||
|
|
||||||
g.auto_str_funcs.writeln('\t}')
|
g.auto_str_funcs.writeln('\t}')
|
||||||
g.auto_str_funcs.writeln('\treturn _STR("Option(%.*s\\000)", 2, res);')
|
|
||||||
|
g.auto_str_funcs.writeln('\treturn ${str_intp_sub('Option(%%)', 'res')};')
|
||||||
|
// g.auto_str_funcs.writeln('\treturn _STR("Option(%.*s\\000)", 2, res);')
|
||||||
g.auto_str_funcs.writeln('}')
|
g.auto_str_funcs.writeln('}')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,223 +236,15 @@ fn (mut g Gen) gen_str_for_alias(info ast.Alias, styp string, str_fn_name string
|
||||||
g.auto_str_funcs.writeln('\tfor (int i = 0; i < indent_count; ++i) {')
|
g.auto_str_funcs.writeln('\tfor (int i = 0; i < indent_count; ++i) {')
|
||||||
g.auto_str_funcs.writeln('\t\tindents = string_add(indents, _SLIT(" "));')
|
g.auto_str_funcs.writeln('\t\tindents = string_add(indents, _SLIT(" "));')
|
||||||
g.auto_str_funcs.writeln('\t}')
|
g.auto_str_funcs.writeln('\t}')
|
||||||
g.auto_str_funcs.writeln('\treturn _STR("%.*s\\000${clean_type_v_type_name}(%.*s\\000)", 3, indents, ${parent_str_fn_name}(it));')
|
|
||||||
g.auto_str_funcs.writeln('}')
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut g Gen) gen_str_for_array(info ast.Array, styp string, str_fn_name string) {
|
g.auto_str_funcs.writeln('\treturn str_intp(3, _MOV((StrIntpData[]){
|
||||||
mut typ := info.elem_type
|
{_SLIT0, $c.si_s_code, {.d_s = indents }},
|
||||||
mut sym := g.table.get_type_symbol(info.elem_type)
|
{_SLIT("${clean_type_v_type_name}("), $c.si_s_code, {.d_s = ${parent_str_fn_name}(it) }},
|
||||||
if mut sym.info is ast.Alias {
|
{_SLIT(")"), 0, {.d_c = 0 }}
|
||||||
typ = sym.info.parent_type
|
}));\n')
|
||||||
sym = g.table.get_type_symbol(typ)
|
|
||||||
}
|
|
||||||
field_styp := g.typ(typ)
|
|
||||||
is_elem_ptr := typ.is_ptr()
|
|
||||||
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
|
|
||||||
mut elem_str_fn_name := ''
|
|
||||||
if sym_has_str_method {
|
|
||||||
elem_str_fn_name = if is_elem_ptr {
|
|
||||||
field_styp.replace('*', '') + '_str'
|
|
||||||
} else {
|
|
||||||
field_styp + '_str'
|
|
||||||
}
|
|
||||||
if sym.kind == .byte {
|
|
||||||
elem_str_fn_name = elem_str_fn_name + '_escaped'
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
elem_str_fn_name = styp_to_str_fn_name(field_styp)
|
|
||||||
}
|
|
||||||
if !sym_has_str_method {
|
|
||||||
g.gen_str_for_type(typ)
|
|
||||||
}
|
|
||||||
g.type_definitions.writeln('static string ${str_fn_name}($styp a); // auto')
|
|
||||||
g.auto_str_funcs.writeln('static string ${str_fn_name}($styp a) { return indent_${str_fn_name}(a, 0);}')
|
|
||||||
g.type_definitions.writeln('static string indent_${str_fn_name}($styp a, int indent_count); // auto')
|
|
||||||
g.auto_str_funcs.writeln('static string indent_${str_fn_name}($styp a, int indent_count) {')
|
|
||||||
g.auto_str_funcs.writeln('\tstrings__Builder sb = strings__new_builder(a.len * 10);')
|
|
||||||
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("["));')
|
|
||||||
g.auto_str_funcs.writeln('\tfor (int i = 0; i < a.len; ++i) {')
|
|
||||||
if sym.kind == .function {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}();')
|
|
||||||
} else {
|
|
||||||
if sym.kind == .array_fixed {
|
|
||||||
g.auto_str_funcs.writeln('\t\t$field_styp it;')
|
|
||||||
g.auto_str_funcs.writeln('\t\tmemcpy(*($field_styp*)it, (byte*)array_get(a, i), sizeof($field_styp));')
|
|
||||||
} else {
|
|
||||||
g.auto_str_funcs.writeln('\t\t$field_styp it = *($field_styp*)array_get(a, i);')
|
|
||||||
}
|
|
||||||
if should_use_indent_func(sym.kind) && !sym_has_str_method {
|
|
||||||
if is_elem_ptr {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstring x = indent_${elem_str_fn_name}(*it, indent_count);')
|
|
||||||
} else {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstring x = indent_${elem_str_fn_name}(it, indent_count);')
|
|
||||||
}
|
|
||||||
} else if sym.kind in [.f32, .f64] {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstring x = _STR("%g", 1, it);')
|
|
||||||
} else if sym.kind == .rune {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstring x = _STR("`%.*s\\000`", 2, ${elem_str_fn_name}(it));')
|
|
||||||
} else if sym.kind == .string {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstring x = _STR("\'%.*s\\000\'", 2, it);')
|
|
||||||
} else {
|
|
||||||
// There is a custom .str() method, so use it.
|
|
||||||
// NB: we need to take account of whether the user has defined
|
|
||||||
// `fn (x T) str() {` or `fn (x &T) str() {`, and convert accordingly
|
|
||||||
deref, deref_label := deref_kind(str_method_expects_ptr, is_elem_ptr, typ)
|
|
||||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _SLIT("$deref_label"));')
|
|
||||||
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}( $deref it);')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, x);')
|
|
||||||
if g.is_autofree && typ != ast.bool_type {
|
|
||||||
// no need to free "true"/"false" literals
|
|
||||||
g.auto_str_funcs.writeln('\t\tstring_free(&x);')
|
|
||||||
}
|
|
||||||
g.auto_str_funcs.writeln('\t\tif (i < a.len-1) {')
|
|
||||||
g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, _SLIT(", "));')
|
|
||||||
g.auto_str_funcs.writeln('\t\t}')
|
|
||||||
g.auto_str_funcs.writeln('\t}')
|
|
||||||
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("]"));')
|
|
||||||
g.auto_str_funcs.writeln('\tstring res = strings__Builder_str(&sb);')
|
|
||||||
g.auto_str_funcs.writeln('\tstrings__Builder_free(&sb);')
|
|
||||||
g.auto_str_funcs.writeln('\treturn res;')
|
|
||||||
g.auto_str_funcs.writeln('}')
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut g Gen) gen_str_for_array_fixed(info ast.ArrayFixed, styp string, str_fn_name string) {
|
// g.auto_str_funcs.writeln('\treturn _STR("%.*s\\000${clean_type_v_type_name}(%.*s\\000)", 3, indents, ${parent_str_fn_name}(it));')
|
||||||
mut typ := info.elem_type
|
|
||||||
mut sym := g.table.get_type_symbol(info.elem_type)
|
|
||||||
if mut sym.info is ast.Alias {
|
|
||||||
typ = sym.info.parent_type
|
|
||||||
sym = g.table.get_type_symbol(typ)
|
|
||||||
}
|
|
||||||
field_styp := g.typ(typ)
|
|
||||||
is_elem_ptr := typ.is_ptr()
|
|
||||||
sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info()
|
|
||||||
mut elem_str_fn_name := ''
|
|
||||||
if sym_has_str_method {
|
|
||||||
elem_str_fn_name = if is_elem_ptr {
|
|
||||||
field_styp.replace('*', '') + '_str'
|
|
||||||
} else {
|
|
||||||
field_styp + '_str'
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
elem_str_fn_name = styp_to_str_fn_name(field_styp)
|
|
||||||
}
|
|
||||||
if !sym.has_method('str') {
|
|
||||||
elem_str_fn_name = g.gen_str_for_type(typ)
|
|
||||||
}
|
|
||||||
g.type_definitions.writeln('static string ${str_fn_name}($styp a); // auto')
|
|
||||||
g.auto_str_funcs.writeln('static string ${str_fn_name}($styp a) { return indent_${str_fn_name}(a, 0);}')
|
|
||||||
g.type_definitions.writeln('static string indent_${str_fn_name}($styp a, int indent_count); // auto')
|
|
||||||
g.auto_str_funcs.writeln('static string indent_${str_fn_name}($styp a, int indent_count) {')
|
|
||||||
g.auto_str_funcs.writeln('\tstrings__Builder sb = strings__new_builder($info.size * 10);')
|
|
||||||
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("["));')
|
|
||||||
if sym.kind == .function {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstring x = ${elem_str_fn_name}();')
|
|
||||||
} else {
|
|
||||||
deref, deref_label := deref_kind(str_method_expects_ptr, is_elem_ptr, typ)
|
|
||||||
g.auto_str_funcs.writeln('\tfor (int i = 0; i < $info.size; ++i) {')
|
|
||||||
if should_use_indent_func(sym.kind) && !sym_has_str_method {
|
|
||||||
if is_elem_ptr {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _SLIT("$deref_label"));')
|
|
||||||
g.auto_str_funcs.writeln('\t\tif ( 0 == a[i] ) {')
|
|
||||||
g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, _SLIT("0"));')
|
|
||||||
g.auto_str_funcs.writeln('\t\t}else{')
|
|
||||||
g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}( $deref a[i]) );')
|
|
||||||
g.auto_str_funcs.writeln('\t\t}')
|
|
||||||
} else {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}( $deref a[i]) );')
|
|
||||||
}
|
|
||||||
} else if sym.kind in [.f32, .f64] {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _STR("%g", 1, a[i]));')
|
|
||||||
} else if sym.kind == .string {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _STR("\'%.*s\\000\'", 2, a[i]));')
|
|
||||||
} else if sym.kind == .rune {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _STR("`%.*s\\000`", 2, ${elem_str_fn_name}( $deref a[i])));')
|
|
||||||
} else {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}( $deref a[i]));')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g.auto_str_funcs.writeln('\t\tif (i < ${info.size - 1}) {')
|
|
||||||
g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, _SLIT(", "));')
|
|
||||||
g.auto_str_funcs.writeln('\t\t}')
|
|
||||||
g.auto_str_funcs.writeln('\t}')
|
|
||||||
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("]"));')
|
|
||||||
g.auto_str_funcs.writeln('\tstring res = strings__Builder_str(&sb);')
|
|
||||||
g.auto_str_funcs.writeln('\tstrings__Builder_free(&sb);')
|
|
||||||
g.auto_str_funcs.writeln('\treturn res;')
|
|
||||||
g.auto_str_funcs.writeln('}')
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut g Gen) gen_str_for_map(info ast.Map, styp string, str_fn_name string) {
|
|
||||||
mut key_typ := info.key_type
|
|
||||||
mut key_sym := g.table.get_type_symbol(key_typ)
|
|
||||||
if mut key_sym.info is ast.Alias {
|
|
||||||
key_typ = key_sym.info.parent_type
|
|
||||||
key_sym = g.table.get_type_symbol(key_typ)
|
|
||||||
}
|
|
||||||
key_styp := g.typ(key_typ)
|
|
||||||
key_str_fn_name := key_styp.replace('*', '') + '_str'
|
|
||||||
if !key_sym.has_method('str') {
|
|
||||||
g.gen_str_for_type(key_typ)
|
|
||||||
}
|
|
||||||
|
|
||||||
mut val_typ := info.value_type
|
|
||||||
mut val_sym := g.table.get_type_symbol(val_typ)
|
|
||||||
if mut val_sym.info is ast.Alias {
|
|
||||||
val_typ = val_sym.info.parent_type
|
|
||||||
val_sym = g.table.get_type_symbol(val_typ)
|
|
||||||
}
|
|
||||||
val_styp := g.typ(val_typ)
|
|
||||||
elem_str_fn_name := val_styp.replace('*', '') + '_str'
|
|
||||||
if !val_sym.has_method('str') {
|
|
||||||
g.gen_str_for_type(val_typ)
|
|
||||||
}
|
|
||||||
|
|
||||||
g.type_definitions.writeln('static string ${str_fn_name}($styp m); // auto')
|
|
||||||
g.auto_str_funcs.writeln('static string ${str_fn_name}($styp m) { return indent_${str_fn_name}(m, 0);}')
|
|
||||||
g.type_definitions.writeln('static string indent_${str_fn_name}($styp m, int indent_count); // auto')
|
|
||||||
g.auto_str_funcs.writeln('static string indent_${str_fn_name}($styp m, int indent_count) { /* gen_str_for_map */')
|
|
||||||
g.auto_str_funcs.writeln('\tstrings__Builder sb = strings__new_builder(m.key_values.len*10);')
|
|
||||||
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("{"));')
|
|
||||||
g.auto_str_funcs.writeln('\tfor (int i = 0; i < m.key_values.len; ++i) {')
|
|
||||||
g.auto_str_funcs.writeln('\t\tif (!DenseArray_has_index(&m.key_values, i)) { continue; }')
|
|
||||||
|
|
||||||
if key_sym.kind == .string {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstring key = *(string*)DenseArray_key(&m.key_values, i);')
|
|
||||||
} else {
|
|
||||||
g.auto_str_funcs.writeln('\t\t$key_styp key = *($key_styp*)DenseArray_key(&m.key_values, i);')
|
|
||||||
}
|
|
||||||
if key_sym.kind == .string {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _STR("\'%.*s\\000\'", 2, key));')
|
|
||||||
} else if key_sym.kind == .rune {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _STR("`%.*s\\000`", 2, ${key_str_fn_name}(key)));')
|
|
||||||
} else {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${key_str_fn_name}(key));')
|
|
||||||
}
|
|
||||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _SLIT(": "));')
|
|
||||||
if val_sym.kind == .function {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}());')
|
|
||||||
} else if val_sym.kind == .string {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _STR("\'%.*s\\000\'", 2, *($val_styp*)DenseArray_value(&m.key_values, i)));')
|
|
||||||
} else if should_use_indent_func(val_sym.kind) && !val_sym.has_method('str') {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, indent_${elem_str_fn_name}(*($val_styp*)DenseArray_value(&m.key_values, i), indent_count));')
|
|
||||||
} else if val_sym.kind in [.f32, .f64] {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _STR("%g", 1, *($val_styp*)DenseArray_value(&m.key_values, i)));')
|
|
||||||
} else if val_sym.kind == .rune {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, _STR("`%.*s\\000`", 2, ${elem_str_fn_name}(*($val_styp*)DenseArray_value(&m.key_values, i))));')
|
|
||||||
} else {
|
|
||||||
g.auto_str_funcs.writeln('\t\tstrings__Builder_write_string(&sb, ${elem_str_fn_name}(*($val_styp*)DenseArray_value(&m.key_values, i)));')
|
|
||||||
}
|
|
||||||
g.auto_str_funcs.writeln('\t\tif (i != m.key_values.len-1) {')
|
|
||||||
g.auto_str_funcs.writeln('\t\t\tstrings__Builder_write_string(&sb, _SLIT(", "));')
|
|
||||||
g.auto_str_funcs.writeln('\t\t}')
|
|
||||||
g.auto_str_funcs.writeln('\t}')
|
|
||||||
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _SLIT("}"));')
|
|
||||||
g.auto_str_funcs.writeln('\tstring res = strings__Builder_str(&sb);')
|
|
||||||
g.auto_str_funcs.writeln('\tstrings__Builder_free(&sb);')
|
|
||||||
g.auto_str_funcs.writeln('\treturn res;')
|
|
||||||
g.auto_str_funcs.writeln('}')
|
g.auto_str_funcs.writeln('}')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,9 +277,18 @@ fn (mut g Gen) gen_str_for_multi_return(info ast.MultiReturn, styp string, str_f
|
||||||
if should_use_indent_func(sym.kind) && !sym_has_str_method {
|
if should_use_indent_func(sym.kind) && !sym_has_str_method {
|
||||||
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, ${arg_str_fn_name}(a.arg$i));')
|
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, ${arg_str_fn_name}(a.arg$i));')
|
||||||
} else if sym.kind in [.f32, .f64] {
|
} else if sym.kind in [.f32, .f64] {
|
||||||
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _STR("%g", 1, a.arg$i));')
|
if sym.kind == .f32 {
|
||||||
|
tmp_val := str_intp_g32('a.arg$i')
|
||||||
|
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, $tmp_val);')
|
||||||
|
} else {
|
||||||
|
tmp_val := str_intp_g64('a.arg$i')
|
||||||
|
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, $tmp_val);')
|
||||||
|
}
|
||||||
|
// g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _STR("%g", 1, a.arg$i));')
|
||||||
} else if sym.kind == .string {
|
} else if sym.kind == .string {
|
||||||
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _STR("\'%.*s\\000\'", 2, a.arg$i));')
|
tmp_str := str_intp_sq('a.arg$i')
|
||||||
|
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, $tmp_str);')
|
||||||
|
// g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, _STR("\'%.*s\\000\'", 2, a.arg$i));')
|
||||||
} else if sym.kind == .function {
|
} else if sym.kind == .function {
|
||||||
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, ${arg_str_fn_name}());')
|
g.auto_str_funcs.writeln('\tstrings__Builder_write_string(&sb, ${arg_str_fn_name}());')
|
||||||
} else {
|
} else {
|
||||||
|
@ -457,136 +307,6 @@ fn (mut g Gen) gen_str_for_multi_return(info ast.MultiReturn, styp string, str_f
|
||||||
g.auto_str_funcs.writeln('}')
|
g.auto_str_funcs.writeln('}')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name string) {
|
|
||||||
// TODO: short it if possible
|
|
||||||
// generates all definitions of substructs
|
|
||||||
mut fnames2strfunc := map{
|
|
||||||
'': ''
|
|
||||||
}
|
|
||||||
for field in info.fields {
|
|
||||||
sym := g.table.get_type_symbol(field.typ)
|
|
||||||
if !sym.has_method('str') {
|
|
||||||
mut typ := field.typ
|
|
||||||
if typ.is_ptr() {
|
|
||||||
typ = typ.deref()
|
|
||||||
}
|
|
||||||
field_styp := g.typ(typ)
|
|
||||||
field_fn_name := g.gen_str_for_type(field.typ)
|
|
||||||
fnames2strfunc[field_styp] = field_fn_name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// _str() functions should have a single argument, the indenting ones take 2:
|
|
||||||
g.type_definitions.writeln('static string ${str_fn_name}($styp it); // auto')
|
|
||||||
g.auto_str_funcs.writeln('static string ${str_fn_name}($styp it) { return indent_${str_fn_name}(it, 0);}')
|
|
||||||
g.type_definitions.writeln('static string indent_${str_fn_name}($styp it, int indent_count); // auto')
|
|
||||||
g.auto_str_funcs.writeln('static string indent_${str_fn_name}($styp it, int indent_count) {')
|
|
||||||
mut clean_struct_v_type_name := styp.replace('__', '.')
|
|
||||||
if clean_struct_v_type_name.contains('_T_') {
|
|
||||||
// TODO: this is a bit hacky. styp shouldn't be even parsed with _T_
|
|
||||||
// use something different than g.typ for styp
|
|
||||||
clean_struct_v_type_name =
|
|
||||||
clean_struct_v_type_name.replace('Array_', '[]').replace('_T_', '<').replace('_', ', ') +
|
|
||||||
'>'
|
|
||||||
}
|
|
||||||
clean_struct_v_type_name = util.strip_main_name(clean_struct_v_type_name)
|
|
||||||
// generate ident / indent length = 4 spaces
|
|
||||||
g.auto_str_funcs.writeln('\tstring indents = _SLIT("");')
|
|
||||||
g.auto_str_funcs.writeln('\tfor (int i = 0; i < indent_count; ++i) {')
|
|
||||||
g.auto_str_funcs.writeln('\t\tindents = string_add(indents, _SLIT(" "));')
|
|
||||||
g.auto_str_funcs.writeln('\t}')
|
|
||||||
if info.fields.len == 0 {
|
|
||||||
g.auto_str_funcs.write_string('\treturn _SLIT("$clean_struct_v_type_name{}");')
|
|
||||||
} else {
|
|
||||||
g.auto_str_funcs.write_string('\treturn _STR("$clean_struct_v_type_name{\\n"')
|
|
||||||
for field in info.fields {
|
|
||||||
mut fmt := if field.typ.is_ptr() { '&' } else { '' }
|
|
||||||
fmt += g.type_to_fmt(field.typ)
|
|
||||||
g.auto_str_funcs.writeln('\t\t"%.*s\\000 $field.name: $fmt\\n"')
|
|
||||||
}
|
|
||||||
g.auto_str_funcs.write_string('\t\t"%.*s\\000}", ${2 * (info.fields.len + 1)}')
|
|
||||||
if info.fields.len > 0 {
|
|
||||||
g.auto_str_funcs.write_string(',\n\t\t')
|
|
||||||
for i, field in info.fields {
|
|
||||||
sym := g.table.get_type_symbol(field.typ)
|
|
||||||
has_custom_str := sym.has_method('str')
|
|
||||||
mut field_styp := g.typ(field.typ).replace('*', '')
|
|
||||||
field_styp_fn_name := if has_custom_str {
|
|
||||||
'${field_styp}_str'
|
|
||||||
} else {
|
|
||||||
fnames2strfunc[field_styp]
|
|
||||||
}
|
|
||||||
g.auto_str_funcs.write_string('indents, ')
|
|
||||||
mut func := struct_auto_str_func(sym, field.typ, field_styp_fn_name, field.name)
|
|
||||||
// reference types can be "nil"
|
|
||||||
if field.typ.is_ptr() && !(field.typ in ast.charptr_types
|
|
||||||
|| field.typ in ast.byteptr_types
|
|
||||||
|| field.typ == ast.voidptr_type_idx) {
|
|
||||||
g.auto_str_funcs.write_string('isnil(it.${c_name(field.name)})')
|
|
||||||
g.auto_str_funcs.write_string(' ? _SLIT("nil") : ')
|
|
||||||
// struct, floats and ints have a special case through the _str function
|
|
||||||
if sym.kind != .struct_ && !field.typ.is_int_valptr()
|
|
||||||
&& !field.typ.is_float_valptr() {
|
|
||||||
g.auto_str_funcs.write_string('*')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// handle circular ref type of struct to the struct itself
|
|
||||||
if styp == field_styp {
|
|
||||||
g.auto_str_funcs.write_string('_SLIT("<circular>")')
|
|
||||||
} else {
|
|
||||||
g.auto_str_funcs.write_string(func)
|
|
||||||
}
|
|
||||||
|
|
||||||
if i < info.fields.len - 1 {
|
|
||||||
g.auto_str_funcs.write_string(',\n\t\t')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g.auto_str_funcs.writeln(',')
|
|
||||||
g.auto_str_funcs.writeln('\t\tindents);')
|
|
||||||
}
|
|
||||||
g.auto_str_funcs.writeln('}')
|
|
||||||
}
|
|
||||||
|
|
||||||
fn struct_auto_str_func(sym &ast.TypeSymbol, field_type ast.Type, fn_name string, field_name string) string {
|
|
||||||
has_custom_str, expects_ptr, _ := sym.str_method_info()
|
|
||||||
if sym.kind == .enum_ {
|
|
||||||
return '${fn_name}(it.${c_name(field_name)})'
|
|
||||||
} else if should_use_indent_func(sym.kind) {
|
|
||||||
mut obj := 'it.${c_name(field_name)}'
|
|
||||||
if field_type.is_ptr() && !expects_ptr {
|
|
||||||
obj = '*$obj'
|
|
||||||
}
|
|
||||||
if has_custom_str {
|
|
||||||
return '${fn_name}($obj)'
|
|
||||||
}
|
|
||||||
return 'indent_${fn_name}($obj, indent_count + 1)'
|
|
||||||
} else if sym.kind in [.array, .array_fixed, .map, .sum_type] {
|
|
||||||
if has_custom_str {
|
|
||||||
return '${fn_name}(it.${c_name(field_name)})'
|
|
||||||
}
|
|
||||||
return 'indent_${fn_name}(it.${c_name(field_name)}, indent_count + 1)'
|
|
||||||
} else if sym.kind == .function {
|
|
||||||
return '${fn_name}()'
|
|
||||||
} else {
|
|
||||||
mut method_str := 'it.${c_name(field_name)}'
|
|
||||||
if sym.kind == .bool {
|
|
||||||
method_str += ' ? _SLIT("true") : _SLIT("false")'
|
|
||||||
} else if (field_type.is_int_valptr() || field_type.is_float_valptr())
|
|
||||||
&& field_type.is_ptr() && !expects_ptr {
|
|
||||||
// ptr int can be "nil", so this needs to be castet to a string
|
|
||||||
fmt := if sym.kind in [.f32, .f64] {
|
|
||||||
'%g\\000'
|
|
||||||
} else if sym.kind == .u64 {
|
|
||||||
'%lld\\000'
|
|
||||||
} else {
|
|
||||||
'%d\\000'
|
|
||||||
}
|
|
||||||
method_str = '_STR("$fmt", 2, *$method_str)'
|
|
||||||
}
|
|
||||||
return method_str
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut g Gen) gen_str_for_enum(info ast.Enum, styp string, str_fn_name string) {
|
fn (mut g Gen) gen_str_for_enum(info ast.Enum, styp string, str_fn_name string) {
|
||||||
s := util.no_dots(styp)
|
s := util.no_dots(styp)
|
||||||
g.type_definitions.writeln('static string ${str_fn_name}($styp it); // auto')
|
g.type_definitions.writeln('static string ${str_fn_name}($styp it); // auto')
|
||||||
|
@ -653,6 +373,38 @@ fn (mut g Gen) gen_str_for_interface(info ast.Interface, styp string, str_fn_nam
|
||||||
if should_use_indent_func(subtype.kind) && !sym_has_str_method {
|
if should_use_indent_func(subtype.kind) && !sym_has_str_method {
|
||||||
func_name = 'indent_$func_name'
|
func_name = 'indent_$func_name'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// str_intp
|
||||||
|
deref := if sym_has_str_method && str_method_expects_ptr { ' ' } else { '*' }
|
||||||
|
if typ == ast.string_type {
|
||||||
|
mut val := '${func_name}(${deref}($subtype.cname*)x._$subtype.cname'
|
||||||
|
if should_use_indent_func(subtype.kind) && !sym_has_str_method {
|
||||||
|
val += ', indent_count'
|
||||||
|
}
|
||||||
|
val += ')'
|
||||||
|
res := 'str_intp(2, _MOV((StrIntpData[]){
|
||||||
|
{_SLIT("${clean_interface_v_type_name}(\'"), $c.si_s_code, {.d_s = $val}},
|
||||||
|
{_SLIT("\')"), 0, {.d_c = 0 }}
|
||||||
|
}))'
|
||||||
|
g.auto_str_funcs.write_string('\tif (x._typ == _${styp}_${subtype.cname}_index)')
|
||||||
|
g.auto_str_funcs.write_string(' return $res;')
|
||||||
|
} else {
|
||||||
|
mut val := '${func_name}(${deref}($subtype.cname*)x._$subtype.cname'
|
||||||
|
if should_use_indent_func(subtype.kind) && !sym_has_str_method {
|
||||||
|
val += ', indent_count'
|
||||||
|
}
|
||||||
|
val += ')'
|
||||||
|
res := 'str_intp(2, _MOV((StrIntpData[]){
|
||||||
|
{_SLIT("${clean_interface_v_type_name}("), $c.si_s_code, {.d_s = $val}},
|
||||||
|
{_SLIT(")"), 0, {.d_c = 0 }}
|
||||||
|
}))'
|
||||||
|
g.auto_str_funcs.write_string('\tif (x._typ == _${styp}_${subtype.cname}_index)')
|
||||||
|
g.auto_str_funcs.write_string(' return $res;\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
/*
|
||||||
deref := if sym_has_str_method && str_method_expects_ptr { ' ' } else { '*' }
|
deref := if sym_has_str_method && str_method_expects_ptr { ' ' } else { '*' }
|
||||||
value_fmt := if typ == ast.string_type { "'%.*s\\000'" } else { '%.*s\\000' }
|
value_fmt := if typ == ast.string_type { "'%.*s\\000'" } else { '%.*s\\000' }
|
||||||
|
|
||||||
|
@ -662,7 +414,9 @@ fn (mut g Gen) gen_str_for_interface(info ast.Interface, styp string, str_fn_nam
|
||||||
if should_use_indent_func(subtype.kind) && !sym_has_str_method {
|
if should_use_indent_func(subtype.kind) && !sym_has_str_method {
|
||||||
g.auto_str_funcs.write_string(', indent_count')
|
g.auto_str_funcs.write_string(', indent_count')
|
||||||
}
|
}
|
||||||
g.auto_str_funcs.writeln('));')
|
g.auto_str_funcs.writeln('));\n')
|
||||||
|
*/
|
||||||
|
//------------------------------------------
|
||||||
}
|
}
|
||||||
g.auto_str_funcs.writeln('\treturn _SLIT("unknown interface value");')
|
g.auto_str_funcs.writeln('\treturn _SLIT("unknown interface value");')
|
||||||
g.auto_str_funcs.writeln('}')
|
g.auto_str_funcs.writeln('}')
|
||||||
|
@ -690,10 +444,6 @@ fn (mut g Gen) gen_str_for_union_sum_type(info ast.SumType, styp string, str_fn_
|
||||||
clean_sum_type_v_type_name = util.strip_main_name(clean_sum_type_v_type_name)
|
clean_sum_type_v_type_name = util.strip_main_name(clean_sum_type_v_type_name)
|
||||||
g.auto_str_funcs.writeln('\tswitch(x._typ) {')
|
g.auto_str_funcs.writeln('\tswitch(x._typ) {')
|
||||||
for typ in info.variants {
|
for typ in info.variants {
|
||||||
mut value_fmt := '%.*s\\000'
|
|
||||||
if typ == ast.string_type {
|
|
||||||
value_fmt = "'$value_fmt'"
|
|
||||||
}
|
|
||||||
typ_str := g.typ(typ)
|
typ_str := g.typ(typ)
|
||||||
mut func_name := if typ_str in gen_fn_names {
|
mut func_name := if typ_str in gen_fn_names {
|
||||||
gen_fn_names[typ_str]
|
gen_fn_names[typ_str]
|
||||||
|
@ -706,11 +456,46 @@ fn (mut g Gen) gen_str_for_union_sum_type(info ast.SumType, styp string, str_fn_
|
||||||
if should_use_indent_func(sym.kind) && !sym_has_str_method {
|
if should_use_indent_func(sym.kind) && !sym_has_str_method {
|
||||||
func_name = 'indent_$func_name'
|
func_name = 'indent_$func_name'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
// str_intp
|
||||||
|
if typ == ast.string_type {
|
||||||
|
mut val := '${func_name}(${deref}($typ_str*)x._$sym.cname'
|
||||||
|
if should_use_indent_func(sym.kind) && !sym_has_str_method {
|
||||||
|
val += ', indent_count'
|
||||||
|
}
|
||||||
|
val += ')'
|
||||||
|
res := 'str_intp(2, _MOV((StrIntpData[]){
|
||||||
|
{_SLIT("${clean_sum_type_v_type_name}(\'"), $c.si_s_code, {.d_s = $val}},
|
||||||
|
{_SLIT("\')"), 0, {.d_c = 0 }}
|
||||||
|
}))'
|
||||||
|
g.auto_str_funcs.write_string('\t\tcase $typ: return $res;')
|
||||||
|
} else {
|
||||||
|
mut val := '${func_name}(${deref}($typ_str*)x._$sym.cname'
|
||||||
|
if should_use_indent_func(sym.kind) && !sym_has_str_method {
|
||||||
|
val += ', indent_count'
|
||||||
|
}
|
||||||
|
val += ')'
|
||||||
|
res := 'str_intp(2, _MOV((StrIntpData[]){
|
||||||
|
{_SLIT("${clean_sum_type_v_type_name}("), $c.si_s_code, {.d_s = $val}},
|
||||||
|
{_SLIT(")"), 0, {.d_c = 0 }}
|
||||||
|
}))'
|
||||||
|
g.auto_str_funcs.write_string('\t\tcase $typ: return $res;')
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
/*
|
||||||
|
mut value_fmt := '%.*s\\000'
|
||||||
|
if typ == ast.string_type {
|
||||||
|
value_fmt = "'$value_fmt'"
|
||||||
|
}
|
||||||
g.auto_str_funcs.write_string('\t\tcase $typ: return _STR("${clean_sum_type_v_type_name}($value_fmt)", 2, ${func_name}(${deref}($typ_str*)x._$sym.cname')
|
g.auto_str_funcs.write_string('\t\tcase $typ: return _STR("${clean_sum_type_v_type_name}($value_fmt)", 2, ${func_name}(${deref}($typ_str*)x._$sym.cname')
|
||||||
if should_use_indent_func(sym.kind) && !sym_has_str_method {
|
if should_use_indent_func(sym.kind) && !sym_has_str_method {
|
||||||
g.auto_str_funcs.write_string(', indent_count')
|
g.auto_str_funcs.write_string(', indent_count')
|
||||||
}
|
}
|
||||||
g.auto_str_funcs.writeln('));')
|
g.auto_str_funcs.writeln('));')
|
||||||
|
*/
|
||||||
|
//------------------------------------------
|
||||||
}
|
}
|
||||||
g.auto_str_funcs.writeln('\t\tdefault: return _SLIT("unknown sum type value");')
|
g.auto_str_funcs.writeln('\t\tdefault: return _SLIT("unknown sum type value");')
|
||||||
g.auto_str_funcs.writeln('\t}')
|
g.auto_str_funcs.writeln('\t}')
|
||||||
|
@ -730,7 +515,8 @@ fn (mut g Gen) fn_decl_str(info ast.FnType) string {
|
||||||
}
|
}
|
||||||
fn_str += ')'
|
fn_str += ')'
|
||||||
if info.func.return_type != ast.void_type {
|
if info.func.return_type != ast.void_type {
|
||||||
fn_str += ' ${util.strip_main_name(g.table.get_type_name(g.unwrap_generic(info.func.return_type)))}'
|
x := util.strip_main_name(g.table.get_type_name(g.unwrap_generic(info.func.return_type)))
|
||||||
|
fn_str += ' $x'
|
||||||
}
|
}
|
||||||
return fn_str
|
return fn_str
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,387 @@
|
||||||
|
module c
|
||||||
|
|
||||||
|
// Copyright (c) 2019-2021 Alexander Medvednikov. 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.
|
||||||
|
import v.ast
|
||||||
|
import v.util
|
||||||
|
|
||||||
|
fn (g &Gen) type_to_fmt1(typ ast.Type) StrIntpType {
|
||||||
|
if typ == ast.byte_type_idx {
|
||||||
|
return .si_u8
|
||||||
|
}
|
||||||
|
if typ == ast.char_type_idx {
|
||||||
|
return .si_c
|
||||||
|
}
|
||||||
|
if typ == ast.voidptr_type_idx || typ in ast.byteptr_types {
|
||||||
|
return .si_p
|
||||||
|
}
|
||||||
|
if typ in ast.charptr_types {
|
||||||
|
return .si_s
|
||||||
|
// return '%C\\000' // a C string
|
||||||
|
}
|
||||||
|
sym := g.table.get_type_symbol(typ)
|
||||||
|
if typ.is_ptr() && (typ.is_int_valptr() || typ.is_float_valptr()) {
|
||||||
|
return .si_s
|
||||||
|
} else if sym.kind in [.struct_, .array, .array_fixed, .map, .bool, .enum_, .interface_,
|
||||||
|
.sum_type, .function, .alias] {
|
||||||
|
return .si_s
|
||||||
|
} else if sym.kind == .string {
|
||||||
|
return .si_s
|
||||||
|
// return "'%.*s\\000'"
|
||||||
|
} else if sym.kind in [.f32, .f64] {
|
||||||
|
if sym.kind == .f32 {
|
||||||
|
return .si_g32
|
||||||
|
}
|
||||||
|
return .si_g64
|
||||||
|
} else if sym.kind == .int {
|
||||||
|
return .si_i32
|
||||||
|
} else if sym.kind == .u32 {
|
||||||
|
return .si_u32
|
||||||
|
} else if sym.kind == .u64 {
|
||||||
|
return .si_u64
|
||||||
|
} else if sym.kind == .i64 {
|
||||||
|
return .si_i64
|
||||||
|
}
|
||||||
|
|
||||||
|
return .si_i32
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name string) {
|
||||||
|
// g.gen_str_for_struct1(info, styp, str_fn_name)
|
||||||
|
|
||||||
|
// TODO: short it if possible
|
||||||
|
// generates all definitions of substructs
|
||||||
|
mut fnames2strfunc := map{
|
||||||
|
'': ''
|
||||||
|
}
|
||||||
|
for field in info.fields {
|
||||||
|
sym := g.table.get_type_symbol(field.typ)
|
||||||
|
if !sym.has_method('str') {
|
||||||
|
mut typ := field.typ
|
||||||
|
if typ.is_ptr() {
|
||||||
|
typ = typ.deref()
|
||||||
|
}
|
||||||
|
field_styp := g.typ(typ)
|
||||||
|
field_fn_name := g.gen_str_for_type(field.typ)
|
||||||
|
fnames2strfunc[field_styp] = field_fn_name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// _str() functions should have a single argument, the indenting ones take 2:
|
||||||
|
g.type_definitions.writeln('static string ${str_fn_name}($styp it); // auto')
|
||||||
|
g.auto_str_funcs.writeln('static string ${str_fn_name}($styp it) { return indent_${str_fn_name}(it, 0);}')
|
||||||
|
g.type_definitions.writeln('static string indent_${str_fn_name}($styp it, int indent_count); // auto')
|
||||||
|
g.auto_str_funcs.writeln('static string indent_${str_fn_name}($styp it, int indent_count) {')
|
||||||
|
mut clean_struct_v_type_name := styp.replace('__', '.')
|
||||||
|
if clean_struct_v_type_name.contains('_T_') {
|
||||||
|
// TODO: this is a bit hacky. styp shouldn't be even parsed with _T_
|
||||||
|
// use something different than g.typ for styp
|
||||||
|
clean_struct_v_type_name =
|
||||||
|
clean_struct_v_type_name.replace('Array_', '[]').replace('_T_', '<').replace('_', ', ') +
|
||||||
|
'>'
|
||||||
|
}
|
||||||
|
clean_struct_v_type_name = util.strip_main_name(clean_struct_v_type_name)
|
||||||
|
// generate ident / indent length = 4 spaces
|
||||||
|
g.auto_str_funcs.writeln('\tstring indents = _SLIT("");')
|
||||||
|
g.auto_str_funcs.writeln('\tfor (int i = 0; i < indent_count; ++i) {')
|
||||||
|
g.auto_str_funcs.writeln('\t\tindents = string_add(indents, _SLIT(" "));')
|
||||||
|
g.auto_str_funcs.writeln('\t}')
|
||||||
|
if info.fields.len == 0 {
|
||||||
|
g.auto_str_funcs.write_string('\treturn _SLIT("$clean_struct_v_type_name{}");')
|
||||||
|
} else {
|
||||||
|
g.auto_str_funcs.write_string('\treturn str_intp( ${info.fields.len * 4 + 3}, _MOV((StrIntpData[]){\n')
|
||||||
|
g.auto_str_funcs.write_string('\t\t{_SLIT("$clean_struct_v_type_name{\\n"), 0, {.d_c=0}},\n')
|
||||||
|
|
||||||
|
for i, field in info.fields {
|
||||||
|
mut ptr_amp := if field.typ.is_ptr() { '&' } else { '' }
|
||||||
|
base_fmt := g.type_to_fmt1(field.typ)
|
||||||
|
|
||||||
|
// manage prefix and quote symbol for the filed
|
||||||
|
mut quote_str := ''
|
||||||
|
mut prefix := ''
|
||||||
|
sym := g.table.get_type_symbol(field.typ)
|
||||||
|
if sym.kind == .string {
|
||||||
|
quote_str = "'"
|
||||||
|
} else if field.typ in ast.charptr_types {
|
||||||
|
quote_str = '\\"'
|
||||||
|
prefix = 'C'
|
||||||
|
}
|
||||||
|
|
||||||
|
// first fields doesn't need \n
|
||||||
|
if i == 0 {
|
||||||
|
g.auto_str_funcs.write_string('\t\t{_SLIT0, $si_s_code, {.d_s=indents}}, {_SLIT(" $field.name: $ptr_amp$prefix"), 0, {.d_c=0}}, ')
|
||||||
|
} else {
|
||||||
|
g.auto_str_funcs.write_string('\t\t{_SLIT("\\n"), $si_s_code, {.d_s=indents}}, {_SLIT(" $field.name: $ptr_amp$prefix"), 0, {.d_c=0}}, ')
|
||||||
|
}
|
||||||
|
|
||||||
|
// custom methods management
|
||||||
|
has_custom_str := sym.has_method('str')
|
||||||
|
mut field_styp := g.typ(field.typ).replace('*', '')
|
||||||
|
field_styp_fn_name := if has_custom_str {
|
||||||
|
'${field_styp}_str'
|
||||||
|
} else {
|
||||||
|
fnames2strfunc[field_styp]
|
||||||
|
}
|
||||||
|
|
||||||
|
// manage the fact hat with float we use always the g representation
|
||||||
|
if sym.kind !in [.f32, .f64] {
|
||||||
|
g.auto_str_funcs.write_string('{_SLIT("$quote_str"), ${int(base_fmt)}, {.${data_str(base_fmt)}=')
|
||||||
|
} else {
|
||||||
|
g_fmt := '0x' + (u32(base_fmt) | u32(0x7F) << 9).hex()
|
||||||
|
g.auto_str_funcs.write_string('{_SLIT("$quote_str"), $g_fmt, {.${data_str(base_fmt)}=')
|
||||||
|
}
|
||||||
|
|
||||||
|
mut func := struct_auto_str_func1(sym, field.typ, field_styp_fn_name, field.name)
|
||||||
|
|
||||||
|
// manage reference types can be "nil"
|
||||||
|
if field.typ.is_ptr() && !(field.typ in ast.charptr_types
|
||||||
|
|| field.typ in ast.byteptr_types
|
||||||
|
|| field.typ == ast.voidptr_type_idx) {
|
||||||
|
g.auto_str_funcs.write_string('isnil(it.${c_name(field.name)})')
|
||||||
|
g.auto_str_funcs.write_string(' ? _SLIT("nil") : ')
|
||||||
|
// struct, floats and ints have a special case through the _str function
|
||||||
|
if sym.kind != .struct_ && !field.typ.is_int_valptr()
|
||||||
|
&& !field.typ.is_float_valptr() {
|
||||||
|
g.auto_str_funcs.write_string('*')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// handle circular ref type of struct to the struct itself
|
||||||
|
if styp == field_styp {
|
||||||
|
g.auto_str_funcs.write_string('_SLIT("<circular>")')
|
||||||
|
} else {
|
||||||
|
// manage C charptr
|
||||||
|
if field.typ in ast.charptr_types {
|
||||||
|
g.auto_str_funcs.write_string('tos2((byteptr)$func)')
|
||||||
|
} else {
|
||||||
|
g.auto_str_funcs.write_string(func)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g.auto_str_funcs.write_string('}}, {_SLIT("$quote_str"), 0, {.d_c=0}},\n')
|
||||||
|
}
|
||||||
|
g.auto_str_funcs.write_string('\t\t{_SLIT("\\n"), $si_s_code, {.d_s=indents}}, {_SLIT("}"), 0, {.d_c=0}},\n')
|
||||||
|
g.auto_str_funcs.write_string('\t}));\n')
|
||||||
|
}
|
||||||
|
g.auto_str_funcs.writeln('}')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn struct_auto_str_func1(sym &ast.TypeSymbol, field_type ast.Type, fn_name string, field_name string) string {
|
||||||
|
has_custom_str, expects_ptr, _ := sym.str_method_info()
|
||||||
|
if sym.kind == .enum_ {
|
||||||
|
return '${fn_name}(it.${c_name(field_name)})'
|
||||||
|
} else if should_use_indent_func(sym.kind) {
|
||||||
|
mut obj := 'it.${c_name(field_name)}'
|
||||||
|
if field_type.is_ptr() && !expects_ptr {
|
||||||
|
obj = '*$obj'
|
||||||
|
}
|
||||||
|
if has_custom_str {
|
||||||
|
return '${fn_name}($obj)'
|
||||||
|
}
|
||||||
|
return 'indent_${fn_name}($obj, indent_count + 1)'
|
||||||
|
} else if sym.kind in [.array, .array_fixed, .map, .sum_type] {
|
||||||
|
if has_custom_str {
|
||||||
|
return '${fn_name}(it.${c_name(field_name)})'
|
||||||
|
}
|
||||||
|
return 'indent_${fn_name}(it.${c_name(field_name)}, indent_count + 1)'
|
||||||
|
} else if sym.kind == .function {
|
||||||
|
return '${fn_name}()'
|
||||||
|
} else {
|
||||||
|
mut method_str := 'it.${c_name(field_name)}'
|
||||||
|
if sym.kind == .bool {
|
||||||
|
method_str += ' ? _SLIT("true") : _SLIT("false")'
|
||||||
|
} else if (field_type.is_int_valptr() || field_type.is_float_valptr())
|
||||||
|
&& field_type.is_ptr() && !expects_ptr {
|
||||||
|
// ptr int can be "nil", so this needs to be castet to a string
|
||||||
|
|
||||||
|
if sym.kind == .f32 {
|
||||||
|
return 'str_intp(1, _MOV((StrIntpData[]){
|
||||||
|
{_SLIT0, $si_g32_code, {.d_f32 = *$method_str }}
|
||||||
|
}))'
|
||||||
|
} else if sym.kind == .f64 {
|
||||||
|
return 'str_intp(1, _MOV((StrIntpData[]){
|
||||||
|
{_SLIT0, $si_g64_code, {.d_f64 = *$method_str }}
|
||||||
|
}))'
|
||||||
|
} else if sym.kind == .u64 {
|
||||||
|
fmt_type := StrIntpType.si_u64
|
||||||
|
return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_u64 = *$method_str }}}))'
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt_type := StrIntpType.si_i32
|
||||||
|
return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_i32 = *$method_str }}}))'
|
||||||
|
}
|
||||||
|
return method_str
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// OLD CODE
|
||||||
|
//=============================================================================
|
||||||
|
/*
|
||||||
|
fn (g &Gen) type_to_fmt(typ ast.Type) string {
|
||||||
|
if typ == ast.byte_type_idx {
|
||||||
|
return '%hhx\\000'
|
||||||
|
}
|
||||||
|
if typ == ast.char_type_idx {
|
||||||
|
return '%c\\000'
|
||||||
|
}
|
||||||
|
if typ == ast.voidptr_type_idx || typ in ast.byteptr_types {
|
||||||
|
return '%p\\000'
|
||||||
|
}
|
||||||
|
if typ in ast.charptr_types {
|
||||||
|
return '%C\\000' // a C string
|
||||||
|
}
|
||||||
|
sym := g.table.get_type_symbol(typ)
|
||||||
|
if typ.is_ptr() && (typ.is_int_valptr() || typ.is_float_valptr()) {
|
||||||
|
return '%.*s\\000'
|
||||||
|
} else if sym.kind in [.struct_, .array, .array_fixed, .map, .bool, .enum_, .interface_,
|
||||||
|
.sum_type, .function, .alias] {
|
||||||
|
return '%.*s\\000'
|
||||||
|
} else if sym.kind == .string {
|
||||||
|
return "'%.*s\\000'"
|
||||||
|
} else if sym.kind in [.f32, .f64] {
|
||||||
|
return '%g\\000' // g removes trailing zeros unlike %f
|
||||||
|
} else if sym.kind == .int {
|
||||||
|
return '%d\\000'
|
||||||
|
} else if sym.kind == .u32 {
|
||||||
|
return '%u\\000'
|
||||||
|
} else if sym.kind == .u64 {
|
||||||
|
return '%llu\\000'
|
||||||
|
} else if sym.kind == .i64 {
|
||||||
|
return '%lld\\000'
|
||||||
|
}
|
||||||
|
return '%d\\000'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name string) {
|
||||||
|
|
||||||
|
//g.gen_str_for_struct1(info, styp, str_fn_name)
|
||||||
|
|
||||||
|
// TODO: short it if possible
|
||||||
|
// generates all definitions of substructs
|
||||||
|
mut fnames2strfunc := map{
|
||||||
|
'': ''
|
||||||
|
}
|
||||||
|
for field in info.fields {
|
||||||
|
sym := g.table.get_type_symbol(field.typ)
|
||||||
|
if !sym.has_method('str') {
|
||||||
|
mut typ := field.typ
|
||||||
|
if typ.is_ptr() {
|
||||||
|
typ = typ.deref()
|
||||||
|
}
|
||||||
|
field_styp := g.typ(typ)
|
||||||
|
field_fn_name := g.gen_str_for_type(field.typ)
|
||||||
|
fnames2strfunc[field_styp] = field_fn_name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// _str() functions should have a single argument, the indenting ones take 2:
|
||||||
|
g.type_definitions.writeln('static string ${str_fn_name}($styp it); // auto')
|
||||||
|
g.auto_str_funcs.writeln('static string ${str_fn_name}($styp it) { return indent_${str_fn_name}(it, 0);}')
|
||||||
|
g.type_definitions.writeln('static string indent_${str_fn_name}($styp it, int indent_count); // auto')
|
||||||
|
g.auto_str_funcs.writeln('static string indent_${str_fn_name}($styp it, int indent_count) {')
|
||||||
|
mut clean_struct_v_type_name := styp.replace('__', '.')
|
||||||
|
if clean_struct_v_type_name.contains('_T_') {
|
||||||
|
// TODO: this is a bit hacky. styp shouldn't be even parsed with _T_
|
||||||
|
// use something different than g.typ for styp
|
||||||
|
clean_struct_v_type_name =
|
||||||
|
clean_struct_v_type_name.replace('Array_', '[]').replace('_T_', '<').replace('_', ', ') +
|
||||||
|
'>'
|
||||||
|
}
|
||||||
|
clean_struct_v_type_name = util.strip_main_name(clean_struct_v_type_name)
|
||||||
|
// generate ident / indent length = 4 spaces
|
||||||
|
g.auto_str_funcs.writeln('\tstring indents = _SLIT("");')
|
||||||
|
g.auto_str_funcs.writeln('\tfor (int i = 0; i < indent_count; ++i) {')
|
||||||
|
g.auto_str_funcs.writeln('\t\tindents = string_add(indents, _SLIT(" "));')
|
||||||
|
g.auto_str_funcs.writeln('\t}')
|
||||||
|
if info.fields.len == 0 {
|
||||||
|
g.auto_str_funcs.write_string('\treturn _SLIT("$clean_struct_v_type_name{}");')
|
||||||
|
} else {
|
||||||
|
g.auto_str_funcs.write_string('\treturn _STR("$clean_struct_v_type_name{\\n"')
|
||||||
|
for field in info.fields {
|
||||||
|
mut fmt := if field.typ.is_ptr() { '&' } else { '' }
|
||||||
|
fmt += g.type_to_fmt(field.typ)
|
||||||
|
g.auto_str_funcs.writeln('\t\t"%.*s\\000 $field.name: $fmt\\n"')
|
||||||
|
}
|
||||||
|
g.auto_str_funcs.write_string('\t\t"%.*s\\000}", ${2 * (info.fields.len + 1)}')
|
||||||
|
if info.fields.len > 0 {
|
||||||
|
g.auto_str_funcs.write_string(',\n\t\t')
|
||||||
|
for i, field in info.fields {
|
||||||
|
sym := g.table.get_type_symbol(field.typ)
|
||||||
|
has_custom_str := sym.has_method('str')
|
||||||
|
mut field_styp := g.typ(field.typ).replace('*', '')
|
||||||
|
field_styp_fn_name := if has_custom_str {
|
||||||
|
'${field_styp}_str'
|
||||||
|
} else {
|
||||||
|
fnames2strfunc[field_styp]
|
||||||
|
}
|
||||||
|
g.auto_str_funcs.write_string('indents, ')
|
||||||
|
mut func := struct_auto_str_func(sym, field.typ, field_styp_fn_name, field.name)
|
||||||
|
// reference types can be "nil"
|
||||||
|
if field.typ.is_ptr() && !(field.typ in ast.charptr_types
|
||||||
|
|| field.typ in ast.byteptr_types
|
||||||
|
|| field.typ == ast.voidptr_type_idx) {
|
||||||
|
g.auto_str_funcs.write_string('isnil(it.${c_name(field.name)})')
|
||||||
|
g.auto_str_funcs.write_string(' ? _SLIT("nil") : ')
|
||||||
|
// struct, floats and ints have a special case through the _str function
|
||||||
|
if sym.kind != .struct_ && !field.typ.is_int_valptr()
|
||||||
|
&& !field.typ.is_float_valptr() {
|
||||||
|
g.auto_str_funcs.write_string('*')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// handle circular ref type of struct to the struct itself
|
||||||
|
if styp == field_styp {
|
||||||
|
g.auto_str_funcs.write_string('_SLIT("<circular>")')
|
||||||
|
} else {
|
||||||
|
g.auto_str_funcs.write_string(func)
|
||||||
|
}
|
||||||
|
|
||||||
|
if i < info.fields.len - 1 {
|
||||||
|
g.auto_str_funcs.write_string(',\n\t\t')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.auto_str_funcs.writeln(',')
|
||||||
|
g.auto_str_funcs.writeln('\t\tindents);')
|
||||||
|
}
|
||||||
|
g.auto_str_funcs.writeln('}')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn struct_auto_str_func(sym &ast.TypeSymbol, field_type ast.Type, fn_name string, field_name string) string {
|
||||||
|
has_custom_str, expects_ptr, _ := sym.str_method_info()
|
||||||
|
if sym.kind == .enum_ {
|
||||||
|
return '${fn_name}(it.${c_name(field_name)})'
|
||||||
|
} else if should_use_indent_func(sym.kind) {
|
||||||
|
mut obj := 'it.${c_name(field_name)}'
|
||||||
|
if field_type.is_ptr() && !expects_ptr {
|
||||||
|
obj = '*$obj'
|
||||||
|
}
|
||||||
|
if has_custom_str {
|
||||||
|
return '${fn_name}($obj)'
|
||||||
|
}
|
||||||
|
return 'indent_${fn_name}($obj, indent_count + 1)'
|
||||||
|
} else if sym.kind in [.array, .array_fixed, .map, .sum_type] {
|
||||||
|
if has_custom_str {
|
||||||
|
return '${fn_name}(it.${c_name(field_name)})'
|
||||||
|
}
|
||||||
|
return 'indent_${fn_name}(it.${c_name(field_name)}, indent_count + 1)'
|
||||||
|
} else if sym.kind == .function {
|
||||||
|
return '${fn_name}()'
|
||||||
|
} else {
|
||||||
|
mut method_str := 'it.${c_name(field_name)}'
|
||||||
|
if sym.kind == .bool {
|
||||||
|
method_str += ' ? _SLIT("true") : _SLIT("false")'
|
||||||
|
} else if (field_type.is_int_valptr() || field_type.is_float_valptr())
|
||||||
|
&& field_type.is_ptr() && !expects_ptr {
|
||||||
|
// ptr int can be "nil", so this needs to be castet to a string
|
||||||
|
fmt := if sym.kind in [.f32, .f64] {
|
||||||
|
'%g\\000'
|
||||||
|
} else if sym.kind == .u64 {
|
||||||
|
'%lld\\000'
|
||||||
|
} else {
|
||||||
|
'%d\\000'
|
||||||
|
}
|
||||||
|
method_str = '_STR("$fmt", 2, *$method_str)'
|
||||||
|
}
|
||||||
|
return method_str
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
|
@ -408,8 +408,8 @@ pub fn (mut g Gen) init() {
|
||||||
} else {
|
} else {
|
||||||
g.cheaders.writeln(c_headers)
|
g.cheaders.writeln(c_headers)
|
||||||
}
|
}
|
||||||
g.definitions.writeln('string _STR(const char*, int, ...);')
|
// g.definitions.writeln('string _STR(const char*, int, ...);')
|
||||||
g.definitions.writeln('string _STR_TMP(const char*, ...);')
|
// g.definitions.writeln('string _STR_TMP(const char*, ...);')
|
||||||
}
|
}
|
||||||
if g.pref.os == .ios {
|
if g.pref.os == .ios {
|
||||||
g.cheaders.writeln('#define __TARGET_IOS__ 1')
|
g.cheaders.writeln('#define __TARGET_IOS__ 1')
|
||||||
|
@ -4425,7 +4425,7 @@ fn (mut g Gen) select_expr(node ast.SelectExpr) {
|
||||||
g.expr(channels[i])
|
g.expr(channels[i])
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
g.writeln('}));')
|
g.writeln('}));\n')
|
||||||
directions_array := g.new_tmp_var()
|
directions_array := g.new_tmp_var()
|
||||||
g.write('Array_sync__Direction $directions_array = new_array_from_c_array($n_channels, $n_channels, sizeof(sync__Direction), _MOV((sync__Direction[$n_channels]){')
|
g.write('Array_sync__Direction $directions_array = new_array_from_c_array($n_channels, $n_channels, sizeof(sync__Direction), _MOV((sync__Direction[$n_channels]){')
|
||||||
for i in 0 .. n_channels {
|
for i in 0 .. n_channels {
|
||||||
|
@ -4438,7 +4438,7 @@ fn (mut g Gen) select_expr(node ast.SelectExpr) {
|
||||||
g.write('sync__Direction_pop')
|
g.write('sync__Direction_pop')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.writeln('}));')
|
g.writeln('}));\n')
|
||||||
objs_array := g.new_tmp_var()
|
objs_array := g.new_tmp_var()
|
||||||
g.write('Array_voidptr $objs_array = new_array_from_c_array($n_channels, $n_channels, sizeof(voidptr), _MOV((voidptr[$n_channels]){')
|
g.write('Array_voidptr $objs_array = new_array_from_c_array($n_channels, $n_channels, sizeof(voidptr), _MOV((voidptr[$n_channels]){')
|
||||||
for i in 0 .. n_channels {
|
for i in 0 .. n_channels {
|
||||||
|
@ -4453,7 +4453,7 @@ fn (mut g Gen) select_expr(node ast.SelectExpr) {
|
||||||
g.write(tmp_objs[i])
|
g.write(tmp_objs[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.writeln('}));')
|
g.writeln('}));\n')
|
||||||
select_result := g.new_tmp_var()
|
select_result := g.new_tmp_var()
|
||||||
g.write('int $select_result = sync__channel_select(&/*arr*/$chan_array, $directions_array, &/*arr*/$objs_array, ')
|
g.write('int $select_result = sync__channel_select(&/*arr*/$chan_array, $directions_array, &/*arr*/$objs_array, ')
|
||||||
if has_timeout {
|
if has_timeout {
|
||||||
|
@ -6370,7 +6370,7 @@ fn (mut g Gen) as_cast(node ast.AsCast) {
|
||||||
|
|
||||||
fn (g Gen) as_cast_name_table() string {
|
fn (g Gen) as_cast_name_table() string {
|
||||||
if g.as_cast_type_names.len == 0 {
|
if g.as_cast_type_names.len == 0 {
|
||||||
return 'new_array_from_c_array(1, 1, sizeof(VCastTypeIndexName), _MOV((VCastTypeIndexName[1]){(VCastTypeIndexName){.tindex = 0,.tname = _SLIT("unknown")}}));'
|
return 'new_array_from_c_array(1, 1, sizeof(VCastTypeIndexName), _MOV((VCastTypeIndexName[1]){(VCastTypeIndexName){.tindex = 0,.tname = _SLIT("unknown")}}));\n'
|
||||||
}
|
}
|
||||||
mut name_ast := strings.new_builder(1024)
|
mut name_ast := strings.new_builder(1024)
|
||||||
casts_len := g.as_cast_type_names.len + 1
|
casts_len := g.as_cast_type_names.len + 1
|
||||||
|
@ -6379,7 +6379,7 @@ fn (g Gen) as_cast_name_table() string {
|
||||||
for key, value in g.as_cast_type_names {
|
for key, value in g.as_cast_type_names {
|
||||||
name_ast.writeln('\t\t, (VCastTypeIndexName){.tindex = $key, .tname = _SLIT("$value")}')
|
name_ast.writeln('\t\t, (VCastTypeIndexName){.tindex = $key, .tname = _SLIT("$value")}')
|
||||||
}
|
}
|
||||||
name_ast.writeln('\t}));')
|
name_ast.writeln('\t}));\n')
|
||||||
return name_ast.str()
|
return name_ast.str()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,8 @@ static inline void __sort_ptr(uintptr_t a[], bool b[], int l)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'
|
'
|
||||||
|
c_str_fn_defs = '' // NO _STR() test
|
||||||
|
/*
|
||||||
c_str_fn_defs = '
|
c_str_fn_defs = '
|
||||||
void _STR_PRINT_ARG(const char *fmt, char** refbufp, int *nbytes, int *memsize, int guess, ...) {
|
void _STR_PRINT_ARG(const char *fmt, char** refbufp, int *nbytes, int *memsize, int guess, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
|
@ -168,6 +170,7 @@ string _STR_TMP(const char *fmt, ...) {
|
||||||
} // endof _STR_TMP
|
} // endof _STR_TMP
|
||||||
|
|
||||||
'
|
'
|
||||||
|
*/
|
||||||
c_common_macros = '
|
c_common_macros = '
|
||||||
#define EMPTY_VARG_INITIALIZATION 0
|
#define EMPTY_VARG_INITIALIZATION 0
|
||||||
#define EMPTY_STRUCT_DECLARATION
|
#define EMPTY_STRUCT_DECLARATION
|
||||||
|
@ -450,8 +453,11 @@ static inline uint64_t wy2u0k(uint64_t r, uint64_t k){ _wymum(&r,&k); return k;
|
||||||
'
|
'
|
||||||
c_helper_macros = '//============================== HELPER C MACROS =============================*/
|
c_helper_macros = '//============================== HELPER C MACROS =============================*/
|
||||||
//#define tos4(s, slen) ((string){.str=(s), .len=(slen)})
|
//#define tos4(s, slen) ((string){.str=(s), .len=(slen)})
|
||||||
|
// _SLIT0 is used as NULL string for literal arguments
|
||||||
// `"" s` is used to enforce a string literal argument
|
// `"" s` is used to enforce a string literal argument
|
||||||
|
#define _SLIT0 (string){.len=0}
|
||||||
#define _SLIT(s) ((string){.str=(byteptr)("" s), .len=(sizeof(s)-1), .is_lit=1})
|
#define _SLIT(s) ((string){.str=(byteptr)("" s), .len=(sizeof(s)-1), .is_lit=1})
|
||||||
|
//#define _SLIT(s) ((string){.str=(byteptr)("" s), .len=(sizeof(s)-1), .is_lit=1})
|
||||||
// take the address of an rvalue
|
// take the address of an rvalue
|
||||||
#define ADDR(type, expr) (&((type[]){expr}[0]))
|
#define ADDR(type, expr) (&((type[]){expr}[0]))
|
||||||
// copy something to the heap
|
// copy something to the heap
|
||||||
|
|
|
@ -418,7 +418,7 @@ fn (mut g Gen) comp_for(node ast.CompFor) {
|
||||||
attrs := cgen_attrs(method.attrs)
|
attrs := cgen_attrs(method.attrs)
|
||||||
g.writeln(
|
g.writeln(
|
||||||
'\t${node.val_var}.attrs = new_array_from_c_array($attrs.len, $attrs.len, sizeof(string), _MOV((string[$attrs.len]){' +
|
'\t${node.val_var}.attrs = new_array_from_c_array($attrs.len, $attrs.len, sizeof(string), _MOV((string[$attrs.len]){' +
|
||||||
attrs.join(', ') + '}));')
|
attrs.join(', ') + '}));\n')
|
||||||
}
|
}
|
||||||
if method.params.len < 2 {
|
if method.params.len < 2 {
|
||||||
// 0 or 1 (the receiver) args
|
// 0 or 1 (the receiver) args
|
||||||
|
@ -435,7 +435,7 @@ fn (mut g Gen) comp_for(node ast.CompFor) {
|
||||||
}
|
}
|
||||||
g.comptime_var_type_map['${node.val_var}.args[$j].typ'] = typ
|
g.comptime_var_type_map['${node.val_var}.args[$j].typ'] = typ
|
||||||
}
|
}
|
||||||
g.writeln('}));')
|
g.writeln('}));\n')
|
||||||
}
|
}
|
||||||
mut sig := 'anon_fn_'
|
mut sig := 'anon_fn_'
|
||||||
// skip the first (receiver) arg
|
// skip the first (receiver) arg
|
||||||
|
@ -492,7 +492,7 @@ fn (mut g Gen) comp_for(node ast.CompFor) {
|
||||||
attrs := cgen_attrs(field.attrs)
|
attrs := cgen_attrs(field.attrs)
|
||||||
g.writeln(
|
g.writeln(
|
||||||
'\t${node.val_var}.attrs = new_array_from_c_array($attrs.len, $attrs.len, sizeof(string), _MOV((string[$attrs.len]){' +
|
'\t${node.val_var}.attrs = new_array_from_c_array($attrs.len, $attrs.len, sizeof(string), _MOV((string[$attrs.len]){' +
|
||||||
attrs.join(', ') + '}));')
|
attrs.join(', ') + '}));\n')
|
||||||
}
|
}
|
||||||
// field_sym := g.table.get_type_symbol(field.typ)
|
// field_sym := g.table.get_type_symbol(field.typ)
|
||||||
// g.writeln('\t${node.val_var}.typ = _SLIT("$field_sym.name");')
|
// g.writeln('\t${node.val_var}.typ = _SLIT("$field_sym.name");')
|
||||||
|
|
|
@ -176,14 +176,14 @@ fn (mut g Gen) gen_struct_enc_dec(type_info ast.TypeInfo, styp string, mut enc s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if field_sym.kind == .enum_ {
|
if field_sym.kind == .enum_ {
|
||||||
enc.writeln('\tcJSON_AddItemToObject(o, "$name", json__encode_u64(val.${c_name(field.name)}));')
|
enc.writeln('\tcJSON_AddItemToObject(o, "$name", json__encode_u64(val.${c_name(field.name)}));\n')
|
||||||
} else {
|
} else {
|
||||||
if field_sym.name == 'time.Time' {
|
if field_sym.name == 'time.Time' {
|
||||||
// time struct requires special treatment
|
// time struct requires special treatment
|
||||||
// it has to be encoded as a unix timestamp number
|
// it has to be encoded as a unix timestamp number
|
||||||
enc.writeln('\tcJSON_AddItemToObject(o, "$name", json__encode_u64(val.${c_name(field.name)}.v_unix));')
|
enc.writeln('\tcJSON_AddItemToObject(o, "$name", json__encode_u64(val.${c_name(field.name)}.v_unix));')
|
||||||
} else {
|
} else {
|
||||||
enc.writeln('\tcJSON_AddItemToObject(o, "$name", ${enc_name}(val.${c_name(field.name)}));')
|
enc.writeln('\tcJSON_AddItemToObject(o, "$name", ${enc_name}(val.${c_name(field.name)}));\n')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -368,7 +368,7 @@ fn (mut g Gen) sqlite3_select_expr(node ast.SqlExpr, sub bool, line string, sql_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if node.is_array {
|
if node.is_array {
|
||||||
g.writeln('\t array_push((array*)&${tmp}_array, _MOV(($elem_type_str[]){ $tmp }));')
|
g.writeln('\t array_push((array*)&${tmp}_array, _MOV(($elem_type_str[]){ $tmp }));\n')
|
||||||
}
|
}
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
g.writeln('sqlite3_finalize($g.sql_stmt_name);')
|
g.writeln('sqlite3_finalize($g.sql_stmt_name);')
|
||||||
|
@ -678,7 +678,7 @@ fn (mut g Gen) mysql_select_expr(node ast.SqlExpr, sub bool, line string, typ Sq
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if node.is_array {
|
if node.is_array {
|
||||||
g.writeln('\t array_push((array*)&${tmp}_array, _MOV(($elem_type_str[]) { $tmp }));')
|
g.writeln('\t array_push((array*)&${tmp}_array, _MOV(($elem_type_str[]) { $tmp }));\n')
|
||||||
g.writeln('\t $fields = mysql_fetch_row($res);')
|
g.writeln('\t $fields = mysql_fetch_row($res);')
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
}
|
}
|
||||||
|
@ -699,7 +699,9 @@ fn (mut g Gen) mysql_create_table(node ast.SqlStmtLine, typ SqlType, db_expr ast
|
||||||
g.write('Option_mysql__Result $tmp = mysql__Connection_query(&')
|
g.write('Option_mysql__Result $tmp = mysql__Connection_query(&')
|
||||||
g.expr(db_expr)
|
g.expr(db_expr)
|
||||||
g.writeln(', _SLIT("$create_string"));')
|
g.writeln(', _SLIT("$create_string"));')
|
||||||
g.writeln('if (${tmp}.state != 0) { IError err = ${tmp}.err; eprintln(_STR("Something went wrong\\000%.*s", 2, IError_str(err))); }')
|
|
||||||
|
tmp_str := 'str_intp(1, _MOV((StrIntpData[]){_SLIT("Something went wrong: "), $si_s_code ,{.d_s=IError_str(err)}}))'
|
||||||
|
g.writeln('if (${tmp}.state != 0) { IError err = ${tmp}.err; eprintln($tmp_str); }')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) mysql_drop_table(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
|
fn (mut g Gen) mysql_drop_table(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
|
||||||
|
@ -710,7 +712,9 @@ fn (mut g Gen) mysql_drop_table(node ast.SqlStmtLine, typ SqlType, db_expr ast.E
|
||||||
g.write('Option_mysql__Result $tmp = mysql__Connection_query(&')
|
g.write('Option_mysql__Result $tmp = mysql__Connection_query(&')
|
||||||
g.expr(db_expr)
|
g.expr(db_expr)
|
||||||
g.writeln(', _SLIT("$drop_string"));')
|
g.writeln(', _SLIT("$drop_string"));')
|
||||||
g.writeln('if (${tmp}.state != 0) { IError err = ${tmp}.err; eprintln(_STR("Something went wrong\\000%.*s", 2, IError_str(err))); }')
|
|
||||||
|
tmp_str := 'str_intp(1, _MOV((StrIntpData[]){_SLIT("Something went wrong: "), $si_s_code ,{.d_s=IError_str(err)}}))'
|
||||||
|
g.writeln('if (${tmp}.state != 0) { IError err = ${tmp}.err; eprintln($tmp_str); }')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) mysql_bind(val string, typ ast.Type) {
|
fn (mut g Gen) mysql_bind(val string, typ ast.Type) {
|
||||||
|
@ -857,7 +861,10 @@ fn (mut g Gen) psql_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
|
||||||
|
|
||||||
res := g.new_tmp_var()
|
res := g.new_tmp_var()
|
||||||
g.writeln('Option_pg__Row $res = pg__DB_exec_one($db_name, _SLIT("SELECT LASTVAL();"));')
|
g.writeln('Option_pg__Row $res = pg__DB_exec_one($db_name, _SLIT("SELECT LASTVAL();"));')
|
||||||
g.writeln('if (${res}.state != 0) { IError err = ${res}.err; eprintln(_STR("\\000%.*s", 2, IError_str(err))); }')
|
|
||||||
|
tmp_str := 'str_intp(1, _MOV((StrIntpData[]){_SLIT0, $si_s_code ,{.d_s=IError_str(err)}}))'
|
||||||
|
g.writeln('if (${res}.state != 0) { IError err = ${res}.err; eprintln($tmp_str); }')
|
||||||
|
|
||||||
g.sql_buf = strings.new_builder(100)
|
g.sql_buf = strings.new_builder(100)
|
||||||
g.sql_bind('string_int((*(string*)array_get((*(pg__Row*)${res}.data).vals, 0)))',
|
g.sql_bind('string_int((*(string*)array_get((*(pg__Row*)${res}.data).vals, 0)))',
|
||||||
'', ast.int_type, typ)
|
'', ast.int_type, typ)
|
||||||
|
@ -897,7 +904,10 @@ fn (mut g Gen) psql_stmt(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
|
||||||
if arr_stmt.len > 0 {
|
if arr_stmt.len > 0 {
|
||||||
res := g.new_tmp_var()
|
res := g.new_tmp_var()
|
||||||
g.writeln('Option_pg__Row $res = pg__DB_exec_one($db_name, _SLIT("SELECT LASTVAL();"));')
|
g.writeln('Option_pg__Row $res = pg__DB_exec_one($db_name, _SLIT("SELECT LASTVAL();"));')
|
||||||
g.writeln('if (${res}.state != 0) { IError err = ${res}.err; eprintln(_STR("\\000%.*s", 2, IError_str(err))); }')
|
|
||||||
|
tmp_str := 'str_intp(1, _MOV((StrIntpData[]){_SLIT0, $si_s_code ,{.d_s=IError_str(err)}}))'
|
||||||
|
g.writeln('if (${res}.state != 0) { IError err = ${res}.err; eprintln($tmp_str); }')
|
||||||
|
|
||||||
id_name := g.new_tmp_var()
|
id_name := g.new_tmp_var()
|
||||||
g.writeln('int $id_name = string_int((*(string*)array_get((*(pg__Row*)${res}.data).vals, 0)));')
|
g.writeln('int $id_name = string_int((*(string*)array_get((*(pg__Row*)${res}.data).vals, 0)));')
|
||||||
g.sql_arr_stmt(arr_stmt, arr_fkeys, arr_field_name, id_name, db_expr)
|
g.sql_arr_stmt(arr_stmt, arr_fkeys, arr_field_name, id_name, db_expr)
|
||||||
|
@ -928,7 +938,9 @@ fn (mut g Gen) psql_select_expr(node ast.SqlExpr, sub bool, line string, typ Sql
|
||||||
|
|
||||||
res := g.new_tmp_var()
|
res := g.new_tmp_var()
|
||||||
g.writeln('Option_Array_pg__Row $res = pg__DB_exec($db_name, $g.sql_stmt_name);')
|
g.writeln('Option_Array_pg__Row $res = pg__DB_exec($db_name, $g.sql_stmt_name);')
|
||||||
g.writeln('if (${res}.state != 0) { IError err = ${res}.err; eprintln(_STR("Something went wrong\\000%.*s", 2, IError_str(err))); }')
|
|
||||||
|
tmp_str := 'str_intp(1, _MOV((StrIntpData[]){_SLIT("Something went wrong: "), $si_s_code ,{.d_s=IError_str(err)}}))'
|
||||||
|
g.writeln('if (${res}.state != 0) { IError err = ${res}.err; eprintln($tmp_str); }')
|
||||||
|
|
||||||
rows := g.new_tmp_var()
|
rows := g.new_tmp_var()
|
||||||
|
|
||||||
|
@ -1025,7 +1037,7 @@ fn (mut g Gen) psql_select_expr(node ast.SqlExpr, sub bool, line string, typ Sql
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if node.is_array {
|
if node.is_array {
|
||||||
g.writeln('\t array_push((array*)&${tmp}_array, _MOV(($elem_type_str[]) { $tmp }));')
|
g.writeln('\t array_push((array*)&${tmp}_array, _MOV(($elem_type_str[]) { $tmp }));\n')
|
||||||
g.writeln('}')
|
g.writeln('}')
|
||||||
}
|
}
|
||||||
g.writeln('string_free(&$g.sql_stmt_name);')
|
g.writeln('string_free(&$g.sql_stmt_name);')
|
||||||
|
@ -1044,7 +1056,9 @@ fn (mut g Gen) psql_create_table(node ast.SqlStmtLine, typ SqlType, db_expr ast.
|
||||||
g.write('Option_Array_pg__Row $tmp = pg__DB_exec(')
|
g.write('Option_Array_pg__Row $tmp = pg__DB_exec(')
|
||||||
g.expr(db_expr)
|
g.expr(db_expr)
|
||||||
g.writeln(', _SLIT("$create_string"));')
|
g.writeln(', _SLIT("$create_string"));')
|
||||||
g.writeln('if (${tmp}.state != 0) { IError err = ${tmp}.err; eprintln(_STR("Something went wrong\\000%.*s", 2, IError_str(err))); }')
|
|
||||||
|
tmp_str := 'str_intp(1, _MOV((StrIntpData[]){_SLIT("Something went wrong: "), $si_s_code ,{.d_s=IError_str(err)}}))'
|
||||||
|
g.writeln('if (${tmp}.state != 0) { IError err = ${tmp}.err; eprintln($tmp_str); }')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) psql_drop_table(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
|
fn (mut g Gen) psql_drop_table(node ast.SqlStmtLine, typ SqlType, db_expr ast.Expr) {
|
||||||
|
@ -1056,7 +1070,9 @@ fn (mut g Gen) psql_drop_table(node ast.SqlStmtLine, typ SqlType, db_expr ast.Ex
|
||||||
g.write('Option_Array_pg__Row $tmp = pg__DB_exec(')
|
g.write('Option_Array_pg__Row $tmp = pg__DB_exec(')
|
||||||
g.expr(db_expr)
|
g.expr(db_expr)
|
||||||
g.writeln(', _SLIT("$drop_string"));')
|
g.writeln(', _SLIT("$drop_string"));')
|
||||||
g.writeln('if (${tmp}.state != 0) { IError err = ${tmp}.err; eprintln(_STR("Something went wrong\\000%.*s", 2, IError_str(err))); }')
|
|
||||||
|
tmp_str := 'str_intp(1, _MOV((StrIntpData[]){_SLIT("Something went wrong: "), $si_s_code ,{.d_s=IError_str(err)}}))'
|
||||||
|
g.writeln('if (${tmp}.state != 0) { IError err = ${tmp}.err; eprintln($tmp_str); }')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) psql_get_table_type(typ ast.Type) string {
|
fn (mut g Gen) psql_get_table_type(typ ast.Type) string {
|
||||||
|
|
|
@ -74,6 +74,7 @@ fn (mut g Gen) string_inter_literal_sb_optimized(call_expr ast.CallExpr) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
||||||
g.write('_STR("')
|
g.write('_STR("')
|
||||||
// Build the string with %
|
// Build the string with %
|
||||||
|
@ -205,6 +206,7 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
||||||
}
|
}
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
|
fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
|
||||||
is_shared := etype.has_flag(.shared_f)
|
is_shared := etype.has_flag(.shared_f)
|
||||||
|
@ -255,7 +257,8 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
|
||||||
is_var_mut := expr.is_auto_deref_var()
|
is_var_mut := expr.is_auto_deref_var()
|
||||||
str_fn_name := g.gen_str_for_type(typ)
|
str_fn_name := g.gen_str_for_type(typ)
|
||||||
if is_ptr && !is_var_mut {
|
if is_ptr && !is_var_mut {
|
||||||
g.write('_STR("&%.*s\\000", 2, ')
|
g.write('str_intp(1, _MOV((StrIntpData[]){_SLIT("&"), $si_s_code ,{.d_s=')
|
||||||
|
// g.write('_STR("&%.*s\\000", 2, ')
|
||||||
}
|
}
|
||||||
g.write('${str_fn_name}(')
|
g.write('${str_fn_name}(')
|
||||||
if str_method_expects_ptr && !is_ptr {
|
if str_method_expects_ptr && !is_ptr {
|
||||||
|
@ -275,7 +278,8 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
|
||||||
}
|
}
|
||||||
g.write(')')
|
g.write(')')
|
||||||
if is_ptr && !is_var_mut {
|
if is_ptr && !is_var_mut {
|
||||||
g.write(')')
|
g.write('}}))')
|
||||||
|
// g.write(')')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
str_fn_name := g.gen_str_for_type(typ)
|
str_fn_name := g.gen_str_for_type(typ)
|
||||||
|
|
|
@ -0,0 +1,239 @@
|
||||||
|
/*
|
||||||
|
str_intp.v
|
||||||
|
|
||||||
|
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 string interpolation V functions
|
||||||
|
*/
|
||||||
|
module c
|
||||||
|
|
||||||
|
import v.ast
|
||||||
|
import v.util
|
||||||
|
import strings
|
||||||
|
|
||||||
|
fn (mut g Gen) str_format(node ast.StringInterLiteral, i int) (u64, string) {
|
||||||
|
mut base := 0 // numeric base
|
||||||
|
mut upper_case := false // set upercase for the result string
|
||||||
|
mut typ := g.unwrap_generic(node.expr_types[i])
|
||||||
|
sym := g.table.get_type_symbol(typ)
|
||||||
|
if sym.kind == .alias {
|
||||||
|
typ = (sym.info as ast.Alias).parent_type
|
||||||
|
}
|
||||||
|
mut remove_tail_zeros := false
|
||||||
|
fspec := node.fmts[i]
|
||||||
|
mut fmt_type := StrIntpType{}
|
||||||
|
|
||||||
|
// upper cases
|
||||||
|
if (fspec - `A`) <= (`Z` - `A`) {
|
||||||
|
upper_case = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if fspec in [`s`, `S`] {
|
||||||
|
/*
|
||||||
|
if node.fwidths[i] == 0 {
|
||||||
|
fmt_type = .si_s
|
||||||
|
} else {
|
||||||
|
fmt_type = .si_s
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
fmt_type = .si_s
|
||||||
|
} else if typ.is_float() {
|
||||||
|
if fspec in [`g`, `G`] {
|
||||||
|
match typ {
|
||||||
|
ast.f32_type { fmt_type = .si_g32 }
|
||||||
|
// ast.f64_type { fmt_type = .si_g64 }
|
||||||
|
else { fmt_type = .si_g64 }
|
||||||
|
}
|
||||||
|
remove_tail_zeros = true
|
||||||
|
} else if fspec in [`e`, `E`] {
|
||||||
|
match typ {
|
||||||
|
ast.f32_type { fmt_type = .si_e32 }
|
||||||
|
// ast.f64_type { fmt_type = .si_e64 }
|
||||||
|
else { fmt_type = .si_e64 }
|
||||||
|
}
|
||||||
|
} else if fspec in [`f`, `F`] {
|
||||||
|
match typ {
|
||||||
|
ast.f32_type { fmt_type = .si_f32 }
|
||||||
|
// ast.f64_type { fmt_type = .si_f64 }
|
||||||
|
else { fmt_type = .si_f64 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if typ.is_pointer() {
|
||||||
|
if fspec in [`x`, `X`] {
|
||||||
|
base = 16 - 2 // our base start from 2
|
||||||
|
}
|
||||||
|
if fspec in [`p`, `x`, `X`] {
|
||||||
|
fmt_type = .si_p
|
||||||
|
} else {
|
||||||
|
fmt_type = .si_vp
|
||||||
|
}
|
||||||
|
} else if typ.is_int() {
|
||||||
|
if fspec in [`x`, `X`] {
|
||||||
|
base = 16 - 2 // our base start from 2
|
||||||
|
}
|
||||||
|
// if fspec in [`o`] {
|
||||||
|
if fspec == `o` {
|
||||||
|
base = 8 - 2 // our base start from 2
|
||||||
|
}
|
||||||
|
if fspec == `c` {
|
||||||
|
fmt_type = .si_c
|
||||||
|
} else {
|
||||||
|
match typ {
|
||||||
|
ast.i8_type { fmt_type = .si_i8 }
|
||||||
|
ast.byte_type { fmt_type = .si_u8 }
|
||||||
|
ast.i16_type { fmt_type = .si_i16 }
|
||||||
|
ast.u16_type { fmt_type = .si_u16 }
|
||||||
|
ast.i64_type { fmt_type = .si_i64 }
|
||||||
|
ast.u64_type { fmt_type = .si_u64 }
|
||||||
|
ast.u32_type { fmt_type = .si_u32 }
|
||||||
|
else { fmt_type = .si_i32 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// TODO: better check this case
|
||||||
|
fmt_type = .si_p
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// pad filling 64bit format
|
||||||
|
mut pad_ch := u8(0)
|
||||||
|
if node.fills[i] {
|
||||||
|
pad_ch = u8(`0`)
|
||||||
|
}
|
||||||
|
res := get_str_intp_u64_format(fmt_type, node.fwidths[i], node.precisions[i], remove_tail_zeros, node.pluss[i], pad_ch, base, upper_case)
|
||||||
|
*/
|
||||||
|
|
||||||
|
// pad filling 32bit format
|
||||||
|
mut pad_ch := 0
|
||||||
|
if node.fills[i] {
|
||||||
|
pad_ch = 1
|
||||||
|
}
|
||||||
|
res := get_str_intp_u32_format(fmt_type, node.fwidths[i], node.precisions[i], remove_tail_zeros,
|
||||||
|
node.pluss[i], pad_ch, base, upper_case)
|
||||||
|
//
|
||||||
|
return res, fmt_type.str()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) str_val(node ast.StringInterLiteral, i int) string {
|
||||||
|
tmp_out := g.out
|
||||||
|
g.out = strings.new_builder(8)
|
||||||
|
|
||||||
|
expr := node.exprs[i]
|
||||||
|
|
||||||
|
typ := g.unwrap_generic(node.expr_types[i])
|
||||||
|
if typ == ast.string_type {
|
||||||
|
if g.inside_vweb_tmpl {
|
||||||
|
g.write('vweb__filter(')
|
||||||
|
if expr.is_auto_deref_var() {
|
||||||
|
g.write('*')
|
||||||
|
}
|
||||||
|
g.expr(expr)
|
||||||
|
g.write(')')
|
||||||
|
} else {
|
||||||
|
if expr.is_auto_deref_var() {
|
||||||
|
g.write('*')
|
||||||
|
}
|
||||||
|
g.expr(expr)
|
||||||
|
}
|
||||||
|
} else if node.fmts[i] == `s` || typ.has_flag(.variadic) {
|
||||||
|
g.gen_expr_to_string(expr, typ)
|
||||||
|
} else if typ.is_number() || typ.is_pointer() || node.fmts[i] == `d` {
|
||||||
|
if typ.is_signed() && node.fmts[i] in [`x`, `X`, `o`] {
|
||||||
|
// convert to unsigned first befors C's integer propagation strikes
|
||||||
|
if typ == ast.i8_type {
|
||||||
|
g.write('(byte)(')
|
||||||
|
} else if typ == ast.i16_type {
|
||||||
|
g.write('(u16)(')
|
||||||
|
} else if typ == ast.int_type {
|
||||||
|
g.write('(u32)(')
|
||||||
|
} else {
|
||||||
|
g.write('(u64)(')
|
||||||
|
}
|
||||||
|
if expr.is_auto_deref_var() {
|
||||||
|
g.write('*')
|
||||||
|
}
|
||||||
|
g.expr(expr)
|
||||||
|
g.write(')')
|
||||||
|
} else {
|
||||||
|
if expr.is_auto_deref_var() {
|
||||||
|
g.write('*')
|
||||||
|
}
|
||||||
|
g.expr(expr)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if expr.is_auto_deref_var() {
|
||||||
|
g.write('*')
|
||||||
|
}
|
||||||
|
g.expr(expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if node.fmts[i] in [`s`, `S`] && node.fwidths[i] != 0 {
|
||||||
|
g.write(', ${node.fwidths[i]}')
|
||||||
|
}
|
||||||
|
if i < node.exprs.len - 1 {
|
||||||
|
g.write(', ')
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
tmp_res := g.out.str()
|
||||||
|
g.out = tmp_out
|
||||||
|
|
||||||
|
return tmp_res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
||||||
|
// fn (mut g Gen) str_int2(node ast.StringInterLiteral) {
|
||||||
|
mut data := []StrIntpCgenData{}
|
||||||
|
for i, val in node.vals {
|
||||||
|
// mut escaped_val := val.replace_each(['%', '%%'])
|
||||||
|
// escaped_val = util.smart_quote(escaped_val, false)
|
||||||
|
escaped_val := util.smart_quote(val, false)
|
||||||
|
|
||||||
|
if i >= node.exprs.len {
|
||||||
|
// last part of the string without data, manage it with .no_str
|
||||||
|
data << StrIntpCgenData{
|
||||||
|
str: escaped_val
|
||||||
|
fmt: '0' // no_str
|
||||||
|
d: '{ .d_c = 0 }'
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
ft_u64, ft_str := g.str_format(node, i)
|
||||||
|
ft_data := g.str_val(node, i)
|
||||||
|
|
||||||
|
// for pointers we need a void* cast
|
||||||
|
if unsafe { ft_str.str[0] } == `p` {
|
||||||
|
data << StrIntpCgenData{
|
||||||
|
str: escaped_val
|
||||||
|
fmt: '0x' + ft_u64.hex()
|
||||||
|
d: '{.d_$ft_str = (void*)(${ft_data.trim(' ,')})}'
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
data << StrIntpCgenData{
|
||||||
|
str: escaped_val
|
||||||
|
fmt: '0x' + ft_u64.hex()
|
||||||
|
d: '{.d_$ft_str = ${ft_data.trim(' ,')}}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write struct
|
||||||
|
g.write(' str_intp($data.len, ')
|
||||||
|
g.write('_MOV((StrIntpData[]){')
|
||||||
|
for i, item in data {
|
||||||
|
if item.str.len > 0 {
|
||||||
|
g.write('{_SLIT("$item.str"), $item.fmt, $item.d}')
|
||||||
|
} else {
|
||||||
|
g.write('{_SLIT0, $item.fmt, $item.d}')
|
||||||
|
}
|
||||||
|
|
||||||
|
if i < (data.len - 1) {
|
||||||
|
g.write(', ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.write('})) ')
|
||||||
|
}
|
|
@ -16,6 +16,8 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F
|
||||||
mut all_fn_root_names := [
|
mut all_fn_root_names := [
|
||||||
'main.main',
|
'main.main',
|
||||||
'__new_array',
|
'__new_array',
|
||||||
|
'str_intp',
|
||||||
|
'format_sb',
|
||||||
'__new_array_with_default',
|
'__new_array_with_default',
|
||||||
'__new_array_with_array_default',
|
'__new_array_with_array_default',
|
||||||
'v_realloc' /* needed for _STR */,
|
'v_realloc' /* needed for _STR */,
|
||||||
|
|
|
@ -86,19 +86,19 @@ fn test_interpolation_string_prefix_expr() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_inttypes_string_interpolation() {
|
fn test_inttypes_string_interpolation() {
|
||||||
c := i8(-103)
|
c := i8(-103) // -0x67
|
||||||
uc := byte(217)
|
uc := byte(217) // 0xD9
|
||||||
uc2 := byte(13)
|
uc2 := byte(13) // 0x0D
|
||||||
s := i16(-23456)
|
s := i16(-23456) // -0x5BA0
|
||||||
us := u16(54321)
|
us := u16(54321) // 0xD431
|
||||||
i := -1622999040
|
i := -1622999040 // -0x60BD 0000
|
||||||
ui := u32(3421958087)
|
ui := u32(3421958087) // 0xCBF6 EFC7
|
||||||
vp := voidptr(ui)
|
vp := voidptr(ui)
|
||||||
mut bp := byteptr(0)
|
mut bp := byteptr(0)
|
||||||
$if x64 {
|
$if x64 {
|
||||||
bp = byteptr(15541149836)
|
bp = byteptr(15541149836) // 0x3 9E53 208C
|
||||||
} $else {
|
} $else {
|
||||||
bp = byteptr(3541149836)
|
bp = byteptr(3541149836) // 0xD311 A88C
|
||||||
}
|
}
|
||||||
l := i64(-7694555558525237396)
|
l := i64(-7694555558525237396)
|
||||||
ul := u64(17234006112912956370)
|
ul := u64(17234006112912956370)
|
||||||
|
@ -108,10 +108,10 @@ fn test_inttypes_string_interpolation() {
|
||||||
assert '>${s:11}:${us:-13}<' == '> -23456:54321 <'
|
assert '>${s:11}:${us:-13}<' == '> -23456:54321 <'
|
||||||
assert '0x${ul:-19x}:${l:22d}' == '0xef2b7d4001165bd2 : -7694555558525237396'
|
assert '0x${ul:-19x}:${l:22d}' == '0xef2b7d4001165bd2 : -7694555558525237396'
|
||||||
assert '${c:5}${uc:-7}x' == ' -103217 x'
|
assert '${c:5}${uc:-7}x' == ' -103217 x'
|
||||||
assert '${c:x}:${uc:x}:${uc2:02X}' == '99:d9:0D'
|
assert '${c:x}:${uc:x}:${uc2:02X}' == '-67:d9:0D'
|
||||||
assert '${s:X}:${us:x}:${u16(uc):04x}' == 'A460:d431:00d9'
|
assert '${s:X}:${us:x}:${u16(uc):04x}' == '-5BA0:d431:00d9'
|
||||||
assert '${i:x}:${ui:X}:${int(s):x}' == '9f430000:CBF6EFC7:ffffa460'
|
assert '${i:x}:${ui:X}:${int(s):x}' == '-60bd0000:CBF6EFC7:-5ba0'
|
||||||
assert '${l:x}:${ul:X}' == '9537727cad98876c:EF2B7D4001165BD2'
|
assert '${l:x}:${ul:X}' == '-6ac88d8352677894:EF2B7D4001165BD2'
|
||||||
// default pointer format is platform dependent, so try a few
|
// default pointer format is platform dependent, so try a few
|
||||||
eprintln("platform pointer format: '${vp:p}:$bp'")
|
eprintln("platform pointer format: '${vp:p}:$bp'")
|
||||||
$if x64 {
|
$if x64 {
|
||||||
|
|
Loading…
Reference in New Issue