Changeset 7827:8e00d4b32962


Ignore:
Timestamp:
11/23/07 12:58:03 (5 years ago)
Author:
Nick Alexander <ncalexander@…>
Branch:
default
Parents:
7826:b9231b8d1a11 (diff), 7402:cad57dea1832 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge.

Files:
2 edited

Legend:

Unmodified
Added
Removed
  • sage/misc/preparser.py

    r7311 r7827  
    470470def preparse(line, reset=True, do_time=False, ignore_prompts=False): 
    471471    r""" 
     472    sage: preparse("ZZ.<x> = ZZ['x']") 
     473    'ZZ = ZZ["x"]; (x,) = ZZ._first_ngens(Integer(1))' 
     474    sage: preparse("ZZ.<x> = ZZ['y']") 
     475    'ZZ = ZZ["x"]; (x,) = ZZ._first_ngens(Integer(1))' 
     476    sage: preparse("ZZ.<x,y> = ZZ[]") 
     477    'ZZ = ZZ["x, y"]; (x, y,) = ZZ._first_ngens(Integer(2))' 
     478    sage: preparse("ZZ.<x,y> = ZZ['u,v']") 
     479    'ZZ = ZZ["x, y"]; (x, y,) = ZZ._first_ngens(Integer(2))' 
     480    sage: preparse("ZZ.<x> = QQ[2^(1/3)]") 
     481    'ZZ = QQ["x"]; (x,) = ZZ._first_ngens(Integer(1))' 
     482    sage: QQ[2^(1/3)] 
     483    Number Field in a with defining polynomial x^3 - 2 
    472484    """ 
    473485    try: 
  • sage/misc/preparser.py

    r7826 r7827  
    301301        ix = code.find('..') 
    302302    return code 
    303      
     303 
     304def strip_prompts(line): 
     305    r"""Get rid of leading sage: and >>> prompts so that pasting of examples from 
     306    the documentation works. 
     307 
     308    sage: from sage.misc.preparser import strip_prompts 
     309    sage: strip_prompts("sage: 2 + 2") 
     310    '2 + 2' 
     311    sage: strip_prompts(">>>   3 + 2") 
     312    '3 + 2' 
     313    sage: strip_prompts("  2 + 4") 
     314    '  2 + 4' 
     315    """ 
     316    for prompt in ['sage:', '>>>']: 
     317        if line.startswith(prompt): 
     318            line = line[len(prompt):].lstrip() 
     319            break 
     320    return line 
     321 
     322def parse_generators(line, start_index): 
     323    r"""Parse R.<a, b> in line[start_index:]. 
     324 
     325    Returns (modified_line, continue_index); you should resume parsing 
     326    modified_line[continue_index:]. 
     327 
     328    Support for generator construction syntax: 
     329    "obj.<gen0,gen1,...,genN> = objConstructor(...)" 
     330    is converted into 
     331    "obj = objConstructor(..., names=("gen0", "gen1", ..., "genN")); \ 
     332     (gen0, gen1, ..., genN,) = obj.gens()" 
     333 
     334    Also, obj.<gen0,gen1,...,genN> = R[interior] is converted into 
     335    "obj = R[interior]; (gen0, gen1, ..., genN,) = obj.gens()" 
     336 
     337    LIMITATIONS: 
     338       - The entire constructor *must* be on one line. 
     339 
     340    AUTHORS: 
     341        -- 2006-04-14: Joe Wetherell (jlwether@alum.mit.edu) 
     342        -- 2006-04-17: William Stein - improvements to allow multiple statements. 
     343        -- 2006-05-01: William -- fix bug that Joe found 
     344        -- 2006-10-31: William -- fix so obj doesn't have to be mutated 
     345 
     346    TESTS: 
     347        sage: from sage.misc.preparser import preparse 
     348 
     349        Vanilla: 
     350         
     351        sage: preparse("R.<x> = ZZ['x']") 
     352        "R = ZZ['x']; (x,) = R._first_ngens(Integer(1))" 
     353        sage: preparse("R.<x,y> = ZZ['x,y']") 
     354        "R = ZZ['x,y']; (x, y,) = R._first_ngens(Integer(2))" 
     355 
     356        No square brackets: 
     357 
     358        sage: preparse("R.<x> = PolynomialRing(ZZ, 'x')") 
     359        "R = PolynomialRing(ZZ, 'x',names=('x',)); (x,) = R._first_ngens(Integer(1))" 
     360        sage: preparse("R.<x,y> = PolynomialRing(ZZ, 'x,y')") 
     361        "R = PolynomialRing(ZZ, 'x,y',names=('x', 'y')); (x, y,) = R._first_ngens(Integer(2))" 
     362 
     363        Names filled in: 
     364 
     365        sage: preparse("R.<x> = ZZ[]") 
     366        "R = ZZ['x']; (x,) = R._first_ngens(Integer(1))" 
     367        sage: preparse("R.<x,y> = ZZ[]") 
     368        "R = ZZ['x, y']; (x, y,) = R._first_ngens(Integer(2))" 
     369 
     370        Names given not the same as generator names: 
     371 
     372        sage: preparse("R.<x> = ZZ['y']") 
     373        "R = ZZ['y']; (x,) = R._first_ngens(Integer(1))" 
     374        sage: preparse("R.<x,y> = ZZ['u,v']") 
     375        "R = ZZ['u,v']; (x, y,) = R._first_ngens(Integer(2))" 
     376 
     377        Number fields: 
     378 
     379        sage: preparse("K.<a> = QQ[2^(1/3)]") 
     380        'K = QQ[Integer(2)**(Integer(1)/Integer(3))]; (a,) = K._first_ngens(Integer(1))' 
     381        sage: preparse("K.<a, b> = QQ[2^(1/3), 2^(1/2)]") 
     382        'K = QQ[Integer(2)**(Integer(1)/Integer(3)), Integer(2)**(Integer(1)/Integer(2))]; (a, b,) = K._first_ngens(Integer(2))' 
     383 
     384        Just the .<> notation: 
     385 
     386        sage: preparse("R.<x> = ZZx") 
     387        'R = ZZx; (x,) = R._first_ngens(Integer(1))' 
     388        sage: preparse("R.<x, y> = a+b") 
     389        'R = a+b; (x, y,) = R._first_ngens(Integer(2))' 
     390 
     391        Ensure we don't eat too much: 
     392 
     393        sage: preparse("R.<x, y> = ZZ;2") 
     394        'R = ZZ; (x, y,) = R._first_ngens(Integer(2));Integer(2)' 
     395        sage: preparse("R.<x, y> = ZZ['x,y'];2") 
     396        "R = ZZ['x,y']; (x, y,) = R._first_ngens(Integer(2));Integer(2)" 
     397    """ 
     398    i = start_index 
     399    if not line.startswith(".<", i): 
     400        return (line, i) 
     401    try: 
     402        gen_end = line.index(">", i+2) 
     403    except ValueError: 
     404        # Syntax Error -- let Python notice and raise the error 
     405        i += 2 
     406        return (line, i) 
     407 
     408    gen_begin = i 
     409    while gen_begin > 0 and line[gen_begin-1] != ';': 
     410        gen_begin -= 1 
     411 
     412    # parse out the object name and the list of generator names 
     413    gen_obj = line[gen_begin:i].strip() 
     414    gen_list = [s.strip() for s in line[i+2:gen_end].split(',')] 
     415    for g in gen_list: 
     416        if (not g.isalnum() and not g.replace("_","").isalnum()) or len(g) == 0 or not g[0].isalpha(): 
     417            raise SyntaxError, "variable name (='%s') must be alpha-numeric and begin with a letter"%g 
     418 
     419    # format names as a list of strings and a list of variables 
     420    gen_names = tuple(gen_list) 
     421    gen_vars  = ", ".join(gen_list) 
     422 
     423    # find end of constructor: 
     424    #    either end of line, next semicolon, or next #. 
     425    line_after = line[gen_end:] 
     426    c = line_after.find('#') 
     427    if c==-1: c = len(line_after) 
     428    s = line_after.find(';') 
     429    if s==-1: s = len(line_after) 
     430    c = min(c,s) + gen_end 
     431 
     432    gens_assignment = '; (%s,) = %s._first_ngens(%s)' % (gen_vars, gen_obj, gen_vars.count(',')+1) 
     433    ring_assignment = "" 
     434    # Find where the parenthesis of the constructor ends 
     435    if line[:c].rstrip()[-1] == ']': 
     436        # brackets constructor 
     437        c0 = line[:c].find(']') 
     438        d0 = line[:c0].rfind('[') 
     439        if c0 == -1: 
     440            raise SyntaxError, 'constructor must end with ) or ]' 
     441 
     442        in_square_brackets = line[d0+1:c0] 
     443        if in_square_brackets.strip() == '': 
     444            # as a convenience to the user, 'K.<a> = ZZ[]' -> 'K.<a> = ZZ["a"]' 
     445            in_square_brackets = "'%s'" % gen_vars 
     446 
     447        ring_assignment = '%s%s%s' % (line[:i] + line[gen_end+1:d0+1], in_square_brackets, line[c0:c]) 
     448    elif line[:c].rstrip()[-1] == ')': 
     449        c0 = line[:c].rfind(')') 
     450        # General constructor -- rewrite the input line as two commands 
     451        # We have to determine whether or not to put a comma before 
     452        # the list of names.  We do this only if there are already 
     453        # arguments to the constructor.  Some constructors have no 
     454        # arguments, e.g., "K.<a> = f.root_field(  )" 
     455        c1 = line[:c0].rfind('(') 
     456        in_parentheses = line[c1+1:c0].strip() 
     457        if len(in_parentheses) > 0: 
     458            sep = ',' 
     459        else: 
     460            sep = '' 
     461        ring_assignment = '%s%snames=%s)' % (line[:i] + line[gen_end+1:c0], sep, gen_names) 
     462    else: 
     463        ring_assignment = line[:i] + line[gen_end+1:c] 
     464 
     465    line = ring_assignment + gens_assignment + line[c:] 
     466    i += 1 
     467 
     468    return (line, i) 
    304469 
    305470def preparse(line, reset=True, do_time=False, ignore_prompts=False): 
     
    376541 
    377542    if ignore_prompts: 
    378         # Get rid of leading sage: so that pasting of examples from 
     543        # Get rid of leading sage: and >>> so that pasting of examples from 
    379544        # the documentation works. 
    380         for prompt in ['sage:', '>>>']: 
    381             while True: 
    382                 strip = False 
    383                 if line[:3] == prompt: 
    384                     line = line[3:].lstrip() 
    385                     strip = True 
    386                 elif line[:5] == prompt: 
    387                     line = line[5:].lstrip() 
    388                     strip = True 
    389                 if not strip: 
    390                     break 
    391                 else: 
    392                     line = line.lstrip() 
     545        line = strip_prompts(line) 
    393546 
    394547    while i < len(line): 
     
    472625        #     -- 2006-05-01: William -- fix bug that Joe found 
    473626        #     -- 2006-10-31: William -- fix so obj doesn't have to be mutated 
    474         elif (line[i:i+2] == ".<") and not in_quote(): 
    475             try: 
    476                 gen_end = line.index(">", i+2) 
    477             except ValueError: 
    478                 # Syntax Error -- let Python notice and raise the error 
    479                 i += 2 
    480                 continue 
    481                         
    482             gen_begin = i 
    483             while gen_begin > 0 and line[gen_begin-1] != ';': 
    484                 gen_begin -= 1 
    485                         
    486             # parse out the object name and the list of generator names 
    487             gen_obj = line[gen_begin:i].strip() 
    488             gen_list = [s.strip() for s in line[i+2:gen_end].split(',')] 
    489             for g in gen_list: 
    490                 if (not g.isalnum() and not g.replace("_","").isalnum()) or len(g) == 0 or not g[0].isalpha(): 
    491                     raise SyntaxError, "variable name (='%s') must be alpha-numeric and begin with a letter"%g 
    492  
    493             # format names as a list of strings and a list of variables 
    494             gen_names = tuple(gen_list) 
    495             gen_vars  = ", ".join(gen_list) 
    496              
    497             # find end of constructor: 
    498             #    either end of line, next semicolon, or next #. 
    499             line_after = line[gen_end:] 
    500             c = line_after.find('#') 
    501             if c==-1: c = len(line_after) 
    502             s = line_after.find(';') 
    503             if s==-1: s = len(line_after) 
    504             c = min(c,s) + gen_end 
    505  
    506             # Find where the parenthesis of the constructor ends 
    507             if line[:c].rstrip()[-1] == ']': 
    508                 # brackets constructor 
    509                 c0 = line[:c].find(']') 
    510                 d0 = line[:c0].rfind('[') 
    511                 if c0 == -1: 
    512                     raise SyntaxError, 'constructor must end with ) or ]' 
    513                 line_new = '%s"%s"%s; (%s,) = %s._first_ngens(%s)'%( 
    514                     line[:i] + line[gen_end+1:d0+1], gen_vars, 
    515                     line[c0:c], gen_vars, gen_obj, gen_vars.count(',')+1) 
    516             else: 
    517                 c0 = line[:c].rfind(')') 
    518                 # General constructor -- rewrite the input line as two commands 
    519                 # We have to determine whether or not to put a comma before 
    520                 # the list of names.  We do this only if there are already 
    521                 # arguments to the constructor.  Some constructors have no 
    522                 # arguments, e.g., "K.<a> = f.root_field(  )" 
    523                 c1 = line[:c0].rfind('(') 
    524                 if len(line[c1+1:c0].strip()) > 0: 
    525                     sep = ',' 
    526                 else: 
    527                     sep = '' 
    528  
    529                 line_new = '%s%snames=%s); (%s,) = %s._first_ngens(%s)'%( 
    530                     line[:i] + line[gen_end+1:c0], sep, gen_names, 
    531                     gen_vars, gen_obj, gen_vars.count(',')+1) 
    532                         
    533             line = line_new + line[c:] 
    534             #i = len(line_new) 
    535             i += 1 
    536             
    537             continue 
     627        elif not in_quote() and (line[i:i+2] == ".<"): 
     628            line, i = parse_generators(line, i) 
    538629 
    539630        # Support for calculus-like function assignment, the line 
     
    690781    return line 
    691782 
    692  
    693  
    694783###################################################### 
    695784## Apply the preparser to an entire file 
Note: See TracChangeset for help on using the changeset viewer.