Added a very rudimentary fur-to-c compiler
[fur] / parsing.py
1 import collections
2
3 StringLiteral = collections.namedtuple(
4     'StringLiteral',
5     [
6         'value',
7     ],
8 )
9
10 def _string_literal_parser(index, tokens):
11     failure = (False, index, None)
12
13     if tokens[index].type != 'single_quoted_string_literal':
14         return failure
15     value = tokens[index].match[1:-1]
16     index += 1
17
18     return True, index, StringLiteral(value=value)
19
20
21 FunctionCall = collections.namedtuple(
22     'FunctionCall',
23     [
24         'name',
25         'arguments',
26     ],
27 )
28
29 def _function_call_parser(index, tokens):
30     failure = (False, index, None)
31
32     if tokens[index].type != 'symbol':
33         return failure
34     name = tokens[index].match
35     index += 1
36
37     if tokens[index].type != 'open_parenthese':
38         return failure
39     index += 1
40
41     success, index, argument = _string_literal_parser(index, tokens)
42
43     if not success:
44         return failure
45
46     if tokens[index].type != 'close_parenthese':
47         return failure
48     index += 1
49     
50     return True, index, FunctionCall(name=name, arguments=(argument,))
51
52 def _parse(parser, tokens):
53     success, index, result = parser(0, tokens)
54
55     if success:
56         return result
57
58     raise Exception('Unable to parse')
59
60
61 def parse(tokens):
62     return _parse(_function_call_parser, tokens)
63
64 if __name__ == '__main__':
65     import unittest
66
67     import tokenization
68
69     class StringLiteralParserTests(unittest.TestCase):
70         def test_parses_single_quoted_string_literal(self):
71             self.assertEqual(
72                 _string_literal_parser(0, tokenization.tokenize("'Hello, world'")),
73                 (
74                     True,
75                     1,
76                     StringLiteral(value='Hello, world'),
77                 ),
78             )
79
80     class FunctionCallParserTests(unittest.TestCase):
81         def test_parses_function_with_string_literal_argument(self):
82             self.assertEqual(
83                 _function_call_parser(0, tokenization.tokenize("print('Hello, world')")),
84                 (
85                     True,
86                     4,
87                     FunctionCall(
88                         name='print',
89                         arguments=(StringLiteral(value='Hello, world'),),
90                     ),
91                 ),
92             )
93
94     unittest.main()