From db1651d2c0e44a380f876b452f30c2244d3a0d06 Mon Sep 17 00:00:00 2001 From: David Kerkeslager Date: Fri, 4 Aug 2017 16:31:02 -0400 Subject: [PATCH] Handle multiple statements --- examples/03_multiple_statements.fur | 3 + .../03_multiple_statements.fur.output.txt | 3 + parsing.py | 59 +++++++++++++++---- tokenization.py | 2 +- transformation.py | 8 ++- util.py | 15 +++-- 6 files changed, 68 insertions(+), 22 deletions(-) create mode 100644 examples/03_multiple_statements.fur create mode 100644 examples/03_multiple_statements.fur.output.txt diff --git a/examples/03_multiple_statements.fur b/examples/03_multiple_statements.fur new file mode 100644 index 0000000..c3f47f8 --- /dev/null +++ b/examples/03_multiple_statements.fur @@ -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 index 0000000..18edf84 --- /dev/null +++ b/examples/03_multiple_statements.fur.output.txt @@ -0,0 +1,3 @@ +Hello, world +Goodnight, moon +Goodbye, cruel world \ No newline at end of file diff --git a/parsing.py b/parsing.py index 6b11745..03a1744 100644 --- a/parsing.py +++ b/parsing.py @@ -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 diff --git a/tokenization.py b/tokenization.py index 10ed80f..7733ab7 100644 --- a/tokenization.py +++ b/tokenization.py @@ -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 diff --git a/transformation.py b/transformation.py index ef4e9bf..f2bd2a7 100644 --- a/transformation.py +++ b/transformation.py @@ -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 --- 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), -- 2.20.1