Added support for integers
[fur] / parsing.py
1 import collections
2
3 IntegerLiteral = collections.namedtuple(
4     'IntegerLiteral',
5     [
6         'value',
7     ],
8 )
9
10 StringLiteral = collections.namedtuple(
11     'StringLiteral',
12     [
13         'value',
14     ],
15 )
16
17 def _integer_literal_parser(index, tokens):
18     failure = (False, index, None)
19
20     if tokens[index].type != 'integer_literal':
21         return failure
22     value = int(tokens[index].match)
23     index += 1
24
25     return True, index, IntegerLiteral(value=value)
26
27 def _string_literal_parser(index, tokens):
28     failure = (False, index, None)
29
30     if tokens[index].type != 'single_quoted_string_literal':
31         return failure
32     value = tokens[index].match[1:-1]
33     index += 1
34
35     return True, index, StringLiteral(value=value)
36
37 def _argument_parser(index, tokens):
38     failure = (False, index, None)
39
40     for parser in [_integer_literal_parser, _string_literal_parser]:
41         success, index, value = parser(index, tokens)
42
43         if success:
44             return (success, index, value)
45
46     return failure
47
48
49 FunctionCall = collections.namedtuple(
50     'FunctionCall',
51     [
52         'name',
53         'arguments',
54     ],
55 )
56
57 def _function_call_parser(index, tokens):
58     failure = (False, index, None)
59
60     if tokens[index].type != 'symbol':
61         return failure
62     name = tokens[index].match
63     index += 1
64
65     if tokens[index].type != 'open_parenthese':
66         return failure
67     index += 1
68
69     success, index, argument = _argument_parser(index, tokens)
70
71     if not success:
72         return failure
73
74     if tokens[index].type != 'close_parenthese':
75         return failure
76     index += 1
77     
78     return True, index, FunctionCall(name=name, arguments=(argument,))
79
80 def _parse(parser, tokens):
81     success, index, result = parser(0, tokens)
82
83     if success:
84         return result
85
86     raise Exception('Unable to parse')
87
88
89 def parse(tokens):
90     return _parse(_function_call_parser, tokens)
91
92 if __name__ == '__main__':
93     import unittest
94
95     import tokenization
96
97     class StringLiteralParserTests(unittest.TestCase):
98         def test_parses_single_quoted_string_literal(self):
99             self.assertEqual(
100                 _string_literal_parser(0, tokenization.tokenize("'Hello, world'")),
101                 (
102                     True,
103                     1,
104                     StringLiteral(value='Hello, world'),
105                 ),
106             )
107
108     class FunctionCallParserTests(unittest.TestCase):
109         def test_parses_function_with_string_literal_argument(self):
110             self.assertEqual(
111                 _function_call_parser(0, tokenization.tokenize("print('Hello, world')")),
112                 (
113                     True,
114                     4,
115                     FunctionCall(
116                         name='print',
117                         arguments=(StringLiteral(value='Hello, world'),),
118                     ),
119                 ),
120             )
121
122     unittest.main()