3 def _or_parser(*parsers):
4 def result_parser(index, tokens):
5 failure = (False, index, None)
8 success, index, value = parser(index, tokens)
11 return (success, index, value)
17 def _zero_or_more_parser(formatter, parser):
18 def result_parser(index, tokens):
21 while index < len(tokens):
22 success, index, value = parser(index, tokens)
29 return (True, index, formatter(values))
33 FurIntegerLiteralExpression = collections.namedtuple(
34 'FurIntegerLiteralExpression',
40 FurStringLiteralExpression = collections.namedtuple(
41 'FurStringLiteralExpression',
47 FurSymbolExpression = collections.namedtuple(
48 'FurSymbolExpression',
54 FurNegationExpression = collections.namedtuple(
55 'FurNegationExpression',
61 FurParenthesizedExpression = collections.namedtuple(
62 'FurParenthesizedExpression',
68 FurAdditionExpression = collections.namedtuple(
69 'FurAdditionExpression',
76 FurSubtractionExpression = collections.namedtuple(
77 'FurSubtractionExpression',
84 FurMultiplicationExpression = collections.namedtuple(
85 'FurMultiplicationExpression',
92 FurIntegerDivisionExpression = collections.namedtuple(
93 'FurIntegerDivisionExpression',
100 FurModularDivisionExpression = collections.namedtuple(
101 'FurModularDivisionExpression',
108 def _integer_literal_expression_parser(index, tokens):
109 failure = (False, index, None)
111 if tokens[index].type != 'integer_literal':
113 value = int(tokens[index].match)
116 return True, index, FurIntegerLiteralExpression(value=value)
118 def _string_literal_expression_parser(index, tokens):
119 if tokens[index].type == 'single_quoted_string_literal':
120 return (True, index + 1, FurStringLiteralExpression(value=tokens[index].match[1:-1]))
122 return (False, index, None)
124 def _symbol_expression_parser(index, tokens):
125 if tokens[index].type == 'symbol':
126 return (True, index + 1, FurSymbolExpression(value=tokens[index].match))
128 return (False, index, None)
130 def _parenthesized_expression_parser(index, tokens):
131 failure = (False, index, None)
133 if tokens[index].type == 'open_parenthese':
138 success, index, internal = _expression_parser(index, tokens)
142 if tokens[index].type == 'close_parenthese':
145 raise Exception('Expected ")" on line {}, found "{}"'.format(
150 return True, index, FurParenthesizedExpression(internal=internal)
152 def _negation_expression_parser(index, tokens):
153 failure = (False, index, None)
155 if tokens[index].match != '-':
158 success, index, value = _literal_level_expression_parser(index + 1, tokens)
163 return (True, index, FurNegationExpression(value=value))
165 def _literal_level_expression_parser(index, tokens):
167 _negation_expression_parser,
168 _function_call_expression_parser,
169 _parenthesized_expression_parser,
170 _integer_literal_expression_parser,
171 _string_literal_expression_parser,
172 _symbol_expression_parser,
175 def _multiplication_level_expression_parser(index, tokens):
176 failure = (False, index, None)
178 success, index, result = _literal_level_expression_parser(index, tokens)
183 while success and index < len(tokens) and tokens[index].type == 'multiplication_level_operator':
186 if index + 1 < len(tokens):
187 success, try_index, value = _literal_level_expression_parser(index + 1, tokens)
191 '*': FurMultiplicationExpression,
192 '//': FurIntegerDivisionExpression,
193 '%': FurModularDivisionExpression,
194 }[tokens[index].match](left=result, right=value)
197 return True, index, result
199 def _addition_level_expression_parser(index, tokens):
200 failure = (False, index, None)
202 success, index, result = _multiplication_level_expression_parser(index, tokens)
207 while success and index < len(tokens) and tokens[index].type == 'addition_level_operator':
210 if index + 1 < len(tokens):
211 success, try_index, value = _multiplication_level_expression_parser(index + 1, tokens)
215 '+': FurAdditionExpression,
216 '-': FurSubtractionExpression,
217 }[tokens[index].match](left=result, right=value)
220 return True, index, result
222 def _comma_separated_list_parser(index, tokens):
223 failure = (False, index, None)
227 success, index, expression = _addition_level_expression_parser(index, tokens)
230 expressions.append(expression)
234 while success and index < len(tokens) and tokens[index].type == 'comma':
237 if index + 1 < len(tokens):
238 success, try_index, expression = _addition_level_expression_parser(index + 1, tokens)
241 expressions.append(expression)
244 return True, index, tuple(expressions)
247 FurFunctionCallExpression = collections.namedtuple(
248 'FurFunctionCallExpression',
255 FurAssignmentStatement = collections.namedtuple(
256 'FurAssignmentStatement',
263 FurProgram = collections.namedtuple(
270 def _function_call_expression_parser(index, tokens):
271 # TODO Use a FurSymbolExpression for the name
272 failure = (False, index, None)
274 success, index, function = _symbol_expression_parser(index, tokens)
279 if tokens[index].type != 'open_parenthese':
283 success, index, arguments = _comma_separated_list_parser(index, tokens)
288 if tokens[index].type != 'close_parenthese':
289 raise Exception('Expected ")", found "{}" on line {}'.format(
295 return True, index, FurFunctionCallExpression(function=function, arguments=arguments)
297 _expression_parser = _addition_level_expression_parser
299 def _assignment_statement_parser(index, tokens):
300 # TODO Use a FurSymbolExpression for the target
301 failure = (False, index, None)
303 if tokens[index].type != 'symbol':
305 target = tokens[index].match
308 if tokens[index].type != 'assignment_operator':
310 assignment_operator_index = index
312 success, index, expression = _expression_parser(index + 1, tokens)
316 'Expected expression after assignment operator on line {}'.format(
317 tokens[assignment_operator_index].line
321 return True, index, FurAssignmentStatement(target=target, expression=expression)
323 def _statement_parser(index, tokens):
325 _assignment_statement_parser,
329 def _program_formatter(statement_list):
330 return FurProgram(statement_list=statement_list)
332 _program_parser = _zero_or_more_parser(_program_formatter, _statement_parser)
334 def _parse(parser, tokens):
335 success, index, result = parser(0, tokens)
337 if index < len(tokens):
338 raise Exception('Unable to parse token {}'.format(tokens[index]))
343 raise Exception('Unable to parse')
346 return _parse(_program_parser, tokens)
348 if __name__ == '__main__':
353 class FurStringLiteralExpressionParserTests(unittest.TestCase):
354 def test_parses_single_quoted_string_literal(self):
356 _string_literal_expression_parser(0, tokenization.tokenize("'Hello, world'")),
360 FurStringLiteralExpression(value='Hello, world'),
364 class FurFunctionCallExpressionParserTests(unittest.TestCase):
365 def test_parses_function_with_string_literal_argument(self):
367 _function_call_expression_parser(0, tokenization.tokenize("print('Hello, world')")),
371 FurFunctionCallExpression(
373 arguments=(FurStringLiteralExpression(value='Hello, world'),),