From 81045023c4fb08c1c4b91efddab4e951ebe65493 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 18 Dec 2019 08:13:31 +0300 Subject: [PATCH] run vfmt on scanner.v --- vlib/compiler/compile_errors.v | 6 +- vlib/compiler/parser.v | 14 +- vlib/compiler/scanner.v | 795 +++++++++++++------------- vlib/compiler/struct.v | 1 + vlib/compiler/tests/type_alias_test.v | 2 +- vlib/compiler/vfmt.v | 12 +- vlib/sdl/examples/basic_window/main.v | 2 +- 7 files changed, 412 insertions(+), 420 deletions(-) diff --git a/vlib/compiler/compile_errors.v b/vlib/compiler/compile_errors.v index 8e270b3e24..28a18e1010 100644 --- a/vlib/compiler/compile_errors.v +++ b/vlib/compiler/compile_errors.v @@ -89,7 +89,7 @@ fn (s &Scanner) error_with_col(msg string, col int) { // to find the source file, when the IDE has a different working folder than v itself. eprintln('${fullpath}:${s.line_nr + 1}:${col}: $final_message') - if s.should_print_line_on_error && s.nlines > 0 { + if s.print_line_on_error && s.nlines > 0 { context_start_line := imax(0, (s.line_nr - error_context_before )) context_end_line := imin(s.nlines-1, (s.line_nr + error_context_after + 1 )) for cline := context_start_line; cline < context_end_line; cline++ { @@ -130,7 +130,7 @@ fn (s &Scanner) get_error_filepath() string { use_relative_paths := match verror_paths_override { 'relative' { true } 'absolute' { false } - else { s.should_print_relative_paths_on_error } + else { s.print_rel_paths_on_error } } if use_relative_paths { workdir := os.getwd() + os.path_separator @@ -143,7 +143,7 @@ fn (s &Scanner) get_error_filepath() string { } fn (s &Scanner) is_color_output_on() bool { - return s.should_print_errors_in_color && term.can_show_color_on_stderr() + return s.print_colored_error && term.can_show_color_on_stderr() } fn (p mut Parser) print_error_context(){ diff --git a/vlib/compiler/parser.v b/vlib/compiler/parser.v index b7c9460f61..a5ab9ff9b8 100644 --- a/vlib/compiler/parser.v +++ b/vlib/compiler/parser.v @@ -172,7 +172,7 @@ fn (v mut V) new_parser_from_file(path string) Parser { println('new_parser: V script') } if p.pref.building_v { - p.scanner.should_print_relative_paths_on_error = true + p.scanner.print_rel_paths_on_error = true } // if p.pref.generating_vh { // Keep newlines @@ -205,9 +205,9 @@ fn (v mut V) new_parser(scanner &Scanner) Parser { p.is_js = true } if p.pref.is_repl { - p.scanner.should_print_line_on_error = false - p.scanner.should_print_errors_in_color = false - p.scanner.should_print_relative_paths_on_error = true + p.scanner.print_line_on_error = false + p.scanner.print_colored_error = false + p.scanner.print_rel_paths_on_error = true } return p } @@ -942,7 +942,7 @@ fn (p mut Parser) get_type() string { // fn type if p.tok == .key_fn { mut f := Fn{ - name: '_', + name: '_' mod: p.mod } p.next() @@ -2212,8 +2212,8 @@ fn (p mut Parser) index_expr(typ_ string,fn_ph int) string { index_val := l[idx..].trim_space() p.cgen.resetln(l[..fn_ph]) p.table.varg_access << VargAccess{ - fn_name: p.cur_fn.name, - tok_idx: index_error_tok_pos, + fn_name: p.cur_fn.name + tok_idx: index_error_tok_pos index: index_val.int() } p.cgen.set_placeholder(fn_ph, '${v.name}->args[$index_val]') diff --git a/vlib/compiler/scanner.v b/vlib/compiler/scanner.v index c7c6f4d96e..4d59e66bdd 100644 --- a/vlib/compiler/scanner.v +++ b/vlib/compiler/scanner.v @@ -1,103 +1,97 @@ // Copyright (c) 2019 Alexander Medvednikov. All rights reserved. // Use of this source code is governed by an MIT license // that can be found in the LICENSE file. - module compiler import ( os - //strings + // strings ) const ( single_quote = `\'` double_quote = `"` error_context_before = 2 // how many lines of source context to print before the pointer line - error_context_after = 2 // ^^^ same, but after + error_context_after = 2 // ^^^ same, but after ) struct Scanner { mut: - file_path string - text string - pos int - line_nr int - last_nl_pos int // for calculating column - inside_string bool - inter_start bool // for hacky string interpolation TODO simplify - inter_end bool - debug bool - line_comment string - started bool + file_path string + text string + pos int + line_nr int + last_nl_pos int // for calculating column + inside_string bool + inter_start bool // for hacky string interpolation TODO simplify + inter_end bool + debug bool + line_comment string + started bool // vfmt fields TODO move to a separate struct - //fmt_out strings.Builder - fmt_lines []string - //fmt_line string - fmt_indent int - fmt_line_empty bool - //fmt_needs_nl bool - prev_tok TokenKind - fn_name string // needed for @FN - should_print_line_on_error bool - should_print_errors_in_color bool - should_print_relative_paths_on_error bool - quote byte // which quote is used to denote current string: ' or " - line_ends []int // the positions of source lines ends (i.e. \n signs) - nlines int // total number of lines in the source file that were scanned - is_vh bool // Keep newlines - is_fmt bool // Used only for skipping ${} in strings, since we need literal - // string values when generating formatted code. + // fmt_out strings.Builder + fmt_lines []string + // fmt_line string + fmt_indent int + fmt_line_empty bool + // fmt_needs_nl bool + prev_tok TokenKind + fn_name string // needed for @FN + print_line_on_error bool + print_colored_error bool + print_rel_paths_on_error bool + quote byte // which quote is used to denote current string: ' or " + line_ends []int // the positions of source lines ends (i.e. \n signs) + nlines int // total number of lines in the source file that were scanned + is_vh bool // Keep newlines + is_fmt bool // Used only for skipping ${} in strings, since we need literal + // string values when generating formatted code. } - // new scanner from file. fn new_scanner_file(file_path string) &Scanner { if !os.exists(file_path) { verror("$file_path doesn't exist") } - - mut raw_text := os.read_file(file_path) or { + mut raw_text := os.read_file(file_path)or{ verror('scanner: failed to open $file_path') return 0 } - // BOM check if raw_text.len >= 3 { c_text := raw_text.str - if c_text[0] == 0xEF && c_text[1] == 0xBB && c_text[2] == 0xBF { // skip three BOM bytes offset_from_begin := 3 raw_text = tos(c_text[offset_from_begin], vstrlen(c_text) - offset_from_begin) } } - mut s := new_scanner(raw_text) s.init_fmt() s.file_path = file_path - return s } // new scanner from string. fn new_scanner(text string) &Scanner { - return &Scanner { + return &Scanner{ text: text - //fmt_out: strings.new_builder(1000) - should_print_line_on_error: true - should_print_errors_in_color: true - should_print_relative_paths_on_error: true + // fmt_out: strings.new_builder(1000) + + print_line_on_error: true + print_colored_error: true + print_rel_paths_on_error: true } } - // TODO remove once multiple return values are implemented struct ScanRes { tok TokenKind lit string } -fn scan_res(tok TokenKind, lit string) ScanRes { - return ScanRes{tok, lit} +fn scan_res(tok TokenKind,lit string) ScanRes { + return ScanRes{ + tok,lit} } fn (s mut Scanner) ident_name() string { @@ -146,7 +140,8 @@ fn (s mut Scanner) ident_oct_number() string { if !c.is_oct_digit() { s.error('malformed octal constant') } - } else { + } + else { break } s.pos++ @@ -158,12 +153,10 @@ fn (s mut Scanner) ident_oct_number() string { fn (s mut Scanner) ident_dec_number() string { start_pos := s.pos - // scan integer part for s.pos < s.text.len && s.text[s.pos].is_digit() { s.pos++ } - // e.g. 1..9 // we just return '1' and don't scan '..9' if s.expect('..', s.pos) { @@ -171,7 +164,6 @@ fn (s mut Scanner) ident_dec_number() string { s.pos-- return number } - // scan fractional part if s.pos < s.text.len && s.text[s.pos] == `.` { s.pos++ @@ -182,7 +174,6 @@ fn (s mut Scanner) ident_dec_number() string { s.error('no `f` is needed for floats') } } - // scan exponential part mut has_exponential_part := false if s.expect('e+', s.pos) || s.expect('e-', s.pos) { @@ -195,7 +186,6 @@ fn (s mut Scanner) ident_dec_number() string { } has_exponential_part = true } - // error check: 1.23.4, 123.e+3.4 if s.pos < s.text.len && s.text[s.pos] == `.` { if has_exponential_part { @@ -205,7 +195,6 @@ fn (s mut Scanner) ident_dec_number() string { s.error('too many decimal points in number') } } - number := s.text[start_pos..s.pos] s.pos-- return number @@ -215,27 +204,23 @@ fn (s mut Scanner) ident_number() string { if s.expect('0x', s.pos) { return s.ident_hex_number() } - if s.expect('0.', s.pos) || s.expect('0e', s.pos) { return s.ident_dec_number() } - if s.text[s.pos] == `0` { return s.ident_oct_number() } - return s.ident_dec_number() } fn (s mut Scanner) skip_whitespace() { - //if s.is_vh { println('vh') return } + // if s.is_vh { println('vh') return } 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) { + if is_nl(s.text[s.pos]) && !s.expect('\r\n', s.pos - 1) { s.inc_line_number() } s.pos++ @@ -249,10 +234,10 @@ fn (s mut Scanner) end_of_file() ScanRes { } fn (s mut Scanner) scan() ScanRes { - //if s.line_comment != '' { - //s.fgenln('// LC "$s.line_comment"') - //s.line_comment = '' - //} + // if s.line_comment != '' { + // s.fgenln('// LC "$s.line_comment"') + // s.line_comment = '' + // } if s.started { s.pos++ } @@ -288,7 +273,7 @@ fn (s mut Scanner) scan() ScanRes { name := s.ident_name() // tmp hack to detect . in ${} // Check if not .eof to prevent panic - next_char := if s.pos + 1 < s.text.len { s.text[s.pos + 1] } else { `\0` } + next_char := if s.pos + 1 < s.text.len {s.text[s.pos + 1]}else {`\0`} if is_key(name) { return scan_res(key_to_token(name), '') } @@ -308,8 +293,8 @@ fn (s mut Scanner) scan() ScanRes { s.inter_start = false } if s.pos == 0 && next_char == ` ` { - //If a single letter name at the start of the file, increment - //Otherwise the scanner would be stuck at s.pos = 0 + // If a single letter name at the start of the file, increment + // Otherwise the scanner would be stuck at s.pos = 0 s.pos++ } return scan_res(.name, name) @@ -323,7 +308,7 @@ fn (s mut Scanner) scan() ScanRes { if c == `)` && s.inter_start { s.inter_end = true s.inter_start = false - next_char := if s.pos + 1 < s.text.len { s.text[s.pos + 1] } else { `\0` } + next_char := if s.pos + 1 < s.text.len {s.text[s.pos + 1]}else {`\0`} if next_char == s.quote { s.inside_string = false } @@ -331,147 +316,158 @@ fn (s mut Scanner) scan() ScanRes { } // all other tokens match c { - `+` { - if nextc == `+` { - s.pos++ - return scan_res(.inc, '') - } - else if nextc == `=` { - s.pos++ - return scan_res(.plus_assign, '') - } - return scan_res(.plus, '') - } - `-` { - if nextc == `-` { - s.pos++ - return scan_res(.dec, '') - } - else if nextc == `=` { - s.pos++ - return scan_res(.minus_assign, '') - } - return scan_res(.minus, '') - } - `*` { - if nextc == `=` { - s.pos++ - return scan_res(.mult_assign, '') - } - return scan_res(.mul, '') - } - `^` { - if nextc == `=` { - s.pos++ - return scan_res(.xor_assign, '') - } - return scan_res(.xor, '') - } - `%` { - if nextc == `=` { - s.pos++ - return scan_res(.mod_assign, '') - } - return scan_res(.mod, '') - } - `?` { - return scan_res(.question, '') - } - single_quote, double_quote { - return scan_res(.str, s.ident_string()) - } - `\`` { // ` // apostrophe balance comment. do not remove - return scan_res(.chartoken, s.ident_char()) - } - `(` { - - return scan_res(.lpar, '') - } - `)` { - return scan_res(.rpar, '') - } - `[` { - return scan_res(.lsbr, '') - } - `]` { - return scan_res(.rsbr, '') - } - `{` { - // Skip { in `${` in strings - if s.inside_string { - return s.scan() - } - return scan_res(.lcbr, '') - } - `$` { - if s.inside_string { - return scan_res(.str_dollar, '') - } else { - return scan_res(.dollar, '') - } - } - `}` { - // s = `hello $name !` - // s = `hello ${name} !` - if s.inside_string { - s.pos++ - if s.text[s.pos] == s.quote { - s.inside_string = false - return scan_res(.str, '') + `+` { + if nextc == `+` { + s.pos++ + return scan_res(.inc, '') } + else if nextc == `=` { + s.pos++ + return scan_res(.plus_assign, '') + } + return scan_res(.plus, '') + } + `-` { + if nextc == `-` { + s.pos++ + return scan_res(.dec, '') + } + else if nextc == `=` { + s.pos++ + return scan_res(.minus_assign, '') + } + return scan_res(.minus, '') + } + `*` { + if nextc == `=` { + s.pos++ + return scan_res(.mult_assign, '') + } + return scan_res(.mul, '') + } + `^` { + if nextc == `=` { + s.pos++ + return scan_res(.xor_assign, '') + } + return scan_res(.xor, '') + } + `%` { + if nextc == `=` { + s.pos++ + return scan_res(.mod_assign, '') + } + return scan_res(.mod, '') + } + `?` { + return scan_res(.question, '') + } + single_quote,double_quote { return scan_res(.str, s.ident_string()) } - else { - return scan_res(.rcbr, '') + `\`` { + // ` // apostrophe balance comment. do not remove + return scan_res(.chartoken, s.ident_char()) } - } - `&` { - if nextc == `=` { + `(` { + return scan_res(.lpar, '') + } + `)` { + return scan_res(.rpar, '') + } + `[` { + return scan_res(.lsbr, '') + } + `]` { + return scan_res(.rsbr, '') + } + `{` { + // Skip { in `${` in strings + if s.inside_string { + return s.scan() + } + return scan_res(.lcbr, '') + } + `$` { + if s.inside_string { + return scan_res(.str_dollar, '') + } + else { + return scan_res(.dollar, '') + } + } + `}` { + // s = `hello $name !` + // s = `hello ${name} !` + if s.inside_string { + s.pos++ + if s.text[s.pos] == s.quote { + s.inside_string = false + return scan_res(.str, '') + } + return scan_res(.str, s.ident_string()) + } + else { + return scan_res(.rcbr, '') + } + } + `&` { + if nextc == `=` { + s.pos++ + return scan_res(.and_assign, '') + } + if nextc == `&` { + s.pos++ + return scan_res(.and, '') + } + return scan_res(.amp, '') + } + `|` { + if nextc == `|` { + s.pos++ + return scan_res(.logical_or, '') + } + if nextc == `=` { + s.pos++ + return scan_res(.or_assign, '') + } + return scan_res(.pipe, '') + } + `,` { + return scan_res(.comma, '') + } + `@` { s.pos++ - return scan_res(.and_assign, '') + name := s.ident_name() + // @FN => will be substituted with the name of the current V function + // @FILE => will be substituted with the path of the V source file + // @LINE => will be substituted with the V line number where it appears (as a string). + // @COLUMN => will be substituted with the column where it appears (as a string). + // @VHASH => will be substituted with the shortened commit hash of the V compiler (as a string). + // This allows things like this: + // println( 'file: ' + @FILE + ' | line: ' + @LINE + ' | fn: ' + @FN) + // ... which is useful while debugging/tracing + if name == 'FN' { + return scan_res(.str, s.fn_name) + } + if name == 'FILE' { + return scan_res(.str, cescaped_path(os.realpath(s.file_path))) + } + if name == 'LINE' { + return scan_res(.str, (s.line_nr + 1).str()) + } + if name == 'COLUMN' { + return scan_res(.str, (s.current_column()).str()) + } + if name == 'VHASH' { + return scan_res(.str, vhash()) + } + if !is_key(name) { + s.error('@ must be used before keywords (e.g. `@type string`)') + } + return scan_res(.name, name) } - if nextc == `&` { - s.pos++ - return scan_res(.and, '') - } - return scan_res(.amp, '') - } - `|` { - if nextc == `|` { - s.pos++ - return scan_res(.logical_or, '') - } - if nextc == `=` { - s.pos++ - return scan_res(.or_assign, '') - } - return scan_res(.pipe, '') - } - `,` { - return scan_res(.comma, '') - } - `@` { - s.pos++ - name := s.ident_name() - // @FN => will be substituted with the name of the current V function - // @FILE => will be substituted with the path of the V source file - // @LINE => will be substituted with the V line number where it appears (as a string). - // @COLUMN => will be substituted with the column where it appears (as a string). - // @VHASH => will be substituted with the shortened commit hash of the V compiler (as a string). - // This allows things like this: - // println( 'file: ' + @FILE + ' | line: ' + @LINE + ' | fn: ' + @FN) - // ... which is useful while debugging/tracing - if name == 'FN' { return scan_res(.str, s.fn_name) } - if name == 'FILE' { return scan_res(.str, cescaped_path(os.realpath(s.file_path))) } - if name == 'LINE' { return scan_res(.str, (s.line_nr+1).str()) } - if name == 'COLUMN' { return scan_res(.str, (s.current_column()).str()) } - if name == 'VHASH' { return scan_res(.str, vhash()) } - if !is_key(name) { - s.error('@ must be used before keywords (e.g. `@type string`)') - } - return scan_res(.name, name) - } - /* + /* case `\r`: if nextc == `\n` { s.pos++ @@ -484,173 +480,174 @@ fn (s mut Scanner) scan() ScanRes { return scan_res(.nl, '') } */ - `.` { - if nextc == `.` { - s.pos++ - if s.text[s.pos+1] == `.` { + + `.` { + if nextc == `.` { s.pos++ - return scan_res(.ellipsis, '') + if s.text[s.pos + 1] == `.` { + s.pos++ + return scan_res(.ellipsis, '') + } + return scan_res(.dotdot, '') } - return scan_res(.dotdot, '') + return scan_res(.dot, '') } - return scan_res(.dot, '') - } - `#` { - start := s.pos + 1 - s.ignore_line() - if nextc == `!` { - // treat shebang line (#!) as a comment - s.line_comment = s.text[start + 1..s.pos].trim_space() - //s.fgenln('// shebang line "$s.line_comment"') - return s.scan() - } - hash := s.text[start..s.pos] - return scan_res(.hash, hash.trim_space()) - } - `>` { - if nextc == `=` { - s.pos++ - return scan_res(.ge, '') - } - else if nextc == `>` { - if s.pos + 2 < s.text.len && s.text[s.pos + 2] == `=` { - s.pos += 2 - return scan_res(.righ_shift_assign, '') - } - s.pos++ - return scan_res(.righ_shift, '') - } - else { - return scan_res(.gt, '') - } - } - 0xE2 { - //case `≠`: - if nextc == 0x89 && s.text[s.pos + 2] == 0xA0 { - s.pos += 2 - return scan_res(.ne, '') - } - // ⩽ - else if nextc == 0x89 && s.text[s.pos + 2] == 0xBD { - s.pos += 2 - return scan_res(.le, '') - } - // ⩾ - else if nextc == 0xA9 && s.text[s.pos + 2] == 0xBE { - s.pos += 2 - return scan_res(.ge, '') - } - } - `<` { - if nextc == `=` { - s.pos++ - return scan_res(.le, '') - } - else if nextc == `<` { - if s.pos + 2 < s.text.len && s.text[s.pos + 2] == `=` { - s.pos += 2 - return scan_res(.left_shift_assign, '') - } - s.pos++ - return scan_res(.left_shift, '') - } - else { - return scan_res(.lt, '') - } - } - `=` { - if nextc == `=` { - s.pos++ - return scan_res(.eq, '') - } - else if nextc == `>` { - s.pos++ - return scan_res(.arrow, '') - } - else { - return scan_res(.assign, '') - } - } - `:` { - if nextc == `=` { - s.pos++ - return scan_res(.decl_assign, '') - } - else { - return scan_res(.colon, '') - } - } - `;` { - return scan_res(.semicolon, '') - } - `!` { - if nextc == `=` { - s.pos++ - return scan_res(.ne, '') - } - else { - return scan_res(.not, '') - } - } - `~` { - return scan_res(.bit_not, '') - } - `/` { - if nextc == `=` { - s.pos++ - return scan_res(.div_assign, '') - } - if nextc == `/` { + `#` { start := s.pos + 1 s.ignore_line() - s.line_comment = s.text[start + 1..s.pos] - s.line_comment = s.line_comment.trim_space() - if s.is_fmt { - 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) + if nextc == `!` { + // treat shebang line (#!) as a comment + s.line_comment = s.text[start + 1..s.pos].trim_space() + // s.fgenln('// shebang line "$s.line_comment"') + return s.scan() } - //s.fgenln('// ${s.prev_tok.str()} "$s.line_comment"') - // Skip the comment (return the next token) - return s.scan() + hash := s.text[start..s.pos] + return scan_res(.hash, hash.trim_space()) } - // Multiline comments - if nextc == `*` { - start := s.pos - mut nest_count := 1 - // Skip comment - for nest_count > 0 { + `>` { + if nextc == `=` { s.pos++ - if s.pos >= s.text.len { - s.line_nr-- - s.error('comment not terminated') - } - if s.text[s.pos] == `\n` { - s.inc_line_number() - continue - } - if s.expect('/*', s.pos) { - nest_count++ - continue - } - if s.expect('*/', s.pos) { - nest_count-- - } + return scan_res(.ge, '') } - s.pos++ - end := s.pos + 1 - comment := s.text[start..end] - if s.is_fmt { - s.line_comment = comment - return scan_res(.mline_comment, s.line_comment) + else if nextc == `>` { + if s.pos + 2 < s.text.len && s.text[s.pos + 2] == `=` { + s.pos += 2 + return scan_res(.righ_shift_assign, '') + } + s.pos++ + return scan_res(.righ_shift, '') + } + else { + return scan_res(.gt, '') } - // Skip if not in fmt mode - return s.scan() } - return scan_res(.div, '') - } - else { } - } + 0xE2 { + // case `≠`: + if nextc == 0x89 && s.text[s.pos + 2] == 0xA0 { + s.pos += 2 + return scan_res(.ne, '') + } + // ⩽ + else if nextc == 0x89 && s.text[s.pos + 2] == 0xBD { + s.pos += 2 + return scan_res(.le, '') + } + // ⩾ + else if nextc == 0xA9 && s.text[s.pos + 2] == 0xBE { + s.pos += 2 + return scan_res(.ge, '') + } + } + `<` { + if nextc == `=` { + s.pos++ + return scan_res(.le, '') + } + else if nextc == `<` { + if s.pos + 2 < s.text.len && s.text[s.pos + 2] == `=` { + s.pos += 2 + return scan_res(.left_shift_assign, '') + } + s.pos++ + return scan_res(.left_shift, '') + } + else { + return scan_res(.lt, '') + } + } + `=` { + if nextc == `=` { + s.pos++ + return scan_res(.eq, '') + } + else if nextc == `>` { + s.pos++ + return scan_res(.arrow, '') + } + else { + return scan_res(.assign, '') + } + } + `:` { + if nextc == `=` { + s.pos++ + return scan_res(.decl_assign, '') + } + else { + return scan_res(.colon, '') + } + } + `;` { + return scan_res(.semicolon, '') + } + `!` { + if nextc == `=` { + s.pos++ + return scan_res(.ne, '') + } + else { + return scan_res(.not, '') + } + } + `~` { + return scan_res(.bit_not, '') + } + `/` { + if nextc == `=` { + s.pos++ + return scan_res(.div_assign, '') + } + if nextc == `/` { + start := s.pos + 1 + s.ignore_line() + s.line_comment = s.text[start + 1..s.pos] + s.line_comment = s.line_comment.trim_space() + if s.is_fmt { + 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() + } + // Multiline comments + if nextc == `*` { + start := s.pos + mut nest_count := 1 + // Skip comment + for nest_count > 0 { + s.pos++ + if s.pos >= s.text.len { + s.line_nr-- + s.error('comment not terminated') + } + if s.text[s.pos] == `\n` { + s.inc_line_number() + continue + } + if s.expect('/*', s.pos) { + nest_count++ + continue + } + if s.expect('*/', s.pos) { + nest_count-- + } + } + s.pos++ + end := s.pos + 1 + comment := s.text[start..end] + 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() + } + return scan_res(.div, '') + } + else { + }} $if windows { if c == `\0` { return s.end_of_file() @@ -664,28 +661,28 @@ fn (s &Scanner) current_column() int { return s.pos - s.last_nl_pos } -fn (s Scanner) count_symbol_before(p int, sym byte) int { - mut count := 0 - for i:=p; i>=0; i-- { - if s.text[i] != sym { - break +fn (s Scanner) count_symbol_before(p int,sym byte) int { + mut count := 0 + for i := p; i >= 0; i-- { + if s.text[i] != sym { + break + } + count++ } - count++ - } - return count + return count } fn (s mut Scanner) ident_string() string { q := s.text[s.pos] is_quote := q == single_quote || q == double_quote - is_raw := is_quote && s.text[s.pos-1] == `r` + is_raw := is_quote && s.text[s.pos - 1] == `r` if is_quote && !s.inside_string { s.quote = q } - //if s.file_path.contains('string_test') { - //println('\nident_string() at char=${s.text[s.pos].str()}') - //println('linenr=$s.line_nr quote= $qquote ${qquote.str()}') - //} + // if s.file_path.contains('string_test') { + // println('\nident_string() at char=${s.text[s.pos].str()}') + // println('linenr=$s.line_nr quote= $qquote ${qquote.str()}') + // } mut start := s.pos s.inside_string = false slash := `\\` @@ -705,10 +702,10 @@ fn (s mut Scanner) ident_string() string { s.inc_line_number() } // Don't allow \0 - if c == `0` && s.pos > 2 && s.text[s.pos - 1] == slash { - if s.pos < s.text.len - 1 && s.text[s.pos+1].is_digit() { - - } else { + if c == `0` && s.pos > 2 && s.text[s.pos - 1] == slash { + if s.pos < s.text.len - 1 && s.text[s.pos + 1].is_digit() { + } + else { s.error('0 character in a string literal') } } @@ -717,18 +714,14 @@ fn (s mut Scanner) ident_string() string { s.error('0 character in a string literal') } // ${var} (ignore in vfmt mode) - if c == `{` && prevc == `$` && !is_raw && !s.is_fmt && - s.count_symbol_before(s.pos-2, slash) % 2 == 0 - { + if c == `{` && prevc == `$` && !is_raw && !s.is_fmt && s.count_symbol_before(s.pos - 2, slash) % 2 == 0 { s.inside_string = true // so that s.pos points to $ at the next step s.pos -= 2 break } // $var - if (c.is_letter() || c == `_`) && prevc == `$` && !s.is_fmt && - !is_raw && s.count_symbol_before(s.pos-2, slash) % 2 == 0 - { + if (c.is_letter() || c == `_`) && prevc == `$` && !s.is_fmt && !is_raw && s.count_symbol_before(s.pos - 2, slash) % 2 == 0 { s.inside_string = true s.inter_start = true s.pos -= 2 @@ -743,7 +736,8 @@ fn (s mut Scanner) ident_string() string { if s.inside_string { end++ } - if start > s.pos{} + if start > s.pos { + } else { lit = s.text[start..end] } @@ -763,7 +757,8 @@ fn (s mut Scanner) ident_char() string { len++ } double_slash := s.expect('\\\\', s.pos - 2) - if s.text[s.pos] == `\`` && (s.text[s.pos - 1] != slash || double_slash) { // ` // apostrophe balance comment. do not remove + if s.text[s.pos] == `\`` && (s.text[s.pos - 1] != slash || double_slash) { + // ` // apostrophe balance comment. do not remove if double_slash { len++ } @@ -775,18 +770,17 @@ fn (s mut Scanner) ident_char() string { if len != 1 { u := c.ustring() if u.len != 1 { - s.error('invalid character literal (more than one character)\n' + - 'use quotes for strings, backticks for characters') + s.error('invalid character literal (more than one character)\n' + 'use quotes for strings, backticks for characters') } } if c == '\\`' { return '`' } // Escapes a `'` character - return if c == '\'' { '\\' + c } else { c } + return if c == "\'" {'\\' + c}else {c} } -fn (s &Scanner) expect(want string, start_pos int) bool { +fn (s &Scanner) expect(want string,start_pos int) bool { end_pos := start_pos + want.len if start_pos < 0 || start_pos >= s.text.len { return false @@ -794,8 +788,8 @@ fn (s &Scanner) expect(want string, start_pos int) bool { if end_pos < 0 || end_pos > s.text.len { return false } - for pos in start_pos..end_pos { - if s.text[pos] != want[pos-start_pos] { + for pos in start_pos .. end_pos { + if s.text[pos] != want[pos - start_pos] { return false } } @@ -806,10 +800,8 @@ fn (s mut Scanner) debug_tokens() { s.pos = 0 s.started = false s.debug = true - fname := s.file_path.all_after(os.path_separator) println('\n===DEBUG TOKENS $fname===') - for { res := s.scan() tok := res.tok @@ -828,13 +820,12 @@ fn (s mut Scanner) debug_tokens() { } } - fn (s mut Scanner) ignore_line() { s.eat_to_end_of_line() s.inc_line_number() } -fn (s mut Scanner) eat_to_end_of_line(){ +fn (s mut Scanner) eat_to_end_of_line() { for s.pos < s.text.len && s.text[s.pos] != `\n` { s.pos++ } @@ -843,7 +834,7 @@ fn (s mut Scanner) eat_to_end_of_line(){ fn (s mut Scanner) inc_line_number() { s.last_nl_pos = s.pos s.line_nr++ - s.line_ends << s.pos + s.line_ends << s.pos if s.line_nr > s.nlines { s.nlines = s.line_nr } @@ -851,10 +842,9 @@ fn (s mut Scanner) inc_line_number() { fn (s Scanner) line(n int) string { mut res := '' - if n >= 0 && - n < s.line_ends.len { - nline_start := if n == 0 { 0 } else { s.line_ends[ n - 1 ] } - nline_end := s.line_ends[n] + if n >= 0 && n < s.line_ends.len { + nline_start := if n == 0 {0}else {s.line_ends[n - 1]} + nline_end := s.line_ends[n] if nline_start <= nline_end { res = s.text[nline_start..nline_end] } @@ -887,7 +877,7 @@ fn good_type_name(s string) bool { return true } for i in 2 .. s.len { - if s[i].is_capital() && s[i-1].is_capital() && s[i-2].is_capital() { + if s[i].is_capital() && s[i - 1].is_capital() && s[i - 2].is_capital() { return false } } @@ -898,11 +888,6 @@ fn good_type_name(s string) bool { // registrationdate bad fn (s &Scanner) validate_var_name(name string) { if name.len > 15 && !name.contains('_') { - 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` ') - + 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 9ea2725858..54584ccf70 100644 --- a/vlib/compiler/struct.v +++ b/vlib/compiler/struct.v @@ -315,6 +315,7 @@ fn (p mut Parser) struct_init(typ string) string { p.check_types(p.bool_expression(), f.typ) if p.tok == .comma { p.next() + p.fremove_last() } if p.tok != .rcbr { p.gen(',') diff --git a/vlib/compiler/tests/type_alias_test.v b/vlib/compiler/tests/type_alias_test.v index c53fff6df8..690e3be4d2 100644 --- a/vlib/compiler/tests/type_alias_test.v +++ b/vlib/compiler/tests/type_alias_test.v @@ -12,4 +12,4 @@ fn test_type_alias() { -} \ No newline at end of file +} diff --git a/vlib/compiler/vfmt.v b/vlib/compiler/vfmt.v index 6eca59bce9..1b91105d68 100644 --- a/vlib/compiler/vfmt.v +++ b/vlib/compiler/vfmt.v @@ -161,8 +161,8 @@ fn (p mut Parser) fnext() { if p.tokens[p.token_idx].tok in [.line_comment, .mline_comment] { // Newline before the comment and after consts and closing } if p.inside_const { - p.fgen_nl() - p.fgen_nl() + //p.fgen_nl() + //p.fgen_nl() } //is_rcbr := p.tok == .rcbr for p.token_idx < p.tokens.len - 1 { @@ -218,6 +218,12 @@ fn (p mut Parser) fnext() { } } +[if vfmt] +fn (p mut Parser) fremove_last() { + p.scanner.fmt_lines[p.scanner.fmt_lines.len-1] = '' + +} + [if vfmt] fn (p &Parser) gen_fmt() { @@ -237,7 +243,7 @@ fn (p &Parser) gen_fmt() { if s == '' { return } - if !p.file_name.contains('parser.v') {return} + if !p.file_name.contains('scanner.v') {return} path := os.tmpdir() + '/' + p.file_name println('generating ${path}') mut out := os.create(path) or { diff --git a/vlib/sdl/examples/basic_window/main.v b/vlib/sdl/examples/basic_window/main.v index ea454cd109..145c409c89 100644 --- a/vlib/sdl/examples/basic_window/main.v +++ b/vlib/sdl/examples/basic_window/main.v @@ -28,4 +28,4 @@ fn main() { C.SDL_DestroyRenderer(renderer) C.SDL_DestroyWindow(window) C.SDL_Quit() -} \ No newline at end of file +}