mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
parser,checker,builder: make the checker more robust with -check
over files with syntax/parsing errors
This commit is contained in:
parent
d7813965d5
commit
eda65ad660
@ -102,7 +102,7 @@ pub fn (mut b Builder) front_stages(v_files []string) ? {
|
|||||||
timers.show('PARSE')
|
timers.show('PARSE')
|
||||||
timers.show_if_exists('PARSE stmt')
|
timers.show_if_exists('PARSE stmt')
|
||||||
if b.pref.only_check_syntax {
|
if b.pref.only_check_syntax {
|
||||||
return error_with_code('stop_after_parser', 9999)
|
return error_with_code('stop_after_parser', 7001)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ pub fn (mut b Builder) middle_stages() ? {
|
|||||||
return error('too many errors/warnings/notices')
|
return error('too many errors/warnings/notices')
|
||||||
}
|
}
|
||||||
if b.pref.check_only {
|
if b.pref.check_only {
|
||||||
return error_with_code('stop_after_checker', 9999)
|
return error_with_code('stop_after_checker', 8001)
|
||||||
}
|
}
|
||||||
util.timing_start('TRANSFORM')
|
util.timing_start('TRANSFORM')
|
||||||
b.transformer.transform_files(b.parsed_files)
|
b.transformer.transform_files(b.parsed_files)
|
||||||
|
@ -38,10 +38,10 @@ pub fn compile_c(mut b builder.Builder) {
|
|||||||
|
|
||||||
pub fn gen_c(mut b builder.Builder, v_files []string) string {
|
pub fn gen_c(mut b builder.Builder, v_files []string) string {
|
||||||
b.front_and_middle_stages(v_files) or {
|
b.front_and_middle_stages(v_files) or {
|
||||||
if err.code() != 9999 {
|
if err.code() > 7000 {
|
||||||
builder.verror(err.msg())
|
return ''
|
||||||
}
|
}
|
||||||
return ''
|
builder.verror(err.msg())
|
||||||
}
|
}
|
||||||
|
|
||||||
util.timing_start('C GEN')
|
util.timing_start('C GEN')
|
||||||
|
@ -582,10 +582,10 @@ fn (mut c Checker) fail_if_immutable(expr_ ast.Expr) (string, token.Pos) {
|
|||||||
match mut expr {
|
match mut expr {
|
||||||
ast.CastExpr {
|
ast.CastExpr {
|
||||||
// TODO
|
// TODO
|
||||||
return '', pos
|
return '', expr.pos
|
||||||
}
|
}
|
||||||
ast.ComptimeSelector {
|
ast.ComptimeSelector {
|
||||||
return '', pos
|
return '', expr.pos
|
||||||
}
|
}
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
if mut expr.obj is ast.Var {
|
if mut expr.obj is ast.Var {
|
||||||
@ -619,6 +619,9 @@ fn (mut c Checker) fail_if_immutable(expr_ ast.Expr) (string, token.Pos) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.IndexExpr {
|
ast.IndexExpr {
|
||||||
|
if expr.left_type == 0 {
|
||||||
|
return to_lock, pos
|
||||||
|
}
|
||||||
left_sym := c.table.sym(expr.left_type)
|
left_sym := c.table.sym(expr.left_type)
|
||||||
mut elem_type := ast.Type(0)
|
mut elem_type := ast.Type(0)
|
||||||
mut kind := ''
|
mut kind := ''
|
||||||
@ -651,10 +654,10 @@ fn (mut c Checker) fail_if_immutable(expr_ ast.Expr) (string, token.Pos) {
|
|||||||
}
|
}
|
||||||
ast.SelectorExpr {
|
ast.SelectorExpr {
|
||||||
if expr.expr_type == 0 {
|
if expr.expr_type == 0 {
|
||||||
return '', pos
|
return '', expr.pos
|
||||||
}
|
}
|
||||||
// retrieve ast.Field
|
// retrieve ast.Field
|
||||||
c.ensure_type_exists(expr.expr_type, expr.pos) or { return '', pos }
|
c.ensure_type_exists(expr.expr_type, expr.pos) or { return '', expr.pos }
|
||||||
mut typ_sym := c.table.final_sym(c.unwrap_generic(expr.expr_type))
|
mut typ_sym := c.table.final_sym(c.unwrap_generic(expr.expr_type))
|
||||||
match typ_sym.kind {
|
match typ_sym.kind {
|
||||||
.struct_ {
|
.struct_ {
|
||||||
@ -666,7 +669,7 @@ fn (mut c Checker) fail_if_immutable(expr_ ast.Expr) (string, token.Pos) {
|
|||||||
if !has_field {
|
if !has_field {
|
||||||
type_str := c.table.type_to_str(expr.expr_type)
|
type_str := c.table.type_to_str(expr.expr_type)
|
||||||
c.error('unknown field `${type_str}.$expr.field_name`', expr.pos)
|
c.error('unknown field `${type_str}.$expr.field_name`', expr.pos)
|
||||||
return '', pos
|
return '', expr.pos
|
||||||
}
|
}
|
||||||
if field_info.typ.has_flag(.shared_f) {
|
if field_info.typ.has_flag(.shared_f) {
|
||||||
expr_name := '${expr.expr}.$expr.field_name'
|
expr_name := '${expr.expr}.$expr.field_name'
|
||||||
@ -702,7 +705,7 @@ fn (mut c Checker) fail_if_immutable(expr_ ast.Expr) (string, token.Pos) {
|
|||||||
mut field_info := interface_info.find_field(expr.field_name) or {
|
mut field_info := interface_info.find_field(expr.field_name) or {
|
||||||
type_str := c.table.type_to_str(expr.expr_type)
|
type_str := c.table.type_to_str(expr.expr_type)
|
||||||
c.error('unknown field `${type_str}.$expr.field_name`', expr.pos)
|
c.error('unknown field `${type_str}.$expr.field_name`', expr.pos)
|
||||||
return '', pos
|
return '', expr.pos
|
||||||
}
|
}
|
||||||
if !field_info.is_mut {
|
if !field_info.is_mut {
|
||||||
type_str := c.table.type_to_str(expr.expr_type)
|
type_str := c.table.type_to_str(expr.expr_type)
|
||||||
@ -717,7 +720,7 @@ fn (mut c Checker) fail_if_immutable(expr_ ast.Expr) (string, token.Pos) {
|
|||||||
mut field_info := sumtype_info.find_field(expr.field_name) or {
|
mut field_info := sumtype_info.find_field(expr.field_name) or {
|
||||||
type_str := c.table.type_to_str(expr.expr_type)
|
type_str := c.table.type_to_str(expr.expr_type)
|
||||||
c.error('unknown field `${type_str}.$expr.field_name`', expr.pos)
|
c.error('unknown field `${type_str}.$expr.field_name`', expr.pos)
|
||||||
return '', pos
|
return '', expr.pos
|
||||||
}
|
}
|
||||||
if !field_info.is_mut {
|
if !field_info.is_mut {
|
||||||
type_str := c.table.type_to_str(expr.expr_type)
|
type_str := c.table.type_to_str(expr.expr_type)
|
||||||
@ -756,18 +759,18 @@ fn (mut c Checker) fail_if_immutable(expr_ ast.Expr) (string, token.Pos) {
|
|||||||
}
|
}
|
||||||
ast.ArrayInit {
|
ast.ArrayInit {
|
||||||
c.error('array literal can not be modified', expr.pos)
|
c.error('array literal can not be modified', expr.pos)
|
||||||
return '', pos
|
return '', expr.pos
|
||||||
}
|
}
|
||||||
ast.StructInit {
|
ast.StructInit {
|
||||||
return '', pos
|
return '', expr.pos
|
||||||
}
|
}
|
||||||
ast.InfixExpr {
|
ast.InfixExpr {
|
||||||
return '', pos
|
return '', expr.pos
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if !expr.is_pure_literal() {
|
if !expr.is_pure_literal() {
|
||||||
c.error('unexpected expression `$expr.type_name()`', expr.pos())
|
c.error('unexpected expression `$expr.type_name()`', expr.pos())
|
||||||
return '', pos
|
return '', expr.pos()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3495,6 +3498,10 @@ fn (mut c Checker) check_index(typ_sym &ast.TypeSymbol, index ast.Expr, index_ty
|
|||||||
|
|
||||||
pub fn (mut c Checker) index_expr(mut node ast.IndexExpr) ast.Type {
|
pub fn (mut c Checker) index_expr(mut node ast.IndexExpr) ast.Type {
|
||||||
mut typ := c.expr(node.left)
|
mut typ := c.expr(node.left)
|
||||||
|
if typ == 0 {
|
||||||
|
c.error('unknown type for expression `$node.left`', node.pos)
|
||||||
|
return typ
|
||||||
|
}
|
||||||
mut typ_sym := c.table.final_sym(typ)
|
mut typ_sym := c.table.final_sym(typ)
|
||||||
node.left_type = typ
|
node.left_type = typ
|
||||||
match typ_sym.kind {
|
match typ_sym.kind {
|
||||||
|
@ -39,8 +39,12 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) {
|
|||||||
mut expr_idxs := []int{}
|
mut expr_idxs := []int{}
|
||||||
for i, expr in node.exprs {
|
for i, expr in node.exprs {
|
||||||
mut typ := c.expr(expr)
|
mut typ := c.expr(expr)
|
||||||
|
if typ == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
if typ == ast.void_type {
|
if typ == ast.void_type {
|
||||||
c.error('`$expr` used as value', node.pos)
|
c.error('`$expr` used as value', node.pos)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
// Unpack multi return types
|
// Unpack multi return types
|
||||||
sym := c.table.sym(typ)
|
sym := c.table.sym(typ)
|
||||||
|
7
vlib/v/checker/tests/with_check_option/v_tictactoe.out
Normal file
7
vlib/v/checker/tests/with_check_option/v_tictactoe.out
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
vlib/v/checker/tests/with_check_option/v_tictactoe.vv:4:31: error: expected `init:`, not `len`
|
||||||
|
2 |
|
||||||
|
3 | fn new_board() [][]string {
|
||||||
|
4 | mut board := [3][]string{ len: 3, init: []string{ len: 3, init: '' } }
|
||||||
|
| ~~~
|
||||||
|
5 | for i in 0..9 {
|
||||||
|
6 | board[i / 3][i % 3] = (i + 1).str()
|
27
vlib/v/checker/tests/with_check_option/v_tictactoe.vv
Normal file
27
vlib/v/checker/tests/with_check_option/v_tictactoe.vv
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
module main
|
||||||
|
|
||||||
|
fn new_board() [][]string {
|
||||||
|
mut board := [3][]string{ len: 3, init: []string{ len: 3, init: '' } }
|
||||||
|
for i in 0..9 {
|
||||||
|
board[i / 3][i % 3] = (i + 1).str()
|
||||||
|
}
|
||||||
|
return board
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut b [][]string) place(player string, y int, x int) ? {
|
||||||
|
if b[y][x] in ['a'] {
|
||||||
|
error("position is already occupied")
|
||||||
|
}
|
||||||
|
b[y][x] = player
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prompt(player string) (int, int) {
|
||||||
|
return 0, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
mut board := new_board()
|
||||||
|
mut player := 'X'
|
||||||
|
println(board)
|
||||||
|
println(player)
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
vlib/v/checker/tests/with_check_option/v_tictactoe_fixed_syntax_error.vv:8:9: error: cannot use `[3][]string` as type `[][]string` in return argument
|
||||||
|
6 | board[i / 3][i % 3] = (i + 1).str()
|
||||||
|
7 | }
|
||||||
|
8 | return board
|
||||||
|
| ~~~~~
|
||||||
|
9 | }
|
||||||
|
10 |
|
@ -0,0 +1,27 @@
|
|||||||
|
module main
|
||||||
|
|
||||||
|
fn new_board() [][]string {
|
||||||
|
mut board := [3][]string{init: []string{len: 3, init: ''}}
|
||||||
|
for i in 0 .. 9 {
|
||||||
|
board[i / 3][i % 3] = (i + 1).str()
|
||||||
|
}
|
||||||
|
return board
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut b [][]string) place(player string, y int, x int) ? {
|
||||||
|
if b[y][x] == 'a' {
|
||||||
|
error('position is already occupied')
|
||||||
|
}
|
||||||
|
b[y][x] = player
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prompt(player string) (int, int) {
|
||||||
|
return 0, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
mut board := new_board()
|
||||||
|
mut player := 'X'
|
||||||
|
println(board)
|
||||||
|
println(player)
|
||||||
|
}
|
@ -77,6 +77,7 @@ fn test_all() {
|
|||||||
vroot := os.dir(vexe)
|
vroot := os.dir(vexe)
|
||||||
os.chdir(vroot) or {}
|
os.chdir(vroot) or {}
|
||||||
checker_dir := 'vlib/v/checker/tests'
|
checker_dir := 'vlib/v/checker/tests'
|
||||||
|
checker_with_check_option_dir := 'vlib/v/checker/tests/with_check_option'
|
||||||
parser_dir := 'vlib/v/parser/tests'
|
parser_dir := 'vlib/v/parser/tests'
|
||||||
scanner_dir := 'vlib/v/scanner/tests'
|
scanner_dir := 'vlib/v/scanner/tests'
|
||||||
module_dir := '$checker_dir/modules'
|
module_dir := '$checker_dir/modules'
|
||||||
@ -86,7 +87,7 @@ fn test_all() {
|
|||||||
skip_unused_dir := 'vlib/v/tests/skip_unused'
|
skip_unused_dir := 'vlib/v/tests/skip_unused'
|
||||||
trace_calls_dir := 'vlib/v/tests/trace_calls'
|
trace_calls_dir := 'vlib/v/tests/trace_calls'
|
||||||
//
|
//
|
||||||
checker_tests := get_tests_in_dir(checker_dir, false)
|
checker_tests := get_tests_in_dir(checker_dir, false).filter(!it.contains('with_check_option'))
|
||||||
parser_tests := get_tests_in_dir(parser_dir, false)
|
parser_tests := get_tests_in_dir(parser_dir, false)
|
||||||
scanner_tests := get_tests_in_dir(scanner_dir, false)
|
scanner_tests := get_tests_in_dir(scanner_dir, false)
|
||||||
global_tests := get_tests_in_dir(global_dir, false)
|
global_tests := get_tests_in_dir(global_dir, false)
|
||||||
@ -95,6 +96,8 @@ fn test_all() {
|
|||||||
run_tests := get_tests_in_dir(run_dir, false)
|
run_tests := get_tests_in_dir(run_dir, false)
|
||||||
skip_unused_dir_tests := get_tests_in_dir(skip_unused_dir, false)
|
skip_unused_dir_tests := get_tests_in_dir(skip_unused_dir, false)
|
||||||
trace_calls_dir_tests := get_tests_in_dir(trace_calls_dir, false)
|
trace_calls_dir_tests := get_tests_in_dir(trace_calls_dir, false)
|
||||||
|
checker_with_check_option_tests := get_tests_in_dir(checker_with_check_option_dir,
|
||||||
|
false)
|
||||||
mut tasks := Tasks{
|
mut tasks := Tasks{
|
||||||
vexe: vexe
|
vexe: vexe
|
||||||
label: 'all tests'
|
label: 'all tests'
|
||||||
@ -109,6 +112,8 @@ fn test_all() {
|
|||||||
tasks.add('', global_dir, '-enable-globals', '.out', global_tests, false)
|
tasks.add('', global_dir, '-enable-globals', '.out', global_tests, false)
|
||||||
tasks.add('', module_dir, '-prod run', '.out', module_tests, true)
|
tasks.add('', module_dir, '-prod run', '.out', module_tests, true)
|
||||||
tasks.add('', run_dir, 'run', '.run.out', run_tests, false)
|
tasks.add('', run_dir, 'run', '.run.out', run_tests, false)
|
||||||
|
tasks.add('', checker_with_check_option_dir, '-check', '.out', checker_with_check_option_tests,
|
||||||
|
false)
|
||||||
tasks.run()
|
tasks.run()
|
||||||
//
|
//
|
||||||
if os.user_os() == 'linux' {
|
if os.user_os() == 'linux' {
|
||||||
|
@ -1906,7 +1906,7 @@ pub fn (mut p Parser) error_with_pos(s string, pos token.Pos) ast.NodeError {
|
|||||||
util.show_compiler_message(kind, pos: pos, file_path: p.file_name, message: s)
|
util.show_compiler_message(kind, pos: pos, file_path: p.file_name, message: s)
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
if p.pref.output_mode == .stdout && !p.pref.check_only {
|
if p.pref.output_mode == .stdout {
|
||||||
if p.pref.is_verbose {
|
if p.pref.is_verbose {
|
||||||
print_backtrace()
|
print_backtrace()
|
||||||
kind = 'parser error:'
|
kind = 'parser error:'
|
||||||
@ -1923,7 +1923,7 @@ pub fn (mut p Parser) error_with_pos(s string, pos token.Pos) ast.NodeError {
|
|||||||
|
|
||||||
// To avoid getting stuck after an error, the parser
|
// To avoid getting stuck after an error, the parser
|
||||||
// will proceed to the next token.
|
// will proceed to the next token.
|
||||||
if p.pref.check_only {
|
if p.pref.check_only || p.pref.only_check_syntax {
|
||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user