Skip to content

Commit 8cf42cb

Browse files
committed
Add new datapack features and introduce event handler functions
1 parent 9875c01 commit 8cf42cb

File tree

12 files changed

+296
-63
lines changed

12 files changed

+296
-63
lines changed

compiler/asm_extensions.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,24 @@ def __init__(self):
113113
'MOVINDD': self.handle_mov_ind_d,
114114
'MOVINDS': self.handle_mov_ind_s
115115
})
116+
self.event_handlers = []
117+
118+
def handle_directive(self, directive, value):
119+
if directive == 'event_handler':
120+
handler, event, conditions = value.split(' ', 2)
121+
conds = {}
122+
if conditions:
123+
for cond in conditions.split(';'):
124+
key, value = cond.split('=', 1)
125+
path = tuple(key.split('.'))
126+
conds[path] = value
127+
self.event_handlers.append({
128+
'event': event,
129+
'conditions': conds,
130+
'handler': self.sub_to_func_name(handler)
131+
})
132+
return
133+
super().handle_directive(directive, value)
116134

117135
def handle_ret(self):
118136
if not self.enable_sync:
@@ -161,3 +179,10 @@ def handle_mov_ind_s(self, src, s_off, dest):
161179
self.add_command(AddFn(Var('memory_address'), abs(offset)))
162180
self.add_command(Function('mem_get'))
163181
self.add_command(OpAssign(dest, Var('memory_buffer')))
182+
183+
def write_to_session(self, session):
184+
super().write_to_session(session)
185+
for event_handler in self.event_handlers:
186+
session.add_event_handler(event_handler['event'],
187+
event_handler['conditions'],
188+
event_handler['handler'])

compiler/asm_writer.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,15 @@ def write_statement(self, stmt):
1616
self.write_instruction(*args)
1717
elif type == 'local_subroutine':
1818
self.write_local_sub(*args)
19+
elif type == 'directive':
20+
self.write_directive(*args)
1921

2022
def write_constant(self, name, value):
2123
self.write_line('.%s %s' % (name, value))
2224

25+
def write_directive(self, name, value):
26+
self.write_line('#%s %s' % (name, value))
27+
2328
def write_subroutine(self, name):
2429
if name == '__setup__':
2530
return

compiler/compiler.py

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ def handle_insn(self, insn):
4040
self.insn_func_map[type(insn)](insn)
4141

4242
def handle_fn_begin(self, insn):
43+
if insn.pragma:
44+
if 'event_handler' in insn.pragma:
45+
handler = insn.pragma['event_handler']
46+
conds = ';'.join(map(
47+
lambda i: '%s=%s' % i, handler['conditions'].items()))
48+
self.writer.write_directive('event_handler', '%s %s %s' % (
49+
insn.name, handler['event_name'], conds))
4350
self.writer.write_subroutine(insn.name)
4451
self.func_name = insn.name
4552
self.func_store = insn.storage
@@ -472,6 +479,7 @@ def __init__(self, on_instruction):
472479
self.current_function = None
473480
self.loop_attacher = LoopAttacher(None, None, self, None)
474481
self.python_functions = {}
482+
self.pragmas = {}
475483

476484
def import_py_lib(self, lib_exports):
477485
self.python_functions.update(lib_exports)
@@ -525,6 +533,31 @@ def unique_label(self, label):
525533
self.local_labels[label] += 1
526534
return IR.Label('%s_%d' %(label, self.local_labels[label]))
527535

536+
### Pragmas
537+
538+
def visit_pragma(self, pragma):
539+
name, args = pragma.val.split(' ', 1)
540+
pragmas = {
541+
'event_handler': self.visit_pragma_event_handler,
542+
'event_condition': self.visit_pragma_event_condition,
543+
}
544+
assert name in pragmas, "Unknown pragma '%s'" % name
545+
pragmas[name](args)
546+
547+
def visit_pragma_event_handler(self, event_name):
548+
assert self.current_function is None, "event_handler must be outside of function"
549+
assert 'event_handler' not in self.pragmas, "Multiple event handlers"
550+
self.pragmas['event_handler'] = {
551+
'event_name': event_name,
552+
'conditions': {}
553+
}
554+
555+
def visit_pragma_event_condition(self, condition):
556+
assert 'event_handler' in self.pragmas, "Not in event_handler context"
557+
key, operator, value = condition.split(' ', 2)
558+
assert operator == '=='
559+
self.pragmas['event_handler']['conditions'][key] = value
560+
528561
### Declarations
529562

530563
def get_name_and_type(self, type, spec):
@@ -548,10 +581,16 @@ def visit_func_decl(self, decl):
548581

549582
self.local_labels = {}
550583

584+
pragma = {}
585+
# check pragmas
586+
if 'event_handler' in self.pragmas:
587+
pragma['event_handler'] = self.pragmas['event_handler']
588+
del self.pragmas['event_handler']
589+
551590
# Enter function scope
552591
with self.scope:
553592
self.emit(IR.FunctionBegin(func_symbol.name,
554-
self.scope.current_storage))
593+
self.scope.current_storage, pragma))
555594

556595
params = decl.decl.name_spec.params
557596
# Declare parameter symbols
@@ -647,7 +686,8 @@ def read_list_data(self, list_type, init_list, read_next_element):
647686
child = mem_ref.child
648687
index, offset, v_type = read_next_element(list_type, index, mem_ref)
649688
if child is not None:
650-
val = self.visit_list_init_data(v_type, [InitSpec(decl=child, val=init_spec.val)])
689+
val = self.visit_list_init_data(v_type,
690+
[InitSpec(decl=child, val=init_spec.val)])
651691
elif type(init_spec.val) == list:
652692
val = self.visit_list_init_data(v_type, init_spec.val)
653693
else:

compiler/ir.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ class IR:
66

77
_counter = 0
88

9-
FunctionBegin = namedtuple('FunctionBegin', 'name storage')
9+
FunctionBegin = namedtuple('FunctionBegin', 'name storage pragma')
1010
FunctionEnd = namedtuple('FunctionEnd', '')
1111

1212
Label = namedtuple('Label', 'label')

compiler/nodes.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ class Literal(Expression): props = ('val',)
103103
class IntLiteral(Literal): pass
104104
class StringLiteral(Literal): pass
105105

106+
class Pragma(Node): props = ('val',)
107+
106108
class Token:
107109

108110
class Type:

compiler/parser_.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ def parse_program(self):
1515
return stmts
1616

1717
def parse_external_decl(self):
18+
if self.lexer.next.type == Token.Type.IDENTIFIER:
19+
if self.lexer.next.val == '_Pragma':
20+
self.next()
21+
self.read(Token.OPEN_PAREN)
22+
pragma = self.parse_string()
23+
self.read(Token.CLOSE_PAREN)
24+
return Pragma(val=pragma.val)
1825
# TODO using exceptions is bad
1926
pos, next = self.lexer.ptr, self.lexer.next
2027
try:
@@ -616,7 +623,8 @@ def can_next_be_expr(self):
616623

617624
def parse_identifier(self):
618625
token = self.lexer.next_token()
619-
assert token.type == Token.Type.IDENTIFIER
626+
assert token.type == Token.Type.IDENTIFIER, \
627+
'expected identifier, got %r' % token.val
620628
return IdentifierExpr(val=token.val)
621629

622630
def parse_number(self):

compiler/preprocessor.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from collections import namedtuple
22
from .nodes import *
33

4+
import re
5+
46
ConditionalBlock = namedtuple('ConditionalBlock', 'parent source output skip_to_end')
57

68
class ParamStr(str):
@@ -94,8 +96,9 @@ def substitute(self, line):
9496
start = end
9597
line += self.next_line()
9698
args.append(ParamStr(s, args, arg_num))
97-
line = line[:idx] + replacement.format(*args) + line[end:]
98-
line = line.replace('##', '') # needs ro be done properly
99+
replaced = replacement.format(*args)
100+
line = line[:idx] + replaced + line[end:]
101+
line = re.sub('\s*##\s*', '', line) # needs ro be done properly
99102
# Recursively substitute
100103
line = self.substitute(line)
101104
return line
@@ -116,6 +119,7 @@ def process(self, line):
116119
'endif': self.handle_endif,
117120
'define': self.handle_define,
118121
'undef': self.handle_undef,
122+
'pragma': self.handle_pragma,
119123
}
120124
func = dir_map.get(directive)
121125
if func is None:
@@ -188,7 +192,6 @@ def handle_endif(self, arg):
188192
def handle_define(self, arg):
189193
if not self.block.output:
190194
return
191-
import re
192195
match = re.match('(\w+)\s*(\((?:\w+\s*,\s*)*(?:(?:\w+|\.\.\.))\s*\))?(?:\s+|$)(.*)', arg)
193196
if not match:
194197
raise Exception('invalid #define "%s"' % arg)
@@ -226,7 +229,6 @@ def _get_params(self, param_match):
226229
def evaluate(self, expr):
227230
from .lexer import Lexer
228231
from .parser_ import Parser
229-
import re
230232
# Convert "defined var" into "__defined__(__no_def_var__)"
231233
expr = re.sub('defined\s+(\w+)', r'__defined__(__no_def_\1__)', expr)
232234
expr = Parser(Lexer(self.substitute(expr))).parse_constant_expr()
@@ -294,6 +296,9 @@ def handle_undef(self, arg):
294296
return
295297
pass
296298

299+
def handle_pragma(self, arg):
300+
self.append("_Pragma(%s)" % ParamStr(arg, None, None).escape)
301+
297302
def next_line(self):
298303
line = self.lines[self.lineptr]
299304
self.lineptr += 1

compiler/visitor.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,14 @@ def __init__(self):
4242

4343
def visit_program(self, program):
4444
for decl in program:
45+
if isinstance(decl, Pragma):
46+
self.visit_pragma(decl)
47+
continue
4548
self.visit_declaration(decl)
4649

50+
def visit_pragma(self, pragma):
51+
pass
52+
4753
def visit_declaration(self, decl):
4854
if isinstance(decl, Declaration):
4955
return self.visit_decl(decl)

compiler_main.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import argparse
22
import os
33

4-
from session import FunctionWriter, DummyWriter
4+
from datapack import DataPackWriter, DummyWriter
55
from placer import Rel
66

77
from compiler.asm_extensions import CompilerSession, ExtendedAssembler
@@ -14,6 +14,7 @@
1414
parser = argparse.ArgumentParser()
1515
parser.add_argument('file', help="C File", type=argparse.FileType('r'))
1616
parser.add_argument('--world-dir', help="World Directory")
17+
parser.add_argument('--as_zip', action='store_true', help="Write datapack as zip file")
1718
parser.add_argument('--namespace', help="Function namespace", default='c_generated')
1819
parser.add_argument('--rem-existing', help="Remove existing functions in namespace",
1920
action='store_true')
@@ -52,17 +53,19 @@
5253
x, y, z = map(parse_pos, args.place_location.split(',', 3))
5354

5455
if args.world_dir:
55-
world_dir = os.path.realpath(args.world_dir)
56-
writer = FunctionWriter(world_dir, args.namespace)
56+
data_dir = os.path.join(os.path.realpath(args.world_dir), 'datapacks')
57+
writer = DataPackWriter(data_dir, args.namespace, args.as_zip)
5758
if args.rem_existing:
58-
writer.empty_directory()
59+
writer.delete_existing()
5960
else:
6061
writer = DummyWriter()
62+
writer.open()
6163

6264
session = CompilerSession((x, y, z), writer, args.namespace, stack_size=args.stack,
6365
args=sargs, debug=args.debug, page_size=args.page_size)
6466
assembler.write_to_session(session)
6567
setup, cleanup = session.create_up_down_functions()
68+
writer.close()
6669
print('Generated', writer.command_count, 'commands in',
6770
writer.func_count, 'functions')
6871
print('== Setup command ==')

0 commit comments

Comments
 (0)