Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Annlix
ShellCheck
提交
3e5ecaa2
S
ShellCheck
项目概览
Annlix
/
ShellCheck
与 Fork 源项目一致
Fork自
镜像 / koalaman / ShellCheck
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
ShellCheck
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
3e5ecaa2
编写于
6月 26, 2016
作者:
V
Vidar Holen
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Parse indices of associative arrays properly
上级
85e69f86
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
86 addition
and
16 deletion
+86
-16
ShellCheck/AST.hs
ShellCheck/AST.hs
+9
-5
ShellCheck/ASTLib.hs
ShellCheck/ASTLib.hs
+14
-0
ShellCheck/Analytics.hs
ShellCheck/Analytics.hs
+5
-1
ShellCheck/Parser.hs
ShellCheck/Parser.hs
+58
-10
未找到文件。
ShellCheck/AST.hs
浏览文件 @
3e5ecaa2
...
...
@@ -21,6 +21,7 @@ module ShellCheck.AST where
import
Control.Monad
import
Control.Monad.Identity
import
Text.Parsec
import
qualified
ShellCheck.Regex
as
Re
data
Id
=
Id
Int
deriving
(
Show
,
Eq
,
Ord
)
...
...
@@ -51,6 +52,8 @@ data Token =
|
T_Arithmetic
Id
Token
|
T_Array
Id
[
Token
]
|
T_IndexedElement
Id
Token
Token
-- Store the index as string, and parse as arithmetic or string later
|
T_UnparsedIndex
Id
SourcePos
String
|
T_Assignment
Id
AssignmentMode
String
(
Maybe
Token
)
Token
|
T_Backgrounded
Id
Token
|
T_Backticked
Id
[
Token
]
...
...
@@ -145,7 +148,7 @@ tokenEquals a b = kludge a == kludge b
instance
Eq
Token
where
(
==
)
=
tokenEquals
analyze
::
Monad
m
=>
(
Token
->
m
()
)
->
(
Token
->
m
()
)
->
(
Token
->
Token
)
->
Token
->
m
Token
analyze
::
Monad
m
=>
(
Token
->
m
()
)
->
(
Token
->
m
()
)
->
(
Token
->
m
Token
)
->
Token
->
m
Token
analyze
f
g
i
=
round
where
...
...
@@ -153,7 +156,7 @@ analyze f g i =
f
t
newT
<-
delve
t
g
t
return
.
i
$
newT
i
newT
roundAll
=
mapM
round
roundMaybe
Nothing
=
return
Nothing
...
...
@@ -363,10 +366,11 @@ getId t = case t of
T_CoProc
id
_
_
->
id
T_CoProcBody
id
_
->
id
T_Include
id
_
_
->
id
T_UnparsedIndex
id
_
_
->
id
blank
::
Monad
m
=>
Token
->
m
()
blank
=
const
$
return
()
doAnalysis
f
=
analyze
f
blank
id
doStackAnalysis
startToken
endToken
=
analyze
startToken
endToken
id
doTransform
i
=
runIdentity
.
analyze
blank
blank
i
doAnalysis
f
=
analyze
f
blank
(
return
.
id
)
doStackAnalysis
startToken
endToken
=
analyze
startToken
endToken
(
return
.
id
)
doTransform
i
=
runIdentity
.
analyze
blank
blank
(
return
.
i
)
ShellCheck/ASTLib.hs
浏览文件 @
3e5ecaa2
...
...
@@ -21,6 +21,7 @@ module ShellCheck.ASTLib where
import
ShellCheck.AST
import
Control.Monad.Writer
import
Control.Monad
import
Data.List
import
Data.Maybe
...
...
@@ -251,3 +252,16 @@ getCommandSequences t =
T_IfExpression
_
thens
elses
->
map
snd
thens
++
[
elses
]
otherwise
->
[]
getAssociativeArrays
t
=
nub
.
execWriter
$
doAnalysis
f
t
where
f
::
Token
->
Writer
[
String
]
()
f
t
@
(
T_SimpleCommand
{})
=
fromMaybe
(
return
()
)
$
do
name
<-
getCommandName
t
guard
$
name
==
"declare"
let
flags
=
getAllFlags
t
guard
$
elem
"A"
$
map
snd
flags
let
args
=
map
fst
.
filter
((
==
)
""
.
snd
)
$
flags
let
names
=
mapMaybe
getLiteralString
args
return
$
tell
names
f
_
=
return
()
ShellCheck/Analytics.hs
浏览文件 @
3e5ecaa2
...
...
@@ -1322,7 +1322,9 @@ checkBraceExpansionVars params t@(T_BraceExpansion id list) = mapM_ check list
(`
isUnqualifiedCommand
`
"eval"
)
<$>
getClosestCommand
(
parentMap
params
)
t
checkBraceExpansionVars
_
_
=
return
()
prop_checkForDecimals
=
verify
checkForDecimals
"((3.14*c))"
prop_checkForDecimals1
=
verify
checkForDecimals
"((3.14*c))"
prop_checkForDecimals2
=
verify
checkForDecimals
"foo[1.2]=bar"
prop_checkForDecimals3
=
verifyNot
checkForDecimals
"declare -A foo; foo[1.2]=bar"
checkForDecimals
params
t
@
(
TA_Expansion
id
_
)
=
potentially
$
do
guard
$
not
(
hasFloatingPoint
params
)
str
<-
getLiteralString
t
...
...
@@ -2116,6 +2118,8 @@ prop_checkUnassignedReferences19= verifyNotTree checkUnassignedReferences "reado
prop_checkUnassignedReferences20
=
verifyNotTree
checkUnassignedReferences
"printf -v foo bar; echo $foo"
prop_checkUnassignedReferences21
=
verifyTree
checkUnassignedReferences
"echo ${#foo}"
prop_checkUnassignedReferences22
=
verifyNotTree
checkUnassignedReferences
"echo ${!os*}"
prop_checkUnassignedReferences23
=
verifyTree
checkUnassignedReferences
"declare -a foo; foo[bar]=42;"
prop_checkUnassignedReferences24
=
verifyNotTree
checkUnassignedReferences
"declare -A foo; foo[bar]=42;"
checkUnassignedReferences
params
t
=
warnings
where
(
readMap
,
writeMap
)
=
execState
(
mapM
tally
$
variableFlow
params
)
(
Map
.
empty
,
Map
.
empty
)
...
...
ShellCheck/Parser.hs
浏览文件 @
3e5ecaa2
...
...
@@ -897,6 +897,20 @@ readNormalishWord end = do
checkPossibleTermination
pos
x
return
$
T_NormalWord
id
x
readIndexSpan
=
do
id
<-
getNextId
x
<-
many
(
readNormalWordPart
"]"
<|>
someSpace
<|>
otherLiteral
)
return
$
T_NormalWord
id
x
where
someSpace
=
do
id
<-
getNextId
str
<-
spacing1
return
$
T_Literal
id
str
otherLiteral
=
do
id
<-
getNextId
str
<-
many1
$
oneOf
quotableChars
return
$
T_Literal
id
str
checkPossibleTermination
pos
[
T_Literal
_
x
]
=
when
(
x
`
elem
`
[
"do"
,
"done"
,
"then"
,
"fi"
,
"esac"
])
$
parseProblemAt
pos
WarningC
1010
$
"Use semicolon or linefeed before '"
++
x
++
"' (or quote to make it literal)."
...
...
@@ -2251,7 +2265,9 @@ readEvalSuffix = many1 (readIoRedirect <|> readCmdWord <|> evalFallback)
-- Get whatever a parser would parse as a string
readStringForParser
parser
=
do
state
<-
Ms
.
get
pos
<-
lookAhead
(
parser
>>
getPosition
)
Ms
.
put
state
readUntil
pos
where
readUntil
endPos
=
anyChar
`
reluctantlyTill
`
(
getPosition
>>=
guard
.
(
==
endPos
))
...
...
@@ -2316,11 +2332,12 @@ readAssignmentWord = try $ do
return
$
T_Literal
id
""
readArrayIndex
=
do
id
<-
getNextId
char
'['
optional
space
x
<-
readArithmeticContents
pos
<-
getPosition
str
<-
readStringForParser
readIndexSpan
char
']'
return
x
return
$
T_UnparsedIndex
id
pos
str
readArray
=
called
"array assignment"
$
do
id
<-
getNextId
...
...
@@ -2477,12 +2494,12 @@ verifyEof = eof <|> choice [
try
(
lookAhead
p
)
action
prop_readScript1
=
isOk
readScript
"#!/bin/bash
\n
echo hello world
\n
"
prop_readScript2
=
isWarning
readScript
"#!/bin/bash
\r\n
echo hello world
\n
"
prop_readScript3
=
isWarning
readScript
"#!/bin/bash
\n
echo hello
\xA0
world"
prop_readScript4
=
isWarning
readScript
"#!/usr/bin/perl
\n
foo=("
prop_readScript5
=
isOk
readScript
"#!/bin/bash
\n
#This is an empty script
\n\n
"
readScript
=
do
prop_readScript1
=
isOk
readScript
File
"#!/bin/bash
\n
echo hello world
\n
"
prop_readScript2
=
isWarning
readScript
File
"#!/bin/bash
\r\n
echo hello world
\n
"
prop_readScript3
=
isWarning
readScript
File
"#!/bin/bash
\n
echo hello
\xA0
world"
prop_readScript4
=
isWarning
readScript
File
"#!/usr/bin/perl
\n
foo=("
prop_readScript5
=
isOk
readScript
File
"#!/bin/bash
\n
#This is an empty script
\n\n
"
readScript
File
=
do
id
<-
getNextId
pos
<-
getPosition
optional
$
do
...
...
@@ -2497,7 +2514,8 @@ readScript = do
annotations
<-
readAnnotations
commands
<-
withAnnotations
annotations
readCompoundListOrEmpty
verifyEof
return
$
T_Annotation
annotationId
annotations
$
T_Script
id
sb
commands
let
script
=
T_Annotation
annotationId
annotations
$
T_Script
id
sb
commands
reparseIndices
script
else
do
many
anyChar
return
$
T_Script
id
sb
[]
...
...
@@ -2549,6 +2567,9 @@ readScript = do
readUtf8Bom
=
called
"Byte Order Mark"
$
string
"
\xFEFF
"
readScript
=
do
script
<-
readScriptFile
reparseIndices
script
isWarning
p
s
=
parsesCleanly
p
s
==
Just
False
isOk
p
s
=
parsesCleanly
p
s
==
Just
True
...
...
@@ -2635,6 +2656,33 @@ parseShell sys name contents = do
second
(
ContextName
pos
str
)
=
ParseNote
pos
InfoC
1009
$
"The mentioned parser error was in this "
++
str
++
"."
-- Go over all T_UnparsedIndex and reparse them as either arithmetic or text
-- depending on declare -A statements.
reparseIndices
root
=
analyze
blank
blank
f
root
where
associative
=
getAssociativeArrays
root
isAssociative
s
=
s
`
elem
`
associative
f
(
T_Assignment
id
mode
name
(
Just
(
T_UnparsedIndex
_
pos
src
))
value
)
=
do
new
<-
parsed
name
pos
src
return
$
T_Assignment
id
mode
name
(
Just
new
)
value
f
(
T_Assignment
id
mode
name
Nothing
(
T_Array
id2
words
))
=
do
newwords
<-
mapM
(
fix
name
)
words
return
$
T_Assignment
id
mode
name
Nothing
(
T_Array
id2
newwords
)
f
t
=
return
t
fix
name
word
=
case
word
of
T_IndexedElement
id
(
T_UnparsedIndex
_
pos
src
)
value
->
do
new
<-
parsed
name
pos
src
return
$
T_IndexedElement
id
new
value
otherwise
->
return
word
parsed
name
pos
src
=
if
isAssociative
name
then
subParse
pos
readIndexSpan
src
else
subParse
pos
(
optional
space
>>
readArithmeticContents
)
src
reattachHereDocs
root
map
=
doTransform
f
root
where
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录