From 66f271f100666edfd3c853c9c017b516557db157 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Tue, 3 Dec 2019 13:08:57 +0300 Subject: [PATCH] fix a string interpolation bug --- vlib/builtin/string_test.v | 9 ++++++++- vlib/compiler/expression.v | 2 +- vlib/compiler/parser.v | 6 +++--- vlib/compiler/scanner.v | 29 +++++++++++++++++------------ vlib/compiler/struct.v | 12 ++++++------ vlib/compiler/token.v | 16 +++++++++------- vlib/gx/gx.v | 14 ++++++++++---- vlib/http/download.v | 2 +- vlib/http/download_nix.v | 2 +- vlib/http/http.v | 5 +++-- vlib/os/os.v | 4 ++-- 11 files changed, 61 insertions(+), 40 deletions(-) diff --git a/vlib/builtin/string_test.v b/vlib/builtin/string_test.v index 3f50b6d64c..a42aad0d81 100644 --- a/vlib/builtin/string_test.v +++ b/vlib/builtin/string_test.v @@ -555,6 +555,13 @@ fn test_c_r() { println('$c') r := 50 println('$r') - +} + +fn test_inter_before_comp_if() { + s := '123' + // This used to break ('123 $....') + $if linux { + println(s) + } } diff --git a/vlib/compiler/expression.v b/vlib/compiler/expression.v index cf728d93a2..748f8f5252 100644 --- a/vlib/compiler/expression.v +++ b/vlib/compiler/expression.v @@ -167,7 +167,7 @@ fn (p mut Parser) name_expr() string { } // Raw string (`s := r'hello \n ') - if (name == 'r' || name == 'c') && p.peek() == .str && p.prev_tok != .dollar { + if (name == 'r' || name == 'c') && p.peek() == .str && p.prev_tok != .str_dollar { p.string_expr() return 'string' } diff --git a/vlib/compiler/parser.v b/vlib/compiler/parser.v index 18922f1428..415e2f0afc 100644 --- a/vlib/compiler/parser.v +++ b/vlib/compiler/parser.v @@ -2265,7 +2265,7 @@ fn (p mut Parser) string_expr() { } str := p.lit // No ${}, just return a simple string - if p.peek() != .dollar || is_raw { + if p.peek() != .str_dollar || is_raw { f := if is_raw { cescaped_path(str) } else { format_str(str) } // `C.puts('hi')` => `puts("hi");` /* @@ -2299,11 +2299,11 @@ fn (p mut Parser) string_expr() { p.lit = p.lit.replace('%', '%%') format += format_str(p.lit) p.next()// skip $ - if p.tok != .dollar { + if p.tok != .str_dollar { continue } // Handle .dollar - p.check(.dollar) + p.check(.str_dollar) // If there's no string after current token, it means we are in // a complex expression (`${...}`) if p.peek() != .str { diff --git a/vlib/compiler/scanner.v b/vlib/compiler/scanner.v index c367b71601..bb101c563b 100644 --- a/vlib/compiler/scanner.v +++ b/vlib/compiler/scanner.v @@ -56,7 +56,7 @@ fn new_scanner_file(file_path string) &Scanner { verror('scanner: failed to open $file_path') return 0 } - + // BOM check if raw_text.len >= 3 { c_text := raw_text.str @@ -229,8 +229,8 @@ fn (s mut Scanner) skip_whitespace() { for s.pos < s.text.len && s.text[s.pos].is_white() { if is_nl(s.text[s.pos]) && s.is_vh { return - - } + + } // Count \r\n as one line if is_nl(s.text[s.pos]) && !s.expect('\r\n', s.pos-1) { s.inc_line_number() @@ -369,7 +369,7 @@ fn (s mut Scanner) scan() ScanRes { return scan_res(.chartoken, s.ident_char()) } `(` { - + return scan_res(.lpar, '') } `)` { @@ -390,7 +390,12 @@ fn (s mut Scanner) scan() ScanRes { return scan_res(.lcbr, '') } `$` { - return scan_res(.dollar, '') + // if s.inter_start { + if s.inside_string {// || s.inter_start { + return scan_res(.str_dollar, '') + } else { + return scan_res(.dollar, '') + } } `}` { // s = `hello $name !` @@ -592,7 +597,7 @@ fn (s mut Scanner) scan() ScanRes { s.pos-- // fix line_nr, \n was read, and the comment is marked on the next line s.line_nr-- return scan_res(.line_comment, s.line_comment) - } + } //s.fgenln('// ${s.prev_tok.str()} "$s.line_comment"') // Skip the comment (return the next token) return s.scan() @@ -626,7 +631,7 @@ fn (s mut Scanner) scan() ScanRes { if s.is_fmt { s.line_comment = comment return scan_res(.mline_comment, s.line_comment) - } + } // Skip if not in fmt mode return s.scan() } @@ -758,7 +763,7 @@ fn (s mut Scanner) ident_char() string { } if c == '\\`' { return '`' - } + } // Escapes a `'` character return if c == '\'' { '\\' + c } else { c } } @@ -807,7 +812,7 @@ fn (s mut Scanner) debug_tokens() { fn (s mut Scanner) ignore_line() { - s.eat_to_end_of_line() + s.eat_to_end_of_line() s.inc_line_number() } @@ -835,7 +840,7 @@ fn (s Scanner) line(n int) string { if nline_start <= nline_end { res = s.text[nline_start..nline_end] } - } + } return res.trim_right('\r\n').trim_left('\r\n') } @@ -878,8 +883,8 @@ fn (s &Scanner) validate_var_name(name string) { s.error('bad variable name `$name`\n' + 'looks like you have a multi-word name without separating them with `_`' + '\nfor example, use `registration_date` instead of `registrationdate` ') - - } + + } } diff --git a/vlib/compiler/struct.v b/vlib/compiler/struct.v index 436197383c..781c305265 100644 --- a/vlib/compiler/struct.v +++ b/vlib/compiler/struct.v @@ -10,7 +10,7 @@ fn (p mut Parser) struct_decl() { if is_pub { p.next() p.fspace() - } + } // V can generate Objective C for integration with Cocoa // `[objc_interface:ParentInterface]` is_objc := p.attr.starts_with('objc_interface') @@ -53,7 +53,7 @@ fn (p mut Parser) struct_decl() { } if name.len == 1 && !p.pref.building_v && !p.pref.is_repl { p.warn('struct names must have more than one character') - } + } if !is_c && !good_type_name(name) { p.error('bad struct name, e.g. use `HttpRequest` instead of `HTTPRequest`') } @@ -123,7 +123,7 @@ fn (p mut Parser) struct_decl() { } } //println('fmt max len = $max_len nrfields=$typ.fields.len pass=$p.pass') - + if !is_ph && p.first_pass() { p.table.register_type2(typ) @@ -218,7 +218,7 @@ fn (p mut Parser) struct_decl() { if !p.first_pass() { p.table.add_default_val(i, typ.name, expr) } - } + } // [ATTR] mut attr := '' if p.tok == .lsbr { @@ -262,7 +262,7 @@ fn (p mut Parser) struct_init(typ string) string { t := p.table.find_type(typ) if !t.is_public && t.mod != p.mod { p.warn('type `$t.name` is private') - } + } if p.gen_struct_init(typ, t) { return typ } ptr := typ.contains('*') mut did_gen_something := false @@ -318,7 +318,7 @@ fn (p mut Parser) struct_init(typ string) string { } field_typ := field.typ if !p.builtin_mod && field_typ.ends_with('*') && p.mod != 'os' { //&& - p.warn('pointer field `${typ}.${field.name}` must be initialized') + p.warn('reference field `${typ}.${field.name}` must be initialized') } // init map fields if field_typ.starts_with('map_') { diff --git a/vlib/compiler/token.v b/vlib/compiler/token.v index cae409e24e..111aa60705 100644 --- a/vlib/compiler/token.v +++ b/vlib/compiler/token.v @@ -41,6 +41,7 @@ enum TokenKind { amp hash dollar + str_dollar left_shift righ_shift //at // @ @@ -197,6 +198,7 @@ fn build_token_str() []string { s[TokenKind.mline_comment] = '/* mline comment */' s[TokenKind.nl] = 'NLL' s[TokenKind.dollar] = '$' + s[TokenKind.str_dollar] = '$2' s[TokenKind.key_assert] = 'assert' s[TokenKind.key_struct] = 'struct' s[TokenKind.key_if] = 'if' @@ -272,7 +274,7 @@ const ( .or_assign, .and_assign, .righ_shift_assign, .left_shift_assign ] - + ) fn (t TokenKind) is_assign() bool { @@ -291,17 +293,17 @@ fn (t []TokenKind) contains(val TokenKind) bool { fn (t Token) str() string { if t.tok == .number { return t.lit - - } + + } if t.tok == .chartoken { return '`$t.lit`' - } + } if t.tok == .str { return "'$t.lit'" - } + } if t.tok < .plus { return t.lit // string, number etc - } + } return t.tok.str() -} +} diff --git a/vlib/gx/gx.v b/vlib/gx/gx.v index 360e1ec7f9..d8dc6f29ed 100644 --- a/vlib/gx/gx.v +++ b/vlib/gx/gx.v @@ -11,30 +11,36 @@ pub: b int } -pub const ( +pub const ( Blue = Color { r: 0, g: 0, b: 255 } + blue = Color { r: 0, g: 0, b: 255 } Red = Color { r: 255, g: 0, b: 0 } Green = Color { r: 0, g: 255, b: 0 } green = Color { r: 0, g: 255, b: 0 } Yellow = Color { r: 255, g: 255, b: 0 } - + Orange = Color { r: 255, g: 165, b: 0 } + orange = Color { r: 255, g: 165, b: 0 } Purple = Color { r: 128, g: 0, b: 128 } - + Black = Color { r: 0, g: 0, b: 0 } + black = Color { r: 0, g: 0, b: 0 } Gray = Color { r: 128, g: 128, b: 128 } + gray = Color { r: 128, g: 128, b: 128 } Indigo = Color { r: 75, g: 0, b: 130 } Pink = Color { r: 255, g: 192, b: 203 } Violet = Color { r: 238, g: 130, b: 238 } White = Color { r: 255, g: 255, b: 255 } white = Color { r: 255, g: 255, b: 255 } - + // Shades DarkBlue = Color { r: 0, g: 0, b: 139 } DarkGray = Color { r: 169, g: 169, b: 169 } + dark_gray = Color { r: 169, g: 169, b: 169 } DarkGreen = Color { r: 0, g: 100, b: 0 } DarkRed = Color { r: 139, g: 0, b: 0 } LightBlue = Color { r: 173, g: 216, b: 230 } + light_blue = Color { r: 173, g: 216, b: 230 } LightGray = Color { r: 211, g: 211, b: 211 } LightGreen = Color { r: 144, g: 238, b: 144 } LightRed = Color { r: 255, g: 204, b: 203 } diff --git a/vlib/http/download.v b/vlib/http/download.v index 388177f27a..6df47df9dd 100644 --- a/vlib/http/download.v +++ b/vlib/http/download.v @@ -6,7 +6,7 @@ module http import os -fn download_file(url, out string) bool { +pub fn download_file(url, out string) bool { s := http.get(url) or { return false } os.write_file(out, s.text) return true diff --git a/vlib/http/download_nix.v b/vlib/http/download_nix.v index e0b22da3dd..0500c84c48 100644 --- a/vlib/http/download_nix.v +++ b/vlib/http/download_nix.v @@ -27,7 +27,7 @@ fn download_cb(ptr voidptr, size, nmemb size_t, userp voidptr) { */ } -fn download_file_with_progress(url, out string, cb downloadfn, cb_finished fn()) { +pub fn download_file_with_progress(url, out string, cb downloadfn, cb_finished fn()) { /* curl := C.curl_easy_init() if isnil(curl) { diff --git a/vlib/http/http.v b/vlib/http/http.v index 73d17bc733..07a85274b2 100644 --- a/vlib/http/http.v +++ b/vlib/http/http.v @@ -21,10 +21,11 @@ pub: typ string // GET POST data string url string - ws_func voidptr - user_ptr voidptr verbose bool user_agent string +mut: + user_ptr voidptr + ws_func voidptr } pub struct Response { diff --git a/vlib/os/os.v b/vlib/os/os.v index b4850798e5..f0f0b35857 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -33,7 +33,7 @@ pub const ( pub struct File { cfile voidptr // Using void* instead of FILE* -mut: +mut: opened bool } @@ -738,7 +738,7 @@ pub fn clear() { } } -fn on_segfault(f voidptr) { +pub fn on_segfault(f voidptr) { $if windows { return }