ast, parser: implement simple AST poisoning (#9525)

pull/9531/head
Ned Palacios 2021-03-30 15:33:29 +08:00 committed by GitHub
parent 999c385b7f
commit b319068151
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 77 additions and 90 deletions

View File

@ -14,14 +14,14 @@ pub type Expr = AnonFn | ArrayDecompose | ArrayInit | AsCast | Assoc | AtExpr |
CTempVar | CallExpr | CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall | CTempVar | CallExpr | CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall |
ComptimeSelector | ConcatExpr | DumpExpr | EnumVal | FloatLiteral | GoExpr | Ident | ComptimeSelector | ConcatExpr | DumpExpr | EnumVal | FloatLiteral | GoExpr | Ident |
IfExpr | IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral | Likely | LockExpr | IfExpr | IfGuardExpr | IndexExpr | InfixExpr | IntegerLiteral | Likely | LockExpr |
MapInit | MatchExpr | None | OffsetOf | OrExpr | ParExpr | PostfixExpr | PrefixExpr | MapInit | MatchExpr | NodeError | None | OffsetOf | OrExpr | ParExpr | PostfixExpr |
RangeExpr | SelectExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | StringLiteral | PrefixExpr | RangeExpr | SelectExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral |
StructInit | Type | TypeOf | UnsafeExpr StringLiteral | StructInit | Type | TypeOf | UnsafeExpr
pub type Stmt = AsmStmt | AssertStmt | AssignStmt | Block | BranchStmt | CompFor | ConstDecl | pub type Stmt = AsmStmt | AssertStmt | AssignStmt | Block | BranchStmt | CompFor | ConstDecl |
DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl | DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | GlobalDecl |
GoStmt | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | Return | GoStmt | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | NodeError |
SqlStmt | StructDecl | TypeDecl Return | SqlStmt | StructDecl | TypeDecl
// NB: when you add a new Expr or Stmt type with a .pos field, remember to update // NB: when you add a new Expr or Stmt type with a .pos field, remember to update
// the .position() token.Position methods too. // the .position() token.Position methods too.
@ -1083,7 +1083,7 @@ pub:
pub struct AsmAddressing { pub struct AsmAddressing {
pub: pub:
displacement u32 // 8, 16 or 32 bit literal value 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 mode AddressingMode
pos token.Position pos token.Position
pub mut: pub mut:
@ -1408,6 +1408,12 @@ pub mut:
sub_structs map[int]SqlExpr sub_structs map[int]SqlExpr
} }
pub struct NodeError {
pub:
idx int // index for referencing the related ast.File error
pos token.Position
}
[inline] [inline]
pub fn (expr Expr) is_blank_ident() bool { pub fn (expr Expr) is_blank_ident() bool {
match expr { match expr {
@ -1422,12 +1428,12 @@ pub fn (expr Expr) position() token.Position {
AnonFn { AnonFn {
return expr.decl.pos return expr.decl.pos
} }
ArrayDecompose, ArrayInit, AsCast, Assoc, AtExpr, BoolLiteral, CallExpr, CastExpr, ChanInit, NodeError, ArrayDecompose, ArrayInit, AsCast, Assoc, AtExpr, BoolLiteral, CallExpr, CastExpr,
CharLiteral, ConcatExpr, Comment, ComptimeCall, ComptimeSelector, EnumVal, DumpExpr, FloatLiteral, ChanInit, CharLiteral, ConcatExpr, Comment, ComptimeCall, ComptimeSelector, EnumVal, DumpExpr,
GoExpr, Ident, IfExpr, IndexExpr, IntegerLiteral, Likely, LockExpr, MapInit, MatchExpr, FloatLiteral, GoExpr, Ident, IfExpr, IndexExpr, IntegerLiteral, Likely, LockExpr, MapInit,
None, OffsetOf, OrExpr, ParExpr, PostfixExpr, PrefixExpr, RangeExpr, SelectExpr, SelectorExpr, MatchExpr, None, OffsetOf, OrExpr, ParExpr, PostfixExpr, PrefixExpr, RangeExpr, SelectExpr,
SizeOf, SqlExpr, StringInterLiteral, StringLiteral, StructInit, Type, TypeOf, UnsafeExpr SelectorExpr, SizeOf, SqlExpr, StringInterLiteral, StringLiteral, StructInit, Type, TypeOf,
{ UnsafeExpr {
return expr.pos return expr.pos
} }
IfGuardExpr { IfGuardExpr {

View File

@ -3324,6 +3324,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
} }
// c.expected_type = table.void_type // c.expected_type = table.void_type
match mut node { match mut node {
ast.NodeError {}
ast.AsmStmt { ast.AsmStmt {
c.asm_stmt(mut node) c.asm_stmt(mut node)
} }
@ -3950,6 +3951,7 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
return table.void_type return table.void_type
} }
match mut node { match mut node {
ast.NodeError {}
ast.CTempVar { ast.CTempVar {
return node.typ return node.typ
} }

View File

@ -382,6 +382,7 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
eprintln('stmt: ${node.pos:-42} | node: ${node.type_name():-20}') eprintln('stmt: ${node.pos:-42} | node: ${node.type_name():-20}')
} }
match node { match node {
ast.NodeError {}
ast.AsmStmt { ast.AsmStmt {
f.asm_stmt(node) 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()') eprintln('expr: ${node.position():-42} | node: ${node.type_name():-20} | $node.str()')
} }
match mut node { match mut node {
ast.NodeError {}
ast.AnonFn { ast.AnonFn {
f.fn_decl(node.decl) f.fn_decl(node.decl)
} }

View File

@ -1187,6 +1187,7 @@ fn (mut g Gen) stmt(node ast.Stmt) {
// g.cur_mod = node.name // g.cur_mod = node.name
g.cur_mod = node g.cur_mod = node
} }
ast.NodeError {}
ast.Return { ast.Return {
g.write_defer_stmts_when_needed() g.write_defer_stmts_when_needed()
// af := g.autofree && node.exprs.len > 0 && node.exprs[0] is ast.CallExpr && !g.is_builtin_mod // 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 { ast.MapInit {
g.map_init(node) g.map_init(node)
} }
ast.NodeError {}
ast.None { ast.None {
g.write('_const_none__') g.write('_const_none__')
} }

View File

@ -427,6 +427,7 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
ast.Module { ast.Module {
// skip: namespacing implemented externally // skip: namespacing implemented externally
} }
ast.NodeError {}
ast.Return { ast.Return {
if g.defer_stmts.len > 0 { if g.defer_stmts.len > 0 {
g.gen_defer_stmts() g.gen_defer_stmts()
@ -445,6 +446,7 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
fn (mut g JsGen) expr(node ast.Expr) { fn (mut g JsGen) expr(node ast.Expr) {
match node { match node {
ast.NodeError {}
ast.CTempVar { ast.CTempVar {
g.write('/* ast.CTempVar: node.name */') g.write('/* ast.CTempVar: node.name */')
} }
@ -693,7 +695,7 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt) {
} else { } else {
g.write(' $op ') g.write(' $op ')
// TODO: Multiple types?? // TODO: Multiple types??
should_cast := should_cast :=
(g.table.type_kind(stmt.left_types.first()) in js.shallow_equatables) (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()) && (g.cast_stack.len <= 0 || stmt.left_types.first() != g.cast_stack.last())

View File

@ -123,6 +123,7 @@ pub fn (mut w Walker) stmt(node ast.Stmt) {
ast.InterfaceDecl {} ast.InterfaceDecl {}
ast.Module {} ast.Module {}
ast.TypeDecl {} ast.TypeDecl {}
ast.NodeError {}
} }
} }
@ -335,6 +336,7 @@ fn (mut w Walker) expr(node ast.Expr) {
ast.UnsafeExpr { ast.UnsafeExpr {
w.expr(node.expr) w.expr(node.expr)
} }
ast.NodeError {}
} }
} }

View File

@ -110,8 +110,7 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme
// a, b := a + 1, b // a, b := a + 1, b
for r in right { for r in right {
p.check_undefined_variables(left, r) or { p.check_undefined_variables(left, r) or {
p.error('check_undefined_variables failed') return p.error('check_undefined_variables failed')
return ast.Stmt{}
} }
} }
} else if left.len > 1 { } 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 { for r in right {
has_cross_var = p.check_cross_variables(left, r) has_cross_var = p.check_cross_variables(left, r)
if op !in [.assign, .decl_assign] { if op !in [.assign, .decl_assign] {
p.error_with_pos('unexpected $op.str(), expecting := or = or comma', pos) return p.error_with_pos('unexpected $op.str(), expecting := or = or comma',
return ast.Stmt{} pos)
} }
if has_cross_var { if has_cross_var {
break break
@ -133,8 +132,7 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme
ast.Ident { ast.Ident {
if op == .decl_assign { if op == .decl_assign {
if p.scope.known_var(lx.name) { if p.scope.known_var(lx.name) {
p.error_with_pos('redefinition of `$lx.name`', lx.pos) return p.error_with_pos('redefinition of `$lx.name`', lx.pos)
return ast.Stmt{}
} }
mut share := table.ShareType(0) mut share := table.ShareType(0)
if lx.info is ast.IdentVar { 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 share = iv.share
if iv.is_static { if iv.is_static {
if !p.pref.translated && !p.pref.is_fmt && !p.inside_unsafe_fn { 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) lx.pos)
return ast.Stmt{}
} }
is_static = true is_static = true
} }
@ -175,9 +172,8 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme
} }
ast.IndexExpr { ast.IndexExpr {
if op == .decl_assign { 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) lx.pos)
return ast.Stmt{}
} }
lx.is_setter = true 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.PrefixExpr {}
ast.SelectorExpr { ast.SelectorExpr {
if op == .decl_assign { 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) lx.pos)
return ast.Stmt{}
} }
} }
else { else {

View File

@ -12,8 +12,7 @@ fn (mut p Parser) for_stmt() ast.Stmt {
p.open_scope() p.open_scope()
p.inside_for = true p.inside_for = true
if p.tok.kind == .key_match { if p.tok.kind == .key_match {
p.error('cannot use `match` in `for` loop') return p.error('cannot use `match` in `for` loop')
return ast.Stmt{}
} }
// defer { p.close_scope() } // defer { p.close_scope() }
// Infinite loop // 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) { && 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++ {` // `for i := 0; i < 10; i++ {` or `for a,b := 0,1; a < 10; a++ {`
if p.tok.kind == .key_mut { if p.tok.kind == .key_mut {
p.error('`mut` is not needed in `for ;;` loops: use `for i := 0; i < n; i ++ {`') return p.error('`mut` is not needed in `for ;;` loops: use `for i := 0; i < n; i ++ {`')
return ast.Stmt{}
} }
mut init := ast.Stmt{} mut init := ast.Stmt{}
mut cond := p.new_true_expr() mut cond := p.new_true_expr()
@ -55,8 +53,7 @@ fn (mut p Parser) for_stmt() ast.Stmt {
if p.tok.kind != .semicolon { if p.tok.kind != .semicolon {
// Disallow `for i := 0; i++; i < ...` // Disallow `for i := 0; i++; i < ...`
if p.tok.kind == .name && p.peek_tok.kind in [.inc, .dec] { 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 p.error('cannot use $p.tok.lit$p.peek_tok.kind as value')
return ast.Stmt{}
} }
cond = p.expr(0) cond = p.expr(0)
has_cond = true has_cond = true
@ -112,16 +109,14 @@ fn (mut p Parser) for_stmt() ast.Stmt {
val_var_pos = p.tok.position() val_var_pos = p.tok.position()
val_var_name = p.check_name() val_var_name = p.check_name()
if key_var_name == val_var_name && key_var_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 p.error_with_pos('key and value in a for loop cannot be the same',
return ast.Stmt{} val_var_pos)
} }
if p.scope.known_var(key_var_name) { if p.scope.known_var(key_var_name) {
p.error('redefinition of key iteration variable `$key_var_name`') return p.error('redefinition of key iteration variable `$key_var_name`')
return ast.Stmt{}
} }
if p.scope.known_var(val_var_name) { if p.scope.known_var(val_var_name) {
p.error('redefinition of value iteration variable `$val_var_name`') return p.error('redefinition of value iteration variable `$val_var_name`')
return ast.Stmt{}
} }
p.scope.register(ast.Var{ p.scope.register(ast.Var{
name: key_var_name name: key_var_name
@ -130,13 +125,11 @@ fn (mut p Parser) for_stmt() ast.Stmt {
is_tmp: true is_tmp: true
}) })
} else if p.scope.known_var(val_var_name) { } else if p.scope.known_var(val_var_name) {
p.error('redefinition of value iteration variable `$val_var_name`') return p.error('redefinition of value iteration variable `$val_var_name`')
return ast.Stmt{}
} }
p.check(.key_in) p.check(.key_in)
if p.tok.kind == .name && p.tok.lit in [key_var_name, val_var_name] { 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 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{}
} }
// arr_expr // arr_expr
cond := p.expr(0) cond := p.expr(0)
@ -156,8 +149,8 @@ fn (mut p Parser) for_stmt() ast.Stmt {
is_tmp: true is_tmp: true
}) })
if key_var_name.len > 0 { if key_var_name.len > 0 {
p.error_with_pos('cannot declare index variable with range `for`', key_var_pos) return p.error_with_pos('cannot declare index variable with range `for`',
return ast.Stmt{} key_var_pos)
} }
} else { } else {
// this type will be set in checker // this type will be set in checker

View File

@ -516,8 +516,7 @@ pub fn (mut p Parser) top_stmt() ast.Stmt {
return p.type_decl() return p.type_decl()
} }
else { else {
p.error('wrong pub keyword usage') return p.error('wrong pub keyword usage')
return ast.Stmt{}
} }
} }
} }
@ -591,8 +590,7 @@ pub fn (mut p Parser) top_stmt() ast.Stmt {
} else if p.pref.is_fmt { } else if p.pref.is_fmt {
return p.stmt(false) return p.stmt(false)
} else { } else {
p.error('bad top level statement ' + p.tok.str()) return p.error('bad top level statement ' + p.tok.str())
return ast.Stmt{}
} }
} }
} }
@ -720,12 +718,10 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
pos: spos.extend(p.tok.position()) pos: spos.extend(p.tok.position())
} }
} else if p.peek_tok.kind == .name { } else if p.peek_tok.kind == .name {
p.error_with_pos('unexpected name `$p.peek_tok.lit`', p.peek_tok.position()) return p.error_with_pos('unexpected name `$p.peek_tok.lit`', p.peek_tok.position())
return ast.Stmt{}
} else if !p.inside_if_expr && !p.inside_match_body && !p.inside_or_expr } 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.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 p.error_with_pos('`$p.tok.lit` evaluated but not used', p.tok.position())
return ast.Stmt{}
} }
return p.parse_multi_expr(is_top_level) 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 { else {
p.error_with_pos('unexpected \$', p.tok.position()) return p.error_with_pos('unexpected \$', p.tok.position())
return ast.Stmt{}
} }
} }
} }
@ -820,9 +815,8 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
} }
} }
.key_const { .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()) p.tok.position())
return ast.Stmt{}
} }
.key_asm { .key_asm {
return p.asm_stmt(false) 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) { pub fn (mut p Parser) error(s string) ast.NodeError {
p.error_with_pos(s, p.tok.position()) return p.error_with_pos(s, p.tok.position())
} }
pub fn (mut p Parser) warn(s string) { 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()) 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 { if p.pref.fatal_errors {
exit(1) 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. // The p.next() here is needed, so the parser is more robust, and *always* advances, even in the -silent mode.
p.next() p.next()
} }
return ast.NodeError{
idx: p.errors.len - 1
pos: pos
}
} }
pub fn (mut p Parser) error_with_error(error errors.Error) { 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() left, left_comments := p.expr_list()
left0 := left[0] left0 := left[0]
if tok.kind == .key_mut && p.tok.kind != .decl_assign { if tok.kind == .key_mut && p.tok.kind != .decl_assign {
p.error('expecting `:=` (e.g. `mut x :=`)') return p.error('expecting `:=` (e.g. `mut x :=`)')
return ast.Stmt{}
} }
// TODO remove translated // TODO remove translated
if p.tok.kind in [.assign, .decl_assign] || p.tok.kind.is_assign() { 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 !is ast.PostfixExpr && !(node is ast.InfixExpr
&& (node as ast.InfixExpr).op in [.left_shift, .arrow]) && node !is ast.ComptimeCall && (node as ast.InfixExpr).op in [.left_shift, .arrow]) && node !is ast.ComptimeCall
&& node !is ast.SelectorExpr && node !is ast.DumpExpr { && node !is ast.SelectorExpr && node !is ast.DumpExpr {
p.error_with_pos('expression evaluated but not used', node.position()) return p.error_with_pos('expression evaluated but not used', node.position())
return ast.Stmt{}
} }
} }
} }
@ -1819,12 +1815,10 @@ pub fn (mut p Parser) name_expr() ast.Expr {
cap_expr = p.expr(0) cap_expr = p.expr(0)
} }
'len', 'init' { 'len', 'init' {
p.error('`$key` cannot be initialized for `chan`. Did you mean `cap`?') return p.error('`$key` cannot be initialized for `chan`. Did you mean `cap`?')
return ast.Expr{}
} }
else { else {
p.error('wrong field `$key`, expecting `cap`') return p.error('wrong field `$key`, expecting `cap`')
return ast.Expr{}
} }
} }
last_pos = p.tok.position() last_pos = p.tok.position()
@ -1843,15 +1837,13 @@ pub fn (mut p Parser) name_expr() ast.Expr {
return p.string_expr() return p.string_expr()
} else { } else {
// don't allow any other string prefix except `r`, `js` and `c` // 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 p.error('only `c`, `r`, `js` are recognized string prefixes, but you tried to use `$p.tok.lit`')
return ast.Expr{}
} }
} }
// don't allow r`byte` and c`byte` // don't allow r`byte` and c`byte`
if p.tok.lit in ['r', 'c'] && p.peek_tok.kind == .chartoken { 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)' } opt := if p.tok.lit == 'r' { '`r` (raw string)' } else { '`c` (c string)' }
p.error('cannot use $opt with `byte` and `rune`') return p.error('cannot use $opt with `byte` and `rune`')
return ast.Expr{}
} }
known_var := p.mark_var_as_used(p.tok.lit) known_var := p.mark_var_as_used(p.tok.lit)
mut is_mod_cast := false mut is_mod_cast := false
@ -2342,8 +2334,7 @@ fn (mut p Parser) string_expr() ast.Expr {
has_fmt = true has_fmt = true
p.next() p.next()
} else { } else {
p.error('format specifier may only be one letter') return p.error('format specifier may only be one letter')
return ast.Expr{}
} }
} }
} }
@ -3072,13 +3063,11 @@ fn (mut p Parser) unsafe_stmt() ast.Stmt {
mut pos := p.tok.position() mut pos := p.tok.position()
p.next() p.next()
if p.tok.kind != .lcbr { if p.tok.kind != .lcbr {
p.error_with_pos('please use `unsafe {`', p.tok.position()) return p.error_with_pos('please use `unsafe {`', p.tok.position())
return ast.Stmt{}
} }
p.next() p.next()
if p.inside_unsafe { if p.inside_unsafe {
p.error_with_pos('already inside `unsafe` block', pos) return p.error_with_pos('already inside `unsafe` block', pos)
return ast.Stmt{}
} }
if p.tok.kind == .rcbr { if p.tok.kind == .rcbr {
// `unsafe {}` // `unsafe {}`

View File

@ -69,8 +69,7 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
return p.if_expr(true) return p.if_expr(true)
} }
else { else {
p.error_with_pos('unexpected `$`', p.peek_tok.position()) return p.error_with_pos('unexpected `$`', p.peek_tok.position())
return ast.Expr{}
} }
} }
} }
@ -135,8 +134,7 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
mut pos := p.tok.position() mut pos := p.tok.position()
p.next() p.next()
if p.inside_unsafe { if p.inside_unsafe {
p.error_with_pos('already inside `unsafe` block', pos) return p.error_with_pos('already inside `unsafe` block', pos)
return ast.Expr{}
} }
p.inside_unsafe = true p.inside_unsafe = true
p.check(.lcbr) p.check(.lcbr)
@ -240,8 +238,8 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
st := p.parse_type() st := p.parse_type()
p.check(.comma) p.check(.comma)
if p.tok.kind != .name { if p.tok.kind != .name {
p.error_with_pos('unexpected `$p.tok.lit`, expecting struct field', p.tok.position()) return p.error_with_pos('unexpected `$p.tok.lit`, expecting struct field',
return ast.Expr{} p.tok.position())
} }
field := p.tok.lit field := p.tok.lit
p.next() p.next()
@ -281,13 +279,11 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
node = p.struct_init(true) // short_syntax: true node = p.struct_init(true) // short_syntax: true
} else if p.tok.kind == .name { } else if p.tok.kind == .name {
p.next() 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()) p.tok.position())
return ast.Expr{}
} else { } 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()) p.tok.position())
return ast.Expr{}
} }
} }
p.check(.rcbr) p.check(.rcbr)
@ -326,8 +322,7 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
else { else {
if p.tok.kind != .eof && !(p.tok.kind == .rsbr && p.inside_asm) { if p.tok.kind != .eof && !(p.tok.kind == .rsbr && p.inside_asm) {
// eof should be handled where it happens // eof should be handled where it happens
p.error_with_pos('invalid expression: unexpected $p.tok', p.tok.position()) return p.error_with_pos('invalid expression: unexpected $p.tok', p.tok.position())
return ast.Expr{}
} }
} }
} }

View File

@ -52,8 +52,7 @@ fn (mut p Parser) sql_expr() ast.Expr {
if p.tok.kind == .name && p.tok.lit == 'by' { if p.tok.kind == .name && p.tok.lit == 'by' {
p.check_name() // `by` p.check_name() // `by`
} else { } else {
p.error_with_pos('use `order by` in ORM queries', order_pos) return p.error_with_pos('use `order by` in ORM queries', order_pos)
return ast.Expr{}
} }
has_order = true has_order = true
order_expr = p.expr(0) order_expr = p.expr(0)