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

all: new string interpolation "hello {name}!"

This commit is contained in:
Alexander Medvednikov 2022-10-27 11:00:51 +03:00
parent e6fad82b87
commit 18c7da9a5e
26 changed files with 124 additions and 88 deletions

View File

@ -222,6 +222,7 @@ jobs:
git clone --depth 1 https://github.com/vlang/ved git clone --depth 1 https://github.com/vlang/ved
cd ved && ../v -o ved . cd ved && ../v -o ved .
../v -autofree . ../v -autofree .
../v -prod .
cd .. cd ..
# - name: Test c2v # - name: Test c2v
# run: | # run: |

View File

@ -9,7 +9,7 @@
- [ ] Recursive structs via optionals: `struct Node { next ?Node }` - [ ] Recursive structs via optionals: `struct Node { next ?Node }`
- [ ] Optional function struct fields - [ ] Optional function struct fields
- [ ] Handle function pointers safely, remove `if function == 0 {` - [ ] Handle function pointers safely, remove `if function == 0 {`
- [ ] Bundle OpenSSL like GC - [x] Bundle OpenSSL like GC
- [x] Anonymous structs - [x] Anonymous structs
- [ ] -usecache on by default - [ ] -usecache on by default
- [ ] -skip-unused on by default - [ ] -skip-unused on by default

View File

@ -169,10 +169,10 @@ pub fn (mut ws WebhookServer) genhook() {
ws.gen_vc.generate() ws.gen_vc.generate()
// error in generate // error in generate
if ws.gen_vc.gen_error { if ws.gen_vc.gen_error {
ws.json('{status: "failed"}') ws.json('{ status: "failed" }')
return return
} }
ws.json('{status: "ok"}') ws.json('{ status: "ok" }')
} }
pub fn (ws &WebhookServer) reset() { pub fn (ws &WebhookServer) reset() {

View File

@ -112,10 +112,10 @@ pub fn (mut vgit_context VGitContext) compile_oldv_if_needed() {
mut command_for_selfbuilding := '' mut command_for_selfbuilding := ''
if 'windows' == os.user_os() { if 'windows' == os.user_os() {
command_for_building_v_from_c_source = '$vgit_context.cc -std=c99 -I ./thirdparty/stdatomic/win -municode -w -o cv.exe "$vgit_context.path_vc/v_win.c" ' command_for_building_v_from_c_source = '$vgit_context.cc -std=c99 -I ./thirdparty/stdatomic/win -municode -w -o cv.exe "$vgit_context.path_vc/v_win.c" '
command_for_selfbuilding = './cv.exe -o $vgit_context.vexename {SOURCE}' command_for_selfbuilding = './cv.exe -o $vgit_context.vexename \{SOURCE}'
} else { } else {
command_for_building_v_from_c_source = '$vgit_context.cc -std=gnu11 -I ./thirdparty/stdatomic/nix -w -o cv "$vgit_context.path_vc/v.c" -lm -lpthread' command_for_building_v_from_c_source = '$vgit_context.cc -std=gnu11 -I ./thirdparty/stdatomic/nix -w -o cv "$vgit_context.path_vc/v.c" -lm -lpthread'
command_for_selfbuilding = './cv -o $vgit_context.vexename {SOURCE}' command_for_selfbuilding = './cv -o $vgit_context.vexename \{SOURCE}'
} }
scripting.chdir(vgit_context.workdir) scripting.chdir(vgit_context.workdir)
clone_or_pull(vgit_context.v_repo_url, vgit_context.path_v) clone_or_pull(vgit_context.v_repo_url, vgit_context.path_v)
@ -146,7 +146,7 @@ pub fn (mut vgit_context VGitContext) compile_oldv_if_needed() {
scripting.run('make fresh_tcc') scripting.run('make fresh_tcc')
} }
scripting.run(command_for_building_v_from_c_source) scripting.run(command_for_building_v_from_c_source)
build_cmd := command_for_selfbuilding.replace('{SOURCE}', vgit_context.vvlocation) build_cmd := command_for_selfbuilding.replace('\{SOURCE}', vgit_context.vvlocation)
scripting.run(build_cmd) scripting.run(build_cmd)
// At this point, there exists a file vgit_context.vexepath // At this point, there exists a file vgit_context.vexepath
// which should be a valid working V executable. // which should be a valid working V executable.

View File

@ -72,7 +72,7 @@ fn (mut a App) collect_info() {
os_details += ' (WSL)' os_details += ' (WSL)'
} }
// From https://unix.stackexchange.com/a/14346 // From https://unix.stackexchange.com/a/14346
awk_cmd := '[ "$(awk \'\$5=="/" {print \$1}\' </proc/1/mountinfo)" != "$(awk \'\$5=="/" {print \$1}\' </proc/$$/mountinfo)" ] ; echo \$?' awk_cmd := '[ "$(awk \'\$5=="/" { print \$1 }\' </proc/1/mountinfo)" != "$(awk \'\$5=="/" { print \$1 }\' </proc/$$/mountinfo)" ] ; echo \$?'
if a.cmd(command: awk_cmd) == '0' { if a.cmd(command: awk_cmd) == '0' {
os_details += ' (chroot)' os_details += ' (chroot)'
} }

View File

@ -29,7 +29,7 @@ const (
'hg': 'hg clone' 'hg': 'hg clone'
} }
supported_vcs_outdated_steps = { supported_vcs_outdated_steps = {
'git': ['git fetch', 'git rev-parse @', 'git rev-parse @{u}'] 'git': ['git fetch', 'git rev-parse @', 'git rev-parse @\{u}']
'hg': ['hg incoming'] 'hg': ['hg incoming']
} }
supported_vcs_version_cmds = { supported_vcs_version_cmds = {

View File

@ -687,22 +687,22 @@ pub const (
[inline] [inline]
pub fn str_intp_sq(in_str string) string { 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 }}}))' return 'str_intp(2, _MOV((StrIntpData[]){{ _SLIT("\'"), $si_s_code, {.d_s = $in_str}},{ _SLIT("\'"), 0, {.d_c = 0 }}}))'
} }
[inline] [inline]
pub fn str_intp_rune(in_str string) string { 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 }}}))' return 'str_intp(2, _MOV((StrIntpData[]){{ _SLIT("\`"), $si_s_code, {.d_s = $in_str}},{ _SLIT("\`"), 0, {.d_c = 0 }}}))'
} }
[inline] [inline]
pub fn str_intp_g32(in_str string) string { pub fn str_intp_g32(in_str string) string {
return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT0, $si_g32_code, {.d_f32 = $in_str }}}))' return 'str_intp(1, _MOV((StrIntpData[]){{ _SLIT0, $si_g32_code, {.d_f32 = $in_str }}}))'
} }
[inline] [inline]
pub fn str_intp_g64(in_str string) string { pub fn str_intp_g64(in_str string) string {
return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT0, $si_g64_code, {.d_f64 = $in_str }}}))' return 'str_intp(1, _MOV((StrIntpData[]){{ _SLIT0, $si_g64_code, {.d_f64 = $in_str }}}))'
} }
// replace %% with the in_str // replace %% with the in_str
@ -718,12 +718,12 @@ pub fn str_intp_sub(base_str string, in_str string) string {
st_str := base_str[..index] st_str := base_str[..index]
if index + 2 < base_str.len { if index + 2 < base_str.len {
en_str := base_str[index + 2..] en_str := base_str[index + 2..]
res_str := 'str_intp(2, _MOV((StrIntpData[]){{_SLIT("$st_str"), $si_s_code, {.d_s = $in_str }},{_SLIT("$en_str"), 0, {.d_c = 0}}}))' res_str := 'str_intp(2, _MOV((StrIntpData[]){{ _SLIT("$st_str"), $si_s_code, {.d_s = $in_str }},{ _SLIT("$en_str"), 0, {.d_c = 0}}}))'
st_str.free() st_str.free()
en_str.free() en_str.free()
return res_str return res_str
} }
res2_str := 'str_intp(1, _MOV((StrIntpData[]){{_SLIT("$st_str"), $si_s_code, {.d_s = $in_str }}}))' res2_str := 'str_intp(1, _MOV((StrIntpData[]){{ _SLIT("$st_str"), $si_s_code, { .d_s = $in_str }}}))'
st_str.free() st_str.free()
return res2_str return res2_str
} }

View File

@ -849,6 +849,11 @@ fn test_raw_inter() {
assert s.contains('$') assert s.contains('$')
} }
fn test_new_inter() {
// world := 'world'
// assert 'hello {world}' == 'hello world'
}
fn test_c_r() { fn test_c_r() {
// This used to break because of r'' and c'' // This used to break because of r'' and c''
c := 42 c := 42

View File

@ -10,10 +10,10 @@ module eval
import v.token import v.token
import v.ast import v.ast
fn(e Eval)infix_expr(left Object,right Object,op token.Kind,expecting ast.Type)Object{match op{' fn(e Eval)infix_expr(left Object,right Object,op token.Kind,expecting ast.Type)Object{match op{'
footer = "else{e.error('unknown infix expression: \$op')}}return empty // should e.error before this anyway footer = "else{ e.error('unknown infix expression: \$op')}}return empty // should e.error before this anyway
} }
" "
uk_expect_footer = "else{e.error('unknown infix expectation: \${e.table.sym(expecting).str()}')}}" uk_expect_footer = "else{ e.error('unknown infix expectation: \${e.table.sym(expecting).str()}')}}"
comparison = { comparison = {
'gt': '>' 'gt': '>'
'lt': '<' 'lt': '<'
@ -46,7 +46,7 @@ fn main() {
for lt2 in literal_types { for lt2 in literal_types {
b.write_string('$lt2{return left.val${op}right}') b.write_string('$lt2{return left.val${op}right}')
} }
b.write_string("else{e.error('invalid operands to $op: $ct and \$right.type_name()')}}}") b.write_string("else{ e.error('invalid operands to $op: $ct and \$right.type_name()')}}}")
} }
for lt in literal_types { for lt in literal_types {
b.write_string('$lt {match right{') b.write_string('$lt {match right{')
@ -61,9 +61,9 @@ fn main() {
b.write_string(" literal and \$right.type_name()')}}}") b.write_string(" literal and \$right.type_name()')}}}")
} }
if op in ['==', '!='] { if op in ['==', '!='] {
b.write_string('string{match right{string{return left${op}right}else{e.error(\'invalid operands to $op: string and \$right.type_name()\')}}}') b.write_string('string{ match right{ string{ return left${op}right}else{ e.error(\'invalid operands to $op: string and \$right.type_name()\')}}}')
} }
b.write_string("else {e.error('invalid operands to $op: \$left.type_name() and \$right.type_name()')}}}") b.write_string("else { e.error('invalid operands to $op: \$left.type_name() and \$right.type_name()')}}}")
} }
for math, op in math_ops { for math, op in math_ops {
b.write_string('.$math{match left{') b.write_string('.$math{match left{')
@ -77,9 +77,9 @@ fn main() {
continue continue
} }
unsafe_start, unsafe_end := if op in ['<<', '>>'] { 'unsafe{', '}' } else { '', '' } unsafe_start, unsafe_end := if op in ['<<', '>>'] { 'unsafe{', '}' } else { '', '' }
b.write_string('$ct2{if expecting in ast.signed_integer_type_idxs{return Int{i64(left.val)${op}i64(right.val),i8(e.type_to_size(expecting))}}else if expecting in ast.unsigned_integer_type_idxs{return Uint{u64(left.val)${op}u64(right.val),i8(e.type_to_size(expecting))}}else if expecting==ast.int_literal_type_idx{${unsafe_start}return i64(i64(left.val)${op}i64(right.val))$unsafe_end}') b.write_string('$ct2{ if expecting in ast.signed_integer_type_idxs{ return Int{ i64(left.val)${op}i64(right.val),i8(e.type_to_size(expecting))}}else if expecting in ast.unsigned_integer_type_idxs{ return Uint{ u64(left.val)${op}u64(right.val),i8(e.type_to_size(expecting))}}else if expecting==ast.int_literal_type_idx{${unsafe_start}return i64(i64(left.val)${op}i64(right.val))$unsafe_end}')
if op !in ['<<', '>>'] { if op !in ['<<', '>>'] {
b.write_string('else if expecting in ast.float_type_idxs{return Float{f64(left.val)${op}f64(right.val), i8(e.type_to_size(expecting))}}else if expecting==ast.float_literal_type_idx{return f64(f64(left.val)${op}f64(right.val))}') b.write_string('else if expecting in ast.float_type_idxs{ return Float{ f64(left.val)${op}f64(right.val),i8(e.type_to_size(expecting))}}else if expecting==ast.float_literal_type_idx{ return f64(f64(left.val)${op}f64(right.val))}')
} }
b.write_string(uk_expect_footer) b.write_string(uk_expect_footer)
} }
@ -88,13 +88,13 @@ fn main() {
continue continue
} }
unsafe_start, unsafe_end := if op in ['<<', '>>'] { 'unsafe{', '}' } else { '', '' } unsafe_start, unsafe_end := if op in ['<<', '>>'] { 'unsafe{', '}' } else { '', '' }
b.write_string('$lt2{if expecting in ast.signed_integer_type_idxs{return Int{i64(left.val)${op}i64(right),i8(e.type_to_size(expecting))}}else if expecting in ast.unsigned_integer_type_idxs{return Uint{u64(left.val)${op}u64(right),i8(e.type_to_size(expecting))}}else if expecting==ast.int_literal_type_idx{${unsafe_start}return i64(i64(left.val)${op}i64(right))$unsafe_end}') b.write_string('$lt2{ if expecting in ast.signed_integer_type_idxs{ return Int{ i64(left.val)${op}i64(right),i8(e.type_to_size(expecting))}}else if expecting in ast.unsigned_integer_type_idxs{ return Uint{ u64(left.val)${op}u64(right),i8(e.type_to_size(expecting))}}else if expecting==ast.int_literal_type_idx{${unsafe_start}return i64(i64(left.val)${op}i64(right))$unsafe_end}')
if op !in ['<<', '>>'] { if op !in ['<<', '>>'] {
b.write_string('else if expecting in ast.float_type_idxs{return Float{f64(left.val)${op}f64(right), i8(e.type_to_size(expecting))}}else if expecting==ast.float_literal_type_idx{return f64(f64(left.val)${op}f64(right))}') b.write_string('else if expecting in ast.float_type_idxs{ return Float{ f64(left.val)${op}f64(right), i8(e.type_to_size(expecting))}}else if expecting==ast.float_literal_type_idx{ return f64(f64(left.val)${op}f64(right))}')
} }
b.write_string(uk_expect_footer) b.write_string(uk_expect_footer)
} }
b.write_string("else {e.error('invalid operands to $op: $ct and \$right.type_name()')}}}") b.write_string("else { e.error('invalid operands to $op: $ct and \$right.type_name()')}}}")
} }
for lt in literal_types { for lt in literal_types {
if op in ['<<', '>>'] && lt == 'f64' { if op in ['<<', '>>'] && lt == 'f64' {
@ -106,9 +106,9 @@ fn main() {
continue continue
} }
unsafe_start, unsafe_end := if op in ['<<', '>>'] { 'unsafe{', '}' } else { '', '' } unsafe_start, unsafe_end := if op in ['<<', '>>'] { 'unsafe{', '}' } else { '', '' }
b.write_string('$ct2{if expecting in ast.signed_integer_type_idxs{return Int{i64(left)${op}i64(right.val),i8(e.type_to_size(expecting))}}else if expecting in ast.unsigned_integer_type_idxs{return Uint{u64(left)${op}u64(right.val),i8(e.type_to_size(expecting))}}else if expecting==ast.int_literal_type_idx{${unsafe_start}return i64(i64(left)${op}i64(right.val))$unsafe_end}') b.write_string('$ct2{ if expecting in ast.signed_integer_type_idxs{ return Int{ i64(left)${op}i64(right.val),i8(e.type_to_size(expecting))}}else if expecting in ast.unsigned_integer_type_idxs{ return Uint{ u64(left)${op}u64(right.val),i8(e.type_to_size(expecting))}}else if expecting==ast.int_literal_type_idx{${unsafe_start}return i64(i64(left)${op}i64(right.val))$unsafe_end}')
if op !in ['<<', '>>'] { if op !in ['<<', '>>'] {
b.write_string('else if expecting in ast.float_type_idxs{return Float{f64(left)${op}f64(right.val), i8(e.type_to_size(expecting))}}else if expecting==ast.float_literal_type_idx{return f64(f64(left)${op}f64(right.val))}') b.write_string('else if expecting in ast.float_type_idxs{ return Float{ f64(left)${op}f64(right.val), i8(e.type_to_size(expecting))}}else if expecting==ast.float_literal_type_idx{ return f64(f64(left)${op}f64(right.val))}')
} }
b.write_string(uk_expect_footer) b.write_string(uk_expect_footer)
} }
@ -117,9 +117,9 @@ fn main() {
continue continue
} }
unsafe_start, unsafe_end := if op in ['<<', '>>'] { 'unsafe{', '}' } else { '', '' } unsafe_start, unsafe_end := if op in ['<<', '>>'] { 'unsafe{', '}' } else { '', '' }
b.write_string('$lt2{if expecting in ast.signed_integer_type_idxs{return Int{i64(left)${op}i64(right),i8(e.type_to_size(expecting))}}else if expecting in ast.unsigned_integer_type_idxs{return Uint{u64(left)${op}u64(right),i8(e.type_to_size(expecting))}}else if expecting==ast.int_literal_type_idx{${unsafe_start}return i64(i64(left)${op}i64(right))$unsafe_end}') b.write_string('$lt2{if expecting in ast.signed_integer_type_idxs{ return Int{ i64(left)${op}i64(right),i8(e.type_to_size(expecting))}}else if expecting in ast.unsigned_integer_type_idxs{ return Uint{ u64(left)${op}u64(right),i8(e.type_to_size(expecting))}}else if expecting==ast.int_literal_type_idx{${unsafe_start}return i64(i64(left)${op}i64(right))$unsafe_end}')
if op !in ['<<', '>>'] { if op !in ['<<', '>>'] {
b.write_string('else if expecting in ast.float_type_idxs{return Float{f64(left)${op}f64(right), i8(e.type_to_size(expecting))}}else if expecting==ast.float_literal_type_idx{return f64(f64(left)${op}f64(right))}') b.write_string('else if expecting in ast.float_type_idxs{ return Float{ f64(left)${op}f64(right), i8(e.type_to_size(expecting))}}else if expecting==ast.float_literal_type_idx{ return f64(f64(left)${op}f64(right))}')
} }
b.write_string(uk_expect_footer) b.write_string(uk_expect_footer)
} }
@ -127,7 +127,7 @@ fn main() {
b.write_string(if lt == 'i64' { 'int' } else { 'float' }) b.write_string(if lt == 'i64' { 'int' } else { 'float' })
b.write_string(" literal and \$right.type_name()')}}}") b.write_string(" literal and \$right.type_name()')}}}")
} }
b.write_string("else {e.error('invalid operands to $op: \$left.type_name() and \$right.type_name()')}}}") b.write_string("else { e.error('invalid operands to $op: \$left.type_name() and \$right.type_name()')}}}")
} }
b.write_string(footer) b.write_string(footer)

View File

@ -1663,7 +1663,7 @@ pub fn (mut f Fmt) array_init(node ast.ArrayInit) {
} }
f.write(f.table.type_to_str_using_aliases(node.elem_type, f.mod2alias)) f.write(f.table.type_to_str_using_aliases(node.elem_type, f.mod2alias))
if node.has_default { if node.has_default {
f.write('{init: ') f.write('\{init: ')
f.expr(node.default_expr) f.expr(node.default_expr)
f.write('}') f.write('}')
} else { } else {

View File

@ -209,7 +209,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
g.expr(val) g.expr(val)
} else { } else {
if left_sym.kind == .function { if left_sym.kind == .function {
g.write('{void* _ = ') g.write('{ void* _ = ')
} else { } else {
g.write('{$styp _ = ') g.write('{$styp _ = ')
} }

View File

@ -352,7 +352,7 @@ fn (mut g Gen) gen_map_equality_fn(left_type ast.Type) string {
} }
match kind { match kind {
.string { .string {
fn_builder.writeln('\t\tif (!fast_string_eq(*(string*)map_get(&b, k, &(string[]){_SLIT("")}), v)) {') fn_builder.writeln('\t\tif (!fast_string_eq(*(string*)map_get(&b, k, &(string[]){ _SLIT("")}), v)) {')
} }
.sum_type { .sum_type {
eq_fn := g.gen_sumtype_equality_fn(value.typ) eq_fn := g.gen_sumtype_equality_fn(value.typ)

View File

@ -237,9 +237,9 @@ fn (mut g Gen) gen_str_for_alias(info ast.Alias, styp string, str_fn_name string
g.auto_str_funcs.writeln('\tstring indents = string_repeat(_SLIT(" "), indent_count);') g.auto_str_funcs.writeln('\tstring indents = string_repeat(_SLIT(" "), indent_count);')
g.auto_str_funcs.writeln('\tstring tmp_ds = ${parent_str_fn_name}(it);') g.auto_str_funcs.writeln('\tstring tmp_ds = ${parent_str_fn_name}(it);')
g.auto_str_funcs.writeln('\tstring res = str_intp(3, _MOV((StrIntpData[]){ g.auto_str_funcs.writeln('\tstring res = str_intp(3, _MOV((StrIntpData[]){
{_SLIT0, $c.si_s_code, {.d_s = indents }}, { _SLIT0, $c.si_s_code, {.d_s = indents }},
{_SLIT("${clean_type_v_type_name}("), $c.si_s_code, {.d_s = tmp_ds }}, { _SLIT("${clean_type_v_type_name}("), $c.si_s_code, {.d_s = tmp_ds }},
{_SLIT(")"), 0, {.d_c = 0 }} { _SLIT(")"), 0, {.d_c = 0 }}
}));') }));')
g.auto_str_funcs.writeln('\tstring_free(&indents);') g.auto_str_funcs.writeln('\tstring_free(&indents);')
g.auto_str_funcs.writeln('\tstring_free(&tmp_ds);') g.auto_str_funcs.writeln('\tstring_free(&tmp_ds);')
@ -307,7 +307,7 @@ fn (mut g Gen) gen_str_for_enum(info ast.Enum, styp string, str_fn_name string)
g.auto_str_funcs.writeln('\tstring ret = _SLIT("$clean_name{");') g.auto_str_funcs.writeln('\tstring ret = _SLIT("$clean_name{");')
g.auto_str_funcs.writeln('\tint first = 1;') g.auto_str_funcs.writeln('\tint first = 1;')
for i, val in info.vals { for i, val in info.vals {
g.auto_str_funcs.writeln('\tif (it & (1 << $i)) {if (!first) {ret = string__plus(ret, _SLIT(" | "));} ret = string__plus(ret, _SLIT(".$val")); first = 0;}') g.auto_str_funcs.writeln('\tif (it & (1 << $i)) { if (!first) { ret = string__plus(ret, _SLIT(" | "));} ret = string__plus(ret, _SLIT(".$val")); first = 0;}')
} }
g.auto_str_funcs.writeln('\tret = string__plus(ret, _SLIT("}"));') g.auto_str_funcs.writeln('\tret = string__plus(ret, _SLIT("}"));')
g.auto_str_funcs.writeln('\treturn ret;') g.auto_str_funcs.writeln('\treturn ret;')
@ -366,8 +366,8 @@ fn (mut g Gen) gen_str_for_interface(info ast.Interface, styp string, str_fn_nam
} }
val += ')' val += ')'
res := 'str_intp(2, _MOV((StrIntpData[]){ res := 'str_intp(2, _MOV((StrIntpData[]){
{_SLIT("${clean_interface_v_type_name}(\'"), $c.si_s_code, {.d_s = $val}}, { _SLIT("${clean_interface_v_type_name}(\'"), $c.si_s_code, {.d_s = $val}},
{_SLIT("\')"), 0, {.d_c = 0 }} { _SLIT("\')"), 0, {.d_c = 0 }}
}))' }))'
fn_builder.write_string('\tif (x._typ == _${styp}_${sub_sym.cname}_index)') fn_builder.write_string('\tif (x._typ == _${styp}_${sub_sym.cname}_index)')
fn_builder.write_string(' return $res;') fn_builder.write_string(' return $res;')
@ -378,8 +378,8 @@ fn (mut g Gen) gen_str_for_interface(info ast.Interface, styp string, str_fn_nam
} }
val += ')' val += ')'
res := 'str_intp(2, _MOV((StrIntpData[]){ res := 'str_intp(2, _MOV((StrIntpData[]){
{_SLIT("${clean_interface_v_type_name}("), $c.si_s_code, {.d_s = $val}}, { _SLIT("${clean_interface_v_type_name}("), $c.si_s_code, {.d_s = $val}},
{_SLIT(")"), 0, {.d_c = 0 }} { _SLIT(")"), 0, {.d_c = 0 }}
}))' }))'
fn_builder.write_string('\tif (x._typ == _${styp}_${sub_sym.cname}_index)') fn_builder.write_string('\tif (x._typ == _${styp}_${sub_sym.cname}_index)')
fn_builder.write_string(' return $res;\n') fn_builder.write_string(' return $res;\n')
@ -435,8 +435,8 @@ fn (mut g Gen) gen_str_for_union_sum_type(info ast.SumType, styp string, str_fn_
} }
val += ')' val += ')'
res := 'str_intp(2, _MOV((StrIntpData[]){ res := 'str_intp(2, _MOV((StrIntpData[]){
{_SLIT("${clean_sum_type_v_type_name}(\'"), $c.si_s_code, {.d_s = $val}}, { _SLIT("${clean_sum_type_v_type_name}(\'"), $c.si_s_code, {.d_s = $val}},
{_SLIT("\')"), 0, {.d_c = 0 }} { _SLIT("\')"), 0, {.d_c = 0 }}
}))' }))'
fn_builder.write_string('\t\tcase $typ.idx(): return $res;\n') fn_builder.write_string('\t\tcase $typ.idx(): return $res;\n')
} else { } else {
@ -446,8 +446,8 @@ fn (mut g Gen) gen_str_for_union_sum_type(info ast.SumType, styp string, str_fn_
} }
val += ')' val += ')'
res := 'str_intp(2, _MOV((StrIntpData[]){ res := 'str_intp(2, _MOV((StrIntpData[]){
{_SLIT("${clean_sum_type_v_type_name}("), $c.si_s_code, {.d_s = $val}}, { _SLIT("${clean_sum_type_v_type_name}("), $c.si_s_code, {.d_s = $val}},
{_SLIT(")"), 0, {.d_c = 0 }} { _SLIT(")"), 0, {.d_c = 0 }}
}))' }))'
fn_builder.write_string('\t\tcase $typ.idx(): return $res;\n') fn_builder.write_string('\t\tcase $typ.idx(): return $res;\n')
} }
@ -573,12 +573,12 @@ fn (mut g Gen) gen_str_for_array(info ast.Array, styp string, str_fn_name string
} }
} else if sym.kind == .rune { } else if sym.kind == .rune {
// Rune are managed at this level as strings // Rune are managed at this level as strings
g.auto_str_funcs.writeln('\t\tstring x = str_intp(2, _MOV((StrIntpData[]){{_SLIT("\`"), $c.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_intp(2, _MOV((StrIntpData[]){{ _SLIT("\`"), $c.si_s_code, {.d_s = ${elem_str_fn_name}(it) }}, { _SLIT("\`"), 0, {.d_c = 0 }}}));\n')
} else if sym.kind == .string { } else if sym.kind == .string {
if is_elem_ptr { if is_elem_ptr {
g.auto_str_funcs.writeln('\t\tstring x = str_intp(2, _MOV((StrIntpData[]){{_SLIT("&\'"), $c.si_s_code, {.d_s = *it }}, {_SLIT("\'"), 0, {.d_c = 0 }}}));\n') g.auto_str_funcs.writeln('\t\tstring x = str_intp(2, _MOV((StrIntpData[]){{ _SLIT("&\'"), $c.si_s_code, {.d_s = *it }}, { _SLIT("\'"), 0, {.d_c = 0 }}}));\n')
} else { } else {
g.auto_str_funcs.writeln('\t\tstring x = str_intp(2, _MOV((StrIntpData[]){{_SLIT("\'"), $c.si_s_code, {.d_s = it }}, {_SLIT("\'"), 0, {.d_c = 0 }}}));\n') g.auto_str_funcs.writeln('\t\tstring x = str_intp(2, _MOV((StrIntpData[]){{ _SLIT("\'"), $c.si_s_code, {.d_s = it }}, { _SLIT("\'"), 0, {.d_c = 0 }}}));\n')
} }
} else { } else {
// There is a custom .str() method, so use it. // There is a custom .str() method, so use it.
@ -854,7 +854,7 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name stri
} }
} }
fn_body.writeln('\tstring res = str_intp( ${(info.fields.len - field_skips.len) * 4 + 3}, _MOV((StrIntpData[]){') fn_body.writeln('\tstring res = str_intp( ${(info.fields.len - field_skips.len) * 4 + 3}, _MOV((StrIntpData[]){')
fn_body.writeln('\t\t{_SLIT("$clean_struct_v_type_name{\\n"), 0, {.d_c=0}},') fn_body.writeln('\t\t{ _SLIT("$clean_struct_v_type_name{\\n"), 0, {.d_c=0}},')
mut is_first := true mut is_first := true
for i, field in info.fields { for i, field in info.fields {
// Skip `str:skip` fields // Skip `str:skip` fields
@ -886,10 +886,10 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name stri
if is_first { if is_first {
// first field doesn't need \n // first field doesn't need \n
fn_body.write_string('\t\t{_SLIT0, $c.si_s_code, {.d_s=indents}}, {_SLIT(" $field.name: $ptr_amp$prefix"), 0, {.d_c=0}}, ') fn_body.write_string('\t\t{ _SLIT0, $c.si_s_code, {.d_s=indents}}, { _SLIT(" $field.name: $ptr_amp$prefix"), 0, {.d_c=0}}, ')
is_first = false is_first = false
} else { } else {
fn_body.write_string('\t\t{_SLIT("\\n"), $c.si_s_code, {.d_s=indents}}, {_SLIT(" $field.name: $ptr_amp$prefix"), 0, {.d_c=0}}, ') fn_body.write_string('\t\t{ _SLIT("\\n"), $c.si_s_code, {.d_s=indents}}, { _SLIT(" $field.name: $ptr_amp$prefix"), 0, {.d_c=0}}, ')
} }
// custom methods management // custom methods management
@ -908,10 +908,10 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name stri
// with floats we use always the g representation: // with floats we use always the g representation:
if sym.kind !in [.f32, .f64] { if sym.kind !in [.f32, .f64] {
fn_body.write_string('{_SLIT("$quote_str"), ${int(base_fmt)}, {.${data_str(base_fmt)}=') fn_body.write_string('{ _SLIT("$quote_str"), ${int(base_fmt)}, {.${data_str(base_fmt)}=')
} else { } else {
g_fmt := '0x' + (u32(base_fmt) | u32(0x7F) << 9).hex() g_fmt := '0x' + (u32(base_fmt) | u32(0x7F) << 9).hex()
fn_body.write_string('{_SLIT("$quote_str"), $g_fmt, {.${data_str(base_fmt)}=') fn_body.write_string('{ _SLIT("$quote_str"), $g_fmt, {.${data_str(base_fmt)}=')
} }
mut funcprefix := '' mut funcprefix := ''
@ -954,9 +954,9 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name stri
} }
} }
fn_body.writeln('}}, {_SLIT("$quote_str"), 0, {.d_c=0}},') fn_body.writeln('}}, { _SLIT("$quote_str"), 0, {.d_c=0}},')
} }
fn_body.writeln('\t\t{_SLIT("\\n"), $c.si_s_code, {.d_s=indents}}, {_SLIT("}"), 0, {.d_c=0}},') fn_body.writeln('\t\t{ _SLIT("\\n"), $c.si_s_code, {.d_s=indents}}, { _SLIT("}"), 0, {.d_c=0}},')
fn_body.writeln('\t}));') fn_body.writeln('\t}));')
} }
@ -994,18 +994,18 @@ fn struct_auto_str_func(sym &ast.TypeSymbol, _field_type ast.Type, fn_name strin
// ptr int can be "nil", so this needs to be casted to a string // ptr int can be "nil", so this needs to be casted to a string
if sym.kind == .f32 { if sym.kind == .f32 {
return 'str_intp(1, _MOV((StrIntpData[]){ return 'str_intp(1, _MOV((StrIntpData[]){
{_SLIT0, $si_g32_code, {.d_f32 = *$method_str }} { _SLIT0, $si_g32_code, {.d_f32 = *$method_str }}
}))', true }))', true
} else if sym.kind == .f64 { } else if sym.kind == .f64 {
return 'str_intp(1, _MOV((StrIntpData[]){ return 'str_intp(1, _MOV((StrIntpData[]){
{_SLIT0, $si_g64_code, {.d_f64 = *$method_str }} { _SLIT0, $si_g64_code, {.d_f64 = *$method_str }}
}))', true }))', true
} else if sym.kind == .u64 { } else if sym.kind == .u64 {
fmt_type := StrIntpType.si_u64 fmt_type := StrIntpType.si_u64
return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_u64 = *$method_str }}}))', true return 'str_intp(1, _MOV((StrIntpData[]){{ _SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_u64 = *$method_str }}}))', true
} }
fmt_type := StrIntpType.si_i32 fmt_type := StrIntpType.si_i32
return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_i32 = *$method_str }}}))', true return 'str_intp(1, _MOV((StrIntpData[]){{ _SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_i32 = *$method_str }}}))', true
} }
return method_str, false return method_str, false
} }

View File

@ -1250,7 +1250,7 @@ fn (mut g Gen) write_chan_pop_optional_fns() {
static inline $opt_el_type __Option_${styp}_popval($styp ch) { static inline $opt_el_type __Option_${styp}_popval($styp ch) {
$opt_el_type _tmp = {0}; $opt_el_type _tmp = {0};
if (sync__Channel_try_pop_priv(ch, _tmp.data, false)) { if (sync__Channel_try_pop_priv(ch, _tmp.data, false)) {
return ($opt_el_type){ .state = 2, .err = _v_error(_SLIT("channel closed")), .data = {EMPTY_STRUCT_INITIALIZATION} }; return ($opt_el_type){ .state = 2, .err = _v_error(_SLIT("channel closed")), .data = { EMPTY_STRUCT_INITIALIZATION} };
} }
return _tmp; return _tmp;
}') }')
@ -1272,8 +1272,7 @@ fn (mut g Gen) write_chan_push_optional_fns() {
g.channel_definitions.writeln(' g.channel_definitions.writeln('
static inline ${c.option_name}_void __Option_${styp}_pushval($styp ch, $el_type e) { static inline ${c.option_name}_void __Option_${styp}_pushval($styp ch, $el_type e) {
if (sync__Channel_try_push_priv(ch, &e, false)) { if (sync__Channel_try_push_priv(ch, &e, false)) {
return (${c.option_name}_void){ .state = 2, .err = _v_error(_SLIT("channel closed")), .data = {EMPTY_STRUCT_INITIALIZATION} }; return (${c.option_name}_void){ .state = 2, .err = _v_error(_SLIT("channel closed")), .data = { EMPTY_STRUCT_INITIALIZATION} }; }
}
return (${c.option_name}_void){0}; return (${c.option_name}_void){0};
}') }')
} }
@ -2289,7 +2288,7 @@ fn (mut g Gen) call_cfn_for_casting_expr(fname string, expr ast.Expr, exp_is_ptr
} }
} }
if got_styp == 'none' && !g.cur_fn.return_type.has_flag(.optional) { if got_styp == 'none' && !g.cur_fn.return_type.has_flag(.optional) {
g.write('(none){EMPTY_STRUCT_INITIALIZATION}') g.write('(none){ EMPTY_STRUCT_INITIALIZATION}')
} else { } else {
g.expr(expr) g.expr(expr)
} }
@ -4260,7 +4259,7 @@ fn (mut g Gen) gen_result_error(target_type ast.Type, expr ast.Expr) {
styp := g.typ(target_type) styp := g.typ(target_type)
g.write('($styp){ .is_error=true, .err=') g.write('($styp){ .is_error=true, .err=')
g.expr(expr) g.expr(expr)
g.write(', .data={EMPTY_STRUCT_INITIALIZATION} }') g.write(', .data={ EMPTY_STRUCT_INITIALIZATION} }')
} }
// NB: remove this when optional has no errors anymore // NB: remove this when optional has no errors anymore
@ -4268,7 +4267,7 @@ fn (mut g Gen) gen_optional_error(target_type ast.Type, expr ast.Expr) {
styp := g.typ(target_type) styp := g.typ(target_type)
g.write('($styp){ .state=2, .err=') g.write('($styp){ .state=2, .err=')
g.expr(expr) g.expr(expr)
g.write(', .data={EMPTY_STRUCT_INITIALIZATION} }') g.write(', .data={ EMPTY_STRUCT_INITIALIZATION} }')
} }
fn (mut g Gen) return_stmt(node ast.Return) { fn (mut g Gen) return_stmt(node ast.Return) {
@ -5124,13 +5123,13 @@ fn (mut g Gen) write_init_function() {
// Note: os.args in this case will be []. // Note: os.args in this case will be [].
g.writeln('__attribute__ ((constructor))') g.writeln('__attribute__ ((constructor))')
g.writeln('void _vinit_caller() {') g.writeln('void _vinit_caller() {')
g.writeln('\tstatic bool once = false; if (once) {return;} once = true;') g.writeln('\tstatic bool once = false; if (once) { return;} once = true;')
g.writeln('\t_vinit(0,0);') g.writeln('\t_vinit(0,0);')
g.writeln('}') g.writeln('}')
g.writeln('__attribute__ ((destructor))') g.writeln('__attribute__ ((destructor))')
g.writeln('void _vcleanup_caller() {') g.writeln('void _vcleanup_caller() {')
g.writeln('\tstatic bool once = false; if (once) {return;} once = true;') g.writeln('\tstatic bool once = false; if (once) { return;} once = true;')
g.writeln('\t_vcleanup();') g.writeln('\t_vcleanup();')
g.writeln('}') g.writeln('}')
} }
@ -5686,7 +5685,7 @@ fn (mut g Gen) type_default(typ_ ast.Type) string {
if field_sym.info is ast.Struct && field_sym.language == .v { if field_sym.info is ast.Struct && field_sym.language == .v {
if field_sym.info.fields.len == 0 if field_sym.info.fields.len == 0
&& field_sym.info.embeds.len == 0 { && field_sym.info.embeds.len == 0 {
zero_str = '{EMPTY_STRUCT_INITIALIZATION}' zero_str = '{ EMPTY_STRUCT_INITIALIZATION}'
} }
} }
} }

View File

@ -483,14 +483,14 @@ const c_helper_macros = '//============================== HELPER C MACROS ======
#define _SLEN(s, n) ((string){.str=(byteptr)("" s), .len=n, .is_lit=1}) #define _SLEN(s, n) ((string){.str=(byteptr)("" s), .len=n, .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
#define HEAP(type, expr) ((type*)memdup((void*)&((type[]){expr}[0]), sizeof(type))) #define HEAP(type, expr) ((type*)memdup((void*)&((type[]){ expr }[0]), sizeof(type)))
#define HEAP_noscan(type, expr) ((type*)memdup_noscan((void*)&((type[]){expr}[0]), sizeof(type))) #define HEAP_noscan(type, expr) ((type*)memdup_noscan((void*)&((type[]){ expr }[0]), sizeof(type)))
#define _PUSH_MANY(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array_push_many(arr, tmp.data, tmp.len);} #define _PUSH_MANY(arr, val, tmp, tmp_typ) { tmp_typ tmp = (val); array_push_many(arr, tmp.data, tmp.len);}
#define _PUSH_MANY_noscan(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array_push_many_noscan(arr, tmp.data, tmp.len);} #define _PUSH_MANY_noscan(arr, val, tmp, tmp_typ) { tmp_typ tmp = (val); array_push_many_noscan(arr, tmp.data, tmp.len);}
' '
const c_headers = c_helper_macros + c_unsigned_comparison_functions + c_common_macros + const c_headers = c_helper_macros + c_unsigned_comparison_functions + c_common_macros +

View File

@ -723,7 +723,7 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
$if msvc { $if msvc {
// MSVC has no support for the statement expressions used below // MSVC has no support for the statement expressions used below
} $else { } $else {
g.write(', ({VUNREACHABLE();})') g.write(', ({ VUNREACHABLE(); })')
} }
} }
} }

View File

@ -290,7 +290,7 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) {
g.writeln('\t$idx = -1;') g.writeln('\t$idx = -1;')
g.writeln('\tcontinue;') g.writeln('\tcontinue;')
g.writeln('}') g.writeln('}')
g.writeln('if (!DenseArray_has_index(&$cond_var${arw_or_pt}key_values, $idx)) {continue;}') g.writeln('if (!DenseArray_has_index(&$cond_var${arw_or_pt}key_values, $idx)) { continue;}')
if node.key_var != '_' { if node.key_var != '_' {
key_styp := g.typ(node.key_type) key_styp := g.typ(node.key_type)
key := c_name(node.key_var) key := c_name(node.key_var)

View File

@ -183,7 +183,7 @@ fn (mut g Gen) sql_insert(node ast.SqlStmtLine, expr string, table_name string,
for sub in subs { for sub in subs {
g.sql_stmt_line(sub, expr, or_expr) g.sql_stmt_line(sub, expr, or_expr)
g.writeln('array_push(&$last_ids_arr, _MOV((orm__Primitive[]){orm__Connection_name_table[${expr}._typ]._method_last_id(${expr}._object)}));') g.writeln('array_push(&$last_ids_arr, _MOV((orm__Primitive[]){ orm__Connection_name_table[${expr}._typ]._method_last_id(${expr}._object)}));')
} }
g.write('${result_name}_void $res = orm__Connection_name_table[${expr}._typ]._method_') g.write('${result_name}_void $res = orm__Connection_name_table[${expr}._typ]._method_')

View File

@ -102,7 +102,7 @@ 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.get_str_fn(typ) str_fn_name := g.get_str_fn(typ)
if is_ptr && !is_var_mut { if is_ptr && !is_var_mut {
g.write('str_intp(1, _MOV((StrIntpData[]){{_SLIT("&"), $si_s_code ,{.d_s = isnil(') g.write('str_intp(1, _MOV((StrIntpData[]){{ _SLIT("&"), $si_s_code ,{.d_s = isnil(')
g.expr(expr) g.expr(expr)
g.write(') ? _SLIT("nil") : ') g.write(') ? _SLIT("nil") : ')
} }

View File

@ -215,9 +215,9 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
escaped_val := util.smart_quote(val, false) escaped_val := util.smart_quote(val, false)
if escaped_val.len > 0 { if escaped_val.len > 0 {
g.write('{_SLIT("$escaped_val"), ') g.write('{ _SLIT("$escaped_val"), ')
} else { } else {
g.write('{_SLIT0, ') g.write('{ _SLIT0, ')
} }
if i >= node.exprs.len { if i >= node.exprs.len {

View File

@ -182,7 +182,7 @@ fn (mut g Gen) struct_init(node ast.StructInit) {
} }
field_name := c_name(field.name) field_name := c_name(field.name)
if field.typ.has_flag(.optional) || field.typ.has_flag(.result) { if field.typ.has_flag(.optional) || field.typ.has_flag(.result) {
g.write('.$field_name = {EMPTY_STRUCT_INITIALIZATION},') g.write('.$field_name = { EMPTY_STRUCT_INITIALIZATION },')
initialized = true initialized = true
continue continue
} }

View File

@ -812,18 +812,18 @@ fn struct_auto_str_func(mut g JsGen, sym &ast.TypeSymbol, field_type ast.Type, f
// ptr int can be "nil", so this needs to be casted to a string // ptr int can be "nil", so this needs to be casted to a string
if sym.kind == .f32 { if sym.kind == .f32 {
return 'str_intp(1, _MOV((StrIntpData[]){ return 'str_intp(1, _MOV((StrIntpData[]){
{_SLIT0, $si_g32_code, {.d_f32 = *$method_str }} { _SLIT0, $si_g32_code, {.d_f32 = *$method_str }}
}))' }))'
} else if sym.kind == .f64 { } else if sym.kind == .f64 {
return 'str_intp(1, _MOV((StrIntpData[]){ return 'str_intp(1, _MOV((StrIntpData[]){
{_SLIT0, $si_g64_code, {.d_f64 = *$method_str }} { _SLIT0, $si_g64_code, {.d_f64 = *$method_str }}
}))' }))'
} else if sym.kind == .u64 { } else if sym.kind == .u64 {
fmt_type := StrIntpType.si_u64 fmt_type := StrIntpType.si_u64
return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_u64 = *$method_str }}}))' return 'str_intp(1, _MOV((StrIntpData[]){{ _SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_u64 = *$method_str }}}))'
} }
fmt_type := StrIntpType.si_i32 fmt_type := StrIntpType.si_i32
return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_i32 = *$method_str }}}))' return 'str_intp(1, _MOV((StrIntpData[]){{ _SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_i32 = *$method_str }}}))'
} }
return method_str return method_str
} }

View File

@ -683,7 +683,7 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl, typ FnGenType) {
is_varg := i == args.len - 1 && it.is_variadic is_varg := i == args.len - 1 && it.is_variadic
arg_name := g.js_name(arg.name) arg_name := g.js_name(arg.name)
if is_varg { if is_varg {
g.writeln('$arg_name = new array(new array_buffer({arr: $arg_name,len: new int(${arg_name}.length),index_start: new int(0)}));') g.writeln('$arg_name = new array(new array_buffer({ arr: $arg_name,len: new int(${arg_name}.length),index_start: new int(0)}));')
} else { } else {
asym := g.table.sym(arg.typ) asym := g.table.sym(arg.typ)
if asym.kind != .interface_ && asym.language != .js { if asym.kind != .interface_ && asym.language != .js {

View File

@ -3,7 +3,7 @@ module sourcemap
fn test_simple() { fn test_simple() {
mut sg := generate_empty_map() mut sg := generate_empty_map()
mut sm := sg.add_map('hello.js', '/', true, 0, 0) mut sm := sg.add_map('hello.js', '/', true, 0, 0)
sm.set_source_content('hello.v', "fn main(){nprintln('Hello World! Helo \$a')\n}") sm.set_source_content('hello.v', "fn main(){ nprintln('Hello World! Helo \$a')\n}")
mlist := [ mlist := [
MappingInput{ MappingInput{
@ -132,7 +132,7 @@ fn test_simple() {
json_data := sm.to_json() json_data := sm.to_json()
expected := '{"version":3,"file":"hello.js","sourceRoot":"\\/","sources":["hello.v"],"sourcesContent":["fn main(){nprintln(\'Hello World! Helo \$a\')\\n}"],"names":["hello_name"],"mappings":"AAAA;AAAA,EAAA,OAAO,CAACA,GAAR,CAAY,aAAZ,CAAA,CAAA;AAAA"}' expected := '{"version":3,"file":"hello.js","sourceRoot":"\\/","sources":["hello.v"],"sourcesContent":["fn main(){ nprintln(\'Hello World! Helo \$a\')\\n}"],"names":["hello_name"],"mappings":"AAAA;AAAA,EAAA,OAAO,CAACA,GAAR,CAAY,aAAZ,CAAA,CAAA;AAAA"}'
assert json_data.str() == expected assert json_data.str() == expected
} }

View File

@ -802,9 +802,13 @@ fn (mut s Scanner) text_scan() token.Token {
return s.new_token(.rsbr, '', 1) return s.new_token(.rsbr, '', 1)
} }
`{` { `{` {
// Skip { in `${` in strings
if s.is_inside_string { if s.is_inside_string {
// Handle new `hello {name}` string interpolation
if !s.text[s.pos + 1].is_space() && s.text[s.pos - 1] != `$` {
return s.new_token(.str_dollar, '', 1)
}
if s.text[s.pos - 1] == `$` { if s.text[s.pos - 1] == `$` {
// Skip { in `${` in strings
continue continue
} else { } else {
s.inter_cbr_count++ s.inter_cbr_count++
@ -1225,6 +1229,33 @@ fn (mut s Scanner) ident_string() string {
s.pos -= 2 s.pos -= 2
break break
} }
// {var} (ignore in vfmt mode) (skip \{)
if c == `{` && util.is_name_char(s.text[s.pos + 1]) && prevc != `$` && !is_raw
&& s.count_symbol_before(s.pos - 1, scanner.backslash) % 2 == 0 {
// Detect certain strings with "{" that are not interpolation:
// e.g. "{init: " (no "}" at the end)
mut is_valid_inter := true
for i := s.pos + 1; i < s.text.len; i++ {
if s.text[i] == `}` {
// No } in this string, so it's not a valid `{x}` interpolation
break
}
if s.text[i] in [`=`, `\n`, s.inter_quote] {
// We reached the end of the line or string without reaching "}".
// Also if there's "=", there's no way it's a valid interpolation expression:
// e.g. `println("{a.b = 42}")`
is_valid_inter = false
break
}
}
if is_valid_inter {
s.is_inside_string = true
s.is_enclosed_inter = true
// so that s.pos points to $ at the next step
s.pos -= 1
break
}
}
if c != scanner.backslash { if c != scanner.backslash {
backslash_count = 0 backslash_count = 0
} }

View File

@ -18,7 +18,7 @@ pub fn (mut p Pos) free() {
} }
pub fn (p Pos) line_str() string { pub fn (p Pos) line_str() string {
return '{l: ${p.line_nr + 1:5}, c: ${p.col:3}, p: ${p.pos:5}, ll: ${p.last_line + 1:5}}' return '\{l: ${p.line_nr + 1:5}, c: ${p.col:3}, p: ${p.pos:5}, ll: ${p.last_line + 1:5}}'
} }
pub fn (pos Pos) extend(end Pos) Pos { pub fn (pos Pos) extend(end Pos) Pos {