3 # TODO Check max symbol length in assignments, function calls, and symbol expressions
6 def _or_parser(*parsers):
7 def result_parser(index, tokens):
8 failure = (False, index, None)
10 for parser in parsers:
11 success, index, value = parser(index, tokens)
14 return (success, index, value)
20 def _zero_or_more_parser(formatter, parser):
21 def result_parser(index, tokens):
24 while index < len(tokens):
25 success, index, value = parser(index, tokens)
32 return (True, index, formatter(values))
36 FurIntegerLiteralExpression = collections.namedtuple(
37 'FurIntegerLiteralExpression',
43 FurStringLiteralExpression = collections.namedtuple(
44 'FurStringLiteralExpression',
50 FurSymbolExpression = collections.namedtuple(
51 'FurSymbolExpression',
57 FurNegationExpression = collections.namedtuple(
58 'FurNegationExpression',
64 FurAdditionExpression = collections.namedtuple(
65 'FurAdditionExpression',
72 FurSubtractionExpression = collections.namedtuple(
73 'FurSubtractionExpression',
80 FurMultiplicationExpression = collections.namedtuple(
81 'FurMultiplicationExpression',
88 FurIntegerDivisionExpression = collections.namedtuple(
89 'FurIntegerDivisionExpression',
96 FurModularDivisionExpression = collections.namedtuple(
97 'FurModularDivisionExpression',
104 def _integer_literal_expression_parser(index, tokens):
105 failure = (False, index, None)
107 if tokens[index].type != 'integer_literal':
109 value = int(tokens[index].match)
112 return True, index, FurIntegerLiteralExpression(value=value)
114 def _string_literal_expression_parser(index, tokens):
115 if tokens[index].type == 'single_quoted_string_literal':
116 return (True, index + 1, FurStringLiteralExpression(value=tokens[index].match[1:-1]))
118 return (False, index, None)
120 def _symbol_expression_parser(index, tokens):
121 if tokens[index].type == 'symbol':
122 return (True, index + 1, FurSymbolExpression(value=tokens[index].match))
124 return (False, index, None)
126 def _negation_expression_parser(index, tokens):
127 failure = (False, index, None)
129 if tokens[index].match != '-':
132 success, index, value = _literal_level_expression_parser(index + 1, tokens)
137 return (True, index, FurNegationExpression(value=value))
139 def _literal_level_expression_parser(index, tokens):
141 _negation_expression_parser,
142 _function_call_expression_parser,
143 _integer_literal_expression_parser,
144 _string_literal_expression_parser,
145 _symbol_expression_parser,
148 def _multiplication_level_expression_parser(index, tokens):
149 failure = (False, index, None)
151 success, index, result = _literal_level_expression_parser(index, tokens)
156 while success and index < len(tokens) and tokens[index].type == 'multiplication_level_operator':
159 if index + 1 < len(tokens):
160 success, try_index, value = _literal_level_expression_parser(index + 1, tokens)
164 '*': FurMultiplicationExpression,
165 '//': FurIntegerDivisionExpression,
166 '%': FurModularDivisionExpression,
167 }[tokens[index].match](left=result, right=value)
170 return True, index, result
172 def _addition_level_expression_parser(index, tokens):
173 failure = (False, index, None)
175 success, index, result = _multiplication_level_expression_parser(index, tokens)
180 while success and index < len(tokens) and tokens[index].type == 'addition_level_operator':
183 if index + 1 < len(tokens):
184 success, try_index, value = _multiplication_level_expression_parser(index + 1, tokens)
188 '+': FurAdditionExpression,
189 '-': FurSubtractionExpression,
190 }[tokens[index].match](left=result, right=value)
193 return True, index, result
195 def _comma_separated_list_parser(index, tokens):
196 failure = (False, index, None)
200 success, index, expression = _addition_level_expression_parser(index, tokens)
203 expressions.append(expression)
207 while success and index < len(tokens) and tokens[index].type == 'comma':
210 if index + 1 < len(tokens):
211 success, try_index, expression = _addition_level_expression_parser(index + 1, tokens)
214 expressions.append(expression)
217 return True, index, tuple(expressions)
220 FurFunctionCallExpression = collections.namedtuple(
221 'FurFunctionCallExpression',
228 FurAssignmentStatement = collections.namedtuple(
229 'FurAssignmentStatement',
236 FurProgram = collections.namedtuple(
243 def _function_call_expression_parser(index, tokens):
244 # TODO Use a FurSymbolExpression for the name
245 failure = (False, index, None)
247 if tokens[index].type != 'symbol':
249 name = tokens[index].match
252 if tokens[index].type != 'open_parenthese':
256 success, index, arguments = _comma_separated_list_parser(index, tokens)
261 if tokens[index].type != 'close_parenthese':
262 raise Exception('Expected ")", found "{}" on line {}'.format(
268 return True, index, FurFunctionCallExpression(name=name, arguments=arguments)
270 _expression_parser = _multiplication_level_expression_parser
272 def _assignment_statement_parser(index, tokens):
273 # TODO Use a FurSymbolExpression for the target
274 failure = (False, index, None)
276 if tokens[index].type != 'symbol':
278 target = tokens[index].match
281 if tokens[index].type != 'assignment_operator':
283 assignment_operator_index = index
285 success, index, expression = _expression_parser(index + 1, tokens)
289 'Expected expression after assignment operator on line {}'.format(
290 tokens[assignment_operator_index].line
294 return True, index, FurAssignmentStatement(target=target, expression=expression)
296 def _statement_parser(index, tokens):
298 _assignment_statement_parser,
302 def _program_formatter(statement_list):
303 return FurProgram(statement_list=statement_list)
305 _program_parser = _zero_or_more_parser(_program_formatter, _statement_parser)
307 def _parse(parser, tokens):
308 success, index, result = parser(0, tokens)
310 if index < len(tokens):
311 raise Exception('Unable to parse token {}'.format(tokens[index]))
316 raise Exception('Unable to parse')
319 return _parse(_program_parser, tokens)
321 if __name__ == '__main__':
326 class FurStringLiteralExpressionParserTests(unittest.TestCase):
327 def test_parses_single_quoted_string_literal(self):
329 _string_literal_expression_parser(0, tokenization.tokenize("'Hello, world'")),
333 FurStringLiteralExpression(value='Hello, world'),
337 class FurFunctionCallExpressionParserTests(unittest.TestCase):
338 def test_parses_function_with_string_literal_argument(self):
340 _function_call_expression_parser(0, tokenization.tokenize("print('Hello, world')")),
344 FurFunctionCallExpression(
346 arguments=(FurStringLiteralExpression(value='Hello, world'),),