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')
r := 50
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 ')
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'
}

View File

@ -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 {

View File

@ -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` ')
}
}
}

View File

@ -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_') {

View File

@ -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()
}
}

View File

@ -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 }

View File

@ -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

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()
if isnil(curl) {

View File

@ -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 {

View File

@ -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
}