Skip to content

Commit

Permalink
various fixes, result formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kus committed Mar 6, 2020
1 parent 26b0e6e commit 853b34f
Show file tree
Hide file tree
Showing 319 changed files with 1,100 additions and 1,019 deletions.
10 changes: 6 additions & 4 deletions pytezos/repl/blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,9 @@ def do_implicit_account(ctx: Context, prim, args, annots):

def decrease_balance(ctx: Context, amount: Mutez):
balance = get_balance(ctx)
assert int(amount) <= int(balance), f'needed {int(amount)} utz, got only {int(balance)} utz'
ctx.set('BALANCE', Mutez(int(balance) - int(amount)))
if int(balance) > 0:
assert int(amount) <= int(balance), f'needed {int(amount)} utz, got only {int(balance)} utz'
ctx.set('BALANCE', Mutez(int(balance) - int(amount)))


@instruction('CREATE_CONTRACT', args_len=1)
Expand All @@ -177,20 +178,21 @@ def do_create_contract(ctx: Context, prim, args, annots):
assert_stack_type(delegate, Option)
assert_equal_types(storage_type, storage.type_expr)

originated_address = Address.new(ctx.dummy_gen.get_fresh_address())
content = {
'kind': 'origination',
'source': ctx.dummy_gen.self,
'balance': str(int(amount)),
'script': {
'storage': storage.val_expr,
'code': code
}
},
'originated_contract': str(originated_address)
}

if not delegate.is_none():
content['delegate'] = str(delegate.get_some())

originated_address = Address.new(ctx.dummy_gen.get_fresh_address())
orig = Operation.new(content)
ctx.push(originated_address)
ctx.push(orig)
Expand Down
28 changes: 14 additions & 14 deletions pytezos/repl/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,24 +61,24 @@ def spawn(self, stack):
return ctx

def reset(self):
self.stdout.clear()
self.stdout = []
self.pushed = False

def protect(self, count: int):
assert len(self.stack) >= count, f'got {len(self.stack)} items, wanted to protect {count}'
self.protected += count
self._print(f' protect {count} item(s);')
self.print(f' protect {count} item(s);')

def restore(self, count: int):
assert self.protected >= count, f'wanted to restore {count}, only {self.protected} protected'
self._print(f' restore {count} item(s);')
self.print(f' restore {count} item(s);')
self.protected -= count

def push(self, item: StackItem, annots=None):
assert_stack_item(item)
self.stack.insert(self.protected, item.rename(annots))
self.pushed = True
self._print(f' push {repr(item)};')
self.print(f' push {repr(item)};')

def peek(self):
assert len(self.stack) > 0, 'stack is empty'
Expand All @@ -92,7 +92,7 @@ def pop(self, count: int) -> List[StackItem]:
body = ', '.join(map(repr, res)) # TODO: restrict line length
else:
body = f'{count} items'
self._print(f' pop {body};')
self.print(f' pop {body};')
return res

def pop1(self):
Expand All @@ -114,25 +114,24 @@ def set(self, key, value):
val = micheline_to_michelson(value, inline=True)
else:
val = repr(value)
self._print(f' set {key}={val};')
self.print(f' set {key}={val};')

def unset(self, key):
del self.meta[key]
self._print(f' unset {key};')
if key in self.meta:
del self.meta[key]
self.print(f' unset {key};')

def drop_all(self):
self.stack.clear()
self.protected = 0
self._print(f' drop all;')
self.print(f' drop all;')

def dump(self, count: int):
if len(self.stack) > 0:
count = min(count, len(self.stack))
return self.stack[:count]
else:
return 'stack is empty'

def _print(self, message):
def print(self, message):
if self.debug:
self.stdout.append(message)

Expand All @@ -143,13 +142,14 @@ def format_stack_item(match):
return repr(self.stack[i])

message = re.sub(r'\{(\d+)\}', format_stack_item, template)
self.stdout.append(message)
indent = ' ' * (self.exec_depth - 1)
self.stdout.append(f'\n{indent}PRINT: {message};')

def begin(self, prim=None):
self.pushed = False
if prim:
indent = ' ' * self.exec_depth
self._print(f'\n{indent}{prim}:')
self.print(f'\n{indent}{prim}:')
self.exec_depth += 1

def end(self):
Expand Down
4 changes: 2 additions & 2 deletions pytezos/repl/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def do_drop(ctx: Context, prim, args, annots):

@instruction('DROP')
def do_drop_1(ctx: Context, prim, args, annots):
return do_drop(ctx, prim, [{'int': '1'}], annots)
do_drop(ctx, prim, [{'int': '1'}], annots)


@instruction('DUP')
Expand Down Expand Up @@ -123,7 +123,7 @@ def do_dip(ctx: Context, prim, args, annots):

@instruction('DIP', args_len=1)
def do_dip_1(ctx: Context, prim, args, annots):
return do_dip(ctx, prim, [{'int': '1'}, args[0]], annots)
do_dip(ctx, prim, [{'int': '1'}, args[0]], annots)


@instruction('LAMBDA', args_len=3)
Expand Down
27 changes: 17 additions & 10 deletions pytezos/repl/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@

from pytezos import Contract, pytezos
from pytezos.encoding import is_kt
from pytezos.michelson.converter import micheline_to_michelson
from pytezos.repl.control import instruction, do_interpret
from pytezos.repl.context import Context
from pytezos.repl.parser import get_int, get_string, get_bool, parse_prim_expr, get_entry_expr, assert_expr_equal
from pytezos.repl.types import Pair, Mutez, Address, ChainID, Timestamp, assert_stack_type, List
from pytezos.repl.types import Pair, Mutez, Address, ChainID, Timestamp, assert_stack_type, List, Operation

helpers_prim = ['DUMP', 'PRINT', 'DROP_ALL', 'EXPAND', 'RUN', 'PATCH',
'INCLUDE', 'DEBUG', 'BIG_MAP_DIFF', 'BEGIN', 'COMMIT']
Expand All @@ -15,17 +14,21 @@

@instruction('DUMP', args_len=1)
def do_dump(ctx: Context, prim, args, annots):
return ctx.dump(count=get_int(args[0]))
res = ctx.dump(count=get_int(args[0]))
if res:
return {'kind': 'stack', 'stack': res}
else:
return {'kind': 'message', 'value': 'stack is empty'}


@instruction('DUMP')
def do_dump(ctx: Context, prim, args, annots):
return ctx.dump(count=len(ctx))
def do_dump_all(ctx: Context, prim, args, annots):
return do_dump(ctx, prim, args=[{'int': str(len(ctx))}], annots=annots)


@instruction('PRINT', args_len=1)
def do_print(ctx: Context, prim, args, annots):
ctx.printf(template=f' {get_string(args[0])};')
ctx.printf(template=get_string(args[0]))


@instruction('DEBUG', args_len=1)
Expand All @@ -40,7 +43,7 @@ def do_drop_all(ctx: Context, prim, args, annots):

@instruction('EXPAND', args_len=1)
def do_expand(ctx: Context, prim, args, annots):
return micheline_to_michelson(args[0])
return {'kind': 'code', 'code': args[0]}


@instruction('BEGIN', args_len=2)
Expand All @@ -49,7 +52,7 @@ def do_begin(ctx: Context, prim, args, annots):
assert p_type_expr, f'parameter type is not initialized'

entrypoint = next((a for a in annots if a[0] == '%'), '%default')
ctx.printf(f' use {entrypoint};')
ctx.print(f' use {entrypoint};')

p_type_expr = get_entry_expr(p_type_expr, entrypoint)
parameter = ctx.big_maps.pre_alloc(args[0], p_type_expr, copy=True)
Expand All @@ -72,6 +75,7 @@ def do_commit(ctx: Context, prim, args, annots):

operations = output.get_element(0)
assert_stack_type(operations, List)
assert operations.val_type() == Operation, f'expected list of operations'

s_type_expr = ctx.get('storage')
assert s_type_expr, f'storage type is not initialized'
Expand All @@ -84,7 +88,10 @@ def do_commit(ctx: Context, prim, args, annots):
res = Pair.new(operations, storage)
ctx.push(res)
ctx.debug = debug
return operations, storage, big_map_diff
return {'kind': 'output',
'operations': operations,
'storage': storage,
'big_map_diff': big_map_diff}


@instruction('RUN', args_len=2)
Expand Down Expand Up @@ -141,4 +148,4 @@ def do_include(ctx: Context, prim, args, annots):
def do_big_map_diff(ctx: Context, prim, args, annots):
top = ctx.peek()
_, big_map_diff = ctx.big_maps.diff(top)
return big_map_diff
return {'kind': 'big_map_diff', 'big_map_diff': big_map_diff}
95 changes: 82 additions & 13 deletions pytezos/repl/interpreter.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import yaml
from copy import deepcopy
from pprint import pformat

Expand All @@ -10,16 +11,74 @@
from pytezos.repl.blockchain import *


def get_content(item: Operation):
content = item.val_expr.get('_content')
if content:
return format_content(content)
return {}


def format_stack_item(item: StackItem):
row = {
'value': micheline_to_michelson(item.val_expr),
'type': micheline_to_michelson(item.type_expr)
}
row = {}
if isinstance(item, Operation):
row['value'] = yaml.dump(get_content(item)).rstrip('\n')
elif isinstance(item, List) and item.val_type() == Operation:
row['value'] = yaml.dump([get_content(x) for x in item.val_expr]).rstrip('\n')
else:
row['value'] = micheline_to_michelson(item.val_expr)

row['type'] = micheline_to_michelson(item.type_expr)
if item.name is not None:
row['name'] = item.name
row['name'] = f'@{item.name}'

return row


def format_diff(diff: dict):
if diff['action'] == 'alloc':
return {'big_map': diff['big_map'],
'action': diff['action'],
'key': micheline_to_michelson(diff['key_type']),
'value': micheline_to_michelson(diff['value_type'])}
elif diff['action'] == 'update':
return {'big_map': diff['big_map'],
'action': diff['action'],
'key': micheline_to_michelson(diff['key']),
'value': micheline_to_michelson(diff['value']) if diff.get('value') else 'null'}
elif diff['action'] == 'copy':
return {'destination_big_map': diff['big_map'],
'action': diff['action'],
'value': diff['source_big_map']}
elif diff['action'] == 'remove':
return {'big_map': diff['big_map'],
'action': diff['action']}
else:
assert False, diff['action']


def format_content(content):
if content['kind'] == 'transaction':
return {'kind': content['kind'],
'target': content['destination'],
'amount': content['amount'],
'entrypoint': content['parameters']['entrypoint'],
'parameters': micheline_to_michelson(content['parameters']['value'])}
elif content['kind'] == 'origination':
res = {'kind': content['kind'],
'target': content['originated_contract'],
'amount': content['balance'],
'storage': micheline_to_michelson(content['script']['storage']),
'code': micheline_to_michelson(content['script']['code'])}
if content.get('delegate'):
res['delegate'] = content['delegate']
return res
elif content['kind'] == 'delegation':
return {'kind': content['kind'],
'target': content['delegate']}
else:
assert False, content['kind']


def format_stdout(items):
res = ''.join(items).lstrip('\n')
return res if any(map(lambda x: x in res, ['\n', 'PRINT'])) else ''
Expand All @@ -28,12 +87,22 @@ def format_stdout(items):
def format_result(result):
if result is None:
return None
elif isinstance(result, StackItem):
return [format_stack_item(result)]
elif isinstance(result, list):
if len(result) > 0 and isinstance(result[0], StackItem):
return list(map(format_stack_item, result))
return result
kind = result['kind']
if kind == 'message':
return result
elif kind == 'big_map_diff':
return {'value': list(map(format_diff, result['big_map_diff'])), **result}
elif kind == 'code':
return {'value': micheline_to_michelson(result['code']), **result}
elif kind == 'stack':
return {'value': list(map(format_stack_item, result['stack'])), **result}
elif kind == 'output':
operations = [format_content(x.get('_content')) for x in result['operations'].val_expr]
storage = [format_stack_item(result['storage'])]
big_map_diff = list(map(format_diff, result['big_map_diff']))
return {'value': (operations, storage, big_map_diff), **result}
else:
assert False, kind


def format_stderr(error):
Expand Down Expand Up @@ -72,7 +141,7 @@ def execute(self, code):
try:
res = do_interpret(self.ctx, code_expr)
if res is None and self.ctx.pushed:
res = self.ctx.dump(count=1)
res = {'kind': 'stack', 'stack': self.ctx.dump(count=1)}

int_res['result'] = format_result(res)
int_res['stdout'] = format_stdout(self.ctx.stdout)
Expand All @@ -92,6 +161,6 @@ def execute(self, code):
if int_res.get('stdout'):
print(int_res['stdout'])
if int_res.get('result'):
print('RETURN: ' + pformat(int_res['result']))
print('RESULT: ' + pformat(int_res['result']))

return int_res
7 changes: 3 additions & 4 deletions pytezos/repl/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def get_prim_args(val_expr, prim, args_len: int):

def dispatch_prim_map(val_expr, mapping: dict):
p, args = parse_prim_expr(val_expr)
expected = ' or '.join(map(lambda x: f'{x[0]} ({x[1]} args)', mapping))
expected = ' or '.join(map(lambda x: f'{x[0]} ({x[1]} args)', mapping.items()))
assert (p, len(args)) in mapping, f'expected {expected}, got {p} ({len(args)} args)'
res = mapping[(p, len(args))]
if callable(res):
Expand Down Expand Up @@ -107,7 +107,7 @@ def get_int(val_expr):


def get_bool(val_expr):
return dispatch_prim_map(val_expr, {'True': True, 'False': False})
return dispatch_prim_map(val_expr, {('True', 0): True, ('False', 0): False})


def get_bytes(val_expr):
Expand Down Expand Up @@ -373,8 +373,7 @@ def parse_contract(val_expr, type_expr, selector):

@primitive('operation')
def parse_operation(val_expr, type_expr, selector):
val = get_string(val_expr)
return selector(val_expr, type_expr, val)
return selector(val_expr, type_expr, get_string(val_expr))


@primitive('key')
Expand Down
Loading

0 comments on commit 853b34f

Please sign in to comment.