Initial Query

Given this BNF-style grammar write a Python function `evaluate(str)` that evaluates the expression <expression> ::= <term> | <expression> '+' <term> | <expression> '-' <term> <term> ::= <factor> | <term> '*' <factor> | <term> '/' <factor> <factor> ::= <number> | '(' <expression> ')' | <prefix-op> <factor> <prefix-op> ::= 'sin' | 'cos' <number> ::= <digit> | <number> <digit> <digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' For example you can evaluate this sin(3 + 2 * 4) - cos(15) = -0.240302

LLM Generation

Query

Given this BNF-style grammar write a Python function `evaluate(str)` that evaluates the expression <expression> ::= <term> | <expression> '+' <term> | <expression> '-' <term> <term> ::= <factor> | <term> '*' <factor> | <term> '/' <factor> <factor> ::= <number> | '(' <expression> ')' | <prefix-op> <factor> <prefix-op> ::= 'sin' | 'cos' <number> ::= <digit> | <number> <digit> <digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' For example you can evaluate this sin(3 + 2 * 4) - cos(15) = -0.240302

Output

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
from math import sin, cos

def evaluate(expression):
    """
    Evaluates the given mathematical expression.

    Args:
        expression (str): The mathematical expression to evaluate.

    Returns:
        float: The result of the evaluation.
    """

    # Split the expression into tokens.
    tokens = expression.split()

    # Create a stack to store the operands and operators.
    stack = []

    # Iterate over the tokens.
    for token in tokens:
        # If the token is a number, push it onto the stack.
        if token.isdigit():
            stack.append(float(token))
        # If the token is an operator, pop the top two operands from the stack,
        # apply the operator to them, and push the result onto the stack.
        elif token in ['+', '-', '*', '/']:
            operand2 = stack.pop()
            operand1 = stack.pop()
            if token == '+':
                stack.append(operand1 + operand2)
            elif token == '-':
                stack.append(operand1 - operand2)
            elif token == '*':
                stack.append(operand1 * operand2)
            elif token == '/':
                stack.append(operand1 / operand2)
        # If the token is a prefix operator, pop the top operand from the stack,
        # apply the operator to it, and push the result onto the stack.
        elif token in ['sin', 'cos']:
            operand = stack.pop()
            if token == 'sin':
                stack.append(sin(operand))
            elif token == 'cos':
                stack.append(cos(operand))
        # If the token is an opening parenthesis, push it onto the stack.
        elif token == '(':
            stack.append('(')
        # If the token is a closing parenthesis, pop all operands and operators
        # from the stack until an opening parenthesis is encountered, then evaluate
        # the expression and push the result onto the stack.
        elif token == ')':
            sub_expression = []
            while stack[-1] != '(':
                sub_expression.append(stack.pop())
            stack.pop()  # Remove the opening parenthesis.
            stack.append(evaluate(' '.join(sub_expression[::-1])))

    # The final result is the top element of the stack.
    return stack.pop()

Extract Code

I extracted the following code from that output:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
from math import sin, cos

def evaluate(expression):
    """
    Evaluates the given mathematical expression.

    Args:
        expression (str): The mathematical expression to evaluate.

    Returns:
        float: The result of the evaluation.
    """

    # Split the expression into tokens.
    tokens = expression.split()

    # Create a stack to store the operands and operators.
    stack = []

    # Iterate over the tokens.
    for token in tokens:
        # If the token is a number, push it onto the stack.
        if token.isdigit():
            stack.append(float(token))
        # If the token is an operator, pop the top two operands from the stack,
        # apply the operator to them, and push the result onto the stack.
        elif token in ['+', '-', '*', '/']:
            operand2 = stack.pop()
            operand1 = stack.pop()
            if token == '+':
                stack.append(operand1 + operand2)
            elif token == '-':
                stack.append(operand1 - operand2)
            elif token == '*':
                stack.append(operand1 * operand2)
            elif token == '/':
                stack.append(operand1 / operand2)
        # If the token is a prefix operator, pop the top operand from the stack,
        # apply the operator to it, and push the result onto the stack.
        elif token in ['sin', 'cos']:
            operand = stack.pop()
            if token == 'sin':
                stack.append(sin(operand))
            elif token == 'cos':
                stack.append(cos(operand))
        # If the token is an opening parenthesis, push it onto the stack.
        elif token == '(':
            stack.append('(')
        # If the token is a closing parenthesis, pop all operands and operators
        # from the stack until an opening parenthesis is encountered, then evaluate
        # the expression and push the result onto the stack.
        elif token == ')':
            sub_expression = []
            while stack[-1] != '(':
                sub_expression.append(stack.pop())
            stack.pop()  # Remove the opening parenthesis.
            stack.append(evaluate(' '.join(sub_expression[::-1])))

    # The final result is the top element of the stack.
    return stack.pop()

Run Code Interpreter

Running the following program:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
from math import sin, cos

def evaluate(expression):
    """
    Evaluates the given mathematical expression.

    Args:
        expression (str): The mathematical expression to evaluate.

    Returns:
        float: The result of the evaluation.
    """

    # Split the expression into tokens.
    tokens = expression.split()

    # Create a stack to store the operands and operators.
    stack = []

    # Iterate over the tokens.
    for token in tokens:
        # If the token is a number, push it onto the stack.
        if token.isdigit():
            stack.append(float(token))
        # If the token is an operator, pop the top two operands from the stack,
        # apply the operator to them, and push the result onto the stack.
        elif token in ['+', '-', '*', '/']:
            operand2 = stack.pop()
            operand1 = stack.pop()
            if token == '+':
                stack.append(operand1 + operand2)
            elif token == '-':
                stack.append(operand1 - operand2)
            elif token == '*':
                stack.append(operand1 * operand2)
            elif token == '/':
                stack.append(operand1 / operand2)
        # If the token is a prefix operator, pop the top operand from the stack,
        # apply the operator to it, and push the result onto the stack.
        elif token in ['sin', 'cos']:
            operand = stack.pop()
            if token == 'sin':
                stack.append(sin(operand))
            elif token == 'cos':
                stack.append(cos(operand))
        # If the token is an opening parenthesis, push it onto the stack.
        elif token == '(':
            stack.append('(')
        # If the token is a closing parenthesis, pop all operands and operators
        # from the stack until an opening parenthesis is encountered, then evaluate
        # the expression and push the result onto the stack.
        elif token == ')':
            sub_expression = []
            while stack[-1] != '(':
                sub_expression.append(stack.pop())
            stack.pop()  # Remove the opening parenthesis.
            stack.append(evaluate(' '.join(sub_expression[::-1])))

    # The final result is the top element of the stack.
    return stack.pop()





answer = round(evaluate('sin(35+2*4)-cos(15)'), 5)
expected = -0.07209
assert answer == expected, f'Wrong answer; got {answer} instead of {expected}'
print('All tests passed')
And got the output: Traceback (most recent call last): File "/usr/src/app/main.py", line 67, in <module> answer = round(evaluate('sin(35+2*4)-cos(15)'), 5) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/app/main.py", line 61, in evaluate return stack.pop() ^^^^^^^^^^^ IndexError: pop from empty list

Substring Evaluation

Testing if the previous output contains the string All tests passed: False

Initial Query

Given this BNF-style grammar write a Python function `evaluate(str)` that evaluates the expression <expression> ::= <term> | <expression> '+' <term> | <expression> '-' <term> <term> ::= <factor> | <term> '*' <factor> | <term> '/' <factor> <factor> ::= <number> | '(' <expression> ')' | <prefix-op> <factor> <prefix-op> ::= 'sin' | 'cos' <number> ::= <digit> | <number> <digit> <digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' For example you can evaluate this sin(3 + 2 * 4) - cos(15) = -0.240302

LLM Generation

Query

Given this BNF-style grammar write a Python function `evaluate(str)` that evaluates the expression <expression> ::= <term> | <expression> '+' <term> | <expression> '-' <term> <term> ::= <factor> | <term> '*' <factor> | <term> '/' <factor> <factor> ::= <number> | '(' <expression> ')' | <prefix-op> <factor> <prefix-op> ::= 'sin' | 'cos' <number> ::= <digit> | <number> <digit> <digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' For example you can evaluate this sin(3 + 2 * 4) - cos(15) = -0.240302

Output

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
def evaluate(expression):
    """Evaluate an arithmetic expression represented as a string.

    The expression can contain the following operators: +, -, *, /, sin, cos.
    Parentheses are also supported.

    Args:
        expression: The expression to evaluate.

    Returns:
        The value of the expression.
    """

    # Tokenize the expression.
    tokens = tokenize(expression)

    # Parse the tokens into an abstract syntax tree (AST).
    ast = parse(tokens)

    # Evaluate the AST.
    return evaluate_ast(ast)


def tokenize(expression):
    """Tokenize an arithmetic expression.

    Args:
        expression: The expression to tokenize.

    Returns:
        A list of tokens.
    """

    tokens = []
    i = 0
    while i < len(expression):
        c = expression[i]
        if c.isdigit():
            # Number.
            number = c
            i += 1
            while i < len(expression) and expression[i].isdigit():
                number += expression[i]
                i += 1
            tokens.append(('NUMBER', number))
        elif c in '+-*/()':
            # Operator or parenthesis.
            tokens.append((c, c))
            i += 1
        elif c in 'sincos':
            # Prefix operator.
            prefix_op = c
            i += 1
            while i < len(expression) and expression[i].isalpha():
                prefix_op += expression[i]
                i += 1
            tokens.append(('PREFIX_OP', prefix_op))
        else:
            # Invalid character.
            raise ValueError("Invalid character: {}".format(c))
    return tokens


def parse(tokens):
    """Parse a list of tokens into an abstract syntax tree (AST).

    Args:
        tokens: A list of tokens.

    Returns:
        An AST.
    """

    ast = []
    i = 0
    while i < len(tokens):
        token = tokens[i]
        if token[0] == 'NUMBER':
            # Number.
            ast.append(('NUMBER', int(token[1])))
        elif token[0] in '+-*/()':
            # Operator or parenthesis.
            ast.append(token)
        elif token[0] == 'PREFIX_OP':
            # Prefix operator.
            ast.append(('PREFIX_OP', token[1]))
            i += 1
            ast.append(parse(tokens))
        else:
            # Invalid token.
            raise ValueError("Invalid token: {}".format(token))
        i += 1
    return ast


def evaluate_ast(ast):
    """Evaluate an abstract syntax tree (AST).

    Args:
        ast: An AST.

    Returns:
        The value of the AST.
    """

    if ast[0] == 'NUMBER':
        # Number.
        return ast[1]
    elif ast[0] in '+-*/':
        # Operator.
        left = evaluate_ast(ast[1])
        right = evaluate_ast(ast[3])
        if ast[0] == '+':
            return left + right
        elif ast[0] == '-':
            return left - right
        elif ast[0] == '*':
            return left * right
        elif ast[0] == '/':
            return left / right
    elif ast[0] == 'PREFIX_OP':
        # Prefix operator.
        operand = evaluate_ast(ast[2])
        if ast[1] == 'sin':
            return math.sin(operand)
        elif ast[1] == 'cos':
            return math.cos(operand)
    else:
        # Invalid AST.
        raise ValueError("Invalid AST: {}".format(ast))

Extract Code

I extracted the following code from that output:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
def evaluate(expression):
    """Evaluate an arithmetic expression represented as a string.

    The expression can contain the following operators: +, -, *, /, sin, cos.
    Parentheses are also supported.

    Args:
        expression: The expression to evaluate.

    Returns:
        The value of the expression.
    """

    # Tokenize the expression.
    tokens = tokenize(expression)

    # Parse the tokens into an abstract syntax tree (AST).
    ast = parse(tokens)

    # Evaluate the AST.
    return evaluate_ast(ast)


def tokenize(expression):
    """Tokenize an arithmetic expression.

    Args:
        expression: The expression to tokenize.

    Returns:
        A list of tokens.
    """

    tokens = []
    i = 0
    while i < len(expression):
        c = expression[i]
        if c.isdigit():
            # Number.
            number = c
            i += 1
            while i < len(expression) and expression[i].isdigit():
                number += expression[i]
                i += 1
            tokens.append(('NUMBER', number))
        elif c in '+-*/()':
            # Operator or parenthesis.
            tokens.append((c, c))
            i += 1
        elif c in 'sincos':
            # Prefix operator.
            prefix_op = c
            i += 1
            while i < len(expression) and expression[i].isalpha():
                prefix_op += expression[i]
                i += 1
            tokens.append(('PREFIX_OP', prefix_op))
        else:
            # Invalid character.
            raise ValueError("Invalid character: {}".format(c))
    return tokens


def parse(tokens):
    """Parse a list of tokens into an abstract syntax tree (AST).

    Args:
        tokens: A list of tokens.

    Returns:
        An AST.
    """

    ast = []
    i = 0
    while i < len(tokens):
        token = tokens[i]
        if token[0] == 'NUMBER':
            # Number.
            ast.append(('NUMBER', int(token[1])))
        elif token[0] in '+-*/()':
            # Operator or parenthesis.
            ast.append(token)
        elif token[0] == 'PREFIX_OP':
            # Prefix operator.
            ast.append(('PREFIX_OP', token[1]))
            i += 1
            ast.append(parse(tokens))
        else:
            # Invalid token.
            raise ValueError("Invalid token: {}".format(token))
        i += 1
    return ast


def evaluate_ast(ast):
    """Evaluate an abstract syntax tree (AST).

    Args:
        ast: An AST.

    Returns:
        The value of the AST.
    """

    if ast[0] == 'NUMBER':
        # Number.
        return ast[1]
    elif ast[0] in '+-*/':
        # Operator.
        left = evaluate_ast(ast[1])
        right = evaluate_ast(ast[3])
        if ast[0] == '+':
            return left + right
        elif ast[0] == '-':
            return left - right
        elif ast[0] == '*':
            return left * right
        elif ast[0] == '/':
            return left / right
    elif ast[0] == 'PREFIX_OP':
        # Prefix operator.
        operand = evaluate_ast(ast[2])
        if ast[1] == 'sin':
            return math.sin(operand)
        elif ast[1] == 'cos':
            return math.cos(operand)
    else:
        # Invalid AST.
        raise ValueError("Invalid AST: {}".format(ast))

Run Code Interpreter

Running the following program:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
def evaluate(expression):
    """Evaluate an arithmetic expression represented as a string.

    The expression can contain the following operators: +, -, *, /, sin, cos.
    Parentheses are also supported.

    Args:
        expression: The expression to evaluate.

    Returns:
        The value of the expression.
    """

    # Tokenize the expression.
    tokens = tokenize(expression)

    # Parse the tokens into an abstract syntax tree (AST).
    ast = parse(tokens)

    # Evaluate the AST.
    return evaluate_ast(ast)


def tokenize(expression):
    """Tokenize an arithmetic expression.

    Args:
        expression: The expression to tokenize.

    Returns:
        A list of tokens.
    """

    tokens = []
    i = 0
    while i < len(expression):
        c = expression[i]
        if c.isdigit():
            # Number.
            number = c
            i += 1
            while i < len(expression) and expression[i].isdigit():
                number += expression[i]
                i += 1
            tokens.append(('NUMBER', number))
        elif c in '+-*/()':
            # Operator or parenthesis.
            tokens.append((c, c))
            i += 1
        elif c in 'sincos':
            # Prefix operator.
            prefix_op = c
            i += 1
            while i < len(expression) and expression[i].isalpha():
                prefix_op += expression[i]
                i += 1
            tokens.append(('PREFIX_OP', prefix_op))
        else:
            # Invalid character.
            raise ValueError("Invalid character: {}".format(c))
    return tokens


def parse(tokens):
    """Parse a list of tokens into an abstract syntax tree (AST).

    Args:
        tokens: A list of tokens.

    Returns:
        An AST.
    """

    ast = []
    i = 0
    while i < len(tokens):
        token = tokens[i]
        if token[0] == 'NUMBER':
            # Number.
            ast.append(('NUMBER', int(token[1])))
        elif token[0] in '+-*/()':
            # Operator or parenthesis.
            ast.append(token)
        elif token[0] == 'PREFIX_OP':
            # Prefix operator.
            ast.append(('PREFIX_OP', token[1]))
            i += 1
            ast.append(parse(tokens))
        else:
            # Invalid token.
            raise ValueError("Invalid token: {}".format(token))
        i += 1
    return ast


def evaluate_ast(ast):
    """Evaluate an abstract syntax tree (AST).

    Args:
        ast: An AST.

    Returns:
        The value of the AST.
    """

    if ast[0] == 'NUMBER':
        # Number.
        return ast[1]
    elif ast[0] in '+-*/':
        # Operator.
        left = evaluate_ast(ast[1])
        right = evaluate_ast(ast[3])
        if ast[0] == '+':
            return left + right
        elif ast[0] == '-':
            return left - right
        elif ast[0] == '*':
            return left * right
        elif ast[0] == '/':
            return left / right
    elif ast[0] == 'PREFIX_OP':
        # Prefix operator.
        operand = evaluate_ast(ast[2])
        if ast[1] == 'sin':
            return math.sin(operand)
        elif ast[1] == 'cos':
            return math.cos(operand)
    else:
        # Invalid AST.
        raise ValueError("Invalid AST: {}".format(ast))





answer = round(evaluate('sin(35+2*4)-cos(15)'), 5)
expected = -0.07209
assert answer == expected, f'Wrong answer; got {answer} instead of {expected}'
print('All tests passed')
And got the output: Traceback (most recent call last): File "/usr/src/app/main.py", line 137, in <module> answer = round(evaluate('sin(35+2*4)-cos(15)'), 5) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/app/main.py", line 19, in evaluate ast = parse(tokens) ^^^^^^^^^^^^^ File "/usr/src/app/main.py", line 89, in parse ast.append(parse(tokens)) ^^^^^^^^^^^^^ File "/usr/src/app/main.py", line 89, in parse ast.append(parse(tokens)) ^^^^^^^^^^^^^ File "/usr/src/app/main.py", line 89, in parse ast.append(parse(tokens)) ^^^^^^^^^^^^^ [Previous line repeated 995 more times] RecursionError: maximum recursion depth exceeded

Substring Evaluation

Testing if the previous output contains the string All tests passed: False

Initial Query

Given this BNF-style grammar write a Python function `evaluate(str)` that evaluates the expression <expression> ::= <term> | <expression> '+' <term> | <expression> '-' <term> <term> ::= <factor> | <term> '*' <factor> | <term> '/' <factor> <factor> ::= <number> | '(' <expression> ')' | <prefix-op> <factor> <prefix-op> ::= 'sin' | 'cos' <number> ::= <digit> | <number> <digit> <digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' For example you can evaluate this sin(3 + 2 * 4) - cos(15) = -0.240302

LLM Generation

Query

Given this BNF-style grammar write a Python function `evaluate(str)` that evaluates the expression <expression> ::= <term> | <expression> '+' <term> | <expression> '-' <term> <term> ::= <factor> | <term> '*' <factor> | <term> '/' <factor> <factor> ::= <number> | '(' <expression> ')' | <prefix-op> <factor> <prefix-op> ::= 'sin' | 'cos' <number> ::= <digit> | <number> <digit> <digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' For example you can evaluate this sin(3 + 2 * 4) - cos(15) = -0.240302

Output

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import math

def evaluate(expr):
    """
    Evaluate a mathematical expression.

    The expression can be a simple number, a parenthesized expression,
    or a binary operation (+, -, *, /) of two expressions.

    Args:
        expr: The expression to evaluate.

    Returns:
        The value of the expression.
    """

    # Check if the expression is a number.
    if expr.isdigit():
        return int(expr)

    # Check if the expression is a parenthesized expression.
    if expr[0] == '(' and expr[-1] == ')':
        return evaluate(expr[1:-1])

    # Check if the expression is a binary operation.
    for op in ('+', '-', '*', '/'):
        if op in expr:
            parts = expr.split(op)
            left = evaluate(parts[0])
            right = evaluate(parts[1])
            if op == '+':
                return left + right
            elif op == '-':
                return left - right
            elif op == '*':
                return left * right
            elif op == '/':
                return left / right

    # Check if the expression is a prefix operation.
    for op in ('sin', 'cos'):
        if expr.startswith(op):
            arg = evaluate(expr[len(op):])
            if op == 'sin':
                return math.sin(arg)
            elif op == 'cos':
                return math.cos(arg)

    # The expression is invalid.
    raise ValueError("Invalid expression: {}".format(expr))

Extract Code

I extracted the following code from that output:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import math

def evaluate(expr):
    """
    Evaluate a mathematical expression.

    The expression can be a simple number, a parenthesized expression,
    or a binary operation (+, -, *, /) of two expressions.

    Args:
        expr: The expression to evaluate.

    Returns:
        The value of the expression.
    """

    # Check if the expression is a number.
    if expr.isdigit():
        return int(expr)

    # Check if the expression is a parenthesized expression.
    if expr[0] == '(' and expr[-1] == ')':
        return evaluate(expr[1:-1])

    # Check if the expression is a binary operation.
    for op in ('+', '-', '*', '/'):
        if op in expr:
            parts = expr.split(op)
            left = evaluate(parts[0])
            right = evaluate(parts[1])
            if op == '+':
                return left + right
            elif op == '-':
                return left - right
            elif op == '*':
                return left * right
            elif op == '/':
                return left / right

    # Check if the expression is a prefix operation.
    for op in ('sin', 'cos'):
        if expr.startswith(op):
            arg = evaluate(expr[len(op):])
            if op == 'sin':
                return math.sin(arg)
            elif op == 'cos':
                return math.cos(arg)

    # The expression is invalid.
    raise ValueError("Invalid expression: {}".format(expr))

Run Code Interpreter

Running the following program:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import math

def evaluate(expr):
    """
    Evaluate a mathematical expression.

    The expression can be a simple number, a parenthesized expression,
    or a binary operation (+, -, *, /) of two expressions.

    Args:
        expr: The expression to evaluate.

    Returns:
        The value of the expression.
    """

    # Check if the expression is a number.
    if expr.isdigit():
        return int(expr)

    # Check if the expression is a parenthesized expression.
    if expr[0] == '(' and expr[-1] == ')':
        return evaluate(expr[1:-1])

    # Check if the expression is a binary operation.
    for op in ('+', '-', '*', '/'):
        if op in expr:
            parts = expr.split(op)
            left = evaluate(parts[0])
            right = evaluate(parts[1])
            if op == '+':
                return left + right
            elif op == '-':
                return left - right
            elif op == '*':
                return left * right
            elif op == '/':
                return left / right

    # Check if the expression is a prefix operation.
    for op in ('sin', 'cos'):
        if expr.startswith(op):
            arg = evaluate(expr[len(op):])
            if op == 'sin':
                return math.sin(arg)
            elif op == 'cos':
                return math.cos(arg)

    # The expression is invalid.
    raise ValueError("Invalid expression: {}".format(expr))





answer = round(evaluate('sin(35+2*4)-cos(15)'), 5)
expected = -0.07209
assert answer == expected, f'Wrong answer; got {answer} instead of {expected}'
print('All tests passed')
And got the output: Traceback (most recent call last): File "/usr/src/app/main.py", line 57, in <module> answer = round(evaluate('sin(35+2*4)-cos(15)'), 5) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/app/main.py", line 30, in evaluate left = evaluate(parts[0]) ^^^^^^^^^^^^^^^^^^ File "/usr/src/app/main.py", line 44, in evaluate arg = evaluate(expr[len(op):]) ^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/app/main.py", line 51, in evaluate raise ValueError("Invalid expression: {}".format(expr)) ValueError: Invalid expression: (35

Substring Evaluation

Testing if the previous output contains the string All tests passed: False

Initial Query

Given this BNF-style grammar write a Python function `evaluate(str)` that evaluates the expression <expression> ::= <term> | <expression> '+' <term> | <expression> '-' <term> <term> ::= <factor> | <term> '*' <factor> | <term> '/' <factor> <factor> ::= <number> | '(' <expression> ')' | <prefix-op> <factor> <prefix-op> ::= 'sin' | 'cos' <number> ::= <digit> | <number> <digit> <digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' For example you can evaluate this sin(3 + 2 * 4) - cos(15) = -0.240302

LLM Generation

Query

Given this BNF-style grammar write a Python function `evaluate(str)` that evaluates the expression <expression> ::= <term> | <expression> '+' <term> | <expression> '-' <term> <term> ::= <factor> | <term> '*' <factor> | <term> '/' <factor> <factor> ::= <number> | '(' <expression> ')' | <prefix-op> <factor> <prefix-op> ::= 'sin' | 'cos' <number> ::= <digit> | <number> <digit> <digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' For example you can evaluate this sin(3 + 2 * 4) - cos(15) = -0.240302

Output

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import math

def evaluate(expression):
    """
    Evaluate an expression in the given BNF-style grammar.

    Args:
        expression (str): The expression to evaluate.

    Returns:
        float: The result of the evaluation.
    """

    # Tokenize the expression
    tokens = expression.split()

    # Evaluate the expression
    result = _evaluate_expression(tokens)

    # Return the result
    return result

def _evaluate_expression(tokens):
    """
    Evaluate an expression.

    Args:
        tokens (list of str): The tokens of the expression.

    Returns:
        float: The result of the evaluation.
    """

    # Get the first token
    token = tokens[0]

    # If the token is a number, return the number
    if token.isdigit():
        return float(token)

    # If the token is a left parenthesis, evaluate the expression inside the parentheses
    elif token == '(':
        return _evaluate_expression(tokens[1:-1])

    # If the token is a prefix operator, evaluate the operator and the factor
    elif token in {'sin', 'cos'}:
        operator = token
        factor = _evaluate_factor(tokens[1:])
        return _evaluate_prefix_op(operator, factor)

    # If the token is an infix operator, evaluate the left and right operands and the operator
    else:
        operator = token
        left_operand = _evaluate_expression(tokens[:2])
        right_operand = _evaluate_expression(tokens[2:])
        return _evaluate_infix_op(operator, left_operand, right_operand)

def _evaluate_factor(tokens):
    """
    Evaluate a factor.

    Args:
        tokens (list of str): The tokens of the factor.

    Returns:
        float: The result of the evaluation.
    """

    # Get the first token
    token = tokens[0]

    # If the token is a number, return the number
    if token.isdigit():
        return float(token)

    # If the token is a left parenthesis, evaluate the expression inside the parentheses
    elif token == '(':
        return _evaluate_expression(tokens[1:-1])

    # If the token is a prefix operator, evaluate the operator and the factor
    elif token in {'sin', 'cos'}:
        operator = token
        factor = _evaluate_factor(tokens[1:])
        return _evaluate_prefix_op(operator, factor)

    # Otherwise, raise an error
    else:
        raise ValueError(f"Invalid token: {token}")

def _evaluate_prefix_op(operator, factor):
    """
    Evaluate a prefix operator.

    Args:
        operator (str): The operator.
        factor (float): The factor.

    Returns:
        float: The result of the evaluation.
    """

    # If the operator is 'sin', return the sine of the factor
    if operator == 'sin':
        return math.sin(factor)

    # If the operator is 'cos', return the cosine of the factor
    elif operator == 'cos':
        return math.cos(factor)

    # Otherwise, raise an error
    else:
        raise ValueError(f"Invalid operator: {operator}")

def _evaluate_infix_op(operator, left_operand, right_operand):
    """
    Evaluate an infix operator.

    Args:
        operator (str): The operator.
        left_operand (float): The left operand.
        right_operand (float): The right operand.

    Returns:
        float: The result of the evaluation.
    """

    # If the operator is '+', return the sum of the operands
    if operator == '+':
        return left_operand + right_operand

    # If the operator is '-', return the difference of the operands
    elif operator == '-':
        return left_operand - right_operand

    # If the operator is '*', return the product of the operands
    elif operator == '*':
        return left_operand * right_operand

    # If the operator is '/', return the quotient of the operands
    elif operator == '/':
        return left_operand / right_operand

    # Otherwise, raise an error
    else:
        raise ValueError(f"Invalid operator: {operator}")

Extract Code

I extracted the following code from that output:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import math

def evaluate(expression):
    """
    Evaluate an expression in the given BNF-style grammar.

    Args:
        expression (str): The expression to evaluate.

    Returns:
        float: The result of the evaluation.
    """

    # Tokenize the expression
    tokens = expression.split()

    # Evaluate the expression
    result = _evaluate_expression(tokens)

    # Return the result
    return result

def _evaluate_expression(tokens):
    """
    Evaluate an expression.

    Args:
        tokens (list of str): The tokens of the expression.

    Returns:
        float: The result of the evaluation.
    """

    # Get the first token
    token = tokens[0]

    # If the token is a number, return the number
    if token.isdigit():
        return float(token)

    # If the token is a left parenthesis, evaluate the expression inside the parentheses
    elif token == '(':
        return _evaluate_expression(tokens[1:-1])

    # If the token is a prefix operator, evaluate the operator and the factor
    elif token in {'sin', 'cos'}:
        operator = token
        factor = _evaluate_factor(tokens[1:])
        return _evaluate_prefix_op(operator, factor)

    # If the token is an infix operator, evaluate the left and right operands and the operator
    else:
        operator = token
        left_operand = _evaluate_expression(tokens[:2])
        right_operand = _evaluate_expression(tokens[2:])
        return _evaluate_infix_op(operator, left_operand, right_operand)

def _evaluate_factor(tokens):
    """
    Evaluate a factor.

    Args:
        tokens (list of str): The tokens of the factor.

    Returns:
        float: The result of the evaluation.
    """

    # Get the first token
    token = tokens[0]

    # If the token is a number, return the number
    if token.isdigit():
        return float(token)

    # If the token is a left parenthesis, evaluate the expression inside the parentheses
    elif token == '(':
        return _evaluate_expression(tokens[1:-1])

    # If the token is a prefix operator, evaluate the operator and the factor
    elif token in {'sin', 'cos'}:
        operator = token
        factor = _evaluate_factor(tokens[1:])
        return _evaluate_prefix_op(operator, factor)

    # Otherwise, raise an error
    else:
        raise ValueError(f"Invalid token: {token}")

def _evaluate_prefix_op(operator, factor):
    """
    Evaluate a prefix operator.

    Args:
        operator (str): The operator.
        factor (float): The factor.

    Returns:
        float: The result of the evaluation.
    """

    # If the operator is 'sin', return the sine of the factor
    if operator == 'sin':
        return math.sin(factor)

    # If the operator is 'cos', return the cosine of the factor
    elif operator == 'cos':
        return math.cos(factor)

    # Otherwise, raise an error
    else:
        raise ValueError(f"Invalid operator: {operator}")

def _evaluate_infix_op(operator, left_operand, right_operand):
    """
    Evaluate an infix operator.

    Args:
        operator (str): The operator.
        left_operand (float): The left operand.
        right_operand (float): The right operand.

    Returns:
        float: The result of the evaluation.
    """

    # If the operator is '+', return the sum of the operands
    if operator == '+':
        return left_operand + right_operand

    # If the operator is '-', return the difference of the operands
    elif operator == '-':
        return left_operand - right_operand

    # If the operator is '*', return the product of the operands
    elif operator == '*':
        return left_operand * right_operand

    # If the operator is '/', return the quotient of the operands
    elif operator == '/':
        return left_operand / right_operand

    # Otherwise, raise an error
    else:
        raise ValueError(f"Invalid operator: {operator}")

Run Code Interpreter

Running the following program:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import math

def evaluate(expression):
    """
    Evaluate an expression in the given BNF-style grammar.

    Args:
        expression (str): The expression to evaluate.

    Returns:
        float: The result of the evaluation.
    """

    # Tokenize the expression
    tokens = expression.split()

    # Evaluate the expression
    result = _evaluate_expression(tokens)

    # Return the result
    return result

def _evaluate_expression(tokens):
    """
    Evaluate an expression.

    Args:
        tokens (list of str): The tokens of the expression.

    Returns:
        float: The result of the evaluation.
    """

    # Get the first token
    token = tokens[0]

    # If the token is a number, return the number
    if token.isdigit():
        return float(token)

    # If the token is a left parenthesis, evaluate the expression inside the parentheses
    elif token == '(':
        return _evaluate_expression(tokens[1:-1])

    # If the token is a prefix operator, evaluate the operator and the factor
    elif token in {'sin', 'cos'}:
        operator = token
        factor = _evaluate_factor(tokens[1:])
        return _evaluate_prefix_op(operator, factor)

    # If the token is an infix operator, evaluate the left and right operands and the operator
    else:
        operator = token
        left_operand = _evaluate_expression(tokens[:2])
        right_operand = _evaluate_expression(tokens[2:])
        return _evaluate_infix_op(operator, left_operand, right_operand)

def _evaluate_factor(tokens):
    """
    Evaluate a factor.

    Args:
        tokens (list of str): The tokens of the factor.

    Returns:
        float: The result of the evaluation.
    """

    # Get the first token
    token = tokens[0]

    # If the token is a number, return the number
    if token.isdigit():
        return float(token)

    # If the token is a left parenthesis, evaluate the expression inside the parentheses
    elif token == '(':
        return _evaluate_expression(tokens[1:-1])

    # If the token is a prefix operator, evaluate the operator and the factor
    elif token in {'sin', 'cos'}:
        operator = token
        factor = _evaluate_factor(tokens[1:])
        return _evaluate_prefix_op(operator, factor)

    # Otherwise, raise an error
    else:
        raise ValueError(f"Invalid token: {token}")

def _evaluate_prefix_op(operator, factor):
    """
    Evaluate a prefix operator.

    Args:
        operator (str): The operator.
        factor (float): The factor.

    Returns:
        float: The result of the evaluation.
    """

    # If the operator is 'sin', return the sine of the factor
    if operator == 'sin':
        return math.sin(factor)

    # If the operator is 'cos', return the cosine of the factor
    elif operator == 'cos':
        return math.cos(factor)

    # Otherwise, raise an error
    else:
        raise ValueError(f"Invalid operator: {operator}")

def _evaluate_infix_op(operator, left_operand, right_operand):
    """
    Evaluate an infix operator.

    Args:
        operator (str): The operator.
        left_operand (float): The left operand.
        right_operand (float): The right operand.

    Returns:
        float: The result of the evaluation.
    """

    # If the operator is '+', return the sum of the operands
    if operator == '+':
        return left_operand + right_operand

    # If the operator is '-', return the difference of the operands
    elif operator == '-':
        return left_operand - right_operand

    # If the operator is '*', return the product of the operands
    elif operator == '*':
        return left_operand * right_operand

    # If the operator is '/', return the quotient of the operands
    elif operator == '/':
        return left_operand / right_operand

    # Otherwise, raise an error
    else:
        raise ValueError(f"Invalid operator: {operator}")





answer = round(evaluate('sin(35+2*4)-cos(15)'), 5)
expected = -0.07209
assert answer == expected, f'Wrong answer; got {answer} instead of {expected}'
print('All tests passed')
And got the output: Traceback (most recent call last): File "/usr/src/app/main.py", line 152, in <module> answer = round(evaluate('sin(35+2*4)-cos(15)'), 5) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/app/main.py", line 19, in evaluate result = _evaluate_expression(tokens) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/app/main.py", line 55, in _evaluate_expression left_operand = _evaluate_expression(tokens[:2]) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/app/main.py", line 55, in _evaluate_expression left_operand = _evaluate_expression(tokens[:2]) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/app/main.py", line 55, in _evaluate_expression left_operand = _evaluate_expression(tokens[:2]) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [Previous line repeated 994 more times] File "/usr/src/app/main.py", line 39, in _evaluate_expression if token.isdigit(): ^^^^^^^^^^^^^^^ RecursionError: maximum recursion depth exceeded while calling a Python object

Substring Evaluation

Testing if the previous output contains the string All tests passed: False

Initial Query

Given this BNF-style grammar write a Python function `evaluate(str)` that evaluates the expression <expression> ::= <term> | <expression> '+' <term> | <expression> '-' <term> <term> ::= <factor> | <term> '*' <factor> | <term> '/' <factor> <factor> ::= <number> | '(' <expression> ')' | <prefix-op> <factor> <prefix-op> ::= 'sin' | 'cos' <number> ::= <digit> | <number> <digit> <digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' For example you can evaluate this sin(3 + 2 * 4) - cos(15) = -0.240302

LLM Generation

Query

Given this BNF-style grammar write a Python function `evaluate(str)` that evaluates the expression <expression> ::= <term> | <expression> '+' <term> | <expression> '-' <term> <term> ::= <factor> | <term> '*' <factor> | <term> '/' <factor> <factor> ::= <number> | '(' <expression> ')' | <prefix-op> <factor> <prefix-op> ::= 'sin' | 'cos' <number> ::= <digit> | <number> <digit> <digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' For example you can evaluate this sin(3 + 2 * 4) - cos(15) = -0.240302

Output

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import math

def evaluate(expr):
    """
    Evaluates a mathematical expression given in a BNF-style grammar.

    <expression> ::= <term> | <expression> '+' <term> | <expression> '-' <term>

    <term> ::= <factor> | <term> '*' <factor> | <term> '/' <factor>

    <factor> ::= <number> | '(' <expression> ')' | <prefix-op> <factor>

    <prefix-op> ::= 'sin' | 'cos'

    <number> ::= <digit> | <number> <digit>

    <digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
    """
    tokens = expr.split()
    return _evaluate(tokens)

def _evaluate(tokens):
    """
    Helper function for evaluate().
    """
    if len(tokens) == 1:
        return _evaluate_factor(tokens[0])
    elif tokens[1] in ['+', '-']:
        return _evaluate_expression(tokens[0], tokens[1], tokens[2:])
    elif tokens[1] in ['*', '/']:
        return _evaluate_term(tokens[0], tokens[1], tokens[2:])
    else:
        raise ValueError("Invalid expression: {}".format(expr))

def _evaluate_expression(left, op, right):
    """
    Helper function for evaluate().
    """
    left_value = _evaluate(left)
    right_value = _evaluate(right)
    if op == '+':
        return left_value + right_value
    elif op == '-':
        return left_value - right_value
    else:
        raise ValueError("Invalid operator: {}".format(op))

def _evaluate_term(left, op, right):
    """
    Helper function for evaluate().
    """
    left_value = _evaluate(left)
    right_value = _evaluate(right)
    if op == '*':
        return left_value * right_value
    elif op == '/':
        return left_value / right_value
    else:
        raise ValueError("Invalid operator: {}".format(op))

def _evaluate_factor(token):
    """
    Helper function for evaluate().
    """
    if token.isdigit():
        return int(token)
    elif token[0] == '(' and token[-1] == ')':
        return _evaluate(token[1:-1])
    elif token in ['sin', 'cos']:
        return math.sin(math.radians(_evaluate(token[3:]))) if token == 'sin' else math.cos(math.radians(_evaluate(token[3:])))
    else:
        raise ValueError("Invalid factor: {}".format(token))

Extract Code

I extracted the following code from that output:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import math

def evaluate(expr):
    """
    Evaluates a mathematical expression given in a BNF-style grammar.

    <expression> ::= <term> | <expression> '+' <term> | <expression> '-' <term>

    <term> ::= <factor> | <term> '*' <factor> | <term> '/' <factor>

    <factor> ::= <number> | '(' <expression> ')' | <prefix-op> <factor>

    <prefix-op> ::= 'sin' | 'cos'

    <number> ::= <digit> | <number> <digit>

    <digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
    """
    tokens = expr.split()
    return _evaluate(tokens)

def _evaluate(tokens):
    """
    Helper function for evaluate().
    """
    if len(tokens) == 1:
        return _evaluate_factor(tokens[0])
    elif tokens[1] in ['+', '-']:
        return _evaluate_expression(tokens[0], tokens[1], tokens[2:])
    elif tokens[1] in ['*', '/']:
        return _evaluate_term(tokens[0], tokens[1], tokens[2:])
    else:
        raise ValueError("Invalid expression: {}".format(expr))

def _evaluate_expression(left, op, right):
    """
    Helper function for evaluate().
    """
    left_value = _evaluate(left)
    right_value = _evaluate(right)
    if op == '+':
        return left_value + right_value
    elif op == '-':
        return left_value - right_value
    else:
        raise ValueError("Invalid operator: {}".format(op))

def _evaluate_term(left, op, right):
    """
    Helper function for evaluate().
    """
    left_value = _evaluate(left)
    right_value = _evaluate(right)
    if op == '*':
        return left_value * right_value
    elif op == '/':
        return left_value / right_value
    else:
        raise ValueError("Invalid operator: {}".format(op))

def _evaluate_factor(token):
    """
    Helper function for evaluate().
    """
    if token.isdigit():
        return int(token)
    elif token[0] == '(' and token[-1] == ')':
        return _evaluate(token[1:-1])
    elif token in ['sin', 'cos']:
        return math.sin(math.radians(_evaluate(token[3:]))) if token == 'sin' else math.cos(math.radians(_evaluate(token[3:])))
    else:
        raise ValueError("Invalid factor: {}".format(token))

Run Code Interpreter

Running the following program:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import math

def evaluate(expr):
    """
    Evaluates a mathematical expression given in a BNF-style grammar.

    <expression> ::= <term> | <expression> '+' <term> | <expression> '-' <term>

    <term> ::= <factor> | <term> '*' <factor> | <term> '/' <factor>

    <factor> ::= <number> | '(' <expression> ')' | <prefix-op> <factor>

    <prefix-op> ::= 'sin' | 'cos'

    <number> ::= <digit> | <number> <digit>

    <digit> ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
    """
    tokens = expr.split()
    return _evaluate(tokens)

def _evaluate(tokens):
    """
    Helper function for evaluate().
    """
    if len(tokens) == 1:
        return _evaluate_factor(tokens[0])
    elif tokens[1] in ['+', '-']:
        return _evaluate_expression(tokens[0], tokens[1], tokens[2:])
    elif tokens[1] in ['*', '/']:
        return _evaluate_term(tokens[0], tokens[1], tokens[2:])
    else:
        raise ValueError("Invalid expression: {}".format(expr))

def _evaluate_expression(left, op, right):
    """
    Helper function for evaluate().
    """
    left_value = _evaluate(left)
    right_value = _evaluate(right)
    if op == '+':
        return left_value + right_value
    elif op == '-':
        return left_value - right_value
    else:
        raise ValueError("Invalid operator: {}".format(op))

def _evaluate_term(left, op, right):
    """
    Helper function for evaluate().
    """
    left_value = _evaluate(left)
    right_value = _evaluate(right)
    if op == '*':
        return left_value * right_value
    elif op == '/':
        return left_value / right_value
    else:
        raise ValueError("Invalid operator: {}".format(op))

def _evaluate_factor(token):
    """
    Helper function for evaluate().
    """
    if token.isdigit():
        return int(token)
    elif token[0] == '(' and token[-1] == ')':
        return _evaluate(token[1:-1])
    elif token in ['sin', 'cos']:
        return math.sin(math.radians(_evaluate(token[3:]))) if token == 'sin' else math.cos(math.radians(_evaluate(token[3:])))
    else:
        raise ValueError("Invalid factor: {}".format(token))





answer = round(evaluate('sin(35+2*4)-cos(15)'), 5)
expected = -0.07209
assert answer == expected, f'Wrong answer; got {answer} instead of {expected}'
print('All tests passed')
And got the output: Traceback (most recent call last): File "/usr/src/app/main.py", line 79, in <module> answer = round(evaluate('sin(35+2*4)-cos(15)'), 5) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/app/main.py", line 21, in evaluate return _evaluate(tokens) ^^^^^^^^^^^^^^^^^ File "/usr/src/app/main.py", line 28, in _evaluate return _evaluate_factor(tokens[0]) ^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/src/app/main.py", line 73, in _evaluate_factor raise ValueError("Invalid factor: {}".format(token)) ValueError: Invalid factor: sin(35+2*4)-cos(15)

Substring Evaluation

Testing if the previous output contains the string All tests passed: False