Ticket #5079: trac_5079.patch

File trac_5079.patch, 23.5 KB (added by mhansen, 12 years ago)
  • sage/misc/preparser.py

    # HG changeset patch
    # User Robert Bradshaw <robertwb@math.washington.edu>
    # Date 1232777584 28800
    # Node ID 64d3162c2180bbc87dedf840fbfeb50a6a86b8a9
    # Parent  350d8f96c73f5177335f8da49a332a396601bac1
    Ticket #5079, better preparsing of literal numbers part 1
    * * *
    [mq]: preparse2
    * * *
    Preparser simplification
    * * *
    Fixed call to strip_string_literals to reflect changes from fixing #5079
    
    diff -r 350d8f96c73f -r 64d3162c2180 sage/misc/preparser.py
    a b  
    194194      'Integer(2)*x'
    195195      sage: implicit_multiplication(False)
    196196      sage: preparse('2x')
    197       'Integer(2)x'
     197      '2x'
    198198    """
    199199    from sage.plot.plot import EMBEDDED_MODE
    200200    if EMBEDDED_MODE:
     
    228228    return in_single_quote or in_double_quote or in_triple_quote
    229229   
    230230
    231 def strip_string_literals(code):
     231def strip_string_literals(code, state=None):
    232232    r"""
    233233    Returns a string with all literal quotes replaced with
    234234    labels and a dict of labels for re-subsitution. This makes
     
    236236   
    237237    EXAMPLES:
    238238        sage: from sage.misc.preparser import strip_string_literals
    239         sage: s, literals = strip_string_literals(r'''['a', "b", 'c', "d\""]''')
     239        sage: s, literals, state = strip_string_literals(r'''['a', "b", 'c', "d\""]''')
    240240        sage: s
    241241        '[%(L1)s, %(L2)s, %(L3)s, %(L4)s]'
    242242        sage: literals
     
    247247        -%(L1)s-%(L2)s-
    248248       
    249249    Triple-quotes are handled as well.
    250         sage: s, literals = strip_string_literals("[a, '''b''', c, '']")
     250        sage: s, literals, state = strip_string_literals("[a, '''b''', c, '']")
    251251        sage: s
    252252        '[a, %(L1)s, c, %(L2)s]'
    253253        sage: print s % literals
    254254        [a, '''b''', c, '']
    255255
    256256    Comments are subsituted too:
    257         sage: s, literals = strip_string_literals("code '#' # ccc 't'"); s
     257        sage: s, literals, state = strip_string_literals("code '#' # ccc 't'"); s
    258258        'code %(L1)s #%(L2)s'
    259259        sage: s % literals
    260260        "code '#' # ccc 't'"
     261       
     262    A state is returned so one can break strings across multiple calls to
     263    this function:
     264        sage: s, literals, state = strip_string_literals('s = "some'); s
     265        's = %(L1)s'
     266        sage: s, literals, state = strip_string_literals('thing" * 5', state); s
     267        '%(L1)s * 5'
    261268    """
    262269    new_code = []
    263270    literals = {}
    264271    counter = 0
    265272    start = q = 0
    266     in_quote = False
    267     raw = False
     273    if state is None:
     274        in_quote = False
     275        raw = False
     276    else:
     277        in_quote, raw = state
    268278    while True:
    269279        sig_q = code.find("'", q)
    270280        dbl_q = code.find('"', q)
     
    282292            new_code.append("#%%(%s)s" % label)
    283293            start = q = newline
    284294        elif q == -1:
    285             new_code.append(code[start:].replace('%','%%'))
     295            if in_quote:
     296                counter += 1
     297                label = "L%s" % counter
     298                literals[label] = code[start:]
     299                new_code.append("%%(%s)s" % label)
     300            else:
     301                new_code.append(code[start:].replace('%','%%'))
    286302            break
    287303        elif in_quote:
    288304            if not raw and code[q-1] == '\\':
     
    302318            else:
    303319                q += 1
    304320        else:
    305             raw = q>0 and code[q-1] in ['r', 'R']
     321            raw = q>0 and code[q-1] in 'rR'
    306322            if len(code) >= q+3 and (code[q+1] == code[q] == code[q+2]):
    307323                in_quote = code[q]*3
    308324            else:
     
    310326            new_code.append(code[start:q].replace('%', '%%'))
    311327            start = q
    312328            q += len(in_quote)
    313            
    314     return "".join(new_code), literals
     329   
     330    return "".join(new_code), literals, (in_quote, raw)
    315331
    316332
    317333def containing_block(code, ix, delimiters=['()','[]','{}'], require_delim=True):
     
    431447        '[_sage_const_1 , _sage_const_1p1 , _sage_const_1e1 , -_sage_const_1en1 , _sage_const_1p ]'
    432448       
    433449        sage: extract_numeric_literals("[1.sqrt(), 1.2.sqrt(), 1r, 1.2r, R.1, R0.1, (1..5)]")[0]
    434         '[_sage_const_1 .sqrt(), _sage_const_1p2 .sqrt(), 1r, 1.2r, R.1, R0.1, (_sage_const_1 .._sage_const_5 )]'
     450        '[_sage_const_1 .sqrt(), _sage_const_1p2 .sqrt(), 1 , 1.2 , R.1, R0.1, (_sage_const_1 .._sage_const_5 )]'
     451    """
     452    return preparse_numeric_literals(code, True)
     453
     454all_num_regex = None
     455
     456def preparse_numeric_literals(code, extract=False):
     457    """
     458    This preparses numerical literals into their sage counterparts,
     459    e.g. Integer, RealNumber, and ComplexNumber.
     460    If extract is true, then it will create names for the literals
     461    and return a dict of name-construction pairs along with the
     462    processed code.
     463   
     464    EXAMPLES:
     465        sage: from sage.misc.preparser import preparse_numeric_literals
     466        sage: preparse_numeric_literals("5")
     467        'Integer(5)'
     468        sage: preparse_numeric_literals("5j")
     469        "ComplexNumber(0, '5')"
     470        sage: preparse_numeric_literals("5jr")
     471        '5J'
     472        sage: preparse_numeric_literals("5l")
     473        '5l'
     474        sage: preparse_numeric_literals("5L")
     475        '5L'
     476        sage: preparse_numeric_literals("1.5")
     477        "RealNumber('1.5')"
     478        sage: preparse_numeric_literals("1.5j")
     479        "ComplexNumber(0, '1.5')"
     480        sage: preparse_numeric_literals(".5j")
     481        "ComplexNumber(0, '.5')"
     482        sage: preparse_numeric_literals("5e9j")
     483        "ComplexNumber(0, '5e9')"
     484        sage: preparse_numeric_literals("5.")
     485        "RealNumber('5.')"
     486        sage: preparse_numeric_literals("5.j")
     487        "ComplexNumber(0, '5.')"
     488        sage: preparse_numeric_literals("5.foo()")
     489        'Integer(5).foo()'
     490        sage: preparse_numeric_literals("5.5.foo()")
     491        "RealNumber('5.5').foo()"
     492        sage: preparse_numeric_literals("5.5j.foo()")
     493        "ComplexNumber(0, '5.5').foo()"
     494        sage: preparse_numeric_literals("5j.foo()")
     495        "ComplexNumber(0, '5').foo()"
     496        sage: preparse_numeric_literals("1.exp()")
     497        'Integer(1).exp()'
     498        sage: preparse_numeric_literals("1e+10")
     499        "RealNumber('1e+10')"
     500        sage: preparse_numeric_literals("0x0af")
     501        'Integer(0x0af)'
     502        sage: preparse_numeric_literals("0x10.sqrt()")
     503        'Integer(0x10).sqrt()'
     504        sage: preparse_numeric_literals('0o100')
     505        "Integer('100', 8)"
     506        sage: preparse_numeric_literals('0b111001')
     507        "Integer('111001', 2)"
    435508    """
    436509    literals = {}
    437510    last = 0
    438511    new_code = []
    439     dec_num = r"\b\d+\b"
    440     hex_num = r"\b0x[0-9a-fA-F]\b"
    441     # This is slightly annoying as floating point numbers may start
    442     # with a decimal point, but if they do the \b will not match.
    443     float_num = r"((\b\d+([.]\d*)?)|([.]\d+))([eE][-+]?\d+)?\b"
    444     all_num = r"(%s)|(%s)|(%s)" % (float_num, dec_num, hex_num)
    445     for m in re.finditer(all_num, code):
    446         num, start, end = m.group(), m.start(), m.end()
    447512
    448         # The Sage preparser does extra things with numbers, which we need to handle here.
    449         if '.' in num:
    450             if start > 0 and num[0] == '.':
    451                 if code[start-1] == '.':
    452                     # handle Ellipsis
    453                     start += 1
    454                     num = num[1:]
    455                 elif re.match(r'[a-zA-Z0-9_\])]', code[start-1]):
    456                     # handle R.0
    457                     continue
    458             elif end < len(code) and num[-1] == '.':
    459                 if re.match('[a-zA-Z]', code[end]):
    460                     # handle 4.sqrt()
    461                     end -= 1
    462                     num = num[:-1]
    463                 elif re.match(r'\d', code[end]):
    464                     # handle 4.0r
    465                     continue
    466         elif end < len(code) and code[end] == '.':
    467             # \b does not match after the .
    468             # two dots in a row would be an ellipsis
    469             if end+1 == len(code) or code[end+1] != '.':
    470                 end += 1
    471                 num += '.'
     513    global all_num_regex
     514    if all_num_regex is None:
     515        dec_num = r"\b\d+"
     516        hex_num = r"\b0x[0-9a-f]+"
     517        oct_num = r"\b0o[0-7]+"
     518        bin_num = r"\b0b[01]+"
     519        # This is slightly annoying as floating point numbers may start
     520        # with a decimal point, but if they do the \b will not match.
     521        float_num = r"((\b\d+([.]\d*)?)|([.]\d+))(e[-+]?\d+)?"
     522        all_num = r"((%s)|(%s)|(%s)|(%s)|(%s))(rj|rL|jr|Lr|j|L|r|)\b" % (float_num, dec_num, hex_num, oct_num, bin_num)
     523        all_num_regex = re.compile(all_num, re.I)
     524       
     525    for m in all_num_regex.finditer(code):
     526        start, end = m.start(), m.end()
     527        num = m.group(1)
     528        postfix = m.groups()[-1].upper()
     529       
     530        if 'R' in postfix:
     531            num_name = num_make = num + postfix.replace('R', '')
     532        elif 'L' in postfix:
     533            continue
     534        else:
     535       
     536            # The Sage preparser does extra things with numbers, which we need to handle here.
     537            if '.' in num:
     538                if start > 0 and num[0] == '.':
     539                    if code[start-1] == '.':
     540                        # handle Ellipsis
     541                        start += 1
     542                        num = num[1:]
     543                    elif re.match(r'[a-zA-Z0-9_\])]', code[start-1]):
     544                        # handle R.0
     545                        continue
     546                elif end < len(code) and num[-1] == '.':
     547                    if re.match('[a-zA-Z_]', code[end]):
     548                        # handle 4.sqrt()
     549                        end -= 1
     550                        num = num[:-1]
     551            elif end < len(code) and code[end] == '.' and not postfix and re.match(r'\d+$', num):
     552                # \b does not match after the . for floating point
     553                # two dots in a row would be an ellipsis
     554                if end+1 == len(code) or code[end+1] != '.':
     555                    end += 1
     556                    num += '.'
     557               
     558            if '.' in num or 'e' in num or 'E' in num or 'J' in postfix:
     559                num_name = numeric_literal_prefix + num.replace('.', 'p').replace('-', 'n').replace('+', '')
     560                if 'J' in postfix:
     561                    num_make = "ComplexNumber(0, '%s')" % num
     562                    num_name += 'j'
     563                else:
     564                    num_make = "RealNumber('%s')" % num
     565            else:
     566                num_name = numeric_literal_prefix + num
     567                if len(num) > 3:
     568                    # Py3 oct and bin support
     569                    if num[1] in 'bB':
     570                        num_make = "Integer('%s', 2)" % num[2:]
     571                    elif num[1] in 'oO':
     572                        num_make = "Integer('%s', 8)" % num[2:]
     573                    else:
     574                        num_make = "Integer(%s)" % num
     575                else:
     576                    num_make = "Integer(%s)" % num
     577       
     578            literals[num_name] = num_make
    472579           
    473         if '.' in num or 'e' in num or 'E' in num:
    474             num_name = numeric_literal_prefix + num.replace('.', 'p').replace('-', 'n').replace('+', '')
    475             num_make = "RealNumber('%s')" % num
     580        new_code.append(code[last:start])
     581        if extract:
     582            new_code.append(num_name+' ')
    476583        else:
    477             num_name = numeric_literal_prefix + num
    478             num_make = "Integer(%s)" % num
    479         literals[num_name] = num_make
    480         new_code.append(code[last:start])
    481         new_code.append(num_name+' ')
     584            new_code.append(num_make)
    482585        last = end
    483586       
    484587    new_code.append(code[last:])
    485     return ''.join(new_code), literals
     588    code = ''.join(new_code)
     589    if extract:
     590        return code, literals
     591    else:
     592        return code
     593
    486594
    487595def strip_prompts(line):
    488596    r"""Get rid of leading sage: and >>> prompts so that pasting of examples from
     
    532640        Vanilla:
    533641       
    534642        sage: preparse("R.<x> = ZZ['x']")
    535         "R = ZZ['x']; (x,) = R._first_ngens(Integer(1))"
     643        "R = ZZ['x']; (x,) = R._first_ngens(1)"
    536644        sage: preparse("R.<x,y> = ZZ['x,y']")
    537         "R = ZZ['x,y']; (x, y,) = R._first_ngens(Integer(2))"
     645        "R = ZZ['x,y']; (x, y,) = R._first_ngens(2)"
    538646
    539647        No square brackets:
    540648
    541649        sage: preparse("R.<x> = PolynomialRing(ZZ, 'x')")
    542         "R = PolynomialRing(ZZ, 'x',names=('x',)); (x,) = R._first_ngens(Integer(1))"
     650        "R = PolynomialRing(ZZ, 'x',names=('x',)); (x,) = R._first_ngens(1)"
    543651        sage: preparse("R.<x,y> = PolynomialRing(ZZ, 'x,y')")
    544         "R = PolynomialRing(ZZ, 'x,y',names=('x', 'y')); (x, y,) = R._first_ngens(Integer(2))"
     652        "R = PolynomialRing(ZZ, 'x,y',names=('x', 'y')); (x, y,) = R._first_ngens(2)"
    545653
    546654        Names filled in:
    547655
    548656        sage: preparse("R.<x> = ZZ[]")
    549         "R = ZZ['x']; (x,) = R._first_ngens(Integer(1))"
     657        "R = ZZ['x']; (x,) = R._first_ngens(1)"
    550658        sage: preparse("R.<x,y> = ZZ[]")
    551         "R = ZZ['x, y']; (x, y,) = R._first_ngens(Integer(2))"
     659        "R = ZZ['x, y']; (x, y,) = R._first_ngens(2)"
    552660
    553661        Names given not the same as generator names:
    554662
    555663        sage: preparse("R.<x> = ZZ['y']")
    556         "R = ZZ['y']; (x,) = R._first_ngens(Integer(1))"
     664        "R = ZZ['y']; (x,) = R._first_ngens(1)"
    557665        sage: preparse("R.<x,y> = ZZ['u,v']")
    558         "R = ZZ['u,v']; (x, y,) = R._first_ngens(Integer(2))"
     666        "R = ZZ['u,v']; (x, y,) = R._first_ngens(2)"
    559667
    560668        Number fields:
    561669
    562670        sage: preparse("K.<a> = QQ[2^(1/3)]")
    563         'K = QQ[Integer(2)**(Integer(1)/Integer(3))]; (a,) = K._first_ngens(Integer(1))'
     671        'K = QQ[Integer(2)**(Integer(1)/Integer(3))]; (a,) = K._first_ngens(1)'
    564672        sage: preparse("K.<a, b> = QQ[2^(1/3), 2^(1/2)]")
    565         'K = QQ[Integer(2)**(Integer(1)/Integer(3)), Integer(2)**(Integer(1)/Integer(2))]; (a, b,) = K._first_ngens(Integer(2))'
     673        'K = QQ[Integer(2)**(Integer(1)/Integer(3)), Integer(2)**(Integer(1)/Integer(2))]; (a, b,) = K._first_ngens(2)'
    566674
    567675        Just the .<> notation:
    568676
    569677        sage: preparse("R.<x> = ZZx")
    570         'R = ZZx; (x,) = R._first_ngens(Integer(1))'
     678        'R = ZZx; (x,) = R._first_ngens(1)'
    571679        sage: preparse("R.<x, y> = a+b")
    572         'R = a+b; (x, y,) = R._first_ngens(Integer(2))'
     680        'R = a+b; (x, y,) = R._first_ngens(2)'
    573681
    574682        Ensure we don't eat too much:
    575683
    576684        sage: preparse("R.<x, y> = ZZ;2")
    577         'R = ZZ; (x, y,) = R._first_ngens(Integer(2));Integer(2)'
     685        'R = ZZ; (x, y,) = R._first_ngens(2);Integer(2)'
    578686        sage: preparse("R.<x, y> = ZZ['x,y'];2")
    579         "R = ZZ['x,y']; (x, y,) = R._first_ngens(Integer(2));Integer(2)"
     687        "R = ZZ['x,y']; (x, y,) = R._first_ngens(2);Integer(2)"
    580688    """
    581689    i = start_index
    582690    if not line.startswith(".<", i):
     
    651759    return (line, i)
    652760
    653761eq_chars_pre = ["=", "!", ">", "<", "+", "-", "*", "/", "^"]
     762quote_state = None
    654763
    655 def preparse(line, reset=True, do_time=False, ignore_prompts=False):
     764def preparse(line, reset=True, do_time=False, ignore_prompts=False, after_semicolon=False):
    656765    r"""
    657766    EXAMPLES:
    658767        sage: preparse("ZZ.<x> = ZZ['x']")
    659         "ZZ = ZZ['x']; (x,) = ZZ._first_ngens(Integer(1))"
     768        "ZZ = ZZ['x']; (x,) = ZZ._first_ngens(1)"
    660769        sage: preparse("ZZ.<x> = ZZ['y']")
    661         "ZZ = ZZ['y']; (x,) = ZZ._first_ngens(Integer(1))"
     770        "ZZ = ZZ['y']; (x,) = ZZ._first_ngens(1)"
    662771        sage: preparse("ZZ.<x,y> = ZZ[]")
    663         "ZZ = ZZ['x, y']; (x, y,) = ZZ._first_ngens(Integer(2))"
     772        "ZZ = ZZ['x, y']; (x, y,) = ZZ._first_ngens(2)"
    664773        sage: preparse("ZZ.<x,y> = ZZ['u,v']")
    665         "ZZ = ZZ['u,v']; (x, y,) = ZZ._first_ngens(Integer(2))"
     774        "ZZ = ZZ['u,v']; (x, y,) = ZZ._first_ngens(2)"
    666775        sage: preparse("ZZ.<x> = QQ[2^(1/3)]")
    667         'ZZ = QQ[Integer(2)**(Integer(1)/Integer(3))]; (x,) = ZZ._first_ngens(Integer(1))'
     776        'ZZ = QQ[Integer(2)**(Integer(1)/Integer(3))]; (x,) = ZZ._first_ngens(1)'
    668777        sage: QQ[2^(1/3)]
    669778        Number Field in a with defining polynomial x^3 - 2
    670779
     
    688797        "def foo(x):\n    '''\n    It's a comment.\n    '''\n    return x**Integer(2)"
    689798
    690799    """
    691     try:
    692         # [1,2,..,n] notation
    693         L, literals = strip_string_literals(line)
    694         L = parse_ellipsis(L, preparse_step=False)
     800    global quote_state
     801    if reset:
     802        quote_state = None
     803
     804    if not after_semicolon:
     805        # This part handles lines with semi-colons all at once
     806        # Then can also handle multiple lines more efficiently, but
     807        # that optimization can be done later.
     808        L, literals, quote_state = strip_string_literals(line, quote_state)
     809       
     810        # Ellipsis Range
     811        # [1..n]
     812        try:
     813            L = parse_ellipsis(L, preparse_step=False)
     814        except SyntaxError:
     815            pass
     816           
     817        # Implicit Multiplication
     818        # 2x -> 2*x
     819        if implicit_mul_level:
     820            L = implicit_mul(L, level = implicit_mul_level)
     821           
     822        # Wrapping
     823        # 1 + 0.5 -> Integer(1) + RealNumber('0.5')
     824        L = preparse_numeric_literals(L)
     825       
     826        # Generators
     827        # R.0 -> R.gen(0)
     828        L = re.sub(r'([_a-zA-Z]\w*|[)\]])\.(\d+)', r'\1.gen(\2)', L)
     829
     830        # Use ^ for exponentiation and ^^ for xor
     831        # (A side effect is that **** becomes xor as well.)
     832        L = L.replace('^', '**').replace('****', '^')
     833
    695834        line = L % literals
    696     except SyntaxError:
    697         pass
    698835
    699     if implicit_mul_level:
    700         line = implicit_mul(line, level = implicit_mul_level)
    701836
    702837    # find where the parens are for function assignment notation
    703838    oparen_index = -1
     
    717852        i = line.find('...')
    718853        return line[:i+3] + preparse(line[i+3:], reset=reset, do_time=do_time, ignore_prompts=ignore_prompts)
    719854
    720     # Wrap integers with ZZ() and reals with RR().
    721     def wrap_num(i, line, is_real, num_start):
    722         zz = line[num_start:i]
    723         if is_real or '.' in zz:
    724             if zz[-1] == '.' and i < len(line) and line[i].isalpha():
    725                 # by popular demand -- this allows, e.g., 173.sqrt().
    726                 if '.' in zz[:-1]:
    727                     O = "RealNumber('"; C="')."
    728                 else:
    729                     O = "Integer("; C = ")."
    730                 zz = zz[:-1]
    731             else:
    732                 O = "RealNumber('"; C="')"
    733         else:
    734             O = "Integer("; C = ")"
    735         line = line[:num_start] + O + zz + C + line[i:]
    736         return line, len(O+C)
    737    
    738855    i = 0
    739     num_start = -1
    740     in_number = False
    741     is_real = False
    742     is_hex = False
    743 
    744856    in_args = False
    745857
    746858    if reset:
     
    789901                    i += 1
    790902                    continue
    791903
    792         # Decide if we should wrap a particular integer or real literal
    793         if in_number:
    794             if line[i] == ".":
    795                 is_real = True
    796             elif not is_real and i == num_start+1 and line[num_start:i+1].lower() == '0x':
    797                 is_hex = True
    798             elif not (line[i].isdigit() or (is_hex and line[i].lower() in 'abcdef')):
    799                 # end of a number
    800                 # Do we wrap?
    801                 if in_quote():
    802                     # do not wrap
    803                     pass
    804                 elif i < len(line) and line[i] == 'x' and line[i-1] == '0' and num_start==i-1:
    805                     # Yes, hex constant.
    806                     i += 1
    807                     continue
    808                 elif i < len(line) and line[i] in 'eE':
    809                     # Yes, in scientific notation, so will wrap later
    810                     is_real = True
    811                     i += 1   
    812                     if i < len(line) and line[i] == '-':
    813                         i += 2
    814                     continue
    815                 elif i < len(line) and line[i] in 'rR':
    816                     # Raw number so do not wrap; but have to get rid of the "r".
    817                     line = line[:i] + line[i+1:]
    818                 else:
    819                     line, n = wrap_num(i, line, is_real, num_start)
    820                     i += n
    821                 in_number = False
    822                 is_real = False
    823                 continue
    824 
    825         elif line[i] == ";" and not in_quote():
    826             line = line[:i+1] + preparse(line[i+1:], reset, do_time, ignore_prompts)
     904        if line[i] == ";" and not in_quote():
     905            line = line[:i+1] + preparse(line[i+1:], reset, do_time, ignore_prompts, after_semicolon=True)
    827906            i = len(line)
    828907            continue
    829908
     
    9411020        #   
    9421021        ####### END CALCULUS ########
    9431022
    944         # Since we use ^ for exponentiation (see below), we
    945         # rewrite ^^ to ^ so that XOR is still accessible
    946         elif line[i:i+2] == "^^" and not in_quote():
    947             line = line[:i] + "^" + line[i+2:]
    948             i += 1
    949             continue
    950 
    951         # exponents can be either ^ or **
    952         elif line[i] == "^" and not in_quote():
    953             line = line[:i] + "**" + line[i+1:]
    954             i += 2
    955             continue
    956 
    957         elif line[i] == "." and i > 0 and i < len(line)-1 and not in_quote() and \
    958                  (isalphadigit_(line[i-1]) or line[i-1] == ")" or line[i-1] == ']') and line[i+1].isdigit():
    959             # Generators: replace all ".<number>" by ".gen(<number>)"
    960             # If . is preceeded by \, then replace "\." by ".".
    961             j = i+1
    962             while j < len(line) and line[j].isdigit():
    963                 j += 1
    964             line = line[:i] + ".gen(" + line[i+1:j] + ")" + line[j:]
    965             i = j+4
    966 
    967         if     not in_number and \
    968                not in_quote():
     1023        if not in_quote():
    9691024
    9701025            if i < len(line)-1 and line[i] == '\\':
    9711026                j = i+1
     
    9761031                    j += 1
    9771032                line = line[:i] + "._backslash_(" + line[i+1:j] + ')' + line[j:]
    9781033               
    979             elif (line[i].isdigit() or \
    980                    (len(line)>i+1 and line[i] == '.' and line[i+1].isdigit())) and \
    981                (i == 0 or (i > 0 and not (isalphadigit_(line[i-1]) \
    982                                           or line[i-1] == ')'))):
    983                 in_number = True
    984                 num_start = i
    985            
     1034
    9861035        # Decide if we hit a comment, so we're done.
    9871036        if line[i] == '#' and not (in_single_quote or in_double_quote or in_triple_quote):
    9881037            i = len(line)
    9891038            break
    9901039
    9911040        i += 1
    992 
    993     if in_number:
    994         line, _ = wrap_num(i, line, is_real, num_start)
    9951041
    9961042    # Time command like in MAGMA: (commented out, since it's standard in IPython now)
    9971043    L = line.lstrip()
     
    10391085        numeric_literals = False
    10401086   
    10411087    if numeric_literals:
    1042         contents, literals = strip_string_literals(contents)
     1088        contents, literals, state = strip_string_literals(contents)
    10431089        contents, nums = extract_numeric_literals(contents)
    10441090        contents = contents % literals
    10451091        if nums:
     
    11491195                                          code[m.end():])
    11501196        return code
    11511197       
    1152     code, literals = strip_string_literals(code)
     1198    code, literals, state = strip_string_literals(code)
    11531199    if level >= 1:
    11541200        no_mul_token = " '''_no_mult_token_''' "
    11551201        code = re.sub(r'\b0x', r'0%sx' % no_mul_token, code)  # hex digits
  • sage/server/notebook/cell.py

    diff -r 350d8f96c73f -r 64d3162c2180 sage/server/notebook/cell.py
    a b  
    860860
    861861        """
    862862        # Do *not* cache
    863         s, _ = strip_string_literals(self.input_text())
     863        s = strip_string_literals(self.input_text())[0]
    864864        return bool(re.search('(?<!\w)interact\s*\(.*\).*', s) or re.search('\s*@\s*interact\s*\n', s))
    865865
    866866    def is_interacting(self):