ast, parser: implement simple AST poisoning (#9525)
							parent
							
								
									999c385b7f
								
							
						
					
					
						commit
						b319068151
					
				|  | @ -14,14 +14,14 @@ pub type Expr = AnonFn | ArrayDecompose | ArrayInit | AsCast | Assoc | AtExpr | | |||
| 	CTempVar | CallExpr | CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall | | ||||
| 	ComptimeSelector | ConcatExpr | DumpExpr | EnumVal | FloatLiteral | GoExpr | Ident | | ||||
| 	IfExpr | IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral | Likely | LockExpr | | ||||
| 	MapInit | MatchExpr | None | OffsetOf | OrExpr | ParExpr | PostfixExpr | PrefixExpr | | ||||
| 	RangeExpr | SelectExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | StringLiteral | | ||||
| 	StructInit | Type | TypeOf | UnsafeExpr | ||||
| 	MapInit | MatchExpr | NodeError | None | OffsetOf | OrExpr | ParExpr | PostfixExpr | | ||||
| 	PrefixExpr | RangeExpr | SelectExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | | ||||
| 	StringLiteral | StructInit | Type | TypeOf | UnsafeExpr | ||||
| 
 | ||||
| pub type Stmt = AsmStmt | AssertStmt | AssignStmt | Block | BranchStmt | CompFor | ConstDecl | | ||||
| 	DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | | ||||
| 	GoStmt | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | Return | | ||||
| 	SqlStmt | StructDecl | TypeDecl | ||||
| 	GoStmt | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | NodeError | | ||||
| 	Return | SqlStmt | StructDecl | TypeDecl | ||||
| 
 | ||||
| // NB: when you add a new Expr or Stmt type with a .pos field, remember to update
 | ||||
| // the .position() token.Position methods too.
 | ||||
|  | @ -1083,7 +1083,7 @@ pub: | |||
| pub struct AsmAddressing { | ||||
| pub: | ||||
| 	displacement u32 // 8, 16 or 32 bit literal value
 | ||||
| 	scale        int = -1 // 1, 2, 4, or 8 literal 
 | ||||
| 	scale        int = -1 // 1, 2, 4, or 8 literal
 | ||||
| 	mode         AddressingMode | ||||
| 	pos          token.Position | ||||
| pub mut: | ||||
|  | @ -1408,6 +1408,12 @@ pub mut: | |||
| 	sub_structs map[int]SqlExpr | ||||
| } | ||||
| 
 | ||||
| pub struct NodeError { | ||||
| pub: | ||||
| 	idx int // index for referencing the related ast.File error
 | ||||
| 	pos token.Position | ||||
| } | ||||
| 
 | ||||
| [inline] | ||||
| pub fn (expr Expr) is_blank_ident() bool { | ||||
| 	match expr { | ||||
|  | @ -1422,12 +1428,12 @@ pub fn (expr Expr) position() token.Position { | |||
| 		AnonFn { | ||||
| 			return expr.decl.pos | ||||
| 		} | ||||
| 		ArrayDecompose, ArrayInit, AsCast, Assoc, AtExpr, BoolLiteral, CallExpr, CastExpr, ChanInit, | ||||
| 		CharLiteral, ConcatExpr, Comment, ComptimeCall, ComptimeSelector, EnumVal, DumpExpr, FloatLiteral, | ||||
| 		GoExpr, Ident, IfExpr, IndexExpr, IntegerLiteral, Likely, LockExpr, MapInit, MatchExpr, | ||||
| 		None, OffsetOf, OrExpr, ParExpr, PostfixExpr, PrefixExpr, RangeExpr, SelectExpr, SelectorExpr, | ||||
| 		SizeOf, SqlExpr, StringInterLiteral, StringLiteral, StructInit, Type, TypeOf, UnsafeExpr | ||||
| 		 { | ||||
| 		NodeError, ArrayDecompose, ArrayInit, AsCast, Assoc, AtExpr, BoolLiteral, CallExpr, CastExpr, | ||||
| 		ChanInit, CharLiteral, ConcatExpr, Comment, ComptimeCall, ComptimeSelector, EnumVal, DumpExpr, | ||||
| 		FloatLiteral, GoExpr, Ident, IfExpr, IndexExpr, IntegerLiteral, Likely, LockExpr, MapInit, | ||||
| 		MatchExpr, None, OffsetOf, OrExpr, ParExpr, PostfixExpr, PrefixExpr, RangeExpr, SelectExpr, | ||||
| 		SelectorExpr, SizeOf, SqlExpr, StringInterLiteral, StringLiteral, StructInit, Type, TypeOf, | ||||
| 		UnsafeExpr { | ||||
| 			return expr.pos | ||||
| 		} | ||||
| 		IfGuardExpr { | ||||
|  |  | |||
|  | @ -3324,6 +3324,7 @@ fn (mut c Checker) stmt(node ast.Stmt) { | |||
| 	} | ||||
| 	// c.expected_type = table.void_type
 | ||||
| 	match mut node { | ||||
| 		ast.NodeError {} | ||||
| 		ast.AsmStmt { | ||||
| 			c.asm_stmt(mut node) | ||||
| 		} | ||||
|  | @ -3950,6 +3951,7 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type { | |||
| 		return table.void_type | ||||
| 	} | ||||
| 	match mut node { | ||||
| 		ast.NodeError {} | ||||
| 		ast.CTempVar { | ||||
| 			return node.typ | ||||
| 		} | ||||
|  |  | |||
|  | @ -382,6 +382,7 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) { | |||
| 		eprintln('stmt: ${node.pos:-42} | node: ${node.type_name():-20}') | ||||
| 	} | ||||
| 	match node { | ||||
| 		ast.NodeError {} | ||||
| 		ast.AsmStmt { | ||||
| 			f.asm_stmt(node) | ||||
| 		} | ||||
|  | @ -480,6 +481,7 @@ pub fn (mut f Fmt) expr(node ast.Expr) { | |||
| 		eprintln('expr: ${node.position():-42} | node: ${node.type_name():-20} | $node.str()') | ||||
| 	} | ||||
| 	match mut node { | ||||
| 		ast.NodeError {} | ||||
| 		ast.AnonFn { | ||||
| 			f.fn_decl(node.decl) | ||||
| 		} | ||||
|  |  | |||
|  | @ -1187,6 +1187,7 @@ fn (mut g Gen) stmt(node ast.Stmt) { | |||
| 			// g.cur_mod = node.name
 | ||||
| 			g.cur_mod = node | ||||
| 		} | ||||
| 		ast.NodeError {} | ||||
| 		ast.Return { | ||||
| 			g.write_defer_stmts_when_needed() | ||||
| 			// af := g.autofree && node.exprs.len > 0 && node.exprs[0] is ast.CallExpr && !g.is_builtin_mod
 | ||||
|  | @ -3013,6 +3014,7 @@ fn (mut g Gen) expr(node ast.Expr) { | |||
| 		ast.MapInit { | ||||
| 			g.map_init(node) | ||||
| 		} | ||||
| 		ast.NodeError {} | ||||
| 		ast.None { | ||||
| 			g.write('_const_none__') | ||||
| 		} | ||||
|  |  | |||
|  | @ -427,6 +427,7 @@ fn (mut g JsGen) stmt(node ast.Stmt) { | |||
| 		ast.Module { | ||||
| 			// skip: namespacing implemented externally
 | ||||
| 		} | ||||
| 		ast.NodeError {} | ||||
| 		ast.Return { | ||||
| 			if g.defer_stmts.len > 0 { | ||||
| 				g.gen_defer_stmts() | ||||
|  | @ -445,6 +446,7 @@ fn (mut g JsGen) stmt(node ast.Stmt) { | |||
| 
 | ||||
| fn (mut g JsGen) expr(node ast.Expr) { | ||||
| 	match node { | ||||
| 		ast.NodeError {} | ||||
| 		ast.CTempVar { | ||||
| 			g.write('/* ast.CTempVar: node.name */') | ||||
| 		} | ||||
|  | @ -693,7 +695,7 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt) { | |||
| 			} else { | ||||
| 				g.write(' $op ') | ||||
| 				// TODO: Multiple types??
 | ||||
| 				should_cast :=  | ||||
| 				should_cast := | ||||
| 					(g.table.type_kind(stmt.left_types.first()) in js.shallow_equatables) | ||||
| 					&& (g.cast_stack.len <= 0 || stmt.left_types.first() != g.cast_stack.last()) | ||||
| 
 | ||||
|  |  | |||
|  | @ -123,6 +123,7 @@ pub fn (mut w Walker) stmt(node ast.Stmt) { | |||
| 		ast.InterfaceDecl {} | ||||
| 		ast.Module {} | ||||
| 		ast.TypeDecl {} | ||||
| 		ast.NodeError {} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -335,6 +336,7 @@ fn (mut w Walker) expr(node ast.Expr) { | |||
| 		ast.UnsafeExpr { | ||||
| 			w.expr(node.expr) | ||||
| 		} | ||||
| 		ast.NodeError {} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -110,8 +110,7 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme | |||
| 		// a, b := a + 1, b
 | ||||
| 		for r in right { | ||||
| 			p.check_undefined_variables(left, r) or { | ||||
| 				p.error('check_undefined_variables failed') | ||||
| 				return ast.Stmt{} | ||||
| 				return p.error('check_undefined_variables failed') | ||||
| 			} | ||||
| 		} | ||||
| 	} else if left.len > 1 { | ||||
|  | @ -119,8 +118,8 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme | |||
| 		for r in right { | ||||
| 			has_cross_var = p.check_cross_variables(left, r) | ||||
| 			if op !in [.assign, .decl_assign] { | ||||
| 				p.error_with_pos('unexpected $op.str(), expecting := or = or comma', pos) | ||||
| 				return ast.Stmt{} | ||||
| 				return p.error_with_pos('unexpected $op.str(), expecting := or = or comma', | ||||
| 					pos) | ||||
| 			} | ||||
| 			if has_cross_var { | ||||
| 				break | ||||
|  | @ -133,8 +132,7 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme | |||
| 			ast.Ident { | ||||
| 				if op == .decl_assign { | ||||
| 					if p.scope.known_var(lx.name) { | ||||
| 						p.error_with_pos('redefinition of `$lx.name`', lx.pos) | ||||
| 						return ast.Stmt{} | ||||
| 						return p.error_with_pos('redefinition of `$lx.name`', lx.pos) | ||||
| 					} | ||||
| 					mut share := table.ShareType(0) | ||||
| 					if lx.info is ast.IdentVar { | ||||
|  | @ -142,9 +140,8 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme | |||
| 						share = iv.share | ||||
| 						if iv.is_static { | ||||
| 							if !p.pref.translated && !p.pref.is_fmt && !p.inside_unsafe_fn { | ||||
| 								p.error_with_pos('static variables are supported only in -translated mode or in [unsafe] fn', | ||||
| 								return p.error_with_pos('static variables are supported only in -translated mode or in [unsafe] fn', | ||||
| 									lx.pos) | ||||
| 								return ast.Stmt{} | ||||
| 							} | ||||
| 							is_static = true | ||||
| 						} | ||||
|  | @ -175,9 +172,8 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme | |||
| 			} | ||||
| 			ast.IndexExpr { | ||||
| 				if op == .decl_assign { | ||||
| 					p.error_with_pos('non-name `$lx.left[$lx.index]` on left side of `:=`', | ||||
| 					return p.error_with_pos('non-name `$lx.left[$lx.index]` on left side of `:=`', | ||||
| 						lx.pos) | ||||
| 					return ast.Stmt{} | ||||
| 				} | ||||
| 				lx.is_setter = true | ||||
| 			} | ||||
|  | @ -185,9 +181,8 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme | |||
| 			ast.PrefixExpr {} | ||||
| 			ast.SelectorExpr { | ||||
| 				if op == .decl_assign { | ||||
| 					p.error_with_pos('struct fields can only be declared during the initialization', | ||||
| 					return p.error_with_pos('struct fields can only be declared during the initialization', | ||||
| 						lx.pos) | ||||
| 					return ast.Stmt{} | ||||
| 				} | ||||
| 			} | ||||
| 			else { | ||||
|  |  | |||
|  | @ -12,8 +12,7 @@ fn (mut p Parser) for_stmt() ast.Stmt { | |||
| 	p.open_scope() | ||||
| 	p.inside_for = true | ||||
| 	if p.tok.kind == .key_match { | ||||
| 		p.error('cannot use `match` in `for` loop') | ||||
| 		return ast.Stmt{} | ||||
| 		return p.error('cannot use `match` in `for` loop') | ||||
| 	} | ||||
| 	// defer { p.close_scope() }
 | ||||
| 	// Infinite loop
 | ||||
|  | @ -34,8 +33,7 @@ fn (mut p Parser) for_stmt() ast.Stmt { | |||
| 		&& p.peek_token(2).kind != .key_mut && p.peek_token(3).kind != .key_in) { | ||||
| 		// `for i := 0; i < 10; i++ {` or `for a,b := 0,1; a < 10; a++ {`
 | ||||
| 		if p.tok.kind == .key_mut { | ||||
| 			p.error('`mut` is not needed in `for ;;` loops: use `for i := 0; i < n; i ++ {`') | ||||
| 			return ast.Stmt{} | ||||
| 			return p.error('`mut` is not needed in `for ;;` loops: use `for i := 0; i < n; i ++ {`') | ||||
| 		} | ||||
| 		mut init := ast.Stmt{} | ||||
| 		mut cond := p.new_true_expr() | ||||
|  | @ -55,8 +53,7 @@ fn (mut p Parser) for_stmt() ast.Stmt { | |||
| 		if p.tok.kind != .semicolon { | ||||
| 			// Disallow `for i := 0; i++; i < ...`
 | ||||
| 			if p.tok.kind == .name && p.peek_tok.kind in [.inc, .dec] { | ||||
| 				p.error('cannot use $p.tok.lit$p.peek_tok.kind as value') | ||||
| 				return ast.Stmt{} | ||||
| 				return p.error('cannot use $p.tok.lit$p.peek_tok.kind as value') | ||||
| 			} | ||||
| 			cond = p.expr(0) | ||||
| 			has_cond = true | ||||
|  | @ -112,16 +109,14 @@ fn (mut p Parser) for_stmt() ast.Stmt { | |||
| 			val_var_pos = p.tok.position() | ||||
| 			val_var_name = p.check_name() | ||||
| 			if key_var_name == val_var_name && key_var_name != '_' { | ||||
| 				p.error_with_pos('key and value in a for loop cannot be the same', val_var_pos) | ||||
| 				return ast.Stmt{} | ||||
| 				return p.error_with_pos('key and value in a for loop cannot be the same', | ||||
| 					val_var_pos) | ||||
| 			} | ||||
| 			if p.scope.known_var(key_var_name) { | ||||
| 				p.error('redefinition of key iteration variable `$key_var_name`') | ||||
| 				return ast.Stmt{} | ||||
| 				return p.error('redefinition of key iteration variable `$key_var_name`') | ||||
| 			} | ||||
| 			if p.scope.known_var(val_var_name) { | ||||
| 				p.error('redefinition of value iteration variable `$val_var_name`') | ||||
| 				return ast.Stmt{} | ||||
| 				return p.error('redefinition of value iteration variable `$val_var_name`') | ||||
| 			} | ||||
| 			p.scope.register(ast.Var{ | ||||
| 				name: key_var_name | ||||
|  | @ -130,13 +125,11 @@ fn (mut p Parser) for_stmt() ast.Stmt { | |||
| 				is_tmp: true | ||||
| 			}) | ||||
| 		} else if p.scope.known_var(val_var_name) { | ||||
| 			p.error('redefinition of value iteration variable `$val_var_name`') | ||||
| 			return ast.Stmt{} | ||||
| 			return p.error('redefinition of value iteration variable `$val_var_name`') | ||||
| 		} | ||||
| 		p.check(.key_in) | ||||
| 		if p.tok.kind == .name && p.tok.lit in [key_var_name, val_var_name] { | ||||
| 			p.error('in a `for x in array` loop, the key or value iteration variable `$p.tok.lit` can not be the same as the array variable') | ||||
| 			return ast.Stmt{} | ||||
| 			return p.error('in a `for x in array` loop, the key or value iteration variable `$p.tok.lit` can not be the same as the array variable') | ||||
| 		} | ||||
| 		// arr_expr
 | ||||
| 		cond := p.expr(0) | ||||
|  | @ -156,8 +149,8 @@ fn (mut p Parser) for_stmt() ast.Stmt { | |||
| 				is_tmp: true | ||||
| 			}) | ||||
| 			if key_var_name.len > 0 { | ||||
| 				p.error_with_pos('cannot declare index variable with range `for`', key_var_pos) | ||||
| 				return ast.Stmt{} | ||||
| 				return p.error_with_pos('cannot declare index variable with range `for`', | ||||
| 					key_var_pos) | ||||
| 			} | ||||
| 		} else { | ||||
| 			// this type will be set in checker
 | ||||
|  |  | |||
|  | @ -516,8 +516,7 @@ pub fn (mut p Parser) top_stmt() ast.Stmt { | |||
| 						return p.type_decl() | ||||
| 					} | ||||
| 					else { | ||||
| 						p.error('wrong pub keyword usage') | ||||
| 						return ast.Stmt{} | ||||
| 						return p.error('wrong pub keyword usage') | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
|  | @ -591,8 +590,7 @@ pub fn (mut p Parser) top_stmt() ast.Stmt { | |||
| 				} else if p.pref.is_fmt { | ||||
| 					return p.stmt(false) | ||||
| 				} else { | ||||
| 					p.error('bad top level statement ' + p.tok.str()) | ||||
| 					return ast.Stmt{} | ||||
| 					return p.error('bad top level statement ' + p.tok.str()) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | @ -720,12 +718,10 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt { | |||
| 					pos: spos.extend(p.tok.position()) | ||||
| 				} | ||||
| 			} else if p.peek_tok.kind == .name { | ||||
| 				p.error_with_pos('unexpected name `$p.peek_tok.lit`', p.peek_tok.position()) | ||||
| 				return ast.Stmt{} | ||||
| 				return p.error_with_pos('unexpected name `$p.peek_tok.lit`', p.peek_tok.position()) | ||||
| 			} else if !p.inside_if_expr && !p.inside_match_body && !p.inside_or_expr | ||||
| 				&& p.peek_tok.kind in [.rcbr, .eof] && !p.mark_var_as_used(p.tok.lit) { | ||||
| 				p.error_with_pos('`$p.tok.lit` evaluated but not used', p.tok.position()) | ||||
| 				return ast.Stmt{} | ||||
| 				return p.error_with_pos('`$p.tok.lit` evaluated but not used', p.tok.position()) | ||||
| 			} | ||||
| 			return p.parse_multi_expr(is_top_level) | ||||
| 		} | ||||
|  | @ -759,8 +755,7 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt { | |||
| 					} | ||||
| 				} | ||||
| 				else { | ||||
| 					p.error_with_pos('unexpected \$', p.tok.position()) | ||||
| 					return ast.Stmt{} | ||||
| 					return p.error_with_pos('unexpected \$', p.tok.position()) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | @ -820,9 +815,8 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt { | |||
| 			} | ||||
| 		} | ||||
| 		.key_const { | ||||
| 			p.error_with_pos('const can only be defined at the top level (outside of functions)', | ||||
| 			return p.error_with_pos('const can only be defined at the top level (outside of functions)', | ||||
| 				p.tok.position()) | ||||
| 			return ast.Stmt{} | ||||
| 		} | ||||
| 		.key_asm { | ||||
| 			return p.asm_stmt(false) | ||||
|  | @ -1483,8 +1477,8 @@ pub fn (mut p Parser) check_for_impure_v(language table.Language, pos token.Posi | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (mut p Parser) error(s string) { | ||||
| 	p.error_with_pos(s, p.tok.position()) | ||||
| pub fn (mut p Parser) error(s string) ast.NodeError { | ||||
| 	return p.error_with_pos(s, p.tok.position()) | ||||
| } | ||||
| 
 | ||||
| pub fn (mut p Parser) warn(s string) { | ||||
|  | @ -1495,7 +1489,7 @@ pub fn (mut p Parser) note(s string) { | |||
| 	p.note_with_pos(s, p.tok.position()) | ||||
| } | ||||
| 
 | ||||
| pub fn (mut p Parser) error_with_pos(s string, pos token.Position) { | ||||
| pub fn (mut p Parser) error_with_pos(s string, pos token.Position) ast.NodeError { | ||||
| 	if p.pref.fatal_errors { | ||||
| 		exit(1) | ||||
| 	} | ||||
|  | @ -1523,6 +1517,10 @@ pub fn (mut p Parser) error_with_pos(s string, pos token.Position) { | |||
| 		// The p.next() here is needed, so the parser is more robust, and *always* advances, even in the -silent mode.
 | ||||
| 		p.next() | ||||
| 	} | ||||
| 	return ast.NodeError{ | ||||
| 		idx: p.errors.len - 1 | ||||
| 		pos: pos | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (mut p Parser) error_with_error(error errors.Error) { | ||||
|  | @ -1611,8 +1609,7 @@ fn (mut p Parser) parse_multi_expr(is_top_level bool) ast.Stmt { | |||
| 	left, left_comments := p.expr_list() | ||||
| 	left0 := left[0] | ||||
| 	if tok.kind == .key_mut && p.tok.kind != .decl_assign { | ||||
| 		p.error('expecting `:=` (e.g. `mut x :=`)') | ||||
| 		return ast.Stmt{} | ||||
| 		return p.error('expecting `:=` (e.g. `mut x :=`)') | ||||
| 	} | ||||
| 	// TODO remove translated
 | ||||
| 	if p.tok.kind in [.assign, .decl_assign] || p.tok.kind.is_assign() { | ||||
|  | @ -1624,8 +1621,7 @@ fn (mut p Parser) parse_multi_expr(is_top_level bool) ast.Stmt { | |||
| 				&& node !is ast.PostfixExpr && !(node is ast.InfixExpr | ||||
| 				&& (node as ast.InfixExpr).op in [.left_shift, .arrow]) && node !is ast.ComptimeCall | ||||
| 				&& node !is ast.SelectorExpr && node !is ast.DumpExpr { | ||||
| 				p.error_with_pos('expression evaluated but not used', node.position()) | ||||
| 				return ast.Stmt{} | ||||
| 				return p.error_with_pos('expression evaluated but not used', node.position()) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | @ -1819,12 +1815,10 @@ pub fn (mut p Parser) name_expr() ast.Expr { | |||
| 					cap_expr = p.expr(0) | ||||
| 				} | ||||
| 				'len', 'init' { | ||||
| 					p.error('`$key` cannot be initialized for `chan`. Did you mean `cap`?') | ||||
| 					return ast.Expr{} | ||||
| 					return p.error('`$key` cannot be initialized for `chan`. Did you mean `cap`?') | ||||
| 				} | ||||
| 				else { | ||||
| 					p.error('wrong field `$key`, expecting `cap`') | ||||
| 					return ast.Expr{} | ||||
| 					return p.error('wrong field `$key`, expecting `cap`') | ||||
| 				} | ||||
| 			} | ||||
| 			last_pos = p.tok.position() | ||||
|  | @ -1843,15 +1837,13 @@ pub fn (mut p Parser) name_expr() ast.Expr { | |||
| 			return p.string_expr() | ||||
| 		} else { | ||||
| 			// don't allow any other string prefix except `r`, `js` and `c`
 | ||||
| 			p.error('only `c`, `r`, `js` are recognized string prefixes, but you tried to use `$p.tok.lit`') | ||||
| 			return ast.Expr{} | ||||
| 			return p.error('only `c`, `r`, `js` are recognized string prefixes, but you tried to use `$p.tok.lit`') | ||||
| 		} | ||||
| 	} | ||||
| 	// don't allow r`byte` and c`byte`
 | ||||
| 	if p.tok.lit in ['r', 'c'] && p.peek_tok.kind == .chartoken { | ||||
| 		opt := if p.tok.lit == 'r' { '`r` (raw string)' } else { '`c` (c string)' } | ||||
| 		p.error('cannot use $opt with `byte` and `rune`') | ||||
| 		return ast.Expr{} | ||||
| 		return p.error('cannot use $opt with `byte` and `rune`') | ||||
| 	} | ||||
| 	known_var := p.mark_var_as_used(p.tok.lit) | ||||
| 	mut is_mod_cast := false | ||||
|  | @ -2342,8 +2334,7 @@ fn (mut p Parser) string_expr() ast.Expr { | |||
| 					has_fmt = true | ||||
| 					p.next() | ||||
| 				} else { | ||||
| 					p.error('format specifier may only be one letter') | ||||
| 					return ast.Expr{} | ||||
| 					return p.error('format specifier may only be one letter') | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | @ -3072,13 +3063,11 @@ fn (mut p Parser) unsafe_stmt() ast.Stmt { | |||
| 	mut pos := p.tok.position() | ||||
| 	p.next() | ||||
| 	if p.tok.kind != .lcbr { | ||||
| 		p.error_with_pos('please use `unsafe {`', p.tok.position()) | ||||
| 		return ast.Stmt{} | ||||
| 		return p.error_with_pos('please use `unsafe {`', p.tok.position()) | ||||
| 	} | ||||
| 	p.next() | ||||
| 	if p.inside_unsafe { | ||||
| 		p.error_with_pos('already inside `unsafe` block', pos) | ||||
| 		return ast.Stmt{} | ||||
| 		return p.error_with_pos('already inside `unsafe` block', pos) | ||||
| 	} | ||||
| 	if p.tok.kind == .rcbr { | ||||
| 		// `unsafe {}`
 | ||||
|  |  | |||
|  | @ -69,8 +69,7 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr { | |||
| 					return p.if_expr(true) | ||||
| 				} | ||||
| 				else { | ||||
| 					p.error_with_pos('unexpected `$`', p.peek_tok.position()) | ||||
| 					return ast.Expr{} | ||||
| 					return p.error_with_pos('unexpected `$`', p.peek_tok.position()) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | @ -135,8 +134,7 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr { | |||
| 			mut pos := p.tok.position() | ||||
| 			p.next() | ||||
| 			if p.inside_unsafe { | ||||
| 				p.error_with_pos('already inside `unsafe` block', pos) | ||||
| 				return ast.Expr{} | ||||
| 				return p.error_with_pos('already inside `unsafe` block', pos) | ||||
| 			} | ||||
| 			p.inside_unsafe = true | ||||
| 			p.check(.lcbr) | ||||
|  | @ -240,8 +238,8 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr { | |||
| 			st := p.parse_type() | ||||
| 			p.check(.comma) | ||||
| 			if p.tok.kind != .name { | ||||
| 				p.error_with_pos('unexpected `$p.tok.lit`, expecting struct field', p.tok.position()) | ||||
| 				return ast.Expr{} | ||||
| 				return p.error_with_pos('unexpected `$p.tok.lit`, expecting struct field', | ||||
| 					p.tok.position()) | ||||
| 			} | ||||
| 			field := p.tok.lit | ||||
| 			p.next() | ||||
|  | @ -281,13 +279,11 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr { | |||
| 					node = p.struct_init(true) // short_syntax: true
 | ||||
| 				} else if p.tok.kind == .name { | ||||
| 					p.next() | ||||
| 					p.error_with_pos('unexpected $p.tok, expecting `:` after struct field name', | ||||
| 					return p.error_with_pos('unexpected $p.tok, expecting `:` after struct field name', | ||||
| 						p.tok.position()) | ||||
| 					return ast.Expr{} | ||||
| 				} else { | ||||
| 					p.error_with_pos('unexpected $p.tok, expecting struct field name', | ||||
| 					return p.error_with_pos('unexpected $p.tok, expecting struct field name', | ||||
| 						p.tok.position()) | ||||
| 					return ast.Expr{} | ||||
| 				} | ||||
| 			} | ||||
| 			p.check(.rcbr) | ||||
|  | @ -326,8 +322,7 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr { | |||
| 		else { | ||||
| 			if p.tok.kind != .eof && !(p.tok.kind == .rsbr && p.inside_asm) { | ||||
| 				// eof should be handled where it happens
 | ||||
| 				p.error_with_pos('invalid expression: unexpected $p.tok', p.tok.position()) | ||||
| 				return ast.Expr{} | ||||
| 				return p.error_with_pos('invalid expression: unexpected $p.tok', p.tok.position()) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  |  | |||
|  | @ -52,8 +52,7 @@ fn (mut p Parser) sql_expr() ast.Expr { | |||
| 		if p.tok.kind == .name && p.tok.lit == 'by' { | ||||
| 			p.check_name() // `by`
 | ||||
| 		} else { | ||||
| 			p.error_with_pos('use `order by` in ORM queries', order_pos) | ||||
| 			return ast.Expr{} | ||||
| 			return p.error_with_pos('use `order by` in ORM queries', order_pos) | ||||
| 		} | ||||
| 		has_order = true | ||||
| 		order_expr = p.expr(0) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue