fix a string interpolation bug

pull/2967/head
Alexander Medvednikov 2019-12-03 13:08:57 +03:00
parent 89d40566f4
commit 66f271f100
11 changed files with 61 additions and 40 deletions

View File

@ -555,6 +555,13 @@ fn test_c_r() {
println('$c') println('$c')
r := 50 r := 50
println('$r') println('$r')
}
fn test_inter_before_comp_if() {
s := '123'
// This used to break ('123 $....')
$if linux {
println(s)
}
} }

View File

@ -167,7 +167,7 @@ fn (p mut Parser) name_expr() string {
} }
// Raw string (`s := r'hello \n ') // 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() p.string_expr()
return 'string' return 'string'
} }

View File

@ -2265,7 +2265,7 @@ fn (p mut Parser) string_expr() {
} }
str := p.lit str := p.lit
// No ${}, just return a simple string // 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) } f := if is_raw { cescaped_path(str) } else { format_str(str) }
// `C.puts('hi')` => `puts("hi");` // `C.puts('hi')` => `puts("hi");`
/* /*
@ -2299,11 +2299,11 @@ fn (p mut Parser) string_expr() {
p.lit = p.lit.replace('%', '%%') p.lit = p.lit.replace('%', '%%')
format += format_str(p.lit) format += format_str(p.lit)
p.next()// skip $ p.next()// skip $
if p.tok != .dollar { if p.tok != .str_dollar {
continue continue
} }
// Handle .dollar // Handle .dollar
p.check(.dollar) p.check(.str_dollar)
// If there's no string after current token, it means we are in // If there's no string after current token, it means we are in
// a complex expression (`${...}`) // a complex expression (`${...}`)
if p.peek() != .str { if p.peek() != .str {

View File

@ -56,7 +56,7 @@ fn new_scanner_file(file_path string) &Scanner {
verror('scanner: failed to open $file_path') verror('scanner: failed to open $file_path')
return 0 return 0
} }
// BOM check // BOM check
if raw_text.len >= 3 { if raw_text.len >= 3 {
c_text := raw_text.str 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() { for s.pos < s.text.len && s.text[s.pos].is_white() {
if is_nl(s.text[s.pos]) && s.is_vh { if is_nl(s.text[s.pos]) && s.is_vh {
return return
} }
// Count \r\n as one line // Count \r\n as one line
if is_nl(s.text[s.pos]) && !s.expect('\r\n', s.pos-1) { if is_nl(s.text[s.pos]) && !s.expect('\r\n', s.pos-1) {
s.inc_line_number() s.inc_line_number()
@ -369,7 +369,7 @@ fn (s mut Scanner) scan() ScanRes {
return scan_res(.chartoken, s.ident_char()) return scan_res(.chartoken, s.ident_char())
} }
`(` { `(` {
return scan_res(.lpar, '') return scan_res(.lpar, '')
} }
`)` { `)` {
@ -390,7 +390,12 @@ fn (s mut Scanner) scan() ScanRes {
return scan_res(.lcbr, '') 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 !` // 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.pos-- // fix line_nr, \n was read, and the comment is marked on the next line
s.line_nr-- s.line_nr--
return scan_res(.line_comment, s.line_comment) return scan_res(.line_comment, s.line_comment)
} }
//s.fgenln('// ${s.prev_tok.str()} "$s.line_comment"') //s.fgenln('// ${s.prev_tok.str()} "$s.line_comment"')
// Skip the comment (return the next token) // Skip the comment (return the next token)
return s.scan() return s.scan()
@ -626,7 +631,7 @@ fn (s mut Scanner) scan() ScanRes {
if s.is_fmt { if s.is_fmt {
s.line_comment = comment s.line_comment = comment
return scan_res(.mline_comment, s.line_comment) return scan_res(.mline_comment, s.line_comment)
} }
// Skip if not in fmt mode // Skip if not in fmt mode
return s.scan() return s.scan()
} }
@ -758,7 +763,7 @@ fn (s mut Scanner) ident_char() string {
} }
if c == '\\`' { if c == '\\`' {
return '`' return '`'
} }
// Escapes a `'` character // Escapes a `'` character
return if c == '\'' { '\\' + c } else { c } return if c == '\'' { '\\' + c } else { c }
} }
@ -807,7 +812,7 @@ fn (s mut Scanner) debug_tokens() {
fn (s mut Scanner) ignore_line() { fn (s mut Scanner) ignore_line() {
s.eat_to_end_of_line() s.eat_to_end_of_line()
s.inc_line_number() s.inc_line_number()
} }
@ -835,7 +840,7 @@ fn (s Scanner) line(n int) string {
if nline_start <= nline_end { if nline_start <= nline_end {
res = s.text[nline_start..nline_end] res = s.text[nline_start..nline_end]
} }
} }
return res.trim_right('\r\n').trim_left('\r\n') 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' + s.error('bad variable name `$name`\n' +
'looks like you have a multi-word name without separating them with `_`' + 'looks like you have a multi-word name without separating them with `_`' +
'\nfor example, use `registration_date` instead of `registrationdate` ') '\nfor example, use `registration_date` instead of `registrationdate` ')
} }
} }

View File

@ -10,7 +10,7 @@ fn (p mut Parser) struct_decl() {
if is_pub { if is_pub {
p.next() p.next()
p.fspace() p.fspace()
} }
// V can generate Objective C for integration with Cocoa // V can generate Objective C for integration with Cocoa
// `[objc_interface:ParentInterface]` // `[objc_interface:ParentInterface]`
is_objc := p.attr.starts_with('objc_interface') 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 { if name.len == 1 && !p.pref.building_v && !p.pref.is_repl {
p.warn('struct names must have more than one character') p.warn('struct names must have more than one character')
} }
if !is_c && !good_type_name(name) { if !is_c && !good_type_name(name) {
p.error('bad struct name, e.g. use `HttpRequest` instead of `HTTPRequest`') 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') //println('fmt max len = $max_len nrfields=$typ.fields.len pass=$p.pass')
if !is_ph && p.first_pass() { if !is_ph && p.first_pass() {
p.table.register_type2(typ) p.table.register_type2(typ)
@ -218,7 +218,7 @@ fn (p mut Parser) struct_decl() {
if !p.first_pass() { if !p.first_pass() {
p.table.add_default_val(i, typ.name, expr) p.table.add_default_val(i, typ.name, expr)
} }
} }
// [ATTR] // [ATTR]
mut attr := '' mut attr := ''
if p.tok == .lsbr { if p.tok == .lsbr {
@ -262,7 +262,7 @@ fn (p mut Parser) struct_init(typ string) string {
t := p.table.find_type(typ) t := p.table.find_type(typ)
if !t.is_public && t.mod != p.mod { if !t.is_public && t.mod != p.mod {
p.warn('type `$t.name` is private') p.warn('type `$t.name` is private')
} }
if p.gen_struct_init(typ, t) { return typ } if p.gen_struct_init(typ, t) { return typ }
ptr := typ.contains('*') ptr := typ.contains('*')
mut did_gen_something := false mut did_gen_something := false
@ -318,7 +318,7 @@ fn (p mut Parser) struct_init(typ string) string {
} }
field_typ := field.typ field_typ := field.typ
if !p.builtin_mod && field_typ.ends_with('*') && p.mod != 'os' { //&& 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 // init map fields
if field_typ.starts_with('map_') { if field_typ.starts_with('map_') {

View File

@ -41,6 +41,7 @@ enum TokenKind {
amp amp
hash hash
dollar dollar
str_dollar
left_shift left_shift
righ_shift righ_shift
//at // @ //at // @
@ -197,6 +198,7 @@ fn build_token_str() []string {
s[TokenKind.mline_comment] = '/* mline comment */' s[TokenKind.mline_comment] = '/* mline comment */'
s[TokenKind.nl] = 'NLL' s[TokenKind.nl] = 'NLL'
s[TokenKind.dollar] = '$' s[TokenKind.dollar] = '$'
s[TokenKind.str_dollar] = '$2'
s[TokenKind.key_assert] = 'assert' s[TokenKind.key_assert] = 'assert'
s[TokenKind.key_struct] = 'struct' s[TokenKind.key_struct] = 'struct'
s[TokenKind.key_if] = 'if' s[TokenKind.key_if] = 'if'
@ -272,7 +274,7 @@ const (
.or_assign, .and_assign, .righ_shift_assign, .or_assign, .and_assign, .righ_shift_assign,
.left_shift_assign .left_shift_assign
] ]
) )
fn (t TokenKind) is_assign() bool { fn (t TokenKind) is_assign() bool {
@ -291,17 +293,17 @@ fn (t []TokenKind) contains(val TokenKind) bool {
fn (t Token) str() string { fn (t Token) str() string {
if t.tok == .number { if t.tok == .number {
return t.lit return t.lit
} }
if t.tok == .chartoken { if t.tok == .chartoken {
return '`$t.lit`' return '`$t.lit`'
} }
if t.tok == .str { if t.tok == .str {
return "'$t.lit'" return "'$t.lit'"
} }
if t.tok < .plus { if t.tok < .plus {
return t.lit // string, number etc return t.lit // string, number etc
} }
return t.tok.str() return t.tok.str()
} }

View File

@ -11,30 +11,36 @@ pub:
b int b int
} }
pub const ( pub const (
Blue = Color { r: 0, g: 0, b: 255 } Blue = Color { r: 0, g: 0, b: 255 }
blue = Color { r: 0, g: 0, b: 255 }
Red = Color { r: 255, g: 0, b: 0 } Red = Color { r: 255, g: 0, b: 0 }
Green = Color { r: 0, g: 255, b: 0 } Green = Color { r: 0, g: 255, 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 } Yellow = Color { r: 255, g: 255, b: 0 }
Orange = Color { r: 255, g: 165, 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 } Purple = Color { r: 128, g: 0, b: 128 }
Black = Color { r: 0, g: 0, b: 0 } 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 }
gray = Color { r: 128, g: 128, b: 128 }
Indigo = Color { r: 75, g: 0, b: 130 } Indigo = Color { r: 75, g: 0, b: 130 }
Pink = Color { r: 255, g: 192, b: 203 } Pink = Color { r: 255, g: 192, b: 203 }
Violet = Color { r: 238, g: 130, b: 238 } Violet = Color { r: 238, g: 130, b: 238 }
White = Color { r: 255, g: 255, b: 255 } White = Color { r: 255, g: 255, b: 255 }
white = Color { r: 255, g: 255, b: 255 } white = Color { r: 255, g: 255, b: 255 }
// Shades // Shades
DarkBlue = Color { r: 0, g: 0, b: 139 } DarkBlue = Color { r: 0, g: 0, b: 139 }
DarkGray = Color { r: 169, g: 169, b: 169 } 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 } DarkGreen = Color { r: 0, g: 100, b: 0 }
DarkRed = Color { r: 139, g: 0, b: 0 } DarkRed = Color { r: 139, g: 0, b: 0 }
LightBlue = Color { r: 173, g: 216, b: 230 } 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 } LightGray = Color { r: 211, g: 211, b: 211 }
LightGreen = Color { r: 144, g: 238, b: 144 } LightGreen = Color { r: 144, g: 238, b: 144 }
LightRed = Color { r: 255, g: 204, b: 203 } LightRed = Color { r: 255, g: 204, b: 203 }

View File

@ -6,7 +6,7 @@ module http
import os import os
fn download_file(url, out string) bool { pub fn download_file(url, out string) bool {
s := http.get(url) or { return false } s := http.get(url) or { return false }
os.write_file(out, s.text) os.write_file(out, s.text)
return true return true

View File

@ -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() curl := C.curl_easy_init()
if isnil(curl) { if isnil(curl) {

View File

@ -21,10 +21,11 @@ pub:
typ string // GET POST typ string // GET POST
data string data string
url string url string
ws_func voidptr
user_ptr voidptr
verbose bool verbose bool
user_agent string user_agent string
mut:
user_ptr voidptr
ws_func voidptr
} }
pub struct Response { pub struct Response {

View File

@ -33,7 +33,7 @@ pub const (
pub struct File { pub struct File {
cfile voidptr // Using void* instead of FILE* cfile voidptr // Using void* instead of FILE*
mut: mut:
opened bool opened bool
} }
@ -738,7 +738,7 @@ pub fn clear() {
} }
} }
fn on_segfault(f voidptr) { pub fn on_segfault(f voidptr) {
$if windows { $if windows {
return return
} }