Handle multiple statements
authorDavid Kerkeslager <kerkeslager@gmail.com>
Fri, 4 Aug 2017 20:31:02 +0000 (16:31 -0400)
committerDavid Kerkeslager <kerkeslager@gmail.com>
Fri, 4 Aug 2017 20:31:02 +0000 (16:31 -0400)
examples/03_multiple_statements.fur [new file with mode: 0644]
examples/03_multiple_statements.fur.output.txt [new file with mode: 0644]
parsing.py
tokenization.py
transformation.py
util.py

diff --git a/examples/03_multiple_statements.fur b/examples/03_multiple_statements.fur
new file mode 100644 (file)
index 0000000..c3f47f8
--- /dev/null
@@ -0,0 +1,3 @@
+print('Hello, world\n')
+print('Goodnight, moon\n')
+print('Goodbye, cruel world')
diff --git a/examples/03_multiple_statements.fur.output.txt b/examples/03_multiple_statements.fur.output.txt
new file mode 100644 (file)
index 0000000..18edf84
--- /dev/null
@@ -0,0 +1,3 @@
+Hello, world
+Goodnight, moon
+Goodbye, cruel world
\ No newline at end of file
index 6b11745..03a1744 100644 (file)
@@ -1,5 +1,35 @@
 import collections
 
+def _or_parser(*parsers):
+    def result_parser(index, tokens):
+        failure = (False, index, None)
+
+        for parser in parsers:
+            success, index, value = parser(index, tokens)
+
+            if success:
+                return (success, index, value)
+
+        return failure
+
+    return result_parser
+
+def _zero_or_more_parser(formatter, parser):
+    def result_parser(index, tokens):
+        values = []
+
+        while index < len(tokens):
+            success, index, value = parser(index, tokens)
+
+            if success:
+                values.append(value)
+            else:
+                break
+
+        return (True, index, formatter(values))
+
+    return result_parser
+
 IntegerLiteral = collections.namedtuple(
     'IntegerLiteral',
     [
@@ -34,17 +64,7 @@ def _string_literal_parser(index, tokens):
 
     return True, index, StringLiteral(value=value)
 
-def _argument_parser(index, tokens):
-    failure = (False, index, None)
-
-    for parser in [_integer_literal_parser, _string_literal_parser]:
-        success, index, value = parser(index, tokens)
-
-        if success:
-            return (success, index, value)
-
-    return failure
-
+_argument_parser = _or_parser(_integer_literal_parser, _string_literal_parser)
 
 FunctionCall = collections.namedtuple(
     'FunctionCall',
@@ -54,6 +74,13 @@ FunctionCall = collections.namedtuple(
     ],
 )
 
+FurProgram = collections.namedtuple(
+    'FurProgram',
+    [
+        'statement_list',
+    ],
+)
+
 def _function_call_parser(index, tokens):
     failure = (False, index, None)
 
@@ -77,9 +104,17 @@ def _function_call_parser(index, tokens):
     
     return True, index, FunctionCall(name=name, arguments=(argument,))
 
+def _program_formatter(statement_list):
+    return FurProgram(statement_list=statement_list)
+
+_program_parser = _zero_or_more_parser(_program_formatter, _function_call_parser)
+
 def _parse(parser, tokens):
     success, index, result = parser(0, tokens)
 
+    if index < len(tokens):
+        raise Exception('Unable to parse token {}'.format(tokens[index]))
+
     if success:
         return result
 
@@ -87,7 +122,7 @@ def _parse(parser, tokens):
 
 
 def parse(tokens):
-    return _parse(_function_call_parser, tokens)
+    return _parse(_program_parser, tokens)
 
 if __name__ == '__main__':
     import unittest
index 10ed80f..7733ab7 100644 (file)
@@ -36,7 +36,7 @@ _TOKEN_MATCHERS = [
 
 _TOKEN_MATCHERS = list(map(_make_token_matcher, _TOKEN_MATCHERS))
 
-@util.force_generator
+@util.force_generator(tuple)
 def tokenize(source):
     index = 0
 
index ef4e9bf..f2bd2a7 100644 (file)
@@ -55,10 +55,12 @@ def transform_function_call_statement(builtin_dependencies, function_call):
     raise Exception()
 
 
-def transform(function_call):
+def transform(program):
     builtins = set()
 
-    statement = transform_function_call_statement(builtins, function_call)
+    c_statements = [
+        transform_function_call_statement(builtins, statement) for statement in program.statement_list
+    ]
 
     standard_libraries = set()
     for builtin in builtins:
@@ -67,7 +69,7 @@ def transform(function_call):
 
     return CProgram(
         builtins=builtins,
-        statements=[statement],
+        statements=c_statements,
         standard_libraries=standard_libraries,
     )
 
diff --git a/util.py b/util.py
index d73990d..678c516 100644 (file)
--- a/util.py
+++ b/util.py
@@ -1,18 +1,21 @@
 import functools
 
-def force_generator(generator_function):
-    @functools.wraps(generator_function)
-    def forced_generator(*args, **kwargs):
-        return list(generator_function(*args, **kwargs))
+def force_generator(to_type):
+    def decorator(generator_function):
+        @functools.wraps(generator_function)
+        def forced_generator(*args, **kwargs):
+            return to_type(generator_function(*args, **kwargs))
 
-    return forced_generator
+        return forced_generator
+
+    return decorator
 
 if __name__ == '__main__':
     import unittest
 
     class ForceGeneratorTests(unittest.TestCase):
         def test_forces_generator(self):
-            forced_range = force_generator(range)
+            forced_range = force_generator(list)(range)
 
             self.assertEqual(
                 forced_range(10),