Skip to content
This repository has been archived by the owner on Nov 15, 2021. It is now read-only.

Commit

Permalink
adding slice notation for string operation
Browse files Browse the repository at this point in the history
  • Loading branch information
localhuman committed Sep 29, 2017
1 parent 0ff3cab commit 20dde71
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 8 deletions.
57 changes: 57 additions & 0 deletions boa/code/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class Block():
iterable_loopcounter = None
iterable_looplength = None
iterable_item_name = None
slice_item_length = None

has_dynamic_iterator = False

def __init__(self, operation_list):
Expand All @@ -30,6 +32,8 @@ def __init__(self, operation_list):
self.iterable_item_name = None
self.has_dynamic_iterator = False

self.slice_item_length = None

def set_label(self, label):
self._label = label
self.oplist[0].jump_label = label
Expand All @@ -41,6 +45,57 @@ def line(self):
return token.line_no
return None


@property
def has_slice(self):
for token in self.oplist:
if token.py_op == pyop.BUILD_SLICE:
return True

def preprocess_slice(self):
print("TOTAL OPLIST: %s " % len(self.oplist))
index_to_remove=-1
do_calculate_item_length = False
getlength_token=None
slicelength_token = None
for index, token in enumerate(self.oplist):
if token.py_op == pyop.BUILD_SLICE:
#first, we want to take out the BINARY_SUBSC op, since we wont need it
index_to_remove = index + 1

#now we want to check the second item, for example item[2:4], we need to check 4
#if you do item[2:], in python, normally the end is inferred
#but we get None.
#in that case, we need to convert None into the length of the item being sliced
end_op = self.oplist[index-1]
print("ENDOP: %s " % end_op.args)

if end_op.args == None:
print("END OP IS NONE, convert to function len call!")
do_calculate_item_length = True
getlength_token = PyToken(op=Opcode(pyop.CALL_FUNCTION), lineno=token.line_no, args=1)
getlength_token.func_params = [self.oplist[0]]
getlength_token.func_name = 'len'

# now we need a variable name to store the length of the array
self.slice_item_length = 'sliceitem_length_%s' % Block.forloop_counter

# now store the variable which is the output of the len(items) call
slicelength_token = PyToken(op=Opcode(pyop.STORE_FAST), lineno=token.line_no, index=-1,
args=self.slice_item_length)

end_op.py_op = Opcode(pyop.LOAD_FAST)
end_op.args = self.slice_item_length

if index_to_remove > -1:
del self.oplist[index_to_remove]

if do_calculate_item_length:
print("DO CALCULATE!!!")
self.oplist = [getlength_token,slicelength_token] + self.oplist

print("TOTAL OPLIST: %s " % len(self.oplist))

@property
def is_return(self):
if len(self.oplist):
Expand Down Expand Up @@ -217,6 +272,8 @@ def process_iter_body(self, setup_block):

@property
def has_unprocessed_method_calls(self):
if self.has_slice:
return False
for token in self.oplist:
if token.py_op == pyop.CALL_FUNCTION and token.func_processed == False:
return True
Expand Down
6 changes: 3 additions & 3 deletions boa/code/builtins.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,17 @@ def __setitem__(self, *args, **kwargs): # real signature unknown
pass


# @TODO this currently reverses the order of str1 and str2

def concat(str1, str2):
"""
range(str1, str2) -> str object
Return a string that is the concatenation of the two arguments
Return a string that is the concatenation of the two arguments ( str1 + str2 )
"""
pass


# @TODO this currently does not work
# This is not necessary. you can use mystring[start:end]
#def substr(source,start_index, count):
# """
# substr(source, start_index, count) -> list object
Expand Down
5 changes: 5 additions & 0 deletions boa/code/method.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,11 @@ def process_block_groups(self):
block.mark_as_end()


if block.has_slice:
block.preprocess_slice()
if block.slice_item_length is not None:
length = len(self.local_stores)
self.local_stores[block.slice_item_length] = length

if block.has_unprocessed_array:
block.preprocess_arrays()
Expand Down
13 changes: 9 additions & 4 deletions boa/code/token.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,10 @@ def to_vm(self, tokenizer, prev_token=None):
elif op == pyop.BINARY_SUBSCR:
token = tokenizer.convert1(VMOp.PICKITEM,self)

elif op == pyop.BUILD_SLICE:
token = tokenizer.convert1(VMOp.SUBSTR, self)

#strings

elif op == pyop.CALL_FUNCTION:

Expand Down Expand Up @@ -739,7 +743,10 @@ def convert_method_call(self, pytoken):
if param_len <= 1:
pass
elif param_len == 2:
self.insert1(VMOp.SWAP)
# if we are using concat, we don't want to swap
if pytoken.func_name != 'concat':
self.insert1(VMOp.SWAP)

elif param_len == 3:
self.insert_push_integer(2)
self.insert1(VMOp.XSWAP)
Expand Down Expand Up @@ -802,7 +809,7 @@ def convert_method_call(self, pytoken):

def is_op_call(self, op):

if op in ['len','abs','min','max','concat','substr','take']:
if op in ['len','abs','min','max','concat','take']:
return True
return False

Expand All @@ -818,8 +825,6 @@ def convert_op_call(self, op, pytoken=None):
return self.convert1(VMOp.MAX,pytoken)
elif op == 'concat':
return self.convert1(VMOp.CAT,pytoken)
elif op == 'substr':
return self.convert1(VMOp.SUBSTR,pytoken)
elif op == 'take':
return self.convert1(VMOp.LEFT,pytoken)
return None
Expand Down
7 changes: 6 additions & 1 deletion boa/tests/src/StringTest1.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
from boa.code.builtins import concat
from boa.blockchain.vm.Neo.Runtime import Notify

def Main(a, b):

c = a + b
c = concat(a, b)

Notify(c)


if c == 'hellogoodbye':

Expand Down
22 changes: 22 additions & 0 deletions boa/tests/src/StringTest2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from boa.code.builtins import concat
from boa.blockchain.vm.Neo.Runtime import Notify

def Main():


mystring = 'abcdefgh'
count = 3
mys = mystring[0:count]

strmy = mystring[4:]

Notify(mys)
Notify(strmy)


myarray = [b'\x10',b'\x20',b'\x30',b'\x40']

#mr1 = myarray[0:2] this does not work, need to implement a bytearray thing of some sort
#Notify(mr1)

return 1

0 comments on commit 20dde71

Please sign in to comment.