Added if expression statements
[fur] / parsing.py
index 82c6528..f2198ad 100644 (file)
@@ -39,21 +39,21 @@ def _zero_or_more_parser(formatter, parser):
 FurIntegerLiteralExpression = collections.namedtuple(
     'FurIntegerLiteralExpression',
     [
-        'value',
+        'integer',
     ],
 )
 
 FurStringLiteralExpression = collections.namedtuple(
     'FurStringLiteralExpression',
     [
-        'value',
+        'string',
     ],
 )
 
 FurSymbolExpression = collections.namedtuple(
     'FurSymbolExpression',
     [
-        'value',
+        'symbol',
     ],
 )
 
@@ -74,6 +74,15 @@ FurInfixExpression = collections.namedtuple(
     ],
 )
 
+FurIfExpression = collections.namedtuple(
+    'FurIfExpression',
+    [
+        'condition_expression',
+        'if_statement_list',
+        'else_statement_list',
+    ],
+)
+
 def _integer_literal_expression_parser(index, tokens):
     failure = (False, index, None)
 
@@ -82,17 +91,17 @@ def _integer_literal_expression_parser(index, tokens):
     value = int(tokens[index].match)
     index += 1
 
-    return True, index, FurIntegerLiteralExpression(value=value)
+    return True, index, FurIntegerLiteralExpression(integer=value)
 
 def _string_literal_expression_parser(index, tokens):
     if tokens[index].type == 'single_quoted_string_literal':
-        return (True, index + 1, FurStringLiteralExpression(value=tokens[index].match[1:-1]))
+        return (True, index + 1, FurStringLiteralExpression(string=tokens[index].match[1:-1]))
 
     return (False, index, None)
 
 def _symbol_expression_parser(index, tokens):
     if tokens[index].type == 'symbol':
-        return (True, index + 1, FurSymbolExpression(value=tokens[index].match))
+        return (True, index + 1, FurSymbolExpression(symbol=tokens[index].match))
 
     return (False, index, None)
 
@@ -315,7 +324,57 @@ def _function_call_expression_parser(index, tokens):
 
     return True, index, function
 
-_expression_parser = _or_level_expression_parser
+def _if_expression_parser(index, tokens):
+    failure = (False, index, None)
+
+    if tokens[index].match == 'if':
+        index += 1
+    else:
+        return failure
+
+    success, index, condition_expression = _or_level_expression_parser(index, tokens)
+
+    if not success:
+        raise Exception('Expected condition after "if" on line {}'.format(tokens[index].line))
+
+    if tokens[index].match == 'do':
+        index += 1
+    else:
+        raise Exception('Expected "do" after "if" on line {}'.format(tokens[index].line))
+
+
+    success, index, if_statement_list = _zero_or_more_parser(tuple, _statement_parser)(index, tokens)
+    _, index, _ = consume_newlines(index, tokens)
+
+    if tokens[index].match == 'else':
+        index += 1
+        success, index, else_statement_list = _zero_or_more_parser(tuple, _statement_parser)(index, tokens)
+        _, index, _ = consume_newlines(index, tokens)
+    else:
+        else_statement_list = ()
+
+    if tokens[index].match == 'end':
+        index += 1
+    else:
+        raise Exception('Expected "end" after "if" on line {}'.format(tokens[index].line))
+
+    return (
+        True,
+        index,
+        FurIfExpression(
+            condition_expression=condition_expression,
+            if_statement_list=if_statement_list,
+            else_statement_list=else_statement_list,
+        ),
+    )
+
+
+
+
+_expression_parser = _or_parser(
+    _or_level_expression_parser,
+    _if_expression_parser, # This should always be at the top level
+)
 
 def _expression_statement_parser(index, tokens):
     failure = (False, index, None)
@@ -327,18 +386,28 @@ def _expression_statement_parser(index, tokens):
 
     return (True, index, FurExpressionStatement(expression=expression))
 
+BUILTINS = {'print', 'pow'}
+
 def _assignment_statement_parser(index, tokens):
-    # TODO Use a FurSymbolExpression for the target? Maybe this is actually not a good idea
     failure = (False, index, None)
 
-    if tokens[index].type != 'symbol':
+    if tokens[index].type == 'symbol':
+        target = tokens[index].match
+        target_assignment_line = tokens[index].line
+
+        index += 1
+    else:
         return failure
-    target = tokens[index].match
-    index += 1
 
-    if tokens[index].type != 'assignment_operator':
+
+    if tokens[index].type == 'assignment_operator':
+        if target in BUILTINS:
+            raise Exception(
+                'Trying to assign to builtin "{}" on line {}'.format(target, target_assignment_line),
+            )
+        assignment_operator_index = index
+    else:
         return failure
-    assignment_operator_index = index
 
     success, index, expression = _expression_parser(index + 1, tokens)
 
@@ -389,7 +458,7 @@ def _function_definition_statement_parser(index, tokens):
             tokens[index].line,
         ))
 
-    if tokens[index].type == 'symbol' and tokens[index].match == 'do':
+    if tokens[index].match == 'do':
         index += 1
     else:
         return failure
@@ -405,7 +474,7 @@ def _function_definition_statement_parser(index, tokens):
 
     return True, index, FurFunctionDefinitionStatement(
         name=name,
-        argument_name_list=tuple(an.value for an in argument_name_list),
+    argument_name_list=tuple(an.symbol for an in argument_name_list),
         statement_list=statement_list,
     )
 
@@ -452,7 +521,7 @@ if __name__ == '__main__':
                 (
                     True,
                     1,
-                    FurStringLiteralExpression(value='Hello, world'),
+                    FurStringLiteralExpression(string='Hello, world'),
                 ),
             )
 
@@ -465,7 +534,7 @@ if __name__ == '__main__':
                     4,
                     FurFunctionCallExpression(
                         name='print',
-                        arguments=(FurStringLiteralExpression(value='Hello, world'),),
+                        arguments=(FurStringLiteralExpression(string='Hello, world'),),
                     ),
                 ),
             )