(text)
return "".join(output_chars)
Migrates text which may contain equals style expressions, e.g. "Hi =UPPER(contact)", converting them to new style
    expressions, e.g. "Hi @(UPPER(contact))"
Migrates text which may contain equals style expressions, e.g. "Hi =UPPER(contact)", converting them to new style
    expressions, e.g. "Hi
Migrates text which may contain equals style expressions e . g . Hi = UPPER ( contact ) converting them to new style expressions e . g . Hi
def _replace_equals_style(text):
    """
    Migrates text which may contain equals style expressions, e.g. "Hi =UPPER(contact)", converting them to new style
    expressions, e.g. "Hi @(UPPER(contact))"
    """
    STATE_BODY = 0  # not in a expression
    STATE_PREFIX = 1  # '=' prefix that denotes the start of an expression
    STATE_IDENTIFIER = 2  # the identifier part, e.g. 'SUM' in '=SUM(1, 2)' or 'contact.age' in '=contact.age'
    STATE_BALANCED = 3  # the balanced parentheses delimited part, e.g. '(1, 2)' in 'SUM(1, 2)'
    STATE_STRING_LITERAL = 4  # a string literal
    input_chars = list(text)
    output_chars = []
    state = STATE_BODY
    current_expression_chars = []
    current_expression_terminated = False
    parentheses_level = 0

    def replace_expression(expression):
        expression_body = expression[1:]

        # if expression doesn't end with ) then check it's an allowed top level context reference
        if not expression_body.endswith(")"):
            top_level = expression_body.split(".")[0].lower()
            if top_level not in ALLOWED_TOP_LEVELS:
                return expression

        return "@" + _convert_equals_style(expression_body)

    # determines whether the given character is a word character, i.e. \w in a regex
    def is_word_char(c):
        return c and (c.isalnum() or c == "_")

    for pos, ch in enumerate(input_chars):
        # in order to determine if the b in a.b terminates an identifier, we have to peek two characters ahead as it
        # could be a.b. (b terminates) or a.b.c (b doesn't terminate)
        next_ch = input_chars[pos + 1] if (pos < (len(input_chars) - 1)) else None
        next_next_ch = input_chars[pos + 2] if (pos < (len(input_chars) - 2)) else None

        if state == STATE_BODY:
            if ch == "=" and (is_word_char(next_ch) or next_ch == "("):
                state = STATE_PREFIX
                current_expression_chars = [ch]
            else:
                output_chars.append(ch)

        elif state == STATE_PREFIX:
            if is_word_char(ch):
                # we're parsing an expression like =XXX or =YYY()
                state = STATE_IDENTIFIER
            elif ch == "(":
                # we're parsing an expression like =(1 + 2)
                state = STATE_BALANCED
                parentheses_level += 1

            current_expression_chars.append(ch)

        elif state == STATE_IDENTIFIER:
            if ch == "(":
                state = STATE_BALANCED
                parentheses_level += 1

            current_expression_chars.append(ch)

        elif state == STATE_BALANCED:
            if ch == "(":
                parentheses_level += 1
            elif ch == ")":
                parentheses_level -= 1
            elif ch == '"':
                state = STATE_STRING_LITERAL

            current_expression_chars.append(ch)

            # expression terminates if parentheses balance
            if parentheses_level == 0:
                current_expression_terminated = True

        elif state == STATE_STRING_LITERAL:
            if ch == '"':
                state = STATE_BALANCED
            current_expression_chars.append(ch)

        # identifier can terminate expression in 3 ways:
        #  1. next char is null (i.e. end of the input)
        #  2. next char is not a word character or period or left parentheses
        #  3. next char is a period, but it's not followed by a word character
        if state == STATE_IDENTIFIER:
            if (
                not next_ch
                or (not is_word_char(next_ch) and not next_ch == "." and not next_ch == "(")
                or (next_ch == "." and not is_word_char(next_next_ch))
            ):
                current_expression_terminated = True

        if current_expression_terminated:
            output_chars.append(replace_expression("".join(current_expression_chars)))
            current_expression_chars = []
            current_expression_terminated = False
            state = STATE_BODY

    return "".join(output_chars)
def _replace_equals_style ( text ) : STATE_BODY = 0 # not in a expression STATE_PREFIX = 1 # '=' prefix that denotes the start of an expression STATE_IDENTIFIER = 2 # the identifier part, e.g. 'SUM' in '=SUM(1, 2)' or 'contact.age' in '=contact.age' STATE_BALANCED = 3 # the balanced parentheses delimited part, e.g. '(1, 2)' in 'SUM(1, 2)' STATE_STRING_LITERAL = 4 # a string literal input_chars = list ( text ) output_chars = [ ] state = STATE_BODY current_expression_chars = [ ] current_expression_terminated = False parentheses_level = 0 def replace_expression ( expression ) : expression_body = expression [ 1 : ] # if expression doesn't end with ) then check it's an allowed top level context reference if not expression_body . endswith ( ")" ) : top_level = expression_body . split ( "." ) [ 0 ] . lower ( ) if top_level not in ALLOWED_TOP_LEVELS : return expression return "@" + _convert_equals_style ( expression_body ) # determines whether the given character is a word character, i.e. \w in a regex def is_word_char ( c ) : return c and ( c . isalnum ( ) or c == "_" ) for pos , ch in enumerate ( input_chars ) : # in order to determine if the b in a.b terminates an identifier, we have to peek two characters ahead as it # could be a.b. (b terminates) or a.b.c (b doesn't terminate) next_ch = input_chars [ pos + 1 ] if ( pos < ( len ( input_chars ) - 1 ) ) else None next_next_ch = input_chars [ pos + 2 ] if ( pos < ( len ( input_chars ) - 2 ) ) else None if state == STATE_BODY : if ch == "=" and ( is_word_char ( next_ch ) or next_ch == "(" ) : state = STATE_PREFIX current_expression_chars = [ ch ] else : output_chars . append ( ch ) elif state == STATE_PREFIX : if is_word_char ( ch ) : # we're parsing an expression like =XXX or =YYY() state = STATE_IDENTIFIER elif ch == "(" : # we're parsing an expression like =(1 + 2) state = STATE_BALANCED parentheses_level += 1 current_expression_chars . append ( ch ) elif state == STATE_IDENTIFIER : if ch == "(" : state = STATE_BALANCED parentheses_level += 1 current_expression_chars . append ( ch ) elif state == STATE_BALANCED : if ch == "(" : parentheses_level += 1 elif ch == ")" : parentheses_level -= 1 elif ch == '"' : state = STATE_STRING_LITERAL current_expression_chars . append ( ch ) # expression terminates if parentheses balance if parentheses_level == 0 : current_expression_terminated = True elif state == STATE_STRING_LITERAL : if ch == '"' : state = STATE_BALANCED current_expression_chars . append ( ch ) # identifier can terminate expression in 3 ways: #  1. next char is null (i.e. end of the input) #  2. next char is not a word character or period or left parentheses #  3. next char is a period, but it's not followed by a word character if state == STATE_IDENTIFIER : if ( not next_ch or ( not is_word_char ( next_ch ) and not next_ch == "." and not next_ch == "(" ) or ( next_ch == "." and not is_word_char ( next_next_ch ) ) ) : current_expression_terminated = True if current_expression_terminated : output_chars . append ( replace_expression ( "" . join ( current_expression_chars ) ) ) current_expression_chars = [ ] current_expression_terminated = False state = STATE_BODY return "" . join ( output_chars )