Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
go
Commits
42e6c03f
Commit
42e6c03f
authored
Aug 17, 2011
by
Robert Griesemer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
go/parser: disallow for statements w/ illegal range clauses
R=rsc CC=golang-dev
https://golang.org/cl/4908047
parent
0f7bc92b
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
42 additions
and
35 deletions
+42
-35
src/pkg/go/parser/parser.go
src/pkg/go/parser/parser.go
+37
-35
src/pkg/go/parser/parser_test.go
src/pkg/go/parser/parser_test.go
+5
-0
No files found.
src/pkg/go/parser/parser.go
View file @
42e6c03f
...
@@ -1366,7 +1366,18 @@ func (p *parser) parseRhsOrType() ast.Expr {
...
@@ -1366,7 +1366,18 @@ func (p *parser) parseRhsOrType() ast.Expr {
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Statements
// Statements
func
(
p
*
parser
)
parseSimpleStmt
(
labelOk
bool
)
ast
.
Stmt
{
// Parsing modes for parseSimpleStmt.
const
(
basic
=
iota
labelOk
rangeOk
)
// parseSimpleStmt returns true as 2nd result if it parsed the assignment
// of a range clause (with mode == rangeOk). The returned statement is an
// assignment with a right-hand side that is a single unary expression of
// the form "range x". No guarantees are given for the left-hand side.
func
(
p
*
parser
)
parseSimpleStmt
(
mode
int
)
(
ast
.
Stmt
,
bool
)
{
if
p
.
trace
{
if
p
.
trace
{
defer
un
(
trace
(
p
,
"SimpleStmt"
))
defer
un
(
trace
(
p
,
"SimpleStmt"
))
}
}
...
@@ -1383,14 +1394,16 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
...
@@ -1383,14 +1394,16 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
pos
,
tok
:=
p
.
pos
,
p
.
tok
pos
,
tok
:=
p
.
pos
,
p
.
tok
p
.
next
()
p
.
next
()
var
y
[]
ast
.
Expr
var
y
[]
ast
.
Expr
if
p
.
tok
==
token
.
RANGE
&&
(
tok
==
token
.
DEFINE
||
tok
==
token
.
ASSIGN
)
{
isRange
:=
false
if
mode
==
rangeOk
&&
p
.
tok
==
token
.
RANGE
&&
(
tok
==
token
.
DEFINE
||
tok
==
token
.
ASSIGN
)
{
pos
:=
p
.
pos
pos
:=
p
.
pos
p
.
next
()
p
.
next
()
y
=
[]
ast
.
Expr
{
&
ast
.
UnaryExpr
{
pos
,
token
.
RANGE
,
p
.
parseRhs
()}}
y
=
[]
ast
.
Expr
{
&
ast
.
UnaryExpr
{
pos
,
token
.
RANGE
,
p
.
parseRhs
()}}
isRange
=
true
}
else
{
}
else
{
y
=
p
.
parseRhsList
()
y
=
p
.
parseRhsList
()
}
}
return
&
ast
.
AssignStmt
{
x
,
pos
,
tok
,
y
}
return
&
ast
.
AssignStmt
{
x
,
pos
,
tok
,
y
}
,
isRange
}
}
if
len
(
x
)
>
1
{
if
len
(
x
)
>
1
{
...
@@ -1403,13 +1416,13 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
...
@@ -1403,13 +1416,13 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
// labeled statement
// labeled statement
colon
:=
p
.
pos
colon
:=
p
.
pos
p
.
next
()
p
.
next
()
if
label
,
isIdent
:=
x
[
0
]
.
(
*
ast
.
Ident
);
labelOk
&&
isIdent
{
if
label
,
isIdent
:=
x
[
0
]
.
(
*
ast
.
Ident
);
mode
==
labelOk
&&
isIdent
{
// Go spec: The scope of a label is the body of the function
// Go spec: The scope of a label is the body of the function
// in which it is declared and excludes the body of any nested
// in which it is declared and excludes the body of any nested
// function.
// function.
stmt
:=
&
ast
.
LabeledStmt
{
label
,
colon
,
p
.
parseStmt
()}
stmt
:=
&
ast
.
LabeledStmt
{
label
,
colon
,
p
.
parseStmt
()}
p
.
declare
(
stmt
,
nil
,
p
.
labelScope
,
ast
.
Lbl
,
label
)
p
.
declare
(
stmt
,
nil
,
p
.
labelScope
,
ast
.
Lbl
,
label
)
return
stmt
return
stmt
,
false
}
}
// The label declaration typically starts at x[0].Pos(), but the label
// The label declaration typically starts at x[0].Pos(), but the label
// declaration may be erroneous due to a token after that position (and
// declaration may be erroneous due to a token after that position (and
...
@@ -1418,24 +1431,24 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
...
@@ -1418,24 +1431,24 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
// before the ':' that caused the problem. Thus, use the (latest) colon
// before the ':' that caused the problem. Thus, use the (latest) colon
// position for error reporting.
// position for error reporting.
p
.
error
(
colon
,
"illegal label declaration"
)
p
.
error
(
colon
,
"illegal label declaration"
)
return
&
ast
.
BadStmt
{
x
[
0
]
.
Pos
(),
colon
+
1
}
return
&
ast
.
BadStmt
{
x
[
0
]
.
Pos
(),
colon
+
1
}
,
false
case
token
.
ARROW
:
case
token
.
ARROW
:
// send statement
// send statement
arrow
:=
p
.
pos
arrow
:=
p
.
pos
p
.
next
()
// consume "<-"
p
.
next
()
// consume "<-"
y
:=
p
.
parseRhs
()
y
:=
p
.
parseRhs
()
return
&
ast
.
SendStmt
{
x
[
0
],
arrow
,
y
}
return
&
ast
.
SendStmt
{
x
[
0
],
arrow
,
y
}
,
false
case
token
.
INC
,
token
.
DEC
:
case
token
.
INC
,
token
.
DEC
:
// increment or decrement
// increment or decrement
s
:=
&
ast
.
IncDecStmt
{
x
[
0
],
p
.
pos
,
p
.
tok
}
s
:=
&
ast
.
IncDecStmt
{
x
[
0
],
p
.
pos
,
p
.
tok
}
p
.
next
()
// consume "++" or "--"
p
.
next
()
// consume "++" or "--"
return
s
return
s
,
false
}
}
// expression
// expression
return
&
ast
.
ExprStmt
{
x
[
0
]}
return
&
ast
.
ExprStmt
{
x
[
0
]}
,
false
}
}
func
(
p
*
parser
)
parseCallExpr
()
*
ast
.
CallExpr
{
func
(
p
*
parser
)
parseCallExpr
()
*
ast
.
CallExpr
{
...
@@ -1540,7 +1553,7 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
...
@@ -1540,7 +1553,7 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
p
.
next
()
p
.
next
()
x
=
p
.
parseRhs
()
x
=
p
.
parseRhs
()
}
else
{
}
else
{
s
=
p
.
parseSimpleStmt
(
false
)
s
,
_
=
p
.
parseSimpleStmt
(
basic
)
if
p
.
tok
==
token
.
SEMICOLON
{
if
p
.
tok
==
token
.
SEMICOLON
{
p
.
next
()
p
.
next
()
x
=
p
.
parseRhs
()
x
=
p
.
parseRhs
()
...
@@ -1631,14 +1644,14 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
...
@@ -1631,14 +1644,14 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
prevLev
:=
p
.
exprLev
prevLev
:=
p
.
exprLev
p
.
exprLev
=
-
1
p
.
exprLev
=
-
1
if
p
.
tok
!=
token
.
SEMICOLON
{
if
p
.
tok
!=
token
.
SEMICOLON
{
s2
=
p
.
parseSimpleStmt
(
false
)
s2
,
_
=
p
.
parseSimpleStmt
(
basic
)
}
}
if
p
.
tok
==
token
.
SEMICOLON
{
if
p
.
tok
==
token
.
SEMICOLON
{
p
.
next
()
p
.
next
()
s1
=
s2
s1
=
s2
s2
=
nil
s2
=
nil
if
p
.
tok
!=
token
.
LBRACE
{
if
p
.
tok
!=
token
.
LBRACE
{
s2
=
p
.
parseSimpleStmt
(
false
)
s2
,
_
=
p
.
parseSimpleStmt
(
basic
)
}
}
}
}
p
.
exprLev
=
prevLev
p
.
exprLev
=
prevLev
...
@@ -1751,22 +1764,23 @@ func (p *parser) parseForStmt() ast.Stmt {
...
@@ -1751,22 +1764,23 @@ func (p *parser) parseForStmt() ast.Stmt {
defer
p
.
closeScope
()
defer
p
.
closeScope
()
var
s1
,
s2
,
s3
ast
.
Stmt
var
s1
,
s2
,
s3
ast
.
Stmt
var
isRange
bool
if
p
.
tok
!=
token
.
LBRACE
{
if
p
.
tok
!=
token
.
LBRACE
{
prevLev
:=
p
.
exprLev
prevLev
:=
p
.
exprLev
p
.
exprLev
=
-
1
p
.
exprLev
=
-
1
if
p
.
tok
!=
token
.
SEMICOLON
{
if
p
.
tok
!=
token
.
SEMICOLON
{
s2
=
p
.
parseSimpleStmt
(
false
)
s2
,
isRange
=
p
.
parseSimpleStmt
(
rangeOk
)
}
}
if
p
.
tok
==
token
.
SEMICOLON
{
if
!
isRange
&&
p
.
tok
==
token
.
SEMICOLON
{
p
.
next
()
p
.
next
()
s1
=
s2
s1
=
s2
s2
=
nil
s2
=
nil
if
p
.
tok
!=
token
.
SEMICOLON
{
if
p
.
tok
!=
token
.
SEMICOLON
{
s2
=
p
.
parseSimpleStmt
(
false
)
s2
,
_
=
p
.
parseSimpleStmt
(
basic
)
}
}
p
.
expectSemi
()
p
.
expectSemi
()
if
p
.
tok
!=
token
.
LBRACE
{
if
p
.
tok
!=
token
.
LBRACE
{
s3
=
p
.
parseSimpleStmt
(
false
)
s3
,
_
=
p
.
parseSimpleStmt
(
basic
)
}
}
}
}
p
.
exprLev
=
prevLev
p
.
exprLev
=
prevLev
...
@@ -1775,12 +1789,8 @@ func (p *parser) parseForStmt() ast.Stmt {
...
@@ -1775,12 +1789,8 @@ func (p *parser) parseForStmt() ast.Stmt {
body
:=
p
.
parseBlockStmt
()
body
:=
p
.
parseBlockStmt
()
p
.
expectSemi
()
p
.
expectSemi
()
if
as
,
isAssign
:=
s2
.
(
*
ast
.
AssignStmt
);
isAssign
{
if
isRange
{
// possibly a for statement with a range clause; check assignment operator
as
:=
s2
.
(
*
ast
.
AssignStmt
)
if
as
.
Tok
!=
token
.
ASSIGN
&&
as
.
Tok
!=
token
.
DEFINE
{
p
.
errorExpected
(
as
.
TokPos
,
"'=' or ':='"
)
return
&
ast
.
BadStmt
{
pos
,
body
.
End
()}
}
// check lhs
// check lhs
var
key
,
value
ast
.
Expr
var
key
,
value
ast
.
Expr
switch
len
(
as
.
Lhs
)
{
switch
len
(
as
.
Lhs
)
{
...
@@ -1792,18 +1802,10 @@ func (p *parser) parseForStmt() ast.Stmt {
...
@@ -1792,18 +1802,10 @@ func (p *parser) parseForStmt() ast.Stmt {
p
.
errorExpected
(
as
.
Lhs
[
0
]
.
Pos
(),
"1 or 2 expressions"
)
p
.
errorExpected
(
as
.
Lhs
[
0
]
.
Pos
(),
"1 or 2 expressions"
)
return
&
ast
.
BadStmt
{
pos
,
body
.
End
()}
return
&
ast
.
BadStmt
{
pos
,
body
.
End
()}
}
}
// check rhs
// parseSimpleStmt returned a right-hand side that
if
len
(
as
.
Rhs
)
!=
1
{
// is a single unary expression of the form "range x"
p
.
errorExpected
(
as
.
Rhs
[
0
]
.
Pos
(),
"1 expression"
)
x
:=
as
.
Rhs
[
0
]
.
(
*
ast
.
UnaryExpr
)
.
X
return
&
ast
.
BadStmt
{
pos
,
body
.
End
()}
return
&
ast
.
RangeStmt
{
pos
,
key
,
value
,
as
.
TokPos
,
as
.
Tok
,
x
,
body
}
}
if
rhs
,
isUnary
:=
as
.
Rhs
[
0
]
.
(
*
ast
.
UnaryExpr
);
isUnary
&&
rhs
.
Op
==
token
.
RANGE
{
// rhs is range expression
// (any short variable declaration was handled by parseSimpleStmt above)
return
&
ast
.
RangeStmt
{
pos
,
key
,
value
,
as
.
TokPos
,
as
.
Tok
,
rhs
.
X
,
body
}
}
p
.
errorExpected
(
s2
.
Pos
(),
"range clause"
)
return
&
ast
.
BadStmt
{
pos
,
body
.
End
()}
}
}
// regular for statement
// regular for statement
...
@@ -1823,7 +1825,7 @@ func (p *parser) parseStmt() (s ast.Stmt) {
...
@@ -1823,7 +1825,7 @@ func (p *parser) parseStmt() (s ast.Stmt) {
token
.
IDENT
,
token
.
INT
,
token
.
FLOAT
,
token
.
CHAR
,
token
.
STRING
,
token
.
FUNC
,
token
.
LPAREN
,
// operand
token
.
IDENT
,
token
.
INT
,
token
.
FLOAT
,
token
.
CHAR
,
token
.
STRING
,
token
.
FUNC
,
token
.
LPAREN
,
// operand
token
.
LBRACK
,
token
.
STRUCT
,
// composite type
token
.
LBRACK
,
token
.
STRUCT
,
// composite type
token
.
MUL
,
token
.
AND
,
token
.
ARROW
,
token
.
ADD
,
token
.
SUB
,
token
.
XOR
:
// unary operators
token
.
MUL
,
token
.
AND
,
token
.
ARROW
,
token
.
ADD
,
token
.
SUB
,
token
.
XOR
:
// unary operators
s
=
p
.
parseSimpleStmt
(
true
)
s
,
_
=
p
.
parseSimpleStmt
(
labelOk
)
// because of the required look-ahead, labeled statements are
// because of the required look-ahead, labeled statements are
// parsed by parseSimpleStmt - don't expect a semicolon after
// parsed by parseSimpleStmt - don't expect a semicolon after
// them
// them
...
...
src/pkg/go/parser/parser_test.go
View file @
42e6c03f
...
@@ -21,6 +21,11 @@ var illegalInputs = []interface{}{
...
@@ -21,6 +21,11 @@ var illegalInputs = []interface{}{
`package p; func f() { if ; /* should have condition */ {} };`
,
`package p; func f() { if ; /* should have condition */ {} };`
,
`package p; func f() { if f(); /* should have condition */ {} };`
,
`package p; func f() { if f(); /* should have condition */ {} };`
,
`package p; const c; /* should have constant value */`
,
`package p; const c; /* should have constant value */`
,
`package p; func f() { if _ = range x; true {} };`
,
`package p; func f() { switch _ = range x; true {} };`
,
`package p; func f() { for _ = range x ; ; {} };`
,
`package p; func f() { for ; ; _ = range x {} };`
,
`package p; func f() { for ; _ = range x ; {} };`
,
`package p; var a = [1]int; /* illegal expression */`
,
`package p; var a = [1]int; /* illegal expression */`
,
`package p; var a = [...]int; /* illegal expression */`
,
`package p; var a = [...]int; /* illegal expression */`
,
`package p; var a = struct{} /* illegal expression */`
,
`package p; var a = struct{} /* illegal expression */`
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment