mirror of
https://github.com/vlang/v.git
synced 2025-09-09 07:15:50 -04:00
parser: fix infinite loop in Parser.sql stmt in -silent -print-watched-files
mode (used by v watch
) (#20873)
This commit is contained in:
parent
d198a89897
commit
efa98d9234
@ -133,6 +133,10 @@ fn (mut p Parser) sql_stmt() ast.SqlStmt {
|
||||
mut lines := []ast.SqlStmtLine{}
|
||||
|
||||
for p.tok.kind != .rcbr {
|
||||
if p.tok.kind == .eof {
|
||||
p.unexpected_with_pos(pos, got: 'eof, while parsing an SQL statement')
|
||||
return ast.SqlStmt{}
|
||||
}
|
||||
lines << p.parse_sql_stmt_line()
|
||||
}
|
||||
|
||||
|
68
vlib/v/parser/testdata/silent/orm_infinite_loop_in_parser_sql_stmt.vv
vendored
Normal file
68
vlib/v/parser/testdata/silent/orm_infinite_loop_in_parser_sql_stmt.vv
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
module main
|
||||
|
||||
import db.sqlite
|
||||
|
||||
@[table: 'modules']
|
||||
struct Module {
|
||||
id int @[primary; sql: serial]
|
||||
name string
|
||||
nr_downloads int @[sql: u64]
|
||||
creator User
|
||||
}
|
||||
|
||||
struct User {
|
||||
id int @[primary; sql: serial]
|
||||
age u32 @[unique: 'user']
|
||||
name string @[sql: 'username'; sql_type: 'VARCHAR(200)'; unique]
|
||||
is_customer bool @[sql: 'abc'; unique: 'user']
|
||||
skipped_string string @[skip]
|
||||
}
|
||||
|
||||
struct Parent {
|
||||
id int @[primary; sql: serial]
|
||||
name string
|
||||
children []Child @[fkey: 'parent_id']
|
||||
}
|
||||
|
||||
struct Child {
|
||||
id int @[primary; sql: serial]
|
||||
parent_id int
|
||||
name string
|
||||
}
|
||||
|
||||
fn main() {
|
||||
eprintln('------------ ${@METHOD} -----------------')
|
||||
mut db := sqlite.connect(':memory:')!
|
||||
defer {
|
||||
sql db {
|
||||
drop table Parent
|
||||
drop table Child
|
||||
} or {}
|
||||
db.close() or {}
|
||||
}
|
||||
|
||||
sql db {
|
||||
create table Parent
|
||||
}!
|
||||
sql db {
|
||||
create table Child
|
||||
}!
|
||||
par := Parent{
|
||||
name: 'test'
|
||||
children: [
|
||||
Child{
|
||||
name: 'abc'
|
||||
},
|
||||
Child{
|
||||
name: 'def'
|
||||
},
|
||||
]
|
||||
}
|
||||
sql db {
|
||||
insert par into Parent
|
||||
}!
|
||||
sql db {
|
||||
select from Parent where id == 1 & name == "whatever"
|
||||
}!
|
||||
eprintln(parent)
|
||||
}
|
0
vlib/v/parser/testdata/stdout/.gitkeep
vendored
Normal file
0
vlib/v/parser/testdata/stdout/.gitkeep
vendored
Normal file
@ -7,6 +7,9 @@ import v.checker
|
||||
import v.pref
|
||||
import term
|
||||
import os
|
||||
import benchmark
|
||||
|
||||
const vroot = os.dir(os.dir(os.dir(os.dir(@FILE))))
|
||||
|
||||
fn test_eval() {
|
||||
/*
|
||||
@ -60,42 +63,40 @@ fn test_eval() {
|
||||
return
|
||||
}
|
||||
|
||||
fn test_parse_file() {
|
||||
if true {
|
||||
return
|
||||
}
|
||||
s := '
|
||||
fn test_parse_text() {
|
||||
println(@LOCATION)
|
||||
source_text := '
|
||||
fn foo() int {
|
||||
f := 23
|
||||
return 10+4
|
||||
return 10+4+f
|
||||
}
|
||||
fn ff(x int) {}
|
||||
|
||||
12 + 3
|
||||
x := 10
|
||||
5+7
|
||||
8+4
|
||||
fn main() {
|
||||
ff(12 + 3)
|
||||
x := 10
|
||||
bar(5+7)
|
||||
ff(8+x)
|
||||
}
|
||||
'
|
||||
table := ast.new_table()
|
||||
vpref := &pref.Preferences{}
|
||||
mut prog := parse_file(s, table, .skip_comments, vpref)
|
||||
mut prog := parse_text(source_text, '', table, .skip_comments, vpref)
|
||||
mut checker_ := checker.new_checker(table, vpref)
|
||||
checker_.check(mut prog)
|
||||
res, _, _, _ := c.gen([prog], table, vpref)
|
||||
println(res)
|
||||
}
|
||||
|
||||
fn test_one() {
|
||||
if true {
|
||||
return
|
||||
}
|
||||
println('\n\ntest_one()')
|
||||
println(@LOCATION)
|
||||
input := ['a := 10', 'b := -a', 'c := 20']
|
||||
expected := 'int a = 10;int b = -a;int c = 20;'
|
||||
table := ast.new_table()
|
||||
vpref := &pref.Preferences{}
|
||||
scope := &ast.Scope{
|
||||
start_pos: 0
|
||||
parent: 0
|
||||
}
|
||||
mut e := []ast.Stmt{}
|
||||
for line in input {
|
||||
@ -113,6 +114,7 @@ fn test_one() {
|
||||
println(res)
|
||||
ok := expected == res
|
||||
println(res)
|
||||
dump(ok)
|
||||
assert ok
|
||||
if !ok {
|
||||
}
|
||||
@ -120,6 +122,7 @@ fn test_one() {
|
||||
}
|
||||
|
||||
fn test_parse_expr() {
|
||||
println(@LOCATION)
|
||||
if true {
|
||||
return
|
||||
}
|
||||
@ -138,7 +141,6 @@ fn test_parse_expr() {
|
||||
mut chk := checker.new_checker(table, vpref)
|
||||
scope := &ast.Scope{
|
||||
start_pos: 0
|
||||
parent: 0
|
||||
}
|
||||
for s in input {
|
||||
println('\n\nst="${s}"')
|
||||
@ -176,6 +178,7 @@ fn test_parse_expr() {
|
||||
}
|
||||
|
||||
fn test_num_literals() {
|
||||
println(@LOCATION)
|
||||
inputs := [
|
||||
'a := -1',
|
||||
'b := -12.e17',
|
||||
@ -185,7 +188,6 @@ fn test_num_literals() {
|
||||
table := ast.new_table()
|
||||
mut scope := &ast.Scope{
|
||||
start_pos: 0
|
||||
parent: 0
|
||||
}
|
||||
mut rhs_types := []string{}
|
||||
for input in inputs {
|
||||
@ -220,6 +222,7 @@ for s in text_expr {
|
||||
*/
|
||||
|
||||
fn test_fn_is_html_open_tag() {
|
||||
println(@LOCATION)
|
||||
mut s := '<style>'
|
||||
mut b := is_html_open_tag('style', s)
|
||||
assert b == true
|
||||
@ -230,44 +233,47 @@ fn test_fn_is_html_open_tag() {
|
||||
|
||||
s = '<style/>'
|
||||
b = is_html_open_tag('style', s)
|
||||
assert b == false
|
||||
assert !b
|
||||
|
||||
s = 'styl'
|
||||
b = is_html_open_tag('style', s)
|
||||
assert b == false
|
||||
assert !b
|
||||
|
||||
s = 'style'
|
||||
b = is_html_open_tag('style', s)
|
||||
assert b == false
|
||||
assert !b
|
||||
|
||||
s = '<style'
|
||||
b = is_html_open_tag('style', s)
|
||||
assert b == false
|
||||
assert !b
|
||||
|
||||
s = '<<style>'
|
||||
b = is_html_open_tag('style', s)
|
||||
assert b == false
|
||||
assert !b
|
||||
|
||||
s = '<style>>'
|
||||
b = is_html_open_tag('style', s)
|
||||
assert b == false
|
||||
assert !b
|
||||
|
||||
s = '<stylex>'
|
||||
b = is_html_open_tag('style', s)
|
||||
assert b == false
|
||||
assert !b
|
||||
|
||||
s = '<html>'
|
||||
b = is_html_open_tag('style', s)
|
||||
assert b == false
|
||||
assert !b
|
||||
|
||||
s = '<script>'
|
||||
b = is_html_open_tag('style', s)
|
||||
assert b == false
|
||||
assert !b
|
||||
}
|
||||
|
||||
fn scan_v(mut files []string, path string) ! {
|
||||
for i in os.ls(path)! {
|
||||
p := os.join_path(path, i)
|
||||
if !os.exists(p) {
|
||||
continue
|
||||
}
|
||||
if os.is_file(p) {
|
||||
if i.ends_with('.v') && !i.contains_any_substr(['_test.', 'test_', 'tests_']) {
|
||||
files << p
|
||||
@ -281,26 +287,30 @@ fn scan_v(mut files []string, path string) ! {
|
||||
}
|
||||
|
||||
fn parse(output_mode pref.OutputMode) ! {
|
||||
mut b := benchmark.start()
|
||||
mut files := []string{}
|
||||
// mode_files := os.walk_ext(os.join_path(vroot, 'vlib/v/parser/testdata/${output_mode}'), '.vv')
|
||||
// files << mode_files
|
||||
scan_v(mut files, os.join_path(parser.vroot, 'vlib'))!
|
||||
scan_v(mut files, os.join_path(parser.vroot, 'cmd'))!
|
||||
mut pref_ := pref.new_preferences()
|
||||
pref_.output_mode = output_mode
|
||||
mut files := []string{}
|
||||
scan_v(mut files, pref_.vlib)!
|
||||
scan_v(mut files, os.join_path(pref_.vroot, 'cmd'))!
|
||||
for f in files {
|
||||
for idx, f in files {
|
||||
// eprintln('> parsing in mode: ${output_mode}, ${idx+1:5}/${files.len} $f ...')
|
||||
table := ast.new_table()
|
||||
p := parse_file(f, table, .parse_comments, pref_)
|
||||
assert isnil(p) == false
|
||||
assert !isnil(p), 'failed to parse `${f}` in mode: ${output_mode}'
|
||||
assert p.errors.len == 0, 'file ${f} should have been parsed with 0 errors'
|
||||
}
|
||||
b.measure('parsing ${files.len} files in ${output_mode} mode')
|
||||
}
|
||||
|
||||
fn test_parse_with_silent() {
|
||||
println(@LOCATION)
|
||||
parse(.silent)!
|
||||
}
|
||||
|
||||
fn test_parse_with_stdout() {
|
||||
println(@LOCATION)
|
||||
parse(.stdout)!
|
||||
}
|
||||
|
||||
// For issue #15516
|
||||
fn test_anon_struct() {
|
||||
}
|
||||
|
30
vlib/v/parser/v_print_v_files_works_test.v
Normal file
30
vlib/v/parser/v_print_v_files_works_test.v
Normal file
@ -0,0 +1,30 @@
|
||||
import os
|
||||
|
||||
const vexe = @VEXE
|
||||
const vroot = os.dir(vexe)
|
||||
|
||||
fn test_print_v_files_in_stdout_mode() {
|
||||
check_parsing_files_in_folder('vlib/v/parser/testdata/stdout', '-print-v-files')
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
fn test_print_v_files_in_silent_mode() {
|
||||
check_parsing_files_in_folder('vlib/v/parser/testdata/silent', '-silent -print-v-files')
|
||||
}
|
||||
|
||||
fn test_print_watched_files_in_silent_mode__used_by_vwatch() {
|
||||
check_parsing_files_in_folder('vlib/v/parser/testdata/silent', '-silent -print-watched-files')
|
||||
}
|
||||
|
||||
fn check_parsing_files_in_folder(folder string, options string) {
|
||||
println('> checking .vv files in folder: `${folder}`, with `${options}` ...')
|
||||
files := os.walk_ext(os.join_path(vroot, folder), '.vv')
|
||||
for f in files {
|
||||
cmd := '${os.quoted_path(vexe)} ${options} ${os.quoted_path(f)}'
|
||||
// eprintln('> cmd: $cmd')
|
||||
res := os.execute(cmd)
|
||||
assert res.exit_code == 0, 'failed cmd: ${cmd}, output:\n${res.output}'
|
||||
assert res.output.split_into_lines().len > 10, 'there should be several files printed by cmd: ${cmd}'
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user