Desugaring pass (#9)
authorDavid Kerkeslager <kerkeslager@gmail.com>
Sun, 31 Dec 2017 03:38:04 +0000 (22:38 -0500)
committerGitHub <noreply@github.com>
Sun, 31 Dec 2017 03:38:04 +0000 (22:38 -0500)
* Implemented the desugaring pass, except for exception support; also badly needs cleanup of dead code

* Pass through metadata to end of desugaring phase (for error reporting)

* Pass through more metadata, package it at tokenization phase

* Added error handling to desugared code

* Add line numbers to function call errors, clean up

* Delete dead code

desugaring.py
examples/29_division_by_zero.fur.stderr.txt
generation.py
normalization.py
parsing.py
templates/function_definition.c
templates/program.c
tokenization.py
transformation.py

index ef51639..e671e04 100644 (file)
@@ -1,5 +1,93 @@
 import collections
 
+import parsing
+
+DesugaredFunctionCallExpression = collections.namedtuple(
+    'DesugaredFunctionCallExpression',
+    (
+        'metadata',
+        'function',
+        'argument_list',
+    ),
+)
+
+DesugaredIfExpression = collections.namedtuple(
+    'DesugaredIfExpression',
+    (
+        'condition_expression',
+        'if_statement_list',
+        'else_statement_list',
+    ),
+)
+
+DesugaredIntegerLiteralExpression = collections.namedtuple(
+    'DesugaredIntegerLiteralExpression',
+    (
+        'integer',
+    ),
+)
+
+DesugaredListLiteralExpression = collections.namedtuple(
+    'DesugaredListLiteralExpression',
+    (
+        'item_expression_list',
+    ),
+)
+
+DesugaredStringLiteralExpression = collections.namedtuple(
+    'DesugaredStringLiteralExpression',
+    (
+        'string',
+    ),
+)
+
+DesugaredSymbolExpressionPair = collections.namedtuple(
+    'DesugaredSymbolExpressionPair',
+    (
+        'symbol',
+        'expression',
+    ),
+)
+
+DesugaredStructureLiteralExpression = collections.namedtuple(
+    'DesugaredStructureLiteralExpression',
+    (
+        'fields',
+    ),
+)
+
+DesugaredSymbolExpression = collections.namedtuple(
+    'DesugaredSymbolExpression',
+    (
+        'metadata',
+        'symbol',
+    ),
+)
+
+DesugaredAssignmentStatement = collections.namedtuple(
+    'DesugaredAssignmentStatement',
+    (
+        'target',
+        'expression',
+    ),
+)
+
+DesugaredExpressionStatement = collections.namedtuple(
+    'DesugaredExpressionStatement',
+    (
+        'expression',
+    ),
+)
+
+DesugaredFunctionDefinitionStatement = collections.namedtuple(
+    'DesugaredFunctionDefinitionStatement',
+    (
+        'name',
+        'argument_name_list',
+        'statement_list',
+    ),
+)
+
 DesugaredProgram = collections.namedtuple(
     'DesugaredProgram',
     (
@@ -7,7 +95,189 @@ DesugaredProgram = collections.namedtuple(
     ),
 )
 
+def desugar_function_call_expression(expression):
+    return DesugaredFunctionCallExpression(
+        metadata=expression.metadata,
+        function=desugar_expression(expression.function),
+        argument_list=tuple(desugar_expression(e) for e in expression.arguments),
+    )
+
+def desugar_if_expression(expression):
+    return DesugaredIfExpression(
+        condition_expression=desugar_expression(expression.condition_expression),
+        if_statement_list=tuple(desugar_statement(s) for s in expression.if_statement_list),
+        else_statement_list=tuple(desugar_statement(s) for s in expression.else_statement_list),
+    )
+
+def desugar_infix_expression(expression):
+    if expression.operator == 'and':
+        return DesugaredIfExpression(
+            condition_expression=desugar_expression(expression.left),
+            if_statement_list=(
+                DesugaredExpressionStatement(expression=desugar_expression(expression.right)),
+            ),
+            else_statement_list=(
+                DesugaredExpressionStatement(
+                    expression=DesugaredSymbolExpression(
+                        metadata=expression.metadata,
+                        symbol='false',
+                    ),
+                ),
+            ),
+        )
+
+    if expression.operator == 'or':
+        return DesugaredIfExpression(
+            condition_expression=desugar_expression(expression.left),
+            if_statement_list=(
+                DesugaredExpressionStatement(
+                    expression=DesugaredSymbolExpression(
+                        metadata=expression.metadata,
+                        symbol='true',
+                    ),
+                ),
+            ),
+            else_statement_list=(
+                DesugaredExpressionStatement(expression=desugar_expression(expression.right)),
+            ),
+        )
+
+    if expression.operator == '.':
+        return DesugaredFunctionCallExpression(
+            metadata=expression.metadata,
+            function=DesugaredSymbolExpression(
+                metadata=expression.metadata,
+                symbol='__field__',
+            ),
+            argument_list=(
+                desugar_expression(expression.left),
+                DesugaredStringLiteralExpression(string=expression.right.symbol),
+            ),
+        )
+
+    function = {
+        '++': '__concat__',
+        '+': '__add__',
+        '-': '__subtract__',
+        '*': '__multiply__',
+        '//': '__integer_divide__',
+        '%': '__modular_divide__',
+        '<': '__lt__',
+        '>': '__gt__',
+        '<=': '__lte__',
+        '>=': '__gte__',
+        '==': '__eq__',
+        '!=': '__neq__',
+    }[expression.operator]
+
+    return DesugaredFunctionCallExpression(
+        metadata=expression.metadata,
+        function=DesugaredSymbolExpression(
+            metadata=expression.metadata,
+            symbol=function,
+        ),
+        argument_list=(
+            desugar_expression(expression.left),
+            desugar_expression(expression.right),
+        ),
+    )
+
+def desugar_integer_literal_expression(expression):
+    return DesugaredIntegerLiteralExpression(
+        integer=expression.integer,
+    )
+
+def desugar_list_item_expression(expression):
+    return DesugaredFunctionCallExpression(
+        metadata=expression.metadata,
+        function=DesugaredSymbolExpression(
+            metadata=expression.metadata,
+            symbol='__get__',
+        ),
+        argument_list=(
+            desugar_expression(expression.list_expression),
+            desugar_expression(expression.index_expression),
+        ),
+    )
+
+def desugar_list_literal_expression(expression):
+    return DesugaredListLiteralExpression(
+        item_expression_list=tuple(desugar_expression(i) for i in expression.item_expression_list),
+    )
+
+def desugar_negation_expression(expression):
+    return DesugaredFunctionCallExpression(
+        metadata=expression.metadata,
+        function=DesugaredSymbolExpression(
+            metadata=expression.metadata,
+            symbol='__negate__',
+        ),
+        argument_list=(
+            desugar_expression(expression.value),
+        ),
+    )
+
+def desugar_string_literal_expression(expression):
+    return DesugaredStringLiteralExpression(
+        string=expression.string,
+    )
+
+def desugar_structure_literal_expression(expression):
+    return DesugaredStructureLiteralExpression(
+        fields=tuple(
+            DesugaredSymbolExpressionPair(
+                symbol=p.symbol,
+                expression=desugar_expression(p.expression),
+            ) for p in expression.fields
+        ),
+    )
+
+def desugar_symbol_expression(expression):
+    return DesugaredSymbolExpression(
+        metadata=expression.metadata,
+        symbol=expression.symbol,
+    )
+
+def desugar_expression(expression):
+    return {
+        parsing.FurFunctionCallExpression: desugar_function_call_expression,
+        parsing.FurIfExpression: desugar_if_expression,
+        parsing.FurInfixExpression: desugar_infix_expression,
+        parsing.FurIntegerLiteralExpression: desugar_integer_literal_expression,
+        parsing.FurListItemExpression: desugar_list_item_expression,
+        parsing.FurListLiteralExpression: desugar_list_literal_expression,
+        parsing.FurNegationExpression: desugar_negation_expression,
+        parsing.FurStringLiteralExpression: desugar_string_literal_expression,
+        parsing.FurStructureLiteralExpression: desugar_structure_literal_expression,
+        parsing.FurSymbolExpression: desugar_symbol_expression,
+    }[type(expression)](expression)
+
+def desugar_assignment_statement(statement):
+    return DesugaredAssignmentStatement(
+        target=statement.target,
+        expression=desugar_expression(statement.expression),
+    )
+
+def desugar_expression_statement(statement):
+    return DesugaredExpressionStatement(
+        expression=desugar_expression(statement.expression),
+    )
+
+def desugar_function_definition_statement(statement):
+    return DesugaredFunctionDefinitionStatement(
+        name=statement.name,
+        argument_name_list=statement.argument_name_list,
+        statement_list=tuple(desugar_statement(s) for s in statement.statement_list),
+    )
+
+def desugar_statement(statement):
+    return {
+        parsing.FurAssignmentStatement: desugar_assignment_statement,
+        parsing.FurExpressionStatement: desugar_expression_statement,
+        parsing.FurFunctionDefinitionStatement: desugar_function_definition_statement,
+    }[type(statement)](statement)
+
 def desugar(program):
     return DesugaredProgram(
-        statement_list=program.statement_list,
+        statement_list=[desugar_statement(s) for s in program.statement_list],
     )
index 9d45c1d..7b22109 100644 (file)
@@ -1,3 +1,3 @@
 DivisionByZeroError on line 2
-       in get_divided_answer
+       in get_divided_answer on line 5
        in __main__
index 64554d0..b2e191e 100644 (file)
@@ -26,12 +26,6 @@ def generate_symbol_expression(symbol_expression):
 def generate_variable_expression(expression):
     return expression.variable
 
-def generate_function_call_for_fur_infix_operator(expression):
-    return 'operator${}(stack, jump, {})'.format(
-        expression.name,
-        expression.metadata.line,
-    )
-
 def generate_structure_literal_expression(expression):
     return 'Structure_construct({}, {}, {})'.format(
         expression.field_count,
@@ -39,13 +33,6 @@ def generate_structure_literal_expression(expression):
         expression.value_list_variable,
     )
 
-def generate_dot_expression(expression):
-    return 'Structure_get(&{}, SYMBOL_LIST[{}] /* symbol: "{}" */)'.format(
-        generate_variable_expression(expression.instance),
-        expression.symbol_list_index,
-        expression.symbol,
-    )
-
 def generate_list_construct_expression(expression):
     return 'List_construct({})'.format(expression.allocate)
 
@@ -57,34 +44,27 @@ def generate_list_get_expression(expression):
 
 def generate_expression(expression):
     return {
-        transformation.CDotExpression: generate_dot_expression,
         transformation.CFunctionCallExpression: generate_function_call,
-        transformation.CFunctionCallForFurInfixOperator: generate_function_call_for_fur_infix_operator,
         transformation.CIntegerLiteral: generate_integer_literal,
         transformation.CListConstructExpression: generate_list_construct_expression,
         transformation.CListGetExpression: generate_list_get_expression,
-        transformation.CNegationExpression: generate_negation_expression,
         transformation.CStringLiteral: generate_string_literal,
         transformation.CStructureLiteralExpression: generate_structure_literal_expression,
         transformation.CSymbolExpression: generate_symbol_expression,
         transformation.CVariableExpression: generate_variable_expression,
     }[type(expression)](expression)
 
-def generate_negation_expression(c_negation_expression):
-    return 'operator$negate({})'.format(
-        generate_expression(c_negation_expression.value)
-    )
-
 def generate_function_call(function_call):
     # This gets called twice, so we want to be sure it is efficient and without side effects
     assert isinstance(function_call.function_expression, transformation.CVariableExpression)
 
     # TODO Check the type of the things being called
     function_expression = generate_variable_expression(function_call.function_expression)
-    return '{}.instance.closure.call(environmentPool, {}.instance.closure.closed, {}, stack, jump)'.format(
+    return '{}.instance.closure.call(environmentPool, {}.instance.closure.closed, {}, stack, {}, jump)'.format(
         function_expression,
         function_expression,
         function_call.argument_count,
+        function_call.metadata.line,
     )
 
 def generate_expression_statement(statement):
index f2b7b13..40e3afd 100644 (file)
@@ -1,6 +1,6 @@
 import collections
 
-import parsing
+import desugaring
 import util
 
 NormalVariableExpression = collections.namedtuple(
@@ -31,30 +31,6 @@ NormalSymbolExpression = collections.namedtuple(
     ],
 )
 
-NormalNegationExpression = collections.namedtuple(
-    'NormalNegationExpression',
-    [
-        'internal_expression',
-    ],
-)
-
-NormalDotExpression = collections.namedtuple(
-    'NormalDotExpression',
-    [
-        'instance',
-        'field',
-    ],
-)
-
-NormalInfixExpression = collections.namedtuple(
-    'NormalInfixExpression',
-    [
-        'metadata',
-        'order',
-        'operator',
-    ],
-)
-
 NormalPushStatement = collections.namedtuple(
     'NormalPushStatement',
     (
@@ -65,6 +41,7 @@ NormalPushStatement = collections.namedtuple(
 NormalFunctionCallExpression = collections.namedtuple(
     'NormalFunctionCallExpression',
     [
+        'metadata',
         'function_expression',
         'argument_count',
     ],
@@ -142,9 +119,6 @@ NormalProgram = collections.namedtuple(
     ],
 )
 
-def fake_normalization(counter, thing):
-    return (counter, (), thing)
-
 def normalize_integer_literal_expression(counter, expression):
     variable = '${}'.format(counter)
     return (
@@ -328,11 +302,9 @@ def normalize_symbol_expression(counter, expression):
     )
 
 def normalize_function_call_expression(counter, expression):
-    assert isinstance(expression, parsing.FurFunctionCallExpression)
-
     prestatements = []
 
-    for argument in expression.arguments:
+    for argument in expression.argument_list:
         counter, argument_prestatements, normalized_argument = normalize_expression(counter, argument)
 
         for s in argument_prestatements:
@@ -381,8 +353,9 @@ def normalize_function_call_expression(counter, expression):
         NormalVariableInitializationStatement(
             variable=result_variable,
             expression=NormalFunctionCallExpression(
+                metadata=expression.metadata,
                 function_expression=function_expression,
-                argument_count=len(expression.arguments),
+                argument_count=len(expression.argument_list),
             ),
         )
     )
@@ -393,156 +366,6 @@ def normalize_function_call_expression(counter, expression):
         NormalVariableExpression(variable=result_variable),
     )
 
-def normalize_basic_infix_operation(counter, expression):
-    counter, left_prestatements, left_expression = normalize_expression(counter, expression.left)
-    counter, right_prestatements, right_expression = normalize_expression(counter, expression.right)
-
-    center_variable = '${}'.format(counter)
-    counter += 1
-
-    root_prestatements = (
-        NormalPushStatement(expression=left_expression),
-        NormalPushStatement(expression=right_expression),
-        NormalVariableInitializationStatement(
-            variable=center_variable,
-            expression=NormalInfixExpression(
-                metadata=expression.metadata,
-                order=expression.order,
-                operator=expression.operator,
-            ),
-        ),
-    )
-
-    return (
-        counter,
-        left_prestatements + right_prestatements + root_prestatements,
-        NormalVariableExpression(variable=center_variable),
-    )
-
-def desugar_ternary_comparison(counter, expression):
-    counter, left_prestatements, left_expression = normalize_expression(counter, expression.left.left)
-    counter, middle_prestatements, middle_expression = normalize_expression(counter, expression.left.right)
-
-    left_variable = '${}'.format(counter)
-    counter += 1
-    middle_variable = '${}'.format(counter)
-    counter += 1
-
-    # TODO Is there a memory leak if the middle expression throws an exception because the first expression result hasn't been added to the stack?
-    juncture_prestatements = (
-        NormalVariableInitializationStatement(
-            variable=left_variable,
-            expression=left_expression,
-        ),
-        NormalVariableInitializationStatement(
-            variable=middle_variable,
-            expression=middle_expression,
-        )
-    )
-
-    counter, boolean_expression_prestatements, boolean_expression =  normalize_boolean_expression(
-        counter,
-        parsing.FurInfixExpression(
-            metadata=expression.left.metadata,
-            order='and_level',
-            operator='and',
-            left=parsing.FurInfixExpression(
-                metadata=expression.left.metadata,
-                order='comparison_level',
-                operator=expression.left.operator,
-                left=NormalVariableExpression(variable=left_variable),
-                right=NormalVariableExpression(variable=middle_variable),
-            ),
-            right=parsing.FurInfixExpression(
-                metadata=expression.metadata,
-                order='comparison_level',
-                operator=expression.operator,
-                left=NormalVariableExpression(variable=middle_variable),
-                right=expression.right,
-            ),
-        )
-    )
-
-    return (
-        counter,
-        left_prestatements + middle_prestatements + juncture_prestatements + boolean_expression_prestatements,
-        boolean_expression,
-    )
-
-def normalize_comparison_expression(counter, expression):
-    if isinstance(expression.left, parsing.FurInfixExpression) and expression.order == 'comparison_level':
-        return desugar_ternary_comparison(counter, expression)
-
-    return normalize_basic_infix_operation(counter, expression)
-
-def normalize_boolean_expression(counter, expression):
-    counter, left_prestatements, left_expression = normalize_expression(counter, expression.left)
-    counter, right_prestatements, right_expression = normalize_expression(counter, expression.right)
-
-    result_variable = '${}'.format(counter)
-    if_else_prestatment = NormalVariableInitializationStatement(
-        variable=result_variable,
-        expression=left_expression,
-    )
-    counter += 1
-
-    condition_expression=NormalVariableExpression(variable=result_variable)
-    short_circuited_statements = right_prestatements + (NormalVariableReassignmentStatement(variable=result_variable, expression=right_expression),)
-
-    if expression.operator == 'and':
-        if_else_statement = NormalIfElseStatement(
-            condition_expression=condition_expression,
-            if_statement_list=short_circuited_statements,
-            else_statement_list=(),
-        )
-
-    elif expression.operator == 'or':
-        if_else_statement = NormalIfElseStatement(
-            condition_expression=condition_expression,
-            if_statement_list=(),
-            else_statement_list=short_circuited_statements,
-        )
-
-    else:
-        raise Exception('Unable to handle operator "{}"'.format(expression.operator))
-
-    return (
-        counter,
-        left_prestatements + (if_else_prestatment, if_else_statement),
-        NormalVariableExpression(variable=result_variable),
-    )
-
-def normalize_dot_expression(counter, expression):
-    assert isinstance(expression.right, parsing.FurSymbolExpression)
-
-    counter, prestatements, left_expression = normalize_expression(counter, expression.left)
-
-    variable = '${}'.format(counter)
-
-    dot_expression_prestatement = NormalVariableInitializationStatement(
-        variable=variable,
-        expression=NormalDotExpression(
-            instance=left_expression,
-            field=expression.right.symbol,
-        ),
-    )
-
-    return (
-        counter + 1,
-        prestatements + (dot_expression_prestatement,),
-        NormalVariableExpression(variable=variable),
-    )
-
-def normalize_infix_expression(counter, expression):
-    return {
-        'multiplication_level': normalize_basic_infix_operation,
-        'addition_level': normalize_basic_infix_operation,
-        'comparison_level': normalize_comparison_expression,
-        'dot_level': normalize_dot_expression,
-        'and_level': normalize_boolean_expression,
-        'or_level': normalize_boolean_expression,
-    }[expression.order](counter, expression)
-
 def normalize_if_expression(counter, expression):
     counter, condition_prestatements, condition_expression = normalize_expression(
         counter,
@@ -579,37 +402,15 @@ def normalize_if_expression(counter, expression):
         NormalVariableExpression(variable=result_variable),
     )
 
-def normalize_negation_expression(counter, expression):
-    counter, prestatements, internal_expression = normalize_expression(counter, expression.value)
-
-    internal_variable = '${}'.format(counter)
-    counter += 1
-
-    return (
-        counter,
-        prestatements + (
-            NormalVariableInitializationStatement(
-                variable=internal_variable,
-                expression=internal_expression,
-            ),
-        ),
-        NormalNegationExpression(internal_expression=NormalVariableExpression(variable=internal_variable)),
-    )
-
 def normalize_expression(counter, expression):
     return {
-        NormalInfixExpression: fake_normalization,
-        NormalVariableExpression: fake_normalization,
-        parsing.FurFunctionCallExpression: normalize_function_call_expression,
-        parsing.FurIfExpression: normalize_if_expression,
-        parsing.FurInfixExpression: normalize_infix_expression,
-        parsing.FurIntegerLiteralExpression: normalize_integer_literal_expression,
-        parsing.FurListLiteralExpression: normalize_list_literal_expression,
-        parsing.FurListItemExpression: normalize_list_item_expression,
-        parsing.FurNegationExpression: normalize_negation_expression,
-        parsing.FurStringLiteralExpression: normalize_string_literal_expression,
-        parsing.FurStructureLiteralExpression: normalize_structure_literal_expression,
-        parsing.FurSymbolExpression: normalize_symbol_expression,
+        desugaring.DesugaredFunctionCallExpression: normalize_function_call_expression,
+        desugaring.DesugaredIfExpression: normalize_if_expression,
+        desugaring.DesugaredIntegerLiteralExpression: normalize_integer_literal_expression,
+        desugaring.DesugaredListLiteralExpression: normalize_list_literal_expression,
+        desugaring.DesugaredStringLiteralExpression: normalize_string_literal_expression,
+        desugaring.DesugaredStructureLiteralExpression: normalize_structure_literal_expression,
+        desugaring.DesugaredSymbolExpression: normalize_symbol_expression,
     }[type(expression)](counter, expression)
 
 def normalize_expression_statement(counter, statement):
@@ -654,9 +455,9 @@ def normalize_assignment_statement(counter, statement):
 
 def normalize_statement(counter, statement):
     return {
-        parsing.FurAssignmentStatement: normalize_assignment_statement,
-        parsing.FurExpressionStatement: normalize_expression_statement,
-        parsing.FurFunctionDefinitionStatement: normalize_function_definition_statement,
+        desugaring.DesugaredAssignmentStatement: normalize_assignment_statement,
+        desugaring.DesugaredExpressionStatement: normalize_expression_statement,
+        desugaring.DesugaredFunctionDefinitionStatement: normalize_function_definition_statement,
     }[type(statement)](counter, statement)
 
 @util.force_generator(tuple)
index 12b93f5..014d74b 100644 (file)
@@ -36,14 +36,6 @@ def _zero_or_more_parser(formatter, parser):
 
     return result_parser
 
-NodeMetadata = collections.namedtuple(
-    'NodeMetadata',
-    [
-        'index',
-        'line',
-    ],
-)
-
 FurIntegerLiteralExpression = collections.namedtuple(
     'FurIntegerLiteralExpression',
     [
@@ -61,6 +53,7 @@ FurStringLiteralExpression = collections.namedtuple(
 FurSymbolExpression = collections.namedtuple(
     'FurSymbolExpression',
     [
+        'metadata',
         'symbol',
     ],
 )
@@ -68,6 +61,7 @@ FurSymbolExpression = collections.namedtuple(
 FurNegationExpression = collections.namedtuple(
     'FurNegationExpression',
     [
+        'metadata',
         'value',
     ],
 )
@@ -135,7 +129,14 @@ def _string_literal_expression_parser(index, tokens):
 
 def _symbol_expression_parser(index, tokens):
     if tokens[index].type == 'symbol':
-        return (True, index + 1, FurSymbolExpression(symbol=tokens[index].match))
+        return (
+            True,
+            index + 1,
+            FurSymbolExpression(
+                metadata=tokens[index].metadata,
+                symbol=tokens[index].match,
+            ),
+        )
 
     return (False, index, None)
 
@@ -249,12 +250,14 @@ def _negation_expression_parser(index, tokens):
     if tokens[index].match != '-':
         return failure
 
+    metadata = tokens[index].metadata
+
     success, index, value = _dot_expression_parser(index + 1, tokens)
 
     if not success:
         return failure
 
-    return (True, index, FurNegationExpression(value=value))
+    return (True, index, FurNegationExpression(metadata=metadata, value=value))
 
 def _negation_level_expression_parser(index, tokens):
     return _or_parser(
@@ -279,10 +282,7 @@ def _left_recursive_infix_operator_parser(operator_token_matcher, operand_parser
 
             if success:
                 result = FurInfixExpression(
-                    metadata=NodeMetadata(
-                        index=tokens[index].index,
-                        line=tokens[index].line,
-                    ),
+                    metadata=tokens[index].metadata,
                     order=order,
                     operator=tokens[index].match,
                     left=result,
@@ -368,6 +368,7 @@ FurListItemExpression = collections.namedtuple(
     'FurListItemExpression',
     [
         'list_expression',
+        'metadata',
         'index_expression',
     ],
 )
@@ -375,6 +376,7 @@ FurListItemExpression = collections.namedtuple(
 FurFunctionCallExpression = collections.namedtuple(
     'FurFunctionCallExpression',
     [
+        'metadata',
         'function',
         'arguments',
     ],
@@ -424,6 +426,8 @@ def _list_item_expression_parser(index, tokens):
     if not success:
         return failure
 
+    metadata = tokens[index].metadata
+
     success, index, index_expression = _bracket_wrapped_parser(_expression_parser)(
         index,
         tokens,
@@ -437,9 +441,12 @@ def _list_item_expression_parser(index, tokens):
         # We can't give this a better name without a bunch of checks, however.
         list_expression = FurListItemExpression(
             list_expression=list_expression,
+            metadata=metadata,
             index_expression=index_expression,
         )
 
+        metadata = tokens[index].metadata
+
         success, index, index_expression = _bracket_wrapped_parser(_expression_parser)(
             index,
             tokens,
@@ -460,6 +467,8 @@ def _function_call_expression_parser(index, tokens):
     if not success:
         return failure
 
+    metadata = tokens[index].metadata
+
     success, index, arguments = _parenthese_wrapped_parser(_comma_separated_expression_list_parser)(
         index,
         tokens,
@@ -472,10 +481,13 @@ def _function_call_expression_parser(index, tokens):
         # "function" is actually the full function call if the next parse attempt doesn't succeed
         # We can't give this a better name without a bunch of checks, however.
         function = FurFunctionCallExpression(
+            metadata=metadata,
             function=function,
             arguments=arguments,
         )
 
+        metadata = tokens[index].metadata
+
         success, index, arguments = _parenthese_wrapped_parser(_comma_separated_expression_list_parser)(
             index,
             tokens,
@@ -549,7 +561,7 @@ def _assignment_statement_parser(index, tokens):
 
     if tokens[index].type == 'symbol':
         target = tokens[index].match
-        target_assignment_line = tokens[index].line
+        target_assignment_line = tokens[index].metadata.line
 
         index += 1
     else:
index 1fc85e4..034a2af 100644 (file)
@@ -4,6 +4,7 @@ Object user${{name}}$implementation(
     Environment* environment,
     size_t argc,
     Stack* stack,
+    const unsigned long line,
     jmp_buf parentJump)
 {
   environment = Environment_construct(environmentPool, environment);
@@ -13,7 +14,7 @@ Object user${{name}}$implementation(
   jmp_buf jump;
   if(setjmp(jump) != 0)
   {
-    fprintf(stderr, "\tin {{name}}\n");
+    fprintf(stderr, "\tin {{name}} on line %zu\n", line);
 
     Stack_rewind(stack, stackSnapshot);
     Environment_setLive(environment, false);
index 25f9acb..f8095bf 100644 (file)
@@ -67,7 +67,7 @@ typedef struct Closure Closure;
 struct Closure
 {
   Environment* closed;
-  Object (*call)(EnvironmentPool*, Environment*, size_t, Stack*, jmp_buf);
+  Object (*call)(EnvironmentPool*, Environment*, size_t, Stack*, const unsigned long, jmp_buf);
 };
 
 struct List;
@@ -573,20 +573,105 @@ Object stringLiteral(const char* literal)
   return result;
 }
 
-// TODO Make this conditionally added
-Object operator$negate(Object input)
+{% if 'pow' in builtins %}
+Object builtin$pow$implementation(
+    EnvironmentPool* environmentPool,
+    Environment* parent,
+    size_t argc,
+    Stack* stack,
+    const unsigned long line,
+    jmp_buf parentJump)
 {
-  assert(input.type == INTEGER);
+  // Must unload items in reverse order
+  Object exponent = Stack_pop(stack);
+  Object base = Stack_pop(stack);
+
+  assert(base.type == INTEGER);
+  assert(exponent.type == INTEGER);
 
   Object result;
   result.type = INTEGER;
-  result.instance.integer = -input.instance.integer;
+  result.instance.integer = pow(base.instance.integer, exponent.instance.integer);
   return result;
 }
 
-// TODO Make this conditionally added
-Object operator$concatenate(Stack* stack, jmp_buf parentJump, size_t line)
+Object builtin$pow = { CLOSURE, (Instance)(Closure){ NULL, builtin$pow$implementation } };
+{% endif %}
+
+Object builtin$negate$implementation(
+  EnvironmentPool* environmentPool,
+  Environment* parent,
+  size_t argc,
+  Stack* stack,
+  const unsigned long line,
+  jmp_buf parentJump)
+{
+  assert(argc == 1);
+
+  Object argument = Stack_pop(stack);
+
+  assert(argument.type == INTEGER);
+
+  Object result = (Object){
+    INTEGER,
+    (Instance)(int32_t) (-argument.instance.integer)
+  };
+
+  return result;
+}
+Object builtin$negate = { CLOSURE, (Instance)(Closure){ NULL, builtin$negate$implementation } };
+
+{% for op in ['lt', 'gt', 'lte', 'gte', 'eq', 'neq'] %}
+Object builtin${{ op }}$implementation(
+  EnvironmentPool* environmentPool,
+  Environment* parent,
+  size_t argc,
+  Stack* stack,
+  const unsigned long line,
+  jmp_buf parentJump)
+{
+  assert(argc == 2);
+
+  Object right = Stack_pop(stack);
+  Object left = Stack_pop(stack);
+
+  assert(left.type == INTEGER);
+  assert(right.type == INTEGER);
+
+  {% if op == 'lt' %}
+  if(left.instance.integer < right.instance.integer)
+  {% elif op == 'gt' %}
+  if(left.instance.integer > right.instance.integer)
+  {% elif op == 'lte' %}
+  if(left.instance.integer <= right.instance.integer)
+  {% elif op == 'gte' %}
+  if(left.instance.integer >= right.instance.integer)
+  {% elif op == 'eq' %}
+  if(left.instance.integer == right.instance.integer)
+  {% elif op == 'neq' %}
+  if(left.instance.integer != right.instance.integer)
+  {% endif %}
+  {
+    return builtin$true;
+  }
+  else
+  {
+    return builtin$false;
+  }
+}
+Object builtin${{ op }} = { CLOSURE, (Instance)(Closure){ NULL, builtin${{ op }}$implementation } };
+{% endfor %}
+
+Object builtin$concat$implementation(
+  EnvironmentPool* environmentPool,
+  Environment* parent,
+  size_t argc,
+  Stack* stack,
+  const unsigned long line,
+  jmp_buf parentJump)
 {
+  assert(argc == 2);
+
   Object right = Stack_pop(stack);
   Object left = Stack_pop(stack);
 
@@ -616,52 +701,195 @@ Object operator$concatenate(Stack* stack, jmp_buf parentJump, size_t line)
   Object result = { STRING_CONCATENATION, (Instance)concatenation };
   return result;
 }
+Object builtin$concat = { CLOSURE, (Instance)(Closure){ NULL, builtin$concat$implementation } };
 
-{% for id in infix_declarations %}
-Object operator${{ id.name }}(Stack* stack, jmp_buf parentJump, size_t line)
+Object builtin$add$implementation(
+  EnvironmentPool* environmentPool,
+  Environment* parent,
+  size_t argc,
+  Stack* stack,
+  const unsigned long line,
+  jmp_buf parentJump)
 {
+  assert(argc == 2);
+
+  Object right = Stack_pop(stack);
+  Object left = Stack_pop(stack);
+
+  assert(left.type == INTEGER);
+  assert(right.type == INTEGER);
+
+  Object result = (Object){
+    INTEGER,
+    (Instance)(int32_t) (left.instance.integer + right.instance.integer)
+  };
+
+  return result;
+}
+Object builtin$add = { CLOSURE, (Instance)(Closure){ NULL, builtin$add$implementation } };
+
+Object builtin$subtract$implementation(
+  EnvironmentPool* environmentPool,
+  Environment* parent,
+  size_t argc,
+  Stack* stack,
+  const unsigned long line,
+  jmp_buf parentJump)
+{
+  assert(argc == 2);
+
+  Object right = Stack_pop(stack);
+  Object left = Stack_pop(stack);
+
+  assert(left.type == INTEGER);
+  assert(right.type == INTEGER);
+
+  Object result = (Object){
+    INTEGER,
+    (Instance)(int32_t) (left.instance.integer - right.instance.integer)
+  };
+
+  return result;
+}
+Object builtin$subtract = { CLOSURE, (Instance)(Closure){ NULL, builtin$subtract$implementation } };
+
+Object builtin$multiply$implementation(
+  EnvironmentPool* environmentPool,
+  Environment* parent,
+  size_t argc,
+  Stack* stack,
+  const unsigned long line,
+  jmp_buf parentJump)
+{
+  assert(argc == 2);
+
   Object right = Stack_pop(stack);
   Object left = Stack_pop(stack);
 
-  assert(left.type == {{ id.in_type.upper() }});
-  assert(right.type == {{ id.in_type.upper() }});
+  assert(left.type == INTEGER);
+  assert(right.type == INTEGER);
+
+  Object result = (Object){
+    INTEGER,
+    (Instance)(int32_t) (left.instance.integer * right.instance.integer)
+  };
+
+  return result;
+}
+Object builtin$multiply = { CLOSURE, (Instance)(Closure){ NULL, builtin$multiply$implementation } };
+
+Object builtin$integer_divide$implementation(
+  EnvironmentPool* environmentPool,
+  Environment* parent,
+  size_t argc,
+  Stack* stack,
+  const unsigned long line,
+  jmp_buf parentJump)
+{
+  assert(argc == 2);
+
+  Object right = Stack_pop(stack);
+  Object left = Stack_pop(stack);
+
+  assert(left.type == INTEGER);
+  assert(right.type == INTEGER);
 
-  {% if id.name == 'integerDivide' or id.name == 'modularDivide' %}
   if(right.instance.integer == 0)
   {
     fprintf(stderr, "DivisionByZeroError on line %zu\n", line);
     longjmp(parentJump, 1);
   }
-  {% endif %}
 
-  Object result;
-  result.type = {{ id.out_type.upper() }};
-  result.instance.{{ id.out_type.lower() }} = left.instance.{{ id.in_type.lower() }} {{ id.operator }} right.instance.{{ id.in_type.lower() }};
+  Object result = (Object){
+    INTEGER,
+    (Instance)(int32_t) (left.instance.integer / right.instance.integer)
+  };
+
   return result;
 }
-{% endfor %}
+Object builtin$integer_divide = { CLOSURE, (Instance)(Closure){ NULL, builtin$integer_divide$implementation } };
 
-{% if 'pow' in builtins %}
-Object builtin$pow$implementation(EnvironmentPool* environmentPool, Environment* parent, size_t argc, Stack* stack, jmp_buf parentJump)
+Object builtin$modular_divide$implementation(
+  EnvironmentPool* environmentPool,
+  Environment* parent,
+  size_t argc,
+  Stack* stack,
+  const unsigned long line,
+  jmp_buf parentJump)
 {
-  // Must unload items in reverse order
-  Object exponent = Stack_pop(stack);
-  Object base = Stack_pop(stack);
+  assert(argc == 2);
 
-  assert(base.type == INTEGER);
-  assert(exponent.type == INTEGER);
+  Object right = Stack_pop(stack);
+  Object left = Stack_pop(stack);
+
+  assert(left.type == INTEGER);
+  assert(right.type == INTEGER);
+
+  if(right.instance.integer == 0)
+  {
+    fprintf(stderr, "DivisionByZeroError on line %zu\n", line);
+    longjmp(parentJump, 1);
+  }
+
+  Object result = (Object){
+    INTEGER,
+    (Instance)(int32_t) (left.instance.integer % right.instance.integer)
+  };
 
-  Object result;
-  result.type = INTEGER;
-  result.instance.integer = pow(base.instance.integer, exponent.instance.integer);
   return result;
 }
+Object builtin$modular_divide = { CLOSURE, (Instance)(Closure){ NULL, builtin$modular_divide$implementation } };
 
-Object builtin$pow = { CLOSURE, (Instance)(Closure){ NULL, builtin$pow$implementation } };
-{% endif %}
+Object builtin$field$implementation(
+  EnvironmentPool* environmentPool,
+  Environment* parent,
+  size_t argc,
+  Stack* stack,
+  const unsigned long line,
+  jmp_buf parentJump)
+{
+  assert(argc == 2);
+
+  Object right = Stack_pop(stack);
+  Object left = Stack_pop(stack);
+
+  assert(left.type == STRUCTURE);
+  assert(right.type == STRING_LITERAL);
+
+  Object result = (Object){
+    INTEGER,
+    (Instance)(int32_t) (left.instance.integer % right.instance.integer)
+  };
+
+  return result;
+}
+Object builtin$field = { CLOSURE, (Instance)(Closure){ NULL, builtin$field$implementation } };
+
+Object builtin$get$implementation(
+  EnvironmentPool* environmentPool,
+  Environment* parent,
+  size_t argc,
+  Stack* stack,
+  const unsigned long line,
+  jmp_buf parentJump)
+{
+  assert(argc == 2);
+
+  Object right = Stack_pop(stack);
+  Object left = Stack_pop(stack);
+
+  return List_get(&left, right);
+}
+Object builtin$get = { CLOSURE, (Instance)(Closure){ NULL, builtin$get$implementation } };
 
 {% if 'print' in builtins %}
-Object builtin$print$implementation(EnvironmentPool* environmentPool, Environment* parent, size_t argc, Stack* stack, jmp_buf parentJump)
+Object builtin$print$implementation(
+  EnvironmentPool* environmentPool,
+  Environment* parent,
+  size_t argc,
+  Stack* stack,
+  const unsigned long line,
+  jmp_buf parentJump)
 {
   Stack reverse_stack;
   Stack_initialize(&reverse_stack);
@@ -691,9 +919,9 @@ Object builtin$print$implementation(EnvironmentPool* environmentPool, Environmen
 
       case STRING_CONCATENATION:
         Stack_push(stack, output.instance.string_concatenation->left);
-        builtin$print$implementation(NULL, NULL, 1, stack, parentJump);
+        builtin$print$implementation(NULL, NULL, 1, stack, line, parentJump);
         Stack_push(stack, output.instance.string_concatenation->right);
-        builtin$print$implementation(NULL, NULL, 1, stack, parentJump);
+        builtin$print$implementation(NULL, NULL, 1, stack, line, parentJump);
         break;
 
       case STRING_LITERAL:
@@ -753,6 +981,22 @@ int main(int argc, char** argv)
   Environment_set(environment, "{{ builtin }}", builtin${{ builtin }});
   {% endfor %}
 
+  Environment_set(environment, "true", builtin$true);
+  Environment_set(environment, "false", builtin$false);
+  Environment_set(environment, "__add__", builtin$add);
+  Environment_set(environment, "__subtract__", builtin$subtract);
+  Environment_set(environment, "__multiply__", builtin$multiply);
+  Environment_set(environment, "__integer_divide__", builtin$integer_divide);
+  Environment_set(environment, "__modular_divide__", builtin$modular_divide);
+  Environment_set(environment, "__negate__", builtin$negate);
+  Environment_set(environment, "__concat__", builtin$concat);
+  Environment_set(environment, "__field__", builtin$field);
+  Environment_set(environment, "__get__", builtin$get);
+
+  {% for op in ['lt', 'gt', 'lte', 'gte', 'eq', 'neq'] %}
+  Environment_set(environment, "__{{ op }}__", builtin${{ op }});
+  {% endfor %}
+
   {% for statement in statements %}
   {{ statement }}
   {% endfor %}
index bc8cf85..88576bd 100644 (file)
@@ -5,12 +5,19 @@ import util
 
 Token = collections.namedtuple(
     'Token',
-    [
+    (
         'type',
         'match',
+        'metadata',
+    ),
+)
+
+NodeMetadata = collections.namedtuple(
+    'NodeMetadata',
+    (
         'index',
         'line',
-    ],
+    ),
 )
 
 def _make_token_matcher(definition):
@@ -26,7 +33,14 @@ def _make_token_matcher(definition):
         return (
             True,
             index + len(match.group()),
-            Token(type=name, match=match.group(), index=index, line=line),
+            Token(
+                type=name,
+                match=match.group(),
+                metadata=NodeMetadata(
+                    index=index,
+                    line=line,
+                ),
+            ),
         )
 
     return token_matcher
index 7d47ed4..eb6d9cb 100644 (file)
@@ -42,30 +42,6 @@ CStructureLiteralExpression = collections.namedtuple(
     ],
 )
 
-CDotExpression = collections.namedtuple(
-    'CDotExpression',
-    [
-        'instance',
-        'symbol',
-        'symbol_list_index',
-    ],
-)
-
-CNegationExpression = collections.namedtuple(
-    'CNegationExpression',
-    [
-        'value',
-    ],
-)
-
-CFunctionCallForFurInfixOperator = collections.namedtuple(
-    'CFunctionCallForFurInfixOperator',
-    [
-        'metadata',
-        'name',
-    ],
-)
-
 CPushStatement = collections.namedtuple(
     'CPushStatement',
     (
@@ -75,10 +51,11 @@ CPushStatement = collections.namedtuple(
 
 CFunctionCallExpression = collections.namedtuple(
     'CFunctionCallExpression',
-    [
+    (
+        'metadata',
         'function_expression',
         'argument_count',
-    ],
+    ),
 )
 
 # TODO We are currently not changing variables, just preventing them from being accessed.
@@ -209,61 +186,9 @@ def transform_symbol_expression(accumulators, expression):
         symbol_list_index=symbol_list_index,
     )
 
-CInfixDeclaration = collections.namedtuple(
-    'CInfixDeclaration',
-    [
-        'name',
-        'in_type',
-        'out_type',
-        'operator',
-    ],
-)
-
-FUR_INFIX_OPERATOR_TO_C_FUNCTION = {
-    '++':   'concatenate',
-}
-
-FUR_INFIX_OPERATOR_TO_C_INFIX_OPERATOR = {
-    '+':    CInfixDeclaration(name='add', in_type='integer', out_type='integer', operator='+'),
-    '-':    CInfixDeclaration(name='subtract', in_type='integer', out_type='integer', operator='-'),
-    '*':    CInfixDeclaration(name='multiply', in_type='integer', out_type='integer', operator='*'),
-    '//':   CInfixDeclaration(name='integerDivide', in_type='integer', out_type='integer', operator='/'),
-    '%':    CInfixDeclaration(name='modularDivide', in_type='integer', out_type='integer', operator='%'),
-    'and':  CInfixDeclaration(name='and', in_type='boolean', out_type='boolean', operator='&&'),
-    'or':   CInfixDeclaration(name='or', in_type='boolean', out_type='boolean', operator='||'),
-    '==':   CInfixDeclaration(name='equals', in_type='integer', out_type='boolean', operator='=='),
-    '!=':   CInfixDeclaration(name='notEquals', in_type='integer', out_type='boolean', operator='!='),
-    '<=':   CInfixDeclaration(name='lessThanOrEqual', in_type='integer', out_type='boolean', operator='<='),
-    '>=':   CInfixDeclaration(name='greaterThanOrEqual', in_type='integer', out_type='boolean', operator='>='),
-    '<':    CInfixDeclaration(name='lessThan', in_type='integer', out_type='boolean', operator='<'),
-    '>':    CInfixDeclaration(name='greaterThan', in_type='integer', out_type='boolean', operator='>'),
-}
-
-def transform_infix_operator_without_c_equivalent(accumulators, expression):
-    return CFunctionCallForFurInfixOperator(
-        metadata=expression.metadata,
-        name='concatenate',
-    )
-
-def transform_infix_expression(accumulators, expression):
-    if expression.operator in FUR_INFIX_OPERATOR_TO_C_FUNCTION:
-        return transform_infix_operator_without_c_equivalent(accumulators, expression)
-
-    accumulators.operator_set.add(FUR_INFIX_OPERATOR_TO_C_INFIX_OPERATOR[expression.operator])
-
-    return CFunctionCallForFurInfixOperator(
-        metadata=expression.metadata,
-        name=FUR_INFIX_OPERATOR_TO_C_INFIX_OPERATOR[expression.operator].name,
-    )
-
 def transform_integer_literal_expression(accumulators, expression):
     return CIntegerLiteral(value=expression.integer)
 
-def transform_negation_expression(accumulators, expression):
-    return CNegationExpression(
-        value=transform_expression(accumulators, expression.internal_expression),
-    )
-
 CListConstructExpression = collections.namedtuple(
     'CListConstructExpression',
     [
@@ -294,20 +219,6 @@ def transform_structure_literal_expression(accumulators, expression):
         value_list_variable=expression.value_list_variable,
     )
 
-def transform_dot_expression(accumulators, expression):
-    try:
-        symbol_list_index = accumulators.symbol_list.index(expression.field)
-
-    except ValueError:
-        symbol_list_index = len(accumulators.symbol_list)
-        accumulators.symbol_list.append(expression.field)
-
-    return CDotExpression(
-        instance=transform_variable_expression(accumulators, expression.instance),
-        symbol=expression.field,
-        symbol_list_index=symbol_list_index,
-    )
-
 def transform_list_construct_expression(accumulators, expression):
     return CListConstructExpression(allocate=expression.allocate)
 
@@ -324,19 +235,11 @@ def transform_list_append_statement(accumulators, expression):
     )
 
 def transform_expression(accumulators, expression):
-    # TODO Clean up handlers for parsing expressions
     return {
-        parsing.FurInfixExpression: transform_infix_expression,
-        parsing.FurIntegerLiteralExpression: transform_integer_literal_expression,
-        parsing.FurNegationExpression: transform_negation_expression,
-        parsing.FurStringLiteralExpression: transform_string_literal_expression,
-        normalization.NormalDotExpression: transform_dot_expression,
         normalization.NormalFunctionCallExpression: transform_function_call_expression,
-        normalization.NormalInfixExpression: transform_infix_expression,
         normalization.NormalIntegerLiteralExpression: transform_integer_literal_expression,
         normalization.NormalListConstructExpression: transform_list_construct_expression,
         normalization.NormalListGetExpression: transform_list_get_expression,
-        normalization.NormalNegationExpression: transform_negation_expression,
         normalization.NormalStructureLiteralExpression: transform_structure_literal_expression,
         normalization.NormalStringLiteralExpression: transform_string_literal_expression,
         normalization.NormalSymbolExpression: transform_symbol_expression,
@@ -363,6 +266,7 @@ def transform_symbol_assignment_statement(accumulators, assignment_statement):
 def transform_function_call_expression(accumulators, function_call):
     # TODO Use the symbol from SYMBOL LIST
     return CFunctionCallExpression(
+        metadata=function_call.metadata,
         function_expression=transform_expression(accumulators, function_call.function_expression),
         argument_count=function_call.argument_count,
     )
@@ -434,7 +338,6 @@ def transform_push_statement(accumulators, statement):
 
 def transform_statement(accumulators, statement):
     return {
-        parsing.FurExpressionStatement: transform_expression_statement,
         normalization.NormalArrayVariableInitializationStatement: transform_array_variable_initialization_statement,
         normalization.NormalAssignmentStatement: transform_symbol_assignment_statement,
         normalization.NormalExpressionStatement: transform_expression_statement,