Skip to content

Commit cfd4640

Browse files
committed
Add /execute API.
Plus some smaller fixes and features
1 parent 6e52bee commit cfd4640

File tree

12 files changed

+540
-24
lines changed

12 files changed

+540
-24
lines changed

assembler.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,18 @@ def init_instructions(self):
260260
'CMD': self.handle_cmd,
261261
'TEST': self.handle_test_cmd,
262262

263+
'EXECAS': self.handle_execute_as,
264+
'EXECASN': self.handle_execute_as_not,
265+
'EXECAT': self.handle_execute_at,
266+
'EXECATP': self.handle_execute_at_position,
267+
'EXECPOS': self.handle_execute_position,
268+
'EXECALI': self.handle_execute_align,
269+
'EXECFACP': self.handle_execute_face_pos,
270+
'EXECFAC': self.handle_execute_face_entity,
271+
'EXECROT': self.handle_execute_rotate,
272+
'EXECROTE': self.handle_execute_rotate_entity,
273+
'EXECANC': self.handle_execute_anchor,
274+
263275
'PUSH': self.handle_push,
264276
'POP': self.handle_pop,
265277

@@ -676,6 +688,106 @@ def handle_print(self, arg1, *args):
676688
def handle_cmd(self, cmd):
677689
self.add_command(Cmd(cmd))
678690

691+
def _read_selector(self, sel_type, pairs):
692+
assert sel_type[0] == 'string'
693+
assert len(pairs) % 2 == 0
694+
simple = {}
695+
sel_args = None
696+
for i in range(0, len(pairs), 2):
697+
key_type, key = pairs[i]
698+
val_type, val = pairs[i + 1]
699+
assert val_type == 'string'
700+
if key_type == 'string':
701+
simple[key] = val
702+
elif key_type == 'symbol':
703+
# Special case where an entity local can be queried
704+
var = self.get_const(key)
705+
assert isinstance(var, EntityLocal)
706+
min, max = map(lambda v: int(v) if v else None, val.split('..')) \
707+
if '..' in val else [int(val)]*2
708+
sel_args = ComboSelectorArgs(sel_args, SelRange(var, min, max))
709+
else:
710+
assert False, "Bad key type: " + pairs[i]
711+
if simple:
712+
sel_args = ComboSelectorArgs(sel_args, SimpleSelectorArgs(simple))
713+
return Selector(sel_type[1], sel_args)
714+
715+
def _read_pos(self, x, y, z):
716+
coords = []
717+
for coord in (x, y, z):
718+
type_, val = coord
719+
if type_ == 'string':
720+
assert val, "Empty string"
721+
assert val[0] in '~^', "Invalid pos string '%s'" % val
722+
if len(val) > 1:
723+
# check it can parse as a float
724+
float(val[1:])
725+
else:
726+
ref = self.resolve_ref(type_, val)
727+
assert type(ref) == int, "Unknown type %s %s" % (type(ref), ref)
728+
val = ref
729+
coords.append(val)
730+
return Pos(*coords)
731+
732+
def _execute_chain_helper(self, lbl, chain):
733+
arg_type, symbol = lbl
734+
assert arg_type == 'symbol'
735+
exec_func = self.symbol_to_func(symbol)
736+
self.add_command(chain.run(Function(exec_func)))
737+
738+
def do_execute_as(self, lbl, sel_type, pairs, inverse):
739+
chain = ExecuteChain()
740+
if inverse:
741+
chain = chain.cond('unless')
742+
selector = self._read_selector(sel_type, pairs)
743+
self._execute_chain_helper(lbl, chain.where(selector))
744+
745+
def handle_execute_as(self, lbl, sel_type, *pairs):
746+
self.do_execute_as(lbl, sel_type, pairs, False)
747+
748+
def handle_execute_as_not(self, lbl, sel_type, *pairs):
749+
self.do_execute_as(lbl, sel_type, pairs, True)
750+
751+
def handle_execute_at(self, lbl, sel_type, *pairs):
752+
self._execute_chain_helper(lbl, ExecuteChain().at(
753+
self._read_selector(sel_type, pairs)))
754+
755+
def handle_execute_at_position(self, lbl, sel_type, *pairs):
756+
self._execute_chain_helper(lbl, ExecuteChain().at_entity_pos(
757+
self._read_selector(sel_type, pairs)))
758+
759+
def handle_execute_position(self, lbl, x, y, z):
760+
self._execute_chain_helper(lbl, ExecuteChain().at_pos(
761+
self._read_pos(x, y, z)))
762+
763+
def handle_execute_align(self, lbl, axes):
764+
arg_type, axes = axes
765+
assert arg_type == 'string'
766+
self._execute_chain_helper(lbl, ExecuteChain().align(axes))
767+
768+
def handle_execute_face_pos(self, lbl, x, y, z):
769+
self._execute_chain_helper(lbl, ExecuteChain().facing(
770+
self._read_pos(x, y, z)))
771+
772+
def handle_execute_face_entity(self, lbl, sel_type, *pairs):
773+
self._execute_chain_helper(lbl, ExecuteChain().facing_entity(
774+
self._read_selector(sel_type, pairs)))
775+
776+
def handle_execute_rotate(self, lbl, y, x):
777+
y, x = self.resolve_ref(*y), self.resolve_ref(*x)
778+
assert type(y) == int
779+
assert type(x) == int
780+
self._execute_chain_helper(lbl, ExecuteChain().rotated(y, x))
781+
782+
def handle_execute_rotate_entity(self, lbl, sel_type, *pairs):
783+
self._execute_chain_helper(lbl, ExecuteChain().rotated_as_entity(
784+
self._read_selector(sel_type, pairs)))
785+
786+
def handle_execute_anchor(self, lbl, anchor):
787+
arg_type, anchor = anchor
788+
assert arg_type == 'string'
789+
self._execute_chain_helper(lbl, ExecuteChain().anchored(anchor))
790+
679791
def handle_push(self):
680792
self.add_command(Function('stack_push_0'))
681793

commands.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,39 @@ def if_where(cond):
221221
def where(self, select_arg):
222222
return self.add('as', ensure_selector(select_arg))
223223

224+
def at(self, select_arg):
225+
return self.add('at', ensure_selector(select_arg))
226+
227+
def at_pos(self, pos):
228+
return self.add('positioned', pos)
229+
230+
def at_entity_pos(self, select_arg):
231+
return self.add('positioned', 'as', ensure_selector(select_arg))
232+
233+
def align(self, axes):
234+
assert [axis for axis in axes if axis in 'xyz']
235+
return self.add('align', axes)
236+
237+
def facing(self, pos):
238+
return self.add('facing', pos)
239+
240+
def facing_entity(self, select_arg, feature):
241+
assert feature == 'eyes' or feature == 'feet'
242+
return self.add('facing', 'entity', ensure_selector(select_arg), \
243+
feature)
244+
245+
def rotated(self, y, x):
246+
return self.add('rotated', y, x)
247+
248+
def rotated_as_entity(self, select_arg):
249+
return self.add('rotated', 'as', ensure_selector(select_arg))
250+
251+
def anchored(self, anchor):
252+
assert anchor == 'feet' or anchor == 'eyes'
253+
return self.add('anchored', anchor)
254+
224255
def cond(self, cond_type):
256+
assert cond_type == 'if' or cond_type == 'unless'
225257
return ExecuteChain.Cond(self, cond_type)
226258

227259
class Cond:
@@ -421,6 +453,25 @@ class SelEquals(SelRange):
421453
def __init__(self, varref, value):
422454
super(SelEquals, self).__init__(varref, value, value)
423455

456+
class ComboSelectorArgs(SelectorArgs):
457+
def __new__(cls, first, second):
458+
if first is None: return second
459+
if second is None: return first
460+
return SelectorArgs.__new__(cls)
461+
462+
def __init__(self, first, second):
463+
self.first = first
464+
self.second = second
465+
466+
def as_selector(self):
467+
raise TypeError('Cannot get ComboSelectorArgs as a selector')
468+
469+
def resolve(self, scope):
470+
sel = {}
471+
sel.update(self.first.resolve(scope))
472+
sel.update(self.second.resolve(scope))
473+
return sel
474+
424475
class LabelledSequence(CommandSequence):
425476
def __init__(self, label, varname='func_pointer'):
426477
super(LabelledSequence, self).__init__()

compiler/asm_writer.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ def __init__(self):
55
self.indent = 0
66
self.sub = False
77
self._setup = []
8+
self.after_sub = []
89

10+
# TODO unused
911
def write_statement(self, stmt):
1012
type, *args = stmt
1113
if type == 'constant':
@@ -39,6 +41,12 @@ def end_subroutine(self):
3941
self.indent = 0
4042
self.write_line('')
4143
self.sub = False
44+
for after in self.after_sub:
45+
self.output += after
46+
self.after_sub = []
47+
48+
def write_after_subroutine(self, block):
49+
self.after_sub.append(block)
4250

4351
def write_instruction(self, insn, *args, comment=None, raw=False):
4452
if raw:
@@ -60,6 +68,7 @@ def write_line(self, line):
6068
self.output += (' ' * self.indent) + line + '\n'
6169

6270
def get_output(self):
71+
assert not self.sub
6372
setup = ''
6473
if self._setup:
6574
setup = '__setup__:\n '

0 commit comments

Comments
 (0)