'$foo()' string interpolation

pull/3017/head
Alexander Medvednikov 2019-12-08 22:22:47 +03:00
parent ef821379da
commit 8f9b6ac248
11 changed files with 57 additions and 42 deletions

View File

@ -1024,13 +1024,15 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
p.mutable_arg_error(i, arg, f) p.mutable_arg_error(i, arg, f)
} }
if p.peek() != .name { if p.peek() != .name {
p.error('`$arg.name` is a mutable argument, you need to provide a variable to modify: `$f.name(... mut a...)`') p.error('`$arg.name` is a mutable argument, you need to ' +
'provide a variable to modify: `${f.name}(... mut a...)`')
} }
p.check(.key_mut) p.check(.key_mut)
p.fspace() p.fspace()
var_name := p.lit var_name := p.lit
v := p.find_var(var_name) or { v := p.find_var(var_name) or {
p.error('`$arg.name` is a mutable argument, you need to provide a variable to modify: `$f.name(... mut a...)`') p.error('`$arg.name` is a mutable argument, you need to ' +
'provide a variable to modify: `${f.name}(... mut a...)`')
exit(1) exit(1)
} }
if !v.is_changed { if !v.is_changed {
@ -1156,7 +1158,7 @@ fn (p mut Parser) fn_call_args(f mut Fn) {
nr = 'third' nr = 'third'
} }
p.error('cannot use type `$typ` as type `$arg.typ` in $nr ' + p.error('cannot use type `$typ` as type `$arg.typ` in $nr ' +
'argument to `$f.name()`') 'argument to `${f.name}()`')
} else { } else {
saved_args << '' saved_args << ''
} }
@ -1575,7 +1577,7 @@ fn (fns []Fn) contains(f Fn) bool {
return false return false
} }
fn (p &Parser) fn_signature(f &Fn) string { fn (p &Parser) fn_signature(f &Fn) string {
return '$f.typ $f.name(${f.str_args(p.table)})' return '$f.typ ${f.name}(${f.str_args(p.table)})'
} }
pub fn (f &Fn) v_fn_module() string { pub fn (f &Fn) v_fn_module() string {

View File

@ -74,7 +74,7 @@ fn (p mut Parser) gen_blank_identifier_assign() {
p.is_var_decl = true p.is_var_decl = true
typ := p.bool_expression() typ := p.bool_expression()
if typ == 'void' { if typ == 'void' {
p.error_with_token_index('$next_expr() $err_used_as_value', p.token_idx-2) p.error_with_token_index('${next_expr}() $err_used_as_value', p.token_idx-2)
} }
p.is_var_decl = false p.is_var_decl = false
if !is_indexer && !is_fn_call { if !is_indexer && !is_fn_call {
@ -417,7 +417,7 @@ fn (p mut Parser) gen_array_init(typ string, no_alloc bool, new_arr_ph int, nr_e
// Need to do this in the second pass, otherwise it goes to the very top of the out.c file // Need to do this in the second pass, otherwise it goes to the very top of the out.c file
if !p.first_pass() { if !p.first_pass() {
p.cgen.set_placeholder(new_arr_ph, p.cgen.set_placeholder(new_arr_ph,
'$new_arr($nr_elems, $nr_elems, sizeof($typ), EMPTY_ARRAY_OF_ELEMS( $typ, $nr_elems ) { ') '${new_arr}($nr_elems, $nr_elems, sizeof($typ), EMPTY_ARRAY_OF_ELEMS( $typ, $nr_elems ) { ')
} }
} }
@ -494,7 +494,7 @@ fn (p mut Parser) gen_struct_init(typ string, t Type) bool {
else { else {
if p.tok == .not { if p.tok == .not {
// old &User{!} ==> 0 hack // old &User{!} ==> 0 hack
p.error('use `$t.name(0)` instead of `&$t.name{!}`') p.error('use `${t.name}(0)` instead of `&$t.name{!}`')
/* /*
p.next() p.next()
p.gen('0') p.gen('0')

View File

@ -58,7 +58,7 @@ fn (p mut Parser) gen_json_for_type(typ Type) {
// Code gen decoder // Code gen decoder
dec += ' dec += '
//$t $dec_fn.name (cJSON* root) { //$t $dec_fn.name (cJSON* root) {
Option $dec_fn.name(cJSON* root, $t* res) { Option ${dec_fn.name}(cJSON* root, $t* res) {
// $t res; // $t res;
if (!root) { if (!root) {
const char *error_ptr = cJSON_GetErrorPtr(); const char *error_ptr = cJSON_GetErrorPtr();

View File

@ -502,12 +502,14 @@ pub fn (v mut V) generate_main() {
v.gen_main_start(false) v.gen_main_start(false)
if v.pref.is_stats { if v.pref.is_stats {
cgen.genln('BenchedTests bt = main__start_testing();') // QQQ
//cgen.genln('BenchedTests bt = main__start_testing();')
} }
for _, f in v.table.fns { for _, f in v.table.fns {
if f.name.starts_with('main__test_') { if f.name.starts_with('main__test_') {
if v.pref.is_stats { cgen.genln('BenchedTests_testing_step_start(&bt, tos3("$f.name"));') } if v.pref.is_stats {
cgen.genln('BenchedTests_testing_step_start(&bt, tos3("$f.name"));') }
cgen.genln('$f.name ();') cgen.genln('$f.name ();')
if v.pref.is_stats { cgen.genln('BenchedTests_testing_step_end(&bt);') } if v.pref.is_stats { cgen.genln('BenchedTests_testing_step_end(&bt);') }
} }

View File

@ -1408,7 +1408,7 @@ fn ($v.name mut $v.typ) $p.cur_fn.name (...) {
//} //}
if expr_type == 'void' { if expr_type == 'void' {
_, fn_name := p.is_expr_fn_call(p.token_idx-3) _, fn_name := p.is_expr_fn_call(p.token_idx-3)
p.error_with_token_index('$fn_name() $err_used_as_value', p.token_idx-2) p.error_with_token_index('${fn_name}() $err_used_as_value', p.token_idx-2)
} }
// Allow `num = 4` where `num` is an `?int` // Allow `num = 4` where `num` is an `?int`
if p.assigned_type.starts_with('Option_') && if p.assigned_type.starts_with('Option_') &&
@ -1517,7 +1517,7 @@ fn (p mut Parser) var_decl() {
t := p.gen_var_decl(p.var_decl_name, is_static) t := p.gen_var_decl(p.var_decl_name, is_static)
if t == 'void' { if t == 'void' {
_, fn_name := p.is_expr_fn_call(p.token_idx-3) _, fn_name := p.is_expr_fn_call(p.token_idx-3)
p.error_with_token_index('$fn_name() $err_used_as_value', p.token_idx-2) p.error_with_token_index('${fn_name}() $err_used_as_value', p.token_idx-2)
} }
mut var_types := [t] mut var_types := [t]
// multiple returns types // multiple returns types
@ -1698,7 +1698,7 @@ fn (p mut Parser) get_c_func_type(name string) string {
// Do not allow it. // Do not allow it.
if !name.starts_with('gl') && !name.starts_with('glad') { if !name.starts_with('gl') && !name.starts_with('glad') {
p.error('undefined C function `$f.name`\n' + p.error('undefined C function `$f.name`\n' +
'define it with `fn C.$name([args]) [return_type]`') 'define it with `fn C.${name}([args]) [return_type]`')
} }
return 'void*' return 'void*'
} }
@ -2534,7 +2534,7 @@ if (!$tmp) {
tos3("$filename"), tos3("$filename"),
$p.scanner.line_nr, $p.scanner.line_nr,
tos3("$sourceline"), tos3("$sourceline"),
tos3("$p.cur_fn.name()") tos3("${p.cur_fn.name}()")
); );
exit(1); exit(1);
// TODO // TODO
@ -2545,7 +2545,7 @@ if (!$tmp) {
tos3("$filename"), tos3("$filename"),
$p.scanner.line_nr, $p.scanner.line_nr,
tos3("$sourceline"), tos3("$sourceline"),
tos3("$p.cur_fn.name()") tos3("${p.cur_fn.name}()")
); );
} }
@ -2745,7 +2745,7 @@ fn (p mut Parser) js_decode() string {
decl += 'cJSON* $cjson_tmp = json__json_parse($expr);' decl += 'cJSON* $cjson_tmp = json__json_parse($expr);'
p.cgen.insert_before(decl) p.cgen.insert_before(decl)
// p.gen('jsdecode_$typ(json_parse($expr), &$tmp);') // p.gen('jsdecode_$typ(json_parse($expr), &$tmp);')
p.gen('json__jsdecode_$typ($cjson_tmp, &$tmp); cJSON_Delete($cjson_tmp);') p.gen('json__jsdecode_${typ}($cjson_tmp, &$tmp); cJSON_Delete($cjson_tmp);')
opt_type := 'Option_$typ' opt_type := 'Option_$typ'
p.cgen.typedefs << 'typedef Option $opt_type;' p.cgen.typedefs << 'typedef Option $opt_type;'
p.table.register_builtin(opt_type) p.table.register_builtin(opt_type)
@ -2757,7 +2757,7 @@ fn (p mut Parser) js_decode() string {
T := p.table.find_type(typ) T := p.table.find_type(typ)
p.gen_json_for_type(T) p.gen_json_for_type(T)
p.check(.rpar) p.check(.rpar)
p.gen('json__json_print(json__jsencode_$typ($expr))') p.gen('json__json_print(json__jsencode_${typ}($expr))')
return 'string' return 'string'
} }
else { else {

View File

@ -123,7 +123,8 @@ fn (p mut Parser) select_query(fn_ph int) string {
if field.typ == 'int' { if field.typ == 'int' {
cast = 'v_string_int' cast = 'v_string_int'
} }
obj_gen.writeln('${qprefix}$tmp . $field.name = $cast( *(string*)array_get(${qprefix}row.vals, $i) );') obj_gen.writeln('${qprefix}${tmp}.$field.name = ' +
'${cast}(*(string*)array_get(${qprefix}row.vals, $i));')
} }
// One object // One object
if query_one { if query_one {

View File

@ -299,7 +299,8 @@ fn (s mut Scanner) scan() ScanRes {
} }
} }
// end of `$expr` // end of `$expr`
if s.inter_start && next_char != `.` { // allow `'$a.b'` and `'$a.c()'`
if s.inter_start && next_char != `.` && next_char != `(` {
s.inter_end = true s.inter_end = true
s.inter_start = false s.inter_start = false
} }
@ -315,6 +316,16 @@ fn (s mut Scanner) scan() ScanRes {
num := s.ident_number() num := s.ident_number()
return scan_res(.number, num) return scan_res(.number, num)
} }
// Handle `'$fn()'`
if c == `)` && s.inter_start {
s.inter_end = true
s.inter_start = false
next_char := if s.pos + 1 < s.text.len { s.text[s.pos + 1] } else { `\0` }
if next_char == s.quote {
s.inside_string = false
}
return scan_res(.rpar, '')
}
// all other tokens // all other tokens
match c { match c {
`+` { `+` {
@ -383,8 +394,7 @@ fn (s mut Scanner) scan() ScanRes {
return scan_res(.rsbr, '') return scan_res(.rsbr, '')
} }
`{` { `{` {
// Skip { in ${ in strings // Skip { in `${` in strings
// }
if s.inside_string { if s.inside_string {
return s.scan() return s.scan()
} }

View File

@ -188,7 +188,7 @@ const (
fn (f Fn) str() string { fn (f Fn) str() string {
t := Table{} t := Table{}
str_args := f.str_args(t) str_args := f.str_args(t)
return '$f.name($str_args) $f.typ' return '${f.name}($str_args) $f.typ'
} }
pub fn (t &Table) debug_fns() string { pub fn (t &Table) debug_fns() string {

View File

@ -676,7 +676,7 @@ fn (g mut Game) generate_tetro() {
g.pos_x = FieldWidth / 2 - TetroSize / 2 g.pos_x = FieldWidth / 2 - TetroSize / 2
g.tetro_idx = g.rand_tetro() g.tetro_idx = g.rand_tetro()
// println('idx=${g.tetro_idx}') // println('idx=${g.tetro_idx}')
g.tetro_stats[g.tetro_idx] += 1 g.tetro_stats[g.tetro_idx]+= 2 -1
g.tetro_total++ g.tetro_total++
g.rotation_idx = 0 g.rotation_idx = 0
g.get_tetro() g.get_tetro()