X-Git-Url: https://code.kerkeslager.com/?p=fur;a=blobdiff_plain;f=parsing.py;h=b2a14a888b820346c0f0086beb52e4b58c38e4a0;hp=7240b5243e40ffd7655b4dc5bc4fbb94fbe65f5a;hb=3da330f045ed7fcb66ee9d9447de320680263699;hpb=74c7456042282dd86f9be673cbd1e00496b28710 diff --git a/parsing.py b/parsing.py index 7240b52..b2a14a8 100644 --- a/parsing.py +++ b/parsing.py @@ -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', ], ) @@ -82,41 +82,47 @@ 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) -def _parenthesized_expression_parser(index, tokens): - failure = (False, index, None) +def _parenthese_wrapped_parser(internal_parser): + def result_parser(index, tokens): + failure = (False, index, None) - if tokens[index].type == 'open_parenthese': - index += 1 - else: - return failure + if tokens[index].type == 'open_parenthese': + index += 1 + else: + return failure - success, index, internal = _expression_parser(index, tokens) - if not success: - return failure + success, index, internal = internal_parser(index, tokens) + if not success: + return failure - if tokens[index].type == 'close_parenthese': - index += 1 - else: - raise Exception('Expected ")" on line {}, found "{}"'.format( - tokens[index].line, - tokens[index].match, - )) + if tokens[index].type == 'close_parenthese': + index += 1 + else: + raise Exception('Expected ")" on line {}, found "{}"'.format( + tokens[index].line, + tokens[index].match, + )) + + return True, index, internal - return True, index, internal + return result_parser + +def _parenthesized_expression_parser(index, tokens): + return _parenthese_wrapped_parser(_expression_parser)(index, tokens) def _negation_expression_parser(index, tokens): failure = (False, index, None) @@ -274,8 +280,6 @@ FurProgram = collections.namedtuple( ) def _function_call_expression_parser(index, tokens): - # TODO Allow function calls as the source of the function. This requires a - # left-recursive parser, however. failure = (False, index, None) # We have to be careful what expressions we add here. Otherwise expressions @@ -288,23 +292,28 @@ def _function_call_expression_parser(index, tokens): if not success: return failure - if tokens[index].type != 'open_parenthese': - return failure - index += 1 - - success, index, arguments = _comma_separated_expression_list_parser(index, tokens) + success, index, arguments = _parenthese_wrapped_parser(_comma_separated_expression_list_parser)( + index, + tokens, + ) if not success: return failure - if tokens[index].type != 'close_parenthese': - raise Exception('Expected ")", found "{}" on line {}'.format( - tokens[index].match, - tokens[index].line, - )) - index += 1 + while success and index < len(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( + function=function, + arguments=arguments, + ) + + success, index, arguments = _parenthese_wrapped_parser(_comma_separated_expression_list_parser)( + index, + tokens, + ) - return True, index, FurFunctionCallExpression(function=function, arguments=arguments) + return True, index, function _expression_parser = _or_level_expression_parser @@ -318,18 +327,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) @@ -396,7 +415,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, ) @@ -443,7 +462,7 @@ if __name__ == '__main__': ( True, 1, - FurStringLiteralExpression(value='Hello, world'), + FurStringLiteralExpression(string='Hello, world'), ), ) @@ -456,7 +475,7 @@ if __name__ == '__main__': 4, FurFunctionCallExpression( name='print', - arguments=(FurStringLiteralExpression(value='Hello, world'),), + arguments=(FurStringLiteralExpression(string='Hello, world'),), ), ), )