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

Merge branch 'vlang:master' into sqlite_return_type_consistency

This commit is contained in:
jacksonmowry 2023-08-09 09:19:26 +00:00 committed by GitHub
commit 881fbb6183
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 240 additions and 65 deletions

View File

@ -324,8 +324,8 @@ fn vpm_install_from_vcs(module_names []string, vcs_key string) {
eprintln('Removing module "${minfo.final_module_path}" ...')
os.rmdir_all(minfo.final_module_path) or {
errors++
println('Errors while removing "${minfo.final_module_path}" :')
println(err)
eprintln('Errors while removing "${minfo.final_module_path}" :')
eprintln(err)
continue
}
}
@ -342,6 +342,14 @@ fn vpm_install_from_vcs(module_names []string, vcs_key string) {
continue
}
println('Module "${name}" relocated to "${vmod_.name}" successfully.')
publisher_dir := final_module_path.all_before_last(os.path_separator)
if os.is_dir_empty(publisher_dir) {
os.rmdir(publisher_dir) or {
errors++
eprintln('Errors while removing "${publisher_dir}" :')
eprintln(err)
}
}
final_module_path = minfo.final_module_path
}
name = vmod_.name

View File

@ -32,17 +32,17 @@ const (
fn test_search_tag_by_type() {
mut dom := parse(html.html)
tag := dom.get_tag('body')[0]
assert tag.get_tag('div') or { assert false }.attributes['id'] == '1st'
assert tag.get_tag_by_attribute('href') or { assert false }.content == 'V'
tag := dom.get_tags(GetTagsOptions{'body'})[0]
assert tag.get_tag('div')?.attributes['id'] == '1st'
assert tag.get_tag_by_attribute('href')?.content == 'V'
// TODO: update after improved parsing to not add trailing white space to attribute values
assert tag.get_tag_by_attribute_value('id', '3rd') or { assert false }.str() == '<div id="3rd" ></div>'
assert tag.get_tag_by_class_name('foo') or { assert false }.attributes['class'] == 'foo bar'
assert tag.get_tag_by_attribute_value('id', '3rd')?.str() == '<div id="3rd" ></div>'
assert tag.get_tag_by_class_name('foo')?.attributes['class'] == 'foo bar'
}
fn test_search_tags_by_type() {
mut dom := parse(html.html)
tag := dom.get_tag_by_attribute_value('id', '2nd')[0]
tag := dom.get_tags_by_attribute_value('id', '2nd')[0]
assert tag.get_tags('div').len == 5
assert tag.get_tags_by_attribute('href')[2].content == 'vpm'
assert tag.get_tags_by_attribute_value('class', 'bar').len == 3
@ -65,7 +65,7 @@ fn generate_temp_html_with_classes() string {
fn test_search_by_class() {
mut dom := parse(generate_temp_html_with_classes())
tag := dom.get_tag('body')[0]
tag := dom.get_tags(GetTagsOptions{'body'})[0]
single_class_tags := tag.get_tags_by_class_name('single')
common_class_tags := tag.get_tags_by_class_name('common')
complex_class_tags := tag.get_tags_by_class_name('complex-0', 'complex-1', 'complex-2')

View File

@ -5,34 +5,34 @@ fn test_custom_format() {
assert date.custom_format('YYYY-MM-DD HH:mm') == date.format()
assert date.custom_format('MMM') == date.smonth()
test_str := 'M MM Mo MMM MMMM\nD DD DDD DDDD\nd dd ddd dddd\nYY YYYY a A\nH HH h hh k kk e\nm mm s ss Z ZZ ZZZ\nDo DDDo Q Qo QQ\nN NN w wo ww\nM/D/YYYY N-HH:mm:ss Qo?a'
test_str := 'M MM Mo MMM MMMM\nD DD DDD DDDD\nd dd ddd dddd\nYY YYYY a A\nH HH h hh k kk i ii e\nm mm s ss Z ZZ ZZZ\nDo DDDo Q Qo QQ\nN NN w wo ww\nM/D/YYYY N-HH:mm:ss Qo?a'
println(date.custom_format(test_str))
}
fn test_hours() {
assert time.parse('2023-08-04 00:00:45')!.custom_format('hh A h a') == '00 AM 0 am'
assert time.parse('2023-08-04 01:00:45')!.custom_format('hh A h a') == '01 AM 1 am'
assert time.parse('2023-08-04 02:00:45')!.custom_format('hh A h a') == '02 AM 2 am'
assert time.parse('2023-08-04 03:00:45')!.custom_format('hh A h a') == '03 AM 3 am'
assert time.parse('2023-08-04 04:00:45')!.custom_format('hh A h a') == '04 AM 4 am'
assert time.parse('2023-08-04 05:00:45')!.custom_format('hh A h a') == '05 AM 5 am'
assert time.parse('2023-08-04 06:00:45')!.custom_format('hh A h a') == '06 AM 6 am'
assert time.parse('2023-08-04 07:00:45')!.custom_format('hh A h a') == '07 AM 7 am'
assert time.parse('2023-08-04 08:00:45')!.custom_format('hh A h a') == '08 AM 8 am'
assert time.parse('2023-08-04 09:00:45')!.custom_format('hh A h a') == '09 AM 9 am'
assert time.parse('2023-08-04 10:00:45')!.custom_format('hh A h a') == '10 AM 10 am'
assert time.parse('2023-08-04 11:00:45')!.custom_format('hh A h a') == '11 AM 11 am'
assert time.parse('2023-08-04 12:00:45')!.custom_format('hh A h a') == '12 PM 12 pm'
assert time.parse('2023-08-04 13:00:45')!.custom_format('hh A h a') == '01 PM 1 pm'
assert time.parse('2023-08-04 14:00:45')!.custom_format('hh A h a') == '02 PM 2 pm'
assert time.parse('2023-08-04 15:00:45')!.custom_format('hh A h a') == '03 PM 3 pm'
assert time.parse('2023-08-04 16:00:45')!.custom_format('hh A h a') == '04 PM 4 pm'
assert time.parse('2023-08-04 17:00:45')!.custom_format('hh A h a') == '05 PM 5 pm'
assert time.parse('2023-08-04 18:00:45')!.custom_format('hh A h a') == '06 PM 6 pm'
assert time.parse('2023-08-04 19:00:45')!.custom_format('hh A h a') == '07 PM 7 pm'
assert time.parse('2023-08-04 20:00:45')!.custom_format('hh A h a') == '08 PM 8 pm'
assert time.parse('2023-08-04 21:00:45')!.custom_format('hh A h a') == '09 PM 9 pm'
assert time.parse('2023-08-04 22:00:45')!.custom_format('hh A h a') == '10 PM 10 pm'
assert time.parse('2023-08-04 23:00:45')!.custom_format('hh A h a') == '11 PM 11 pm'
assert time.parse('2023-08-04 00:00:45')!.custom_format('ii A i a hh A h a') == '00 AM 0 am 12 AM 12 am'
assert time.parse('2023-08-04 01:00:45')!.custom_format('ii A i a hh A h a') == '01 AM 1 am 01 AM 1 am'
assert time.parse('2023-08-04 02:00:45')!.custom_format('ii A i a hh A h a') == '02 AM 2 am 02 AM 2 am'
assert time.parse('2023-08-04 03:00:45')!.custom_format('ii A i a hh A h a') == '03 AM 3 am 03 AM 3 am'
assert time.parse('2023-08-04 04:00:45')!.custom_format('ii A i a hh A h a') == '04 AM 4 am 04 AM 4 am'
assert time.parse('2023-08-04 05:00:45')!.custom_format('ii A i a hh A h a') == '05 AM 5 am 05 AM 5 am'
assert time.parse('2023-08-04 06:00:45')!.custom_format('ii A i a hh A h a') == '06 AM 6 am 06 AM 6 am'
assert time.parse('2023-08-04 07:00:45')!.custom_format('ii A i a hh A h a') == '07 AM 7 am 07 AM 7 am'
assert time.parse('2023-08-04 08:00:45')!.custom_format('ii A i a hh A h a') == '08 AM 8 am 08 AM 8 am'
assert time.parse('2023-08-04 09:00:45')!.custom_format('ii A i a hh A h a') == '09 AM 9 am 09 AM 9 am'
assert time.parse('2023-08-04 10:00:45')!.custom_format('ii A i a hh A h a') == '10 AM 10 am 10 AM 10 am'
assert time.parse('2023-08-04 11:00:45')!.custom_format('ii A i a hh A h a') == '11 AM 11 am 11 AM 11 am'
assert time.parse('2023-08-04 12:00:45')!.custom_format('ii A i a hh A h a') == '12 PM 12 pm 12 PM 12 pm'
assert time.parse('2023-08-04 13:00:45')!.custom_format('ii A i a hh A h a') == '01 PM 1 pm 01 PM 1 pm'
assert time.parse('2023-08-04 14:00:45')!.custom_format('ii A i a hh A h a') == '02 PM 2 pm 02 PM 2 pm'
assert time.parse('2023-08-04 15:00:45')!.custom_format('ii A i a hh A h a') == '03 PM 3 pm 03 PM 3 pm'
assert time.parse('2023-08-04 16:00:45')!.custom_format('ii A i a hh A h a') == '04 PM 4 pm 04 PM 4 pm'
assert time.parse('2023-08-04 17:00:45')!.custom_format('ii A i a hh A h a') == '05 PM 5 pm 05 PM 5 pm'
assert time.parse('2023-08-04 18:00:45')!.custom_format('ii A i a hh A h a') == '06 PM 6 pm 06 PM 6 pm'
assert time.parse('2023-08-04 19:00:45')!.custom_format('ii A i a hh A h a') == '07 PM 7 pm 07 PM 7 pm'
assert time.parse('2023-08-04 20:00:45')!.custom_format('ii A i a hh A h a') == '08 PM 8 pm 08 PM 8 pm'
assert time.parse('2023-08-04 21:00:45')!.custom_format('ii A i a hh A h a') == '09 PM 9 pm 09 PM 9 pm'
assert time.parse('2023-08-04 22:00:45')!.custom_format('ii A i a hh A h a') == '10 PM 10 pm 10 PM 10 pm'
assert time.parse('2023-08-04 23:00:45')!.custom_format('ii A i a hh A h a') == '11 PM 11 pm 11 PM 11 pm'
}

View File

@ -20,14 +20,6 @@ pub fn (t Time) format_ss_milli() string {
return '${t.year:04d}-${t.month:02d}-${t.day:02d} ${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${(t.nanosecond / 1_000_000):03d}'
}
// format_rfc3339 returns a date string in "YYYY-MM-DDTHH:mm:ss.123Z" format (24 hours, see https://www.rfc-editor.org/rfc/rfc3339.html)
// RFC3339 is an Internet profile, based on the ISO 8601 standard for for representation of dates and times using the Gregorian calendar.
// It is intended to improve consistency and interoperability, when representing and using date and time in Internet protocols.
pub fn (t Time) format_rfc3339() string {
u := t.local_to_utc()
return '${u.year:04d}-${u.month:02d}-${u.day:02d}T${u.hour:02d}:${u.minute:02d}:${u.second:02d}.${(u.nanosecond / 1_000_000):03d}Z'
}
// format_ss_micro returns a date string in "YYYY-MM-DD HH:mm:ss.123456" format (24h).
pub fn (t Time) format_ss_micro() string {
return '${t.year:04d}-${t.month:02d}-${t.day:02d} ${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${(t.nanosecond / 1_000):06d}'
@ -38,6 +30,20 @@ pub fn (t Time) format_ss_nano() string {
return '${t.year:04d}-${t.month:02d}-${t.day:02d} ${t.hour:02d}:${t.minute:02d}:${t.second:02d}.${t.nanosecond:09d}'
}
// format_rfc3339 returns a date string in "YYYY-MM-DDTHH:mm:ss.123Z" format (24 hours, see https://www.rfc-editor.org/rfc/rfc3339.html)
// RFC3339 is an Internet profile, based on the ISO 8601 standard for for representation of dates and times using the Gregorian calendar.
// It is intended to improve consistency and interoperability, when representing and using date and time in Internet protocols.
pub fn (t Time) format_rfc3339() string {
u := t.local_to_utc()
return '${u.year:04d}-${u.month:02d}-${u.day:02d}T${u.hour:02d}:${u.minute:02d}:${u.second:02d}.${(u.nanosecond / 1_000_000):03d}Z'
}
// format_rfc3339_nano returns a date string in "YYYY-MM-DDTHH:mm:ss.123456789Z" format (24 hours, see https://www.rfc-editor.org/rfc/rfc3339.html)
pub fn (t Time) format_rfc3339_nano() string {
u := t.local_to_utc()
return '${u.year:04d}-${u.month:02d}-${u.day:02d}T${u.hour:02d}:${u.minute:02d}:${u.second:02d}.${(u.nanosecond):09d}Z'
}
// hhmm returns a date string in "HH:mm" format (24h).
pub fn (t Time) hhmm() string {
return '${t.hour:02d}:${t.minute:02d}'
@ -90,8 +96,8 @@ fn ordinal_suffix(n int) string {
}
const (
tokens_2 = ['MM', 'Mo', 'DD', 'Do', 'YY', 'ss', 'kk', 'NN', 'mm', 'hh', 'HH', 'ZZ', 'dd', 'Qo',
'QQ', 'wo', 'ww']
tokens_2 = ['MM', 'Mo', 'DD', 'Do', 'YY', 'ss', 'kk', 'NN', 'mm', 'hh', 'HH', 'ii', 'ZZ', 'dd',
'Qo', 'QQ', 'wo', 'ww']
tokens_3 = ['MMM', 'DDD', 'ZZZ', 'ddd']
tokens_4 = ['MMMM', 'DDDD', 'DDDo', 'dddd', 'YYYY']
)
@ -132,6 +138,8 @@ const (
// | | HH | 00 01 ... 22 23 |
// | | h | 1 2 ... 11 12 |
// | | hh | 01 02 ... 11 12 |
// | | i | 0 1 ... 11 12 1 ... 11 |
// | | ii | 00 01 ... 11 12 01 ... 11 |
// | | k | 1 2 ... 23 24 |
// | | kk | 01 02 ... 23 24 |
// | **Minute** | m | 0 1 ... 58 59 |
@ -226,10 +234,18 @@ pub fn (t Time) custom_format(s string) string {
sb.write_string('${t.hour:02}')
}
'h' {
h := if t.hour > 12 { t.hour - 12 } else { t.hour }
h := (t.hour + 11) % 12 + 1
sb.write_string(h.str())
}
'hh' {
h := (t.hour + 11) % 12 + 1
sb.write_string('${h:02}')
}
'i' {
h := if t.hour > 12 { t.hour - 12 } else { t.hour }
sb.write_string(h.str())
}
'ii' {
h := if t.hour > 12 { t.hour - 12 } else { t.hour }
sb.write_string('${h:02}')
}

View File

@ -89,6 +89,13 @@ fn test_format_rfc3339() {
assert res.contains('T')
}
fn test_format_rfc3339_nano() {
res := time_to_test.format_rfc3339_nano()
assert res.ends_with('23:42.123456789Z')
assert res.starts_with('1980-07-1')
assert res.contains('T')
}
fn test_format_ss() {
assert '11.07.1980 21:23:42' == time_to_test.get_fmt_str(.dot, .hhmmss24, .ddmmyyyy)
}

View File

@ -526,6 +526,9 @@ fn (mut c Checker) alias_type_decl(node ast.AliasTypeDecl) {
// type Sum = int | Alias
// type Alias = Sum
}
.none_ {
c.error('cannot create a type alias of `none` as it is a value', node.type_pos)
}
// The rest of the parent symbol kinds are also allowed, since they are either primitive types,
// that in turn do not allow recursion, or are abstract enough so that they can not be checked at comptime:
else {}
@ -1143,6 +1146,8 @@ fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type ast.Type) ast.Typ
c.check_expr_opt_call(expr.expr, ret_type)
} else if expr is ast.AsCast {
c.check_expr_opt_call(expr.expr, ret_type)
} else if expr is ast.ParExpr {
c.check_expr_opt_call(expr.expr, ret_type)
}
return ret_type
}
@ -1774,9 +1779,6 @@ fn (mut c Checker) enum_decl(mut node ast.EnumDecl) {
useen << uval
}
}
ast.PrefixExpr {
dump(field.expr)
}
ast.InfixExpr {
// Handle `enum Foo { x = 1 + 2 }`
c.infix_expr(mut field.expr)

View File

@ -490,6 +490,9 @@ fn (mut c Checker) call_expr(mut node ast.CallExpr) ast.Type {
c.error('unknown function: ${node.name}', node.pos)
}
}
// If the left expr has an or_block, it needs to be checked for legal or_block statement.
return_type := c.expr(mut node.left)
c.check_expr_opt_call(node.left, return_type)
// TODO merge logic from method_call and fn_call
// First check everything that applies to both fns and methods
old_inside_fn_arg := c.inside_fn_arg

View File

@ -5,6 +5,13 @@ vlib/v/checker/tests/generics_struct_init_err.vv:14:2: notice: uninitialized `fn
| ~~~~~~~~~~~~~~~~~
15 | }
16 |
vlib/v/checker/tests/generics_struct_init_err.vv:58:8: error: cannot initialize builtin type `FnHolder1[neg]`
56 | ret = holder_call_12(neg, 3)
57 | assert ret == -3
58 | ret = FnHolder1{neg}.call(4)
| ~~~~~~~~~~~~~~
59 | assert ret == -4
60 |
vlib/v/checker/tests/generics_struct_init_err.vv:67:8: error: could not infer generic type `T` in generic struct `FnHolder2[T]`
65 | ret = holder_call_22(neg, 5)
66 | assert ret == -5

View File

@ -1,6 +1,6 @@
vlib/v/checker/tests/option_type_call_err.vv:4:5: error: Result type cannot be called directly
2 |
vlib/v/checker/tests/option_type_call_err.vv:4:5: error: os.ls() returns a Result, so it should have either an `or {}` block, or `!` at the end
2 |
3 | fn main() {
4 | os.ls('.').filter(it.ends_with('.v')) or { return }
| ~~~~~~~
5 | }
5 | }

View File

@ -0,0 +1,27 @@
vlib/v/checker/tests/or_block_check_err.vv:6:36: error: assignment requires a non empty `or {}` block
4 |
5 | fn main() {
6 | _ = callexpr_with_or_block_call() or {}.replace('a', 'b')
| ~~~~~
7 | _ = (callexpr_with_or_block_call() or {}).replace('a', 'b')
8 |
vlib/v/checker/tests/or_block_check_err.vv:7:37: error: assignment requires a non empty `or {}` block
5 | fn main() {
6 | _ = callexpr_with_or_block_call() or {}.replace('a', 'b')
7 | _ = (callexpr_with_or_block_call() or {}).replace('a', 'b')
| ~~~~~
8 |
9 | _ = callexpr_with_or_block_call() or { eprintln('error') }.replace('a', 'b')
vlib/v/checker/tests/or_block_check_err.vv:9:41: error: `or` block must provide a default value of type `string`, or return/continue/break or call a [noreturn] function like panic(err) or exit(1)
7 | _ = (callexpr_with_or_block_call() or {}).replace('a', 'b')
8 |
9 | _ = callexpr_with_or_block_call() or { eprintln('error') }.replace('a', 'b')
| ~~~~~~~~~~~~~~~~~
10 | _ = (callexpr_with_or_block_call() or { eprintln('error') }).replace('a', 'b')
11 | }
vlib/v/checker/tests/or_block_check_err.vv:10:42: error: `or` block must provide a default value of type `string`, or return/continue/break or call a [noreturn] function like panic(err) or exit(1)
8 |
9 | _ = callexpr_with_or_block_call() or { eprintln('error') }.replace('a', 'b')
10 | _ = (callexpr_with_or_block_call() or { eprintln('error') }).replace('a', 'b')
| ~~~~~~~~~~~~~~~~~
11 | }

View File

@ -0,0 +1,11 @@
fn callexpr_with_or_block_call() !string {
return error('')
}
fn main() {
_ = callexpr_with_or_block_call() or {}.replace('a', 'b')
_ = (callexpr_with_or_block_call() or {}).replace('a', 'b')
_ = callexpr_with_or_block_call() or { eprintln('error') }.replace('a', 'b')
_ = (callexpr_with_or_block_call() or { eprintln('error') }).replace('a', 'b')
}

View File

@ -1,5 +1,5 @@
vlib/v/checker/tests/result_type_call_err.vv:12:2: error: Result type cannot be called directly
10 |
vlib/v/checker/tests/result_type_call_err.vv:12:2: error: new_foo() returns a Result, so it should have either an `or {}` block, or `!` at the end
10 |
11 | fn main() {
12 | new_foo().foo()
| ~~~~~~~~~

View File

@ -0,0 +1,3 @@
vlib/v/checker/tests/type_alias_none_parent_type_err.vv:1:13: error: cannot create a type alias of `none` as it is a value
1 | type None = none
| ~~~~

View File

@ -0,0 +1 @@
type None = none

View File

@ -648,7 +648,7 @@ fn (mut s Scanner) text_scan() token.Token {
}
// End of $var, start next string
if s.is_inter_end {
if s.text[s.pos] == s.quote {
if s.text[s.pos] == s.quote || (s.text[s.pos] == s.inter_quote && s.is_enclosed_inter) {
s.is_inter_end = false
return s.new_token(.string, '', 1)
}
@ -1472,17 +1472,23 @@ fn (mut s Scanner) ident_char() string {
u := c.runes()
if u.len != 1 {
if escaped_hex || escaped_unicode {
s.error('invalid character literal `${orig}` => `${c}` (${u}) (escape sequence did not refer to a singular rune)')
s.error_with_pos('invalid character literal `${orig}` => `${c}` (${u}) (escape sequence did not refer to a singular rune)',
lspos)
} else if u.len == 0 {
s.add_error_detail_with_pos('use quotes for strings, backticks for characters',
lspos)
s.error('invalid empty character literal `${orig}`')
s.error_with_pos('invalid empty character literal `${orig}`', lspos)
} else {
s.add_error_detail_with_pos('use quotes for strings, backticks for characters',
lspos)
s.error('invalid character literal `${orig}` => `${c}` (${u}) (more than one character)')
s.error_with_pos('invalid character literal `${orig}` => `${c}` (${u}) (more than one character)',
lspos)
}
}
} else if c == '\n' {
s.add_error_detail_with_pos('use quotes for strings, backticks for characters',
lspos)
s.error_with_pos('invalid character literal, use \`\\n\` instead', lspos)
}
// Escapes a `'` character
if c == "'" {
@ -1566,15 +1572,19 @@ fn (mut s Scanner) eat_details() string {
}
pub fn (mut s Scanner) warn(msg string) {
if s.pref.warns_are_errors {
s.error(msg)
return
}
pos := token.Pos{
line_nr: s.line_nr
pos: s.pos
col: s.current_column() - 1
}
s.warn_with_pos(msg, pos)
}
pub fn (mut s Scanner) warn_with_pos(msg string, pos token.Pos) {
if s.pref.warns_are_errors {
s.error_with_pos(msg, pos)
return
}
details := s.eat_details()
if s.pref.output_mode == .stdout && !s.pref.check_only {
util.show_compiler_message('warning:',
@ -1604,6 +1614,10 @@ pub fn (mut s Scanner) error(msg string) {
pos: s.pos
col: s.current_column() - 1
}
s.error_with_pos(msg, pos)
}
pub fn (mut s Scanner) error_with_pos(msg string, pos token.Pos) {
details := s.eat_details()
if s.pref.output_mode == .stdout && !s.pref.check_only {
util.show_compiler_message('error:',

View File

@ -1,10 +1,10 @@
vlib/v/scanner/tests/empty_character_literal_err.vv:2:8: error: invalid empty character literal ``
vlib/v/scanner/tests/empty_character_literal_err.vv:2:7: error: invalid empty character literal ``
1 | fn main() {
2 | a := ``
| ^
| ^
3 | println(a)
4 | }
Details:
Details:
vlib/v/scanner/tests/empty_character_literal_err.vv:2:7: details: use quotes for strings, backticks for characters
1 | fn main() {
2 | a := ``

View File

@ -0,0 +1,13 @@
vlib/v/scanner/tests/newline_character_literal_err.vv:2:7: error: invalid character literal, use `\n` instead
1 | fn main() {
2 | a := `
| ^
3 | `
4 | println(a)
Details:
vlib/v/scanner/tests/newline_character_literal_err.vv:2:7: details: use quotes for strings, backticks for characters
1 | fn main() {
2 | a := `
| ^
3 | `
4 | println(a)

View File

@ -0,0 +1,5 @@
fn main() {
a := `
`
println(a)
}

View File

@ -0,0 +1,7 @@
[vlib/v/slow_tests/inout/dump_expressions_with_literals.vv:5] 2 + 2: 4
[vlib/v/slow_tests/inout/dump_expressions_with_literals.vv:6] 2 * 3 + 50 / 5: 16
[vlib/v/slow_tests/inout/dump_expressions_with_literals.vv:7] 3.14 + 0.1: 3.24
[vlib/v/slow_tests/inout/dump_expressions_with_literals.vv:8] 'abc' + 'a': abca
[vlib/v/slow_tests/inout/dump_expressions_with_literals.vv:9] 'a' + 'b' + 'c': abc
[vlib/v/slow_tests/inout/dump_expressions_with_literals.vv:10] true || (false && true): true
[vlib/v/slow_tests/inout/dump_expressions_with_literals.vv:11] 2 == 4: false

View File

@ -0,0 +1,12 @@
// Note: dump expressions should not get optimised out by the transformer stage,
// even though they could normally, when they are composed of literals, i.e.
// the value of the expression is known at compile time.
fn main() {
dump(2 + 2)
dump(2 * 3 + 50 / 5)
dump(3.14 + 0.1)
dump('abc' + 'a')
dump('a' + 'b' + 'c')
dump(true || (false && true))
dump(2 == 4)
}

View File

@ -0,0 +1,32 @@
fn f(x int, s string) string {
return 'label ${s}: ${x}'
}
// vfmt off
fn test_string_interp_with_inner_quotes() {
x := 'hi'
println('abc ${f(123, 'def')} xyz')
assert 'abc ${f(123, 'def')} xyz' == 'abc label def: 123 xyz'
println('abc ${f(123, "def")} xyz')
assert 'abc ${f(123, "def")} xyz' == 'abc label def: 123 xyz'
println("abc ${f(123, 'def')} xyz")
assert "abc ${f(123, 'def')} xyz" == 'abc label def: 123 xyz'
println("abc ${f(123, "def")} xyz")
assert "abc ${f(123, "def")} xyz" == 'abc label def: 123 xyz'
println("abc ${f(123, "$x $x")} xyz")
assert "abc ${f(123, "$x $x")} xyz" == 'abc label hi hi: 123 xyz'
println('abc ${f(123, '$x $x')} xyz')
assert 'abc ${f(123, '$x $x')} xyz' == 'abc label hi hi: 123 xyz'
println('abc ${f(123, "$x $x")} xyz')
assert 'abc ${f(123, "$x $x")} xyz' == 'abc label hi hi: 123 xyz'
println("abc ${f(123, '$x $x')} xyz")
assert "abc ${f(123, '$x $x')} xyz" == 'abc label hi hi: 123 xyz'
}
// vfmt on

View File

@ -10,7 +10,8 @@ pub mut:
index &IndexState
table &ast.Table = unsafe { nil }
mut:
is_assert bool
is_assert bool
inside_dump bool
}
pub fn new_transformer(pref_ &pref.Preferences) &Transformer {
@ -513,6 +514,9 @@ pub fn (mut t Transformer) interface_decl(mut node ast.InterfaceDecl) ast.Stmt {
}
pub fn (mut t Transformer) expr(mut node ast.Expr) ast.Expr {
if t.inside_dump {
return node
}
match mut node {
ast.AnonFn {
node.decl = t.stmt(mut node.decl) as ast.FnDecl
@ -563,7 +567,10 @@ pub fn (mut t Transformer) expr(mut node ast.Expr) ast.Expr {
}
}
ast.DumpExpr {
old_inside_dump := t.inside_dump
t.inside_dump = true
node.expr = t.expr(mut node.expr)
t.inside_dump = old_inside_dump
}
ast.GoExpr {
node.call_expr = t.expr(mut node.call_expr) as ast.CallExpr