cgen: restructure string_inter_literal()
parent
015d0c5e33
commit
f2d9fa3815
|
@ -73,10 +73,16 @@ pub struct StringInterLiteral {
|
|||
pub:
|
||||
vals []string
|
||||
exprs []Expr
|
||||
expr_fmts []string
|
||||
fwidths []int
|
||||
precisions []int
|
||||
pluss []bool
|
||||
fills []bool
|
||||
fmt_poss []token.Position
|
||||
pos token.Position
|
||||
pub mut:
|
||||
expr_types []table.Type
|
||||
fmts []byte
|
||||
need_fmts []bool // an explicit non-default fmt required, e.g. `x`
|
||||
}
|
||||
|
||||
pub struct CharLiteral {
|
||||
|
|
|
@ -160,10 +160,28 @@ pub fn (x Expr) str() string {
|
|||
continue
|
||||
}
|
||||
res << '$'
|
||||
if it.expr_fmts[i].len > 0 {
|
||||
needs_fspec := it.need_fmts[i] || it.pluss[i] || (it.fills[i] && it.fwidths[i] >= 0) || it.fwidths[i] != 0 || it.precisions[i] != 0
|
||||
if needs_fspec || (it.exprs[i] !is Ident && it.exprs[i] !is SelectorExpr) {
|
||||
res << '{'
|
||||
res << it.exprs[i].str()
|
||||
res << it.expr_fmts[i]
|
||||
if needs_fspec {
|
||||
res << ':'
|
||||
if it.pluss[i] {
|
||||
res << '+'
|
||||
}
|
||||
if it.fills[i] && it.fwidths[i] >= 0 {
|
||||
res << '0'
|
||||
}
|
||||
if it.fwidths[i] != 0 {
|
||||
res << '${it.fwidths[i]}'
|
||||
}
|
||||
if it.precisions[i] != 0 {
|
||||
res << '.${it.precisions[i]}'
|
||||
}
|
||||
if it.need_fmts[i] {
|
||||
res << '${it.fmts[i]:c}'
|
||||
}
|
||||
}
|
||||
res << '}'
|
||||
} else {
|
||||
res << it.exprs[i].str()
|
||||
|
|
|
@ -5,6 +5,7 @@ module checker
|
|||
|
||||
import v.table
|
||||
import v.token
|
||||
import v.ast
|
||||
|
||||
pub fn (c &Checker) check_basic(got, expected table.Type) bool {
|
||||
t := c.table
|
||||
|
@ -254,3 +255,66 @@ pub fn (c &Checker) symmetric_check(left, right table.Type) bool {
|
|||
}
|
||||
return c.check_basic(left, right)
|
||||
}
|
||||
|
||||
pub fn (c &Checker) get_default_fmt(ftyp, typ table.Type) byte {
|
||||
if typ.is_float() {
|
||||
return `g`
|
||||
} else if typ.is_signed() || typ.is_any_int() {
|
||||
return `d`
|
||||
} else if typ.is_unsigned() {
|
||||
return `u`
|
||||
} else if typ.is_pointer() {
|
||||
return `p`
|
||||
} else {
|
||||
sym := c.table.get_type_symbol(ftyp)
|
||||
if ftyp in [table.string_type, table.bool_type] || sym.kind in
|
||||
[.enum_, .array, .array_fixed, .struct_, .map] || ftyp.has_flag(.optional) ||
|
||||
sym.has_method('str') {
|
||||
return `s`
|
||||
} else {
|
||||
return `_`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (c &Checker) string_inter_lit(mut node ast.StringInterLiteral) table.Type {
|
||||
for i, expr in node.exprs {
|
||||
ftyp := c.expr(expr)
|
||||
node.expr_types << ftyp
|
||||
typ := c.table.unalias_num_type(ftyp)
|
||||
mut fmt := node.fmts[i]
|
||||
// analyze and validate format specifier
|
||||
if fmt !in [`E`, `F`, `G`, `e`, `f`, `g`, `d`, `u`, `x`, `X`, `o`, `c`, `s`, `p`, `_`] {
|
||||
c.error('unknown format specifier `${fmt:c}`', node.fmt_poss[i])
|
||||
}
|
||||
if fmt == `_` { // set default representation for type if none has been given
|
||||
fmt = c.get_default_fmt(ftyp, typ)
|
||||
if fmt == `_` {
|
||||
c.error('no known default format for type `${c.table.get_type_name(ftyp)}`',
|
||||
node.fmt_poss[i])
|
||||
} else {
|
||||
node.fmts[i] = fmt
|
||||
node.need_fmts[i] = false
|
||||
}
|
||||
} else { // check if given format specifier is valid for type
|
||||
if node.precisions[i] != 0 && !typ.is_float() {
|
||||
c.error('precision specification only valid for float types', node.fmt_poss[i])
|
||||
}
|
||||
if node.pluss[i] && !typ.is_number() {
|
||||
c.error('plus prefix only allowd for numbers', node.fmt_poss[i])
|
||||
}
|
||||
if (typ.is_unsigned() && fmt !in [`u`, `x`, `X`, `o`, `c`]) ||
|
||||
(typ.is_signed() && fmt !in [`d`, `x`, `X`, `o`, `c`]) ||
|
||||
(typ.is_any_int() && fmt !in [`d`, `c`, `x`, `X`, `o`, `u`, `x`, `X`, `o`]) ||
|
||||
(typ.is_float() && fmt !in [`E`, `F`, `G`, `e`, `f`, `g`]) ||
|
||||
(typ.is_pointer() && fmt !in [`p`, `x`, `X`]) ||
|
||||
(typ.is_string() && fmt != `s`) ||
|
||||
(typ.idx() in [table.i64_type_idx, table.f64_type_idx] && fmt == `c`) {
|
||||
c.error('illegal format specifier `${fmt:c}` for type `${c.table.get_type_name(ftyp)}`',
|
||||
node.fmt_poss[i])
|
||||
}
|
||||
node.need_fmts[i] = fmt != c.get_default_fmt(ftyp, typ)
|
||||
}
|
||||
}
|
||||
return table.string_type
|
||||
}
|
||||
|
|
|
@ -1985,10 +1985,7 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
|
|||
return table.string_type
|
||||
}
|
||||
ast.StringInterLiteral {
|
||||
for expr in it.exprs {
|
||||
it.expr_types << c.expr(expr)
|
||||
}
|
||||
return table.string_type
|
||||
return c.string_inter_lit(mut it)
|
||||
}
|
||||
ast.StructInit {
|
||||
return c.struct_init(mut it)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
vlib/v/checker/tests/string_interpolation_invalid_fmt.v:3:12: error: format specifier may only be one letter
|
||||
1 | fn interpolate_wrong() string {
|
||||
2 | a := 5
|
||||
3 | x := '${a:xy}'
|
||||
| ~~
|
||||
4 | return x
|
||||
5 | }
|
|
@ -0,0 +1,5 @@
|
|||
fn interpolate_wrong() string {
|
||||
a := 5
|
||||
x := '${a:xy}'
|
||||
return x
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
vlib/v/checker/tests/string_interpolation_wrong_fmt.v:3:16: error: precision specification only valid for float types
|
||||
1 | fn interpolate_str() string {
|
||||
2 | a := 'hallo'
|
||||
3 | x := '>${a:8.3s}<'
|
||||
| ^
|
||||
4 | y := '${a:G}'
|
||||
5 | z := '${a:d}'
|
||||
vlib/v/checker/tests/string_interpolation_wrong_fmt.v:4:12: error: illegal format specifier `G` for type `string`
|
||||
2 | a := 'hallo'
|
||||
3 | x := '>${a:8.3s}<'
|
||||
4 | y := '${a:G}'
|
||||
| ^
|
||||
5 | z := '${a:d}'
|
||||
6 | return x + y + z
|
||||
vlib/v/checker/tests/string_interpolation_wrong_fmt.v:5:12: error: illegal format specifier `d` for type `string`
|
||||
3 | x := '>${a:8.3s}<'
|
||||
4 | y := '${a:G}'
|
||||
5 | z := '${a:d}'
|
||||
| ^
|
||||
6 | return x + y + z
|
||||
7 | }
|
||||
vlib/v/checker/tests/string_interpolation_wrong_fmt.v:11:15: error: illegal format specifier `s` for type `f64`
|
||||
9 | fn interpolate_f64() string {
|
||||
10 | b := 1367.57
|
||||
11 | x := '>${b:20s}<'
|
||||
| ^
|
||||
12 | y := '${b:d}'
|
||||
13 | return x + y
|
||||
vlib/v/checker/tests/string_interpolation_wrong_fmt.v:12:12: error: illegal format specifier `d` for type `f64`
|
||||
10 | b := 1367.57
|
||||
11 | x := '>${b:20s}<'
|
||||
12 | y := '${b:d}'
|
||||
| ^
|
||||
13 | return x + y
|
||||
14 | }
|
||||
vlib/v/checker/tests/string_interpolation_wrong_fmt.v:19:14: error: illegal format specifier `d` for type `u32`
|
||||
17 | u := u32(15)
|
||||
18 | s := -12
|
||||
19 | x := '${u:13d}'
|
||||
| ^
|
||||
20 | y := '${s:04u}'
|
||||
21 | z := '${s:f}'
|
||||
vlib/v/checker/tests/string_interpolation_wrong_fmt.v:20:14: error: illegal format specifier `u` for type `int`
|
||||
18 | s := -12
|
||||
19 | x := '${u:13d}'
|
||||
20 | y := '${s:04u}'
|
||||
| ^
|
||||
21 | z := '${s:f}'
|
||||
22 | q := '${u:v}'
|
||||
vlib/v/checker/tests/string_interpolation_wrong_fmt.v:21:12: error: illegal format specifier `f` for type `int`
|
||||
19 | x := '${u:13d}'
|
||||
20 | y := '${s:04u}'
|
||||
21 | z := '${s:f}'
|
||||
| ^
|
||||
22 | q := '${u:v}'
|
||||
23 | return x + y + z + q
|
||||
vlib/v/checker/tests/string_interpolation_wrong_fmt.v:22:12: error: unknown format specifier `v`
|
||||
20 | y := '${s:04u}'
|
||||
21 | z := '${s:f}'
|
||||
22 | q := '${u:v}'
|
||||
| ^
|
||||
23 | return x + y + z + q
|
||||
24 | }
|
|
@ -0,0 +1,24 @@
|
|||
fn interpolate_str() string {
|
||||
a := 'hallo'
|
||||
x := '>${a:8.3s}<'
|
||||
y := '${a:G}'
|
||||
z := '${a:d}'
|
||||
return x + y + z
|
||||
}
|
||||
|
||||
fn interpolate_f64() string {
|
||||
b := 1367.57
|
||||
x := '>${b:20s}<'
|
||||
y := '${b:d}'
|
||||
return x + y
|
||||
}
|
||||
|
||||
fn interpolate_int() string {
|
||||
u := u32(15)
|
||||
s := -12
|
||||
x := '${u:13d}'
|
||||
y := '${s:04u}'
|
||||
z := '${s:f}'
|
||||
q := '${u:v}'
|
||||
return x + y + z + q
|
||||
}
|
|
@ -721,10 +721,28 @@ pub fn (mut f Fmt) expr(node ast.Expr) {
|
|||
continue
|
||||
}
|
||||
f.write('$')
|
||||
if it.expr_fmts[i].len > 0 {
|
||||
needs_fspec := it.need_fmts[i] || it.pluss[i] || (it.fills[i] && it.fwidths[i] >= 0) || it.fwidths[i] != 0 || it.precisions[i] != 0
|
||||
if needs_fspec || (it.exprs[i] !is ast.Ident && it.exprs[i] !is ast.SelectorExpr) {
|
||||
f.write('{')
|
||||
f.expr(it.exprs[i])
|
||||
f.write(it.expr_fmts[i])
|
||||
if needs_fspec {
|
||||
f.write(':')
|
||||
if it.pluss[i] {
|
||||
f.write('+')
|
||||
}
|
||||
if it.fills[i] && it.fwidths[i] >= 0 {
|
||||
f.write('0')
|
||||
}
|
||||
if it.fwidths[i] != 0 {
|
||||
f.write('${it.fwidths[i]}')
|
||||
}
|
||||
if it.precisions[i] != 0 {
|
||||
f.write('.${it.precisions[i]}')
|
||||
}
|
||||
if it.need_fmts[i] {
|
||||
f.write('${it.fmts[i]:c}')
|
||||
}
|
||||
}
|
||||
f.write('}')
|
||||
} else {
|
||||
f.expr(it.exprs[i])
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
module gen
|
||||
|
||||
import strings
|
||||
import strconv
|
||||
import v.ast
|
||||
import v.table
|
||||
import v.pref
|
||||
|
@ -2918,101 +2917,40 @@ fn (g Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
|
|||
}
|
||||
|
||||
fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
||||
//if g.pref.autofree {
|
||||
//g.write('_STR_TMP("')
|
||||
//} else {
|
||||
g.write('_STR("')
|
||||
//}
|
||||
// Build the string with %
|
||||
mut fieldwidths := []int{}
|
||||
mut specs := []byte{}
|
||||
mut end_string := false
|
||||
for i, val in node.vals {
|
||||
escaped_val := val.replace_each(['"', '\\"', '\r\n', '\\n', '\n', '\\n', '%', '%%'])
|
||||
if i >= node.exprs.len {
|
||||
if escaped_val.len > 0 {
|
||||
end_string = true
|
||||
//if !g.pref.autofree {
|
||||
g.write('\\000')
|
||||
//}
|
||||
g.write('\\000')
|
||||
g.write(escaped_val)
|
||||
}
|
||||
continue
|
||||
break
|
||||
}
|
||||
g.write(escaped_val)
|
||||
sym := g.table.get_type_symbol(node.expr_types[i])
|
||||
sfmt := node.expr_fmts[i]
|
||||
mut fspec := `_` // placeholder
|
||||
mut fmt := '' // field width and precision
|
||||
if sfmt.len > 0 {
|
||||
// analyze and validate format specifier
|
||||
if sfmt[sfmt.len - 1] in [`E`, `F`, `G`, `e`, `f`, `g`,
|
||||
`d`, `u`, `x`, `X`, `o`, `c`, `s`, `p`] {
|
||||
fspec = sfmt[sfmt.len - 1]
|
||||
}
|
||||
fmt = if fspec == `_` {
|
||||
sfmt[1..sfmt.len]
|
||||
} else {
|
||||
sfmt[1..sfmt.len - 1]
|
||||
}
|
||||
}
|
||||
if fspec == `_` { // set default representation for type if still missing
|
||||
if node.expr_types[i].is_float() {
|
||||
fspec = `g`
|
||||
} else if node.expr_types[i].is_signed() || node.expr_types[i].is_any_int() {
|
||||
fspec = `d`
|
||||
} else if node.expr_types[i].is_unsigned() {
|
||||
fspec = `u`
|
||||
} else if node.expr_types[i].is_pointer() {
|
||||
fspec = `p`
|
||||
} else if node.expr_types[i] in [table.string_type, table.bool_type] || sym.kind in
|
||||
[.enum_, .array, .array_fixed, .struct_, .map] || g.typ(node.expr_types[i]).starts_with('Option') ||
|
||||
sym.has_method('str') {
|
||||
fspec = `s`
|
||||
} else {
|
||||
// default to int - TODO: should better be checked
|
||||
fspec = `d`
|
||||
}
|
||||
}
|
||||
fields := fmt.split('.')
|
||||
// validate format
|
||||
// only floats should have precision specifier
|
||||
/*
|
||||
if fields.len > 2 || fields.len == 2 && !(node.expr_types[i].is_float()) || node.expr_types[i].is_signed() &&
|
||||
fspec !in [`d`, `c`, `x`, `X`, `o`] || node.expr_types[i].is_unsigned() && fspec !in [`u`, `x`,
|
||||
`X`, `o`, `c`] || node.expr_types[i].is_any_int() && fspec !in [`d`, `c`, `x`, `X`,
|
||||
`o`, `u`,
|
||||
`x`, `X`, `o`] || node.expr_types[i].is_float() && fspec !in [`E`, `F`, `G`, `e`,
|
||||
`f`, `g`] || node.expr_types[i].is_pointer() && fspec !in [`p`, `x`, `X`] {
|
||||
verror('illegal format specifier ${fspec:c} for type ${g.table.get_type_name(node.expr_types[i])}')
|
||||
}
|
||||
*/
|
||||
// make sure that format paramters are valid numbers
|
||||
/*
|
||||
for j, f in fields {
|
||||
for k, c in f {
|
||||
if (c < `0` || c > `9`) && !(j == 0 && k == 0 && (node.expr_types[i].is_number() &&
|
||||
c == `+` || c == `-`)) {
|
||||
verror('illegal character ${c:c} in format specifier ${fmt}')
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
specs << fspec
|
||||
fieldwidths << if fields.len == 0 {
|
||||
0
|
||||
} else {
|
||||
strconv.atoi(fields[0])
|
||||
}
|
||||
// write correct format specifier to intermediate string
|
||||
g.write('%')
|
||||
fspec := node.fmts[i]
|
||||
mut fmt := if node.pluss[i] { '+' } else { '' }
|
||||
if node.fills[i] && node.fwidths[i] >= 0 {
|
||||
fmt = '${fmt}0'
|
||||
}
|
||||
if node.fwidths[i] != 0 {
|
||||
fmt = '$fmt${node.fwidths[i]}'
|
||||
}
|
||||
if node.precisions[i] != 0 {
|
||||
fmt = '${fmt}.${node.precisions[i]}'
|
||||
}
|
||||
if fspec == `s` {
|
||||
if fields.len == 0 || strconv.atoi(fields[0]) == 0 {
|
||||
if node.fwidths[i] == 0 {
|
||||
g.write('.*s')
|
||||
} else {
|
||||
g.write('*.*s')
|
||||
}
|
||||
} else if node.expr_types[i].is_float() || node.expr_types[i].is_pointer() {
|
||||
} else if node.expr_types[i].is_float() {
|
||||
g.write('$fmt${fspec:c}')
|
||||
} else if node.expr_types[i].is_pointer() {
|
||||
if fspec == `p` {
|
||||
|
@ -3022,11 +2960,7 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
|||
}
|
||||
} else if node.expr_types[i].is_int() {
|
||||
if fspec == `c` {
|
||||
if node.expr_types[i].idx() in [table.i64_type_idx, table.f64_type_idx] {
|
||||
verror('64 bit integer types cannot be interpolated as character')
|
||||
} else {
|
||||
g.write('${fmt}c')
|
||||
}
|
||||
g.write('${fmt}c')
|
||||
} else {
|
||||
g.write('${fmt}"PRI${fspec:c}')
|
||||
if node.expr_types[i] in [table.i8_type, table.byte_type] {
|
||||
|
@ -3057,9 +2991,9 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
|||
} else if node.expr_types[i] == table.bool_type {
|
||||
g.expr(expr)
|
||||
g.write(' ? _SLIT("true") : _SLIT("false")')
|
||||
} else if node.expr_types[i].is_number() || node.expr_types[i].is_pointer() || specs[i] ==
|
||||
} else if node.expr_types[i].is_number() || node.expr_types[i].is_pointer() || node.fmts[i] ==
|
||||
`d` {
|
||||
if node.expr_types[i].is_signed() && specs[i] in [`x`, `X`, `o`] {
|
||||
if node.expr_types[i].is_signed() && node.fmts[i] in [`x`, `X`, `o`] {
|
||||
// convert to unsigned first befors C's integer propagation strikes
|
||||
if node.expr_types[i] == table.i8_type {
|
||||
g.write('(byte)(')
|
||||
|
@ -3075,13 +3009,13 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
|
|||
} else {
|
||||
g.expr(expr)
|
||||
}
|
||||
} else if specs[i] == `s` {
|
||||
} else if node.fmts[i] == `s` {
|
||||
g.gen_expr_to_string(expr, node.expr_types[i])
|
||||
} else {
|
||||
g.expr(expr)
|
||||
}
|
||||
if specs[i] == `s` && fieldwidths[i] != 0 {
|
||||
g.write(', ${fieldwidths[i]}')
|
||||
if node.fmts[i] == `s` && node.fwidths[i] != 0 {
|
||||
g.write(', ${node.fwidths[i]}')
|
||||
}
|
||||
if i < node.exprs.len - 1 {
|
||||
g.write(', ')
|
||||
|
|
|
@ -1367,9 +1367,11 @@ fn (mut g JsGen) gen_string_inter_literal(it ast.StringInterLiteral) {
|
|||
continue
|
||||
}
|
||||
expr := it.exprs[i]
|
||||
sfmt := it.expr_fmts[i]
|
||||
fmt := it.fmts[i]
|
||||
fwidth := it.fwidths[i]
|
||||
precision := it.precisions[i]
|
||||
g.write('\${')
|
||||
if sfmt.len > 0 {
|
||||
if fmt != `_` || fwidth !=0 || precision != 0 {
|
||||
// TODO: Handle formatting
|
||||
g.expr(expr)
|
||||
} else {
|
||||
|
|
|
@ -13,6 +13,7 @@ import v.errors
|
|||
import os
|
||||
import runtime
|
||||
import time
|
||||
import strconv
|
||||
|
||||
pub struct Parser {
|
||||
file_name string // "/home/user/hello.v"
|
||||
|
@ -1166,7 +1167,13 @@ fn (mut p Parser) string_expr() ast.Expr {
|
|||
}
|
||||
mut exprs := []ast.Expr{}
|
||||
mut vals := []string{}
|
||||
mut efmts := []string{}
|
||||
mut has_fmts := []bool{}
|
||||
mut fwidths := []int{}
|
||||
mut precisions := []int{}
|
||||
mut visible_pluss := []bool{}
|
||||
mut fills := []bool{}
|
||||
mut fmts := []byte{}
|
||||
mut fposs := []token.Position{}
|
||||
// Handle $ interpolation
|
||||
p.inside_str_interp = true
|
||||
for p.tok.kind == .string {
|
||||
|
@ -1177,31 +1184,66 @@ fn (mut p Parser) string_expr() ast.Expr {
|
|||
}
|
||||
p.next()
|
||||
exprs << p.expr(0)
|
||||
mut efmt := []string{}
|
||||
mut has_fmt := false
|
||||
mut fwidth := 0
|
||||
mut fwidthneg := false
|
||||
mut precision := 0
|
||||
mut visible_plus := false
|
||||
mut fill := false
|
||||
mut fmt := `_` // placeholder
|
||||
if p.tok.kind == .colon {
|
||||
efmt << ':'
|
||||
has_fmt = true
|
||||
p.next()
|
||||
// ${num:-2d}
|
||||
if p.tok.kind == .minus {
|
||||
efmt << '-'
|
||||
fwidthneg = true
|
||||
p.next()
|
||||
} else if p.tok.kind == .plus {
|
||||
visible_plus = true
|
||||
p.next()
|
||||
}
|
||||
// ${num:2d}
|
||||
if p.tok.kind == .number {
|
||||
efmt << p.tok.lit
|
||||
fields := p.tok.lit.split('.')
|
||||
if fields[0].len > 0 && fields[0][0] == `0` {
|
||||
fill = true
|
||||
}
|
||||
fwidth = strconv.atoi(fields[0])
|
||||
if fwidthneg {
|
||||
fwidth = -fwidth
|
||||
}
|
||||
if fields.len > 1 {
|
||||
precision = strconv.atoi(fields[1])
|
||||
}
|
||||
p.next()
|
||||
}
|
||||
if p.tok.kind == .name && p.tok.lit.len == 1 {
|
||||
efmt << p.tok.lit
|
||||
p.next()
|
||||
if p.tok.kind == .name {
|
||||
if p.tok.lit.len == 1 {
|
||||
fmt = p.tok.lit[0]
|
||||
p.next()
|
||||
} else {
|
||||
p.error('format specifier may only be one letter')
|
||||
}
|
||||
}
|
||||
}
|
||||
efmts << efmt.join('')
|
||||
fwidths << fwidth
|
||||
has_fmts << has_fmt
|
||||
precisions << precision
|
||||
visible_pluss << visible_plus
|
||||
fmts << fmt
|
||||
fills << fill
|
||||
fposs << p.prev_tok.position()
|
||||
}
|
||||
node = ast.StringInterLiteral{
|
||||
vals: vals
|
||||
exprs: exprs
|
||||
expr_fmts: efmts
|
||||
need_fmts: has_fmts // prelimery - until checker finds out if really needed
|
||||
fwidths: fwidths
|
||||
precisions: precisions
|
||||
pluss: visible_pluss
|
||||
fills: fills
|
||||
fmts: fmts
|
||||
fmt_poss: fposs
|
||||
pos: pos
|
||||
}
|
||||
p.inside_str_interp = false
|
||||
|
|
|
@ -187,6 +187,11 @@ pub fn (typ Type) is_number() bool {
|
|||
return typ.idx() in number_type_idxs
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (typ Type) is_string() bool {
|
||||
return typ.idx() in string_type_idxs
|
||||
}
|
||||
|
||||
pub const (
|
||||
void_type_idx = 1
|
||||
voidptr_type_idx = 2
|
||||
|
|
Loading…
Reference in New Issue