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
|
from ast_tools import token, symbol, ast_to_string, match, atom_list
def slice_ast_to_dict(ast_seq):
sl_vars = {}
if isinstance(ast_seq, (list, tuple)):
for pattern in slice_patterns:
found,data = match(pattern,ast_seq)
if found:
sl_vars = {'begin':'_beg',
'end':'_end',
'step':'_stp',
'single_index':'_index'}
for key in data.keys():
data[key] = ast_to_string(data[key])
sl_vars.update(data)
break;
return sl_vars
def build_slice_atom(slice_vars, position):
# Note: This produces slices that are incorrect for Python
# evaluation because of slicing being exclusive in Python
# and inclusive for blitz on the top end of the range.
# This difference should really be handle in a blitz specific transform,
# but I've put it here for convenience. This doesn't cause any
# problems in code, its just a maintance hassle (I'll forget I did it here)
# and inelegant. *FIX ME*.
###########################################################################
# Handling negative indices.
#
# Range indices that begin with a negative sign, '-', are assumed to be
# negative. Blitz++ interprets negative indices differently than
# Python. To correct this, we subtract negative indices from the length
# of the array (at run-time). If indices do not start with a negative
# sign, they are assumed to be positive.
#
# This scheme doesn't work in the general case. For example, if you
# are calculating negative indices from a math expression that doesn't
# start with the negative sign, then it will be assumed positive and
# hence generate wrong results (and maybe a seg-fault).
#
# I think this case can might be remedied by calculating all ranges on
# the fly, and then subtracting them from the length of the array in
# that dimension if they are negative. This is major code bloat in the
# funcitons and more work. Save till later...
###########################################################################
# I don't think the strip is necessary, but it insures
# that '-' is the first sign for negative indices.
if slice_vars['single_index'] != '_index':
expr = '%(single_index)s' % slice_vars
else:
begin = slice_vars['begin'].strip()
if begin[0] == '-':
slice_vars['begin'] = 'N' + slice_vars['var']+`position`+begin;
end = slice_vars['end'].strip()
if end != '_end' and end[0] != '-':
#compensate for blitz using inclusive indexing on top end
#of slice for positive indices.
slice_vars['end'] = end + '-1'
if end[0] == '-':
slice_vars['end'] = 'N%s[%d]%s-1' % (slice_vars['var'],position,end)
if slice_vars['step'] == '_stp':
# this if/then isn't strictly necessary, it'll
# just keep the output code a little cleaner
expr = 'slice(%(begin)s,%(end)s)' % slice_vars
else:
expr = 'slice(%(begin)s,%(end)s,%(step)s)' % slice_vars
val = atom_list(expr)
return val
def transform_subscript_list(subscript_dict):
# this is gonna edit the ast_list...
subscript_list = subscript_dict['subscript_list']
var = subscript_dict['var']
#skip the first entry (the subscript_list symbol)
slice_position = -1
for i in range(1,len(subscript_list)):
#skip commas...
if subscript_list[i][0] != token.COMMA:
slice_position += 1
slice_vars = slice_ast_to_dict(subscript_list[i])
slice_vars['var'] = var
# create a slice(b,e,s) atom and insert in
# place of the x:y:z atom in the tree.
subscript_list[i] = build_slice_atom(slice_vars, slice_position)
def harvest_subscript_dicts(ast_list):
""" Needs Tests!
"""
subscript_lists = []
if isinstance(ast_list, list):
found,data = match(indexed_array_pattern,ast_list)
# data is a dict with 'var' = variable name
# and 'subscript_list' = to the ast_seq for the subscript list
if found:
subscript_lists.append(data)
for item in ast_list:
if isinstance(item, list):
subscript_lists.extend(harvest_subscript_dicts(item))
return subscript_lists
def transform_slices(ast_list):
""" Walk through an ast_list converting all x:y:z subscripts
to slice(x,y,z) subscripts.
"""
all_dicts = harvest_subscript_dicts(ast_list)
for subscript_dict in all_dicts:
transform_subscript_list(subscript_dict)
slice_patterns = []
CLN = (token.COLON,':')
CLN2= (symbol.sliceop, (token.COLON, ':'))
CLN2_STEP = (symbol.sliceop, (token.COLON, ':'),['step'])
# [begin:end:step]
slice_patterns.append((symbol.subscript, ['begin'],CLN,['end'], CLN2_STEP ))
# [:end:step]
slice_patterns.append((symbol.subscript, CLN,['end'], CLN2_STEP ))
# [begin::step]
slice_patterns.append((symbol.subscript, ['begin'],CLN, CLN2_STEP ))
# [begin:end:]
slice_patterns.append((symbol.subscript, ['begin'],CLN,['end'], CLN2 ))
# [begin::]
slice_patterns.append((symbol.subscript, ['begin'],CLN, CLN2 ))
# [:end:]
slice_patterns.append((symbol.subscript, CLN,['end'], CLN2, ))
# [::step]
slice_patterns.append((symbol.subscript, CLN, CLN2_STEP ))
# [::]
slice_patterns.append((symbol.subscript, CLN, CLN2 ))
# begin:end variants
slice_patterns.append((symbol.subscript, ['begin'],CLN,['end']))
slice_patterns.append((symbol.subscript, CLN,['end']))
slice_patterns.append((symbol.subscript, ['begin'],CLN))
slice_patterns.append((symbol.subscript, CLN))
# a[0] variant -- can't believe I left this out...
slice_patterns.append((symbol.subscript,['single_index']))
indexed_array_pattern = \
(symbol.power,
(symbol.atom,(token.NAME, ['var'])),
(symbol.trailer,
(token.LSQB, '['),
['subscript_list'],
(token.RSQB, ']')
)
)
|