Skip to content

Commit 020b880

Browse files
committed
Cleaninup grammar, add for loops, add some bash builtins
1 parent 90bc46e commit 020b880

10 files changed

+881
-517
lines changed

grammar.pegjs

+42-24
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,39 @@
11
script
2-
= sections:(spaceNL* statementList spaceNL*)+
2+
= spaceNL* statements:statementList?
33

4-
statementList "a list of statements"
5-
= first:statement
6-
rest:(space* controlOperator spaceNL* statement)*
7-
last:(space* controlOperator)?
4+
statementList
5+
= head:statement
6+
tail:(controlOperator spaceNL* statement)*
7+
space* last:controlOperator? spaceNL*
88

99
statement
1010
= statement:( subshell
11+
/ bashExtensions
1112
/ command
1213
/ variableAssignment
13-
/ conditionalLoop
1414
/ ifBlock
15+
/ conditionalLoop
16+
/ forLoop
1517
)
1618
next:(space* chainedStatement)?
1719

1820
chainedStatement
1921
= operator:('&&' / '||') spaceNL* statement:statement
2022

21-
controlOperator
22-
= op:('&' / ';' / '\n')
23+
subshell "a subshell"
24+
= "(" space* statements:statementList space* ")"
2325

2426
command "a single command"
2527
= pre:((variableAssignment / redirect) space+)*
2628
name:(commandName / builtinCommandName)
2729
post:(space+ (redirect / argument))*
2830
pipe:(space* pipe)?
2931

30-
conditionalLoop
31-
= kind:("while" / "until") spaceNL+ test:condition spaceNL*
32-
"do" spaceNL
33-
body:script
34-
"done"
32+
condition
33+
= test:script
3534

36-
ifBlock
37-
= "if" spaceNL+ test:script
35+
ifBlock "an if/elif/else statement"
36+
= "if" spaceNL+ test:condition
3837
"then" spaceNL+ body:script
3938
elifBlocks:elifBlock*
4039
elseBody:("else" script)?
@@ -43,13 +42,29 @@ ifBlock
4342
elifBlock
4443
= "elif" spaceNL+ test:condition "then" spaceNL+ body:script
4544

46-
condition
47-
= test:script
45+
conditionalLoop "a while/until loop"
46+
= kind:("while" / "until") spaceNL+ test:condition
47+
"do" spaceNL+ body:script
48+
"done"
4849

49-
subshell "a subshell"
50-
= "(" space* statements:statementList space* ")"
50+
forLoop "a for loop"
51+
= "for" space+ loopVar:writableVariableName spaceNL+
52+
subjects:("in" (space+ argument)*)?
53+
space* (";" / "\n") spaceNL*
54+
"do" spaceNL+
55+
body:statementList spaceNL*
56+
"done"
57+
58+
bashExtensions
59+
= time / declare
5160

52-
variableAssignment
61+
time "time builtin"
62+
= "time" space+ flags:("-" [a-z]+ space+)* statements:statementList
63+
64+
declare "declare builtin"
65+
= ("declare" / "typeset") command:[^\n]+ (";" / "\n")
66+
67+
variableAssignment "a variable assignment"
5368
= name:writableVariableName '=' value:argument?
5469

5570
commandName "command name"
@@ -59,8 +74,7 @@ commandName "command name"
5974
name:(concatenation / builtinCommandName)
6075

6176
builtinCommandName
62-
= '['
63-
/ '[['
77+
= '[[' / '['
6478

6579
argument "command argument"
6680
= commandName
@@ -155,15 +169,19 @@ redirectionOperator
155169
fd
156170
= digits:[0-9]+ { return parseInt(join(digits), 10) }
157171

172+
controlOperator
173+
= space* op:('&' / ';' / '\n')
174+
158175
pipe =
159176
"|" spaceNL* command:command
160177

161-
space
178+
space "whitespace"
162179
= " " / "\t"
163180

164181
spaceNL = space / "\n" / comment
165182

166-
comment = '#' [^\n]* ("\n" / EOF)
183+
comment "a comment"
184+
= '#' [^\n]* ("\n" / EOF)
167185

168186
keyword
169187
= ( "while"

overrides.js

+32-23
Original file line numberDiff line numberDiff line change
@@ -70,21 +70,23 @@ exports.initializer = [
7070
}
7171
].join('\n')
7272

73-
rules.script = function (sections) {
74-
var statements = []
75-
map(sections, function (section) {
76-
statements = statements.concat(section[1])
77-
})
78-
return statements
73+
rules.script = function (statements) {
74+
return statements || []
7975
}
8076

81-
rules.statementList = function (first, rest, last) {
82-
var statements = [first]
83-
var prev = first
84-
map(rest, function (spaceOpSpaceCmd, i, cmds) {
85-
setOperator(spaceOpSpaceCmd[1], prev)
86-
statements.push(prev = spaceOpSpaceCmd[3])
77+
rules.statementList = function (first, tail, last) {
78+
var statements = [head]
79+
var prev = head
80+
map(tail, function (spaceOpSpaceCmd, i, cmds) {
81+
setOperator(spaceOpSpaceCmd[0], prev)
82+
statements.push(prev = spaceOpSpaceCmd[2])
8783
})
84+
85+
if (last) {
86+
if (!prev) { debugger }
87+
setOperator(last, prev)
88+
}
89+
8890
return statements
8991

9092
function setOperator(operator, command) {
@@ -96,7 +98,6 @@ rules.statementList = function (first, rest, last) {
9698
}
9799

98100
rules.subshell = function (statements) {
99-
debugger
100101
return {
101102
type: 'subshell',
102103
statements: statements,
@@ -105,12 +106,21 @@ rules.subshell = function (statements) {
105106

106107
rules.conditionalLoop = function (kind, test, body) {
107108
return {
108-
type: kind + '-loop',
109+
type: kind + 'Loop',
109110
test: test,
110111
body: body
111112
}
112113
}
113114

115+
rules.forLoop = function (loopVar, subjects, body) {
116+
return {
117+
type: 'forLoop',
118+
loopVariable: loopVar,
119+
subjects: subjects[1].map(second),
120+
body: body
121+
}
122+
}
123+
114124
rules.ifBlock = function (test, body, elifBlocks, elseBody) {
115125
return {
116126
type: 'ifElse',
@@ -129,6 +139,14 @@ rules.elifBlock = function (test, body) {
129139
}
130140
}
131141

142+
rules.time = function (flags, statements) {
143+
return {
144+
type: 'time',
145+
flags: flags,
146+
command: statements
147+
}
148+
}
149+
132150
rules.condition = function bare (test) {
133151
return test
134152
}
@@ -201,15 +219,6 @@ rules.environmentVariable = function () {
201219
return {type: 'variable', name: name}
202220
}
203221

204-
rules.variableAssignment = function () {
205-
name, val
206-
return {
207-
type: 'assignment',
208-
name: name,
209-
value: val
210-
}
211-
}
212-
213222
rules.variableSubstitution = function () {
214223
return {
215224
type: 'variableSubstitution',

0 commit comments

Comments
 (0)