fix a string interpolation bug
parent
89d40566f4
commit
66f271f100
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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'
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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` ')
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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_') {
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
14
vlib/gx/gx.v
14
vlib/gx/gx.v
|
@ -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 }
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue