• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

RauliL / juokse / 6084826251

05 Sep 2023 12:50PM UTC coverage: 68.054% (-0.4%) from 68.489%
6084826251

push

github

web-flow
Merge pull request #25 from RauliL/functions

Add support for custom functions

174 of 258 branches covered (0.0%)

Branch coverage included in aggregate %.

23 of 23 new or added lines in 4 files covered. (100.0%)

529 of 775 relevant lines covered (68.26%)

132.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.52
/src/parser/parser.ts
1
import {
2
  AssignmentStatement,
3
  BlockStatement,
4
  CommandStatement,
5
  ForStatement,
6
  FunctionDefinition,
7
  IfStatement,
8
  PassStatement,
9
  Position,
10
  Statement,
11
  Token,
12
  WhileStatement,
13
  Word,
14
} from "../ast";
15
import { JuokseError } from "../error";
15✔
16
import { State } from "./state";
15✔
17

18
export const parseBlockStatement = (
15✔
19
  state: State,
20
  position: Position
21
): BlockStatement => {
22
  const body: Statement[] = [];
42✔
23

24
  if (state.peekRead("NewLine")) {
42✔
25
    state.read("Indent");
18✔
26
    for (;;) {
18✔
27
      parseStatement(state, body);
33✔
28
      if (state.eof() || state.peekRead("Dedent")) {
33✔
29
        break;
18✔
30
      }
31
    }
32
  } else {
33
    parseStatementList(state, body);
24✔
34
  }
35

36
  return {
39✔
37
    position,
38
    type: "Block",
39
    body,
40
  };
41
};
42

43
export const parseFunctionDefinition = (state: State): FunctionDefinition => {
15✔
44
  const { position } = state.read("KeywordDef");
6✔
45
  const name = state.read<Word>("Word").text;
3✔
46

47
  state.read(":");
3✔
48

49
  return {
3✔
50
    position,
51
    type: "FunctionDefinition",
52
    name,
53
    body: parseBlockStatement(state, position),
54
  };
55
};
56

57
export const parseForStatement = (state: State): ForStatement => {
15✔
58
  const { position } = state.read("KeywordFor");
24✔
59
  const variable = state.read<Word>("Word").text;
15✔
60
  const subjects: Word[] = [];
12✔
61

62
  if (
12✔
63
    !state.peek("Word") ||
24✔
64
    (state.tokens[state.offset] as Word).text !== "in"
65
  ) {
66
    throw new JuokseError("Missing `in' after `'for'.", position);
3✔
67
  }
68
  state.advance();
9✔
69
  do {
9✔
70
    subjects.push(state.readWord());
15✔
71
  } while (!state.peekRead(":"));
72

73
  return {
6✔
74
    position,
75
    type: "For",
76
    variable,
77
    subjects,
78
    body: parseBlockStatement(state, position),
79
  };
80
};
81

82
export const parseIfStatement = (state: State): IfStatement => {
15✔
83
  const { position } = state.read("KeywordIf");
27✔
84
  const test = parseCommandStatement(state);
24✔
85

86
  state.read(":");
21✔
87

88
  const thenClause = parseBlockStatement(state, position);
18✔
89
  let elseClause: Statement | undefined;
90

91
  if (state.peekRead("KeywordElse")) {
15✔
92
    if (state.peek("KeywordIf")) {
6✔
93
      elseClause = parseIfStatement(state);
3✔
94
    } else {
95
      state.read(":");
3✔
96
      elseClause = parseBlockStatement(state, position);
3✔
97
    }
98
  }
99

100
  return {
15✔
101
    position,
102
    type: "If",
103
    test,
104
    then: thenClause,
105
    else: elseClause,
106
  };
107
};
108

109
export const parseWhileStatement = (state: State): WhileStatement => {
15✔
110
  const { position } = state.read("KeywordWhile");
15✔
111
  const test = parseCommandStatement(state);
12✔
112

113
  state.read(":");
9✔
114

115
  return {
6✔
116
    position,
117
    type: "While",
118
    test,
119
    body: parseBlockStatement(state, position),
120
  };
121
};
122

123
export const parseCommandStatement = (state: State): CommandStatement => {
15✔
124
  const command = state.readWord();
54✔
125
  const args: Word[] = [];
42✔
126

127
  while (state.peekWord()) {
42✔
128
    args.push(state.advance() as Word);
15✔
129
  }
130

131
  return {
42✔
132
    position: command.position,
133
    type: "Command",
134
    command,
135
    args,
136
  };
137
};
138

139
export const parsePassStatement = (state: State): PassStatement => ({
69✔
140
  position: state.read("KeywordPass").position,
141
  type: "Pass",
142
});
143

144
export const parseAssignmentStatement = (state: State): AssignmentStatement => {
15✔
145
  const { position, text: variable } = state.readWord();
15✔
146

147
  // Skip "=".
148
  state.read("Word");
12✔
149

150
  return {
9✔
151
    position,
152
    type: "Assignment",
153
    variable,
154
    value: state.readWord(),
155
  };
156
};
157

158
export const parseSimpleStatement = (state: State): Statement => {
15✔
159
  if (state.eof()) {
81✔
160
    throw new JuokseError(
6✔
161
      "Unexpected end of input; Missing statement.",
162
      state.position
163
    );
164
  }
165

166
  if (state.peek("KeywordPass")) {
75✔
167
    return parsePassStatement(state);
63✔
168
  } else if (
12✔
169
    state.peekWord() &&
33✔
170
    state.offset + 1 < state.tokens.length &&
171
    state.tokens[state.offset + 1].type === "Word" &&
172
    (state.tokens[state.offset + 1] as Word).text === "="
173
  ) {
174
    return parseAssignmentStatement(state);
3✔
175
  }
176

177
  return parseCommandStatement(state);
9✔
178
};
179

180
export const parseStatementList = (state: State, output: Statement[]): void => {
15✔
181
  output.push(parseSimpleStatement(state));
60✔
182
  while (state.peekRead(";")) {
54✔
183
    if (state.eof() || state.peek("NewLine")) {
12✔
184
      return;
3✔
185
    }
186
    output.push(parseSimpleStatement(state));
9✔
187
  }
188
};
189

190
export const parseStatement = (state: State, output: Statement[]): void => {
15✔
191
  if (state.eof()) {
57✔
192
    throw new JuokseError(
3✔
193
      "Unexpected end of input; Missing statement.",
194
      state.position
195
    );
196
  }
197

198
  switch (state.tokens[state.offset].type) {
54!
199
    case "KeywordDef":
200
      output.push(parseFunctionDefinition(state));
×
201
      break;
×
202

203
    case "KeywordFor":
204
      output.push(parseForStatement(state));
3✔
205
      break;
3✔
206

207
    case "KeywordIf":
208
      output.push(parseIfStatement(state));
3✔
209
      break;
3✔
210

211
    case "KeywordWhile":
212
      output.push(parseWhileStatement(state));
3✔
213
      break;
3✔
214

215
    case "NewLine":
216
      state.advance();
18✔
217
      break;
18✔
218

219
    default:
220
      parseStatementList(state, output);
27✔
221
      break;
24✔
222
  }
223
};
224

225
export const parse = (tokens: Token[]): Statement[] => {
15✔
226
  const state = new State(tokens);
6✔
227
  const output: Statement[] = [];
6✔
228

229
  while (!state.eof()) {
6✔
230
    if (!state.peekRead("NewLine")) {
9✔
231
      parseStatement(state, output);
6✔
232
    }
233
  }
234

235
  return output;
3✔
236
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc