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 FurAdditionExpression = collections.namedtuple(
62 'FurAdditionExpression',
69 FurSubtractionExpression = collections.namedtuple(
70 'FurSubtractionExpression',
77 FurMultiplicationExpression = collections.namedtuple(
78 'FurMultiplicationExpression',
85 FurIntegerDivisionExpression = collections.namedtuple(
86 'FurIntegerDivisionExpression',
93 FurModularDivisionExpression = collections.namedtuple(
94 'FurModularDivisionExpression',
101 def _integer_literal_expression_parser(index, tokens):
102 failure = (False, index, None)
104 if tokens[index].type != 'integer_literal':
106 value = int(tokens[index].match)
109 return True, index, FurIntegerLiteralExpression(value=value)
111 def _string_literal_expression_parser(index, tokens):
112 if tokens[index].type == 'single_quoted_string_literal':
113 return (True, index + 1, FurStringLiteralExpression(value=tokens[index].match[1:-1]))
115 return (False, index, None)
117 def _symbol_expression_parser(index, tokens):
118 if tokens[index].type == 'symbol':
119 return (True, index + 1, FurSymbolExpression(value=tokens[index].match))
121 return (False, index, None)
123 def _negation_expression_parser(index, tokens):
124 failure = (False, index, None)
126 if tokens[index].match != '-':
129 success, index, value = _literal_level_expression_parser(index + 1, tokens)
134 return (True, index, FurNegationExpression(value=value))
136 def _literal_level_expression_parser(index, tokens):
138 _negation_expression_parser,
139 _function_call_expression_parser,
140 _integer_literal_expression_parser,
141 _string_literal_expression_parser,
142 _symbol_expression_parser,
145 def _multiplication_level_expression_parser(index, tokens):
146 failure = (False, index, None)
148 success, index, result = _literal_level_expression_parser(index, tokens)
153 while success and index < len(tokens) and tokens[index].type == 'multiplication_level_operator':
156 if index + 1 < len(tokens):
157 success, try_index, value = _literal_level_expression_parser(index + 1, tokens)
161 '*': FurMultiplicationExpression,
162 '//': FurIntegerDivisionExpression,
163 '%': FurModularDivisionExpression,
164 }[tokens[index].match](left=result, right=value)
167 return True, index, result
169 def _addition_level_expression_parser(index, tokens):
170 failure = (False, index, None)
172 success, index, result = _multiplication_level_expression_parser(index, tokens)
177 while success and index < len(tokens) and tokens[index].type == 'addition_level_operator':
180 if index + 1 < len(tokens):
181 success, try_index, value = _multiplication_level_expression_parser(index + 1, tokens)
185 '+': FurAdditionExpression,
186 '-': FurSubtractionExpression,
187 }[tokens[index].match](left=result, right=value)
190 return True, index, result
192 def _comma_separated_list_parser(index, tokens):
193 failure = (False, index, None)
197 success, index, expression = _addition_level_expression_parser(index, tokens)
200 expressions.append(expression)
204 while success and index < len(tokens) and tokens[index].type == 'comma':
207 if index + 1 < len(tokens):
208 success, try_index, expression = _addition_level_expression_parser(index + 1, tokens)
211 expressions.append(expression)
214 return True, index, tuple(expressions)
217 FurFunctionCallExpression = collections.namedtuple(
218 'FurFunctionCallExpression',
225 FurAssignmentStatement = collections.namedtuple(
226 'FurAssignmentStatement',
233 FurProgram = collections.namedtuple(
240 def _function_call_expression_parser(index, tokens):
241 # TODO Use a FurSymbolExpression for the name
242 failure = (False, index, None)
244 success, index, function = _symbol_expression_parser(index, tokens)
249 if tokens[index].type != 'open_parenthese':
253 success, index, arguments = _comma_separated_list_parser(index, tokens)
258 if tokens[index].type != 'close_parenthese':
259 raise Exception('Expected ")", found "{}" on line {}'.format(
265 return True, index, FurFunctionCallExpression(function=function, arguments=arguments)
267 _expression_parser = _multiplication_level_expression_parser
269 def _assignment_statement_parser(index, tokens):
270 # TODO Use a FurSymbolExpression for the target
271 failure = (False, index, None)
273 if tokens[index].type != 'symbol':
275 target = tokens[index].match
278 if tokens[index].type != 'assignment_operator':
280 assignment_operator_index = index
282 success, index, expression = _expression_parser(index + 1, tokens)
286 'Expected expression after assignment operator on line {}'.format(
287 tokens[assignment_operator_index].line
291 return True, index, FurAssignmentStatement(target=target, expression=expression)
293 def _statement_parser(index, tokens):
295 _assignment_statement_parser,
299 def _program_formatter(statement_list):
300 return FurProgram(statement_list=statement_list)
302 _program_parser = _zero_or_more_parser(_program_formatter, _statement_parser)
304 def _parse(parser, tokens):
305 success, index, result = parser(0, tokens)
307 if index < len(tokens):
308 raise Exception('Unable to parse token {}'.format(tokens[index]))
313 raise Exception('Unable to parse')
316 return _parse(_program_parser, tokens)
318 if __name__ == '__main__':
323 class FurStringLiteralExpressionParserTests(unittest.TestCase):
324 def test_parses_single_quoted_string_literal(self):
326 _string_literal_expression_parser(0, tokenization.tokenize("'Hello, world'")),
330 FurStringLiteralExpression(value='Hello, world'),
334 class FurFunctionCallExpressionParserTests(unittest.TestCase):
335 def test_parses_function_with_string_literal_argument(self):
337 _function_call_expression_parser(0, tokenization.tokenize("print('Hello, world')")),
341 FurFunctionCallExpression(
343 arguments=(FurStringLiteralExpression(value='Hello, world'),),