Skip to content

Commit 6cdd3af

Browse files
committed
Implement built-in decorators to select emit type.
1 parent 4b03e77 commit 6cdd3af

9 files changed

Lines changed: 198 additions & 120 deletions

File tree

py/compile.c

Lines changed: 108 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ typedef enum {
2727

2828
#define EMIT(fun, arg...) (comp->emit_method_table->fun(comp->emit, ##arg))
2929

30+
#define EMIT_OPT_NONE (0)
31+
#define EMIT_OPT_BYTE_CODE (1)
32+
#define EMIT_OPT_NATIVE_PYTHON (2)
33+
3034
typedef struct _compiler_t {
3135
qstr qstr___class__;
3236
qstr qstr___locals__;
@@ -35,6 +39,8 @@ typedef struct _compiler_t {
3539
qstr qstr___qualname__;
3640
qstr qstr___doc__;
3741
qstr qstr_assertion_error;
42+
qstr qstr_micropython;
43+
qstr qstr_native;
3844

3945
pass_kind_t pass;
4046

@@ -56,8 +62,8 @@ typedef struct _compiler_t {
5662
scope_t *scope_head;
5763
scope_t *scope_cur;
5864

59-
emit_t *emit;
60-
const emit_method_table_t *emit_method_table;
65+
emit_t *emit; // current emitter
66+
const emit_method_table_t *emit_method_table; // current emit method table
6167
} compiler_t;
6268

6369
py_parse_node_t fold_constants(py_parse_node_t pn) {
@@ -165,8 +171,8 @@ static int comp_next_label(compiler_t *comp) {
165171
return comp->next_label++;
166172
}
167173

168-
static scope_t *scope_new_and_link(compiler_t *comp, scope_kind_t kind, py_parse_node_t pn) {
169-
scope_t *scope = scope_new(kind, pn, rt_get_new_unique_code_id());
174+
static scope_t *scope_new_and_link(compiler_t *comp, scope_kind_t kind, py_parse_node_t pn, uint emit_options) {
175+
scope_t *scope = scope_new(kind, pn, rt_get_new_unique_code_id(), emit_options);
170176
scope->parent = comp->scope_cur;
171177
scope->next = NULL;
172178
if (comp->scope_head == NULL) {
@@ -661,10 +667,10 @@ void compile_funcdef_param(compiler_t *comp, py_parse_node_t pn) {
661667

662668
// leaves function object on stack
663669
// returns function name
664-
qstr compile_funcdef_helper(compiler_t *comp, py_parse_node_struct_t *pns) {
670+
qstr compile_funcdef_helper(compiler_t *comp, py_parse_node_struct_t *pns, uint emit_options) {
665671
if (comp->pass == PASS_1) {
666672
// create a new scope for this function
667-
scope_t *s = scope_new_and_link(comp, SCOPE_FUNCTION, (py_parse_node_t)pns);
673+
scope_t *s = scope_new_and_link(comp, SCOPE_FUNCTION, (py_parse_node_t)pns, emit_options);
668674
// store the function scope so the compiling function can use it at each pass
669675
pns->nodes[4] = (py_parse_node_t)s;
670676
}
@@ -705,10 +711,10 @@ qstr compile_funcdef_helper(compiler_t *comp, py_parse_node_struct_t *pns) {
705711

706712
// leaves class object on stack
707713
// returns class name
708-
qstr compile_classdef_helper(compiler_t *comp, py_parse_node_struct_t *pns) {
714+
qstr compile_classdef_helper(compiler_t *comp, py_parse_node_struct_t *pns, uint emit_options) {
709715
if (comp->pass == PASS_1) {
710716
// create a new scope for this class
711-
scope_t *s = scope_new_and_link(comp, SCOPE_CLASS, (py_parse_node_t)pns);
717+
scope_t *s = scope_new_and_link(comp, SCOPE_CLASS, (py_parse_node_t)pns, emit_options);
712718
// store the class scope so the compiling function can use it at each pass
713719
pns->nodes[3] = (py_parse_node_t)s;
714720
}
@@ -739,41 +745,82 @@ qstr compile_classdef_helper(compiler_t *comp, py_parse_node_struct_t *pns) {
739745
return cscope->simple_name;
740746
}
741747

748+
// returns true if it was a built-in decorator (even if the built-in had an error)
749+
static bool compile_built_in_decorator(compiler_t *comp, int name_len, py_parse_node_t *name_nodes, uint *emit_options) {
750+
if (PY_PARSE_NODE_LEAF_ARG(name_nodes[0]) != comp->qstr_micropython) {
751+
return false;
752+
}
753+
754+
if (name_len != 2) {
755+
printf("SyntaxError: invalid micropython decorator\n");
756+
return true;
757+
}
758+
759+
qstr attr = PY_PARSE_NODE_LEAF_ARG(name_nodes[1]);
760+
if (attr == comp->qstr_native) {
761+
*emit_options = EMIT_OPT_NATIVE_PYTHON;
762+
} else {
763+
printf("SyntaxError: invalid micropython decorator\n");
764+
}
765+
766+
return true;
767+
}
768+
742769
void compile_decorated(compiler_t *comp, py_parse_node_struct_t *pns) {
743770
// get the list of decorators
744771
py_parse_node_t *nodes;
745772
int n = list_get(&pns->nodes[0], PN_decorators, &nodes);
746773

747-
// load each decorator
774+
// inherit emit options for this function/class definition
775+
uint emit_options = comp->scope_cur->emit_options;
776+
777+
// compile each decorator
778+
int num_built_in_decorators = 0;
748779
for (int i = 0; i < n; i++) {
749780
assert(PY_PARSE_NODE_IS_STRUCT_KIND(nodes[i], PN_decorator)); // should be
750781
py_parse_node_struct_t *pns_decorator = (py_parse_node_struct_t*)nodes[i];
751-
py_parse_node_t *nodes2;
752-
int n2 = list_get(&pns_decorator->nodes[0], PN_dotted_name, &nodes2);
753-
compile_node(comp, nodes2[0]);
754-
for (int i = 1; i < n2; i++) {
755-
EMIT(load_attr, PY_PARSE_NODE_LEAF_ARG(nodes2[i]));
756-
}
757-
if (!PY_PARSE_NODE_IS_NULL(pns_decorator->nodes[1])) {
758-
// first call the function with these arguments
759-
compile_node(comp, pns_decorator->nodes[1]);
782+
783+
// nodes[0] contains the decorator function, which is a dotted name
784+
py_parse_node_t *name_nodes;
785+
int name_len = list_get(&pns_decorator->nodes[0], PN_dotted_name, &name_nodes);
786+
787+
// check for built-in decorators
788+
if (compile_built_in_decorator(comp, name_len, name_nodes, &emit_options)) {
789+
// this was a built-in
790+
num_built_in_decorators += 1;
791+
792+
} else {
793+
// not a built-in, compile normally
794+
795+
// compile the decorator function
796+
compile_node(comp, name_nodes[0]);
797+
for (int i = 1; i < name_len; i++) {
798+
assert(PY_PARSE_NODE_IS_ID(name_nodes[i])); // should be
799+
EMIT(load_attr, PY_PARSE_NODE_LEAF_ARG(name_nodes[i]));
800+
}
801+
802+
// nodes[1] contains arguments to the decorator function, if any
803+
if (!PY_PARSE_NODE_IS_NULL(pns_decorator->nodes[1])) {
804+
// call the decorator function with the arguments in nodes[1]
805+
compile_node(comp, pns_decorator->nodes[1]);
806+
}
760807
}
761808
}
762809

763810
// compile the body (funcdef or classdef) and get its name
764811
py_parse_node_struct_t *pns_body = (py_parse_node_struct_t*)pns->nodes[1];
765812
qstr body_name = 0;
766813
if (PY_PARSE_NODE_STRUCT_KIND(pns_body) == PN_funcdef) {
767-
body_name = compile_funcdef_helper(comp, pns_body);
814+
body_name = compile_funcdef_helper(comp, pns_body, emit_options);
768815
} else if (PY_PARSE_NODE_STRUCT_KIND(pns_body) == PN_classdef) {
769-
body_name = compile_classdef_helper(comp, pns_body);
816+
body_name = compile_classdef_helper(comp, pns_body, emit_options);
770817
} else {
771818
// shouldn't happen
772819
assert(0);
773820
}
774821

775822
// call each decorator
776-
for (int i = 0; i < n; i++) {
823+
for (int i = 0; i < n - num_built_in_decorators; i++) {
777824
EMIT(call_function, 1, 0, false, false);
778825
}
779826

@@ -782,7 +829,7 @@ void compile_decorated(compiler_t *comp, py_parse_node_struct_t *pns) {
782829
}
783830

784831
void compile_funcdef(compiler_t *comp, py_parse_node_struct_t *pns) {
785-
qstr fname = compile_funcdef_helper(comp, pns);
832+
qstr fname = compile_funcdef_helper(comp, pns, comp->scope_cur->emit_options);
786833
// store function object into function name
787834
EMIT(store_id, fname);
788835
}
@@ -1514,7 +1561,7 @@ void compile_lambdef(compiler_t *comp, py_parse_node_struct_t *pns) {
15141561

15151562
if (comp->pass == PASS_1) {
15161563
// create a new scope for this lambda
1517-
scope_t *s = scope_new_and_link(comp, SCOPE_LAMBDA, (py_parse_node_t)pns);
1564+
scope_t *s = scope_new_and_link(comp, SCOPE_LAMBDA, (py_parse_node_t)pns, comp->scope_cur->emit_options);
15181565
// store the lambda scope so the compiling function (this one) can use it at each pass
15191566
pns->nodes[2] = (py_parse_node_t)s;
15201567
}
@@ -1780,7 +1827,7 @@ void compile_comprehension(compiler_t *comp, py_parse_node_struct_t *pns, scope_
17801827

17811828
if (comp->pass == PASS_1) {
17821829
// create a new scope for this comprehension
1783-
scope_t *s = scope_new_and_link(comp, kind, (py_parse_node_t)pns);
1830+
scope_t *s = scope_new_and_link(comp, kind, (py_parse_node_t)pns, comp->scope_cur->emit_options);
17841831
// store the comprehension scope so the compiling function (this one) can use it at each pass
17851832
pns_comp_for->nodes[3] = (py_parse_node_t)s;
17861833
}
@@ -2048,7 +2095,7 @@ void compile_dictorsetmaker_item(compiler_t *comp, py_parse_node_struct_t *pns)
20482095
}
20492096

20502097
void compile_classdef(compiler_t *comp, py_parse_node_struct_t *pns) {
2051-
qstr cname = compile_classdef_helper(comp, pns);
2098+
qstr cname = compile_classdef_helper(comp, pns, comp->scope_cur->emit_options);
20522099
// store class object into class name
20532100
EMIT(store_id, cname);
20542101
}
@@ -2332,6 +2379,7 @@ void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
23322379
assert(PY_PARSE_NODE_STRUCT_KIND(pns) == PN_funcdef);
23332380

23342381
// work out number of parameters, keywords and default parameters, and add them to the id_info array
2382+
// must be done before compiling the body so that arguments are numbered first (for LOAD_FAST etc)
23352383
if (comp->pass == PASS_1) {
23362384
comp->have_bare_star = false;
23372385
apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_scope_func_param);
@@ -2351,6 +2399,7 @@ void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
23512399
assert(PY_PARSE_NODE_STRUCT_NUM_NODES(pns) == 3);
23522400

23532401
// work out number of parameters, keywords and default parameters, and add them to the id_info array
2402+
// must be done before compiling the body so that arguments are numbered first (for LOAD_FAST etc)
23542403
if (comp->pass == PASS_1) {
23552404
comp->have_bare_star = false;
23562405
apply_to_single_or_list(comp, pns->nodes[0], PN_varargslist, compile_scope_lambda_param);
@@ -2367,7 +2416,7 @@ void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
23672416
assert(PY_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_comp_for));
23682417
py_parse_node_struct_t *pns_comp_for = (py_parse_node_struct_t*)pns->nodes[1];
23692418

2370-
qstr qstr_arg = qstr_from_strn_copy(".0", 2);
2419+
qstr qstr_arg = qstr_from_str_static(".0");
23712420
if (comp->pass == PASS_1) {
23722421
bool added;
23732422
id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qstr_arg, &added);
@@ -2493,13 +2542,15 @@ void compile_scope_compute_things(compiler_t *comp, scope_t *scope) {
24932542
void py_compile(py_parse_node_t pn) {
24942543
compiler_t *comp = m_new(compiler_t, 1);
24952544

2496-
comp->qstr___class__ = qstr_from_strn_copy("__class__", 9);
2497-
comp->qstr___locals__ = qstr_from_strn_copy("__locals__", 10);
2498-
comp->qstr___name__ = qstr_from_strn_copy("__name__", 8);
2499-
comp->qstr___module__ = qstr_from_strn_copy("__module__", 10);
2500-
comp->qstr___qualname__ = qstr_from_strn_copy("__qualname__", 12);
2501-
comp->qstr___doc__ = qstr_from_strn_copy("__doc__", 7);
2502-
comp->qstr_assertion_error = qstr_from_strn_copy("AssertionError", 14);
2545+
comp->qstr___class__ = qstr_from_str_static("__class__");
2546+
comp->qstr___locals__ = qstr_from_str_static("__locals__");
2547+
comp->qstr___name__ = qstr_from_str_static("__name__");
2548+
comp->qstr___module__ = qstr_from_str_static("__module__");
2549+
comp->qstr___qualname__ = qstr_from_str_static("__qualname__");
2550+
comp->qstr___doc__ = qstr_from_str_static("__doc__");
2551+
comp->qstr_assertion_error = qstr_from_str_static("AssertionError");
2552+
comp->qstr_micropython = qstr_from_str_static("micropython");
2553+
comp->qstr_native = qstr_from_str_static("native");
25032554

25042555
comp->max_num_labels = 0;
25052556
comp->break_label = 0;
@@ -2508,10 +2559,11 @@ void py_compile(py_parse_node_t pn) {
25082559
comp->scope_head = NULL;
25092560
comp->scope_cur = NULL;
25102561

2511-
emit_pass1_new(&comp->emit, &comp->emit_method_table, comp->qstr___class__);
2562+
comp->emit = emit_pass1_new(comp->qstr___class__);
2563+
comp->emit_method_table = &emit_pass1_method_table;
25122564

25132565
pn = fold_constants(pn);
2514-
scope_new_and_link(comp, SCOPE_MODULE, pn);
2566+
scope_new_and_link(comp, SCOPE_MODULE, pn, EMIT_OPT_NONE);
25152567

25162568
for (scope_t *s = comp->scope_head; s != NULL; s = s->next) {
25172569
compile_scope(comp, s, PASS_1);
@@ -2521,11 +2573,29 @@ void py_compile(py_parse_node_t pn) {
25212573
compile_scope_compute_things(comp, s);
25222574
}
25232575

2524-
emit_cpython_new(&comp->emit, &comp->emit_method_table, comp->max_num_labels);
2525-
//emit_bc_new(&comp->emit, &comp->emit_method_table, comp->max_num_labels);
2526-
//emit_x64_new(&comp->emit, &comp->emit_method_table, comp->max_num_labels);
2576+
emit_pass1_free(comp->emit);
2577+
2578+
emit_t *emit_bc = NULL;
2579+
emit_t *emit_x64 = NULL;
25272580

25282581
for (scope_t *s = comp->scope_head; s != NULL; s = s->next) {
2582+
switch (s->emit_options) {
2583+
case EMIT_OPT_NATIVE_PYTHON:
2584+
if (emit_x64 == NULL) {
2585+
emit_x64 = emit_x64_new(comp->max_num_labels);
2586+
}
2587+
comp->emit = emit_x64;
2588+
comp->emit_method_table = &emit_x64_method_table;
2589+
break;
2590+
2591+
default:
2592+
if (emit_bc == NULL) {
2593+
emit_bc = emit_bc_new(comp->max_num_labels);
2594+
}
2595+
comp->emit = emit_bc;
2596+
comp->emit_method_table = &emit_bc_method_table;
2597+
break;
2598+
}
25292599
compile_scope(comp, s, PASS_2);
25302600
compile_scope(comp, s, PASS_3);
25312601
}

py/emit.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,15 @@ void emit_common_load_id(emit_t *emit, const emit_method_table_t *emit_method_ta
116116
void emit_common_store_id(emit_t *emit, const emit_method_table_t *emit_method_table, scope_t *scope, qstr qstr);
117117
void emit_common_delete_id(emit_t *emit, const emit_method_table_t *emit_method_table, scope_t *scope, qstr qstr);
118118

119-
void emit_pass1_new(emit_t **emit, const emit_method_table_t **emit_method_table, qstr qstr___class__);
120-
void emit_cpython_new(emit_t **emit_out, const emit_method_table_t **emit_method_table_out, uint max_num_labels);
121-
void emit_bc_new(emit_t **emit, const emit_method_table_t **emit_method_table, uint max_num_labels);
122-
void emit_x64_new(emit_t **emit, const emit_method_table_t **emit_method_table, uint max_num_labels);
123-
void emit_thumb_new(emit_t **emit, const emit_method_table_t **emit_method_table, uint max_num_labels);
119+
extern const emit_method_table_t emit_pass1_method_table;
120+
extern const emit_method_table_t emit_cpython_method_table;
121+
extern const emit_method_table_t emit_bc_method_table;
122+
extern const emit_method_table_t emit_x64_method_table;
123+
extern const emit_method_table_t emit_thumb_method_table;
124+
125+
emit_t *emit_pass1_new(qstr qstr___class__);
126+
void emit_pass1_free(emit_t *emit);
127+
emit_t *emit_cpython_new(uint max_num_labels);
128+
emit_t *emit_bc_new(uint max_num_labels);
129+
emit_t *emit_x64_new(uint max_num_labels);
130+
emit_t *emit_thumb_new(uint max_num_labels);

py/emitbc.c

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,15 @@ struct _emit_t {
3232
byte dummy_data[8];
3333
};
3434

35-
// forward declaration
36-
static const emit_method_table_t emit_bc_method_table;
35+
emit_t *emit_bc_new(uint max_num_labels) {
36+
emit_t *emit = m_new(emit_t, 1);
37+
emit->max_num_labels = max_num_labels;
38+
emit->label_offsets = m_new(uint, emit->max_num_labels);
39+
emit->code_offset = 0;
40+
emit->code_size = 0;
41+
emit->code_base = NULL;
42+
return emit;
43+
}
3744

3845
uint emit_bc_get_code_size(emit_t* emit) {
3946
return emit->code_size;
@@ -672,7 +679,7 @@ static void emit_bc_yield_from(emit_t *emit) {
672679
emit_write_byte_1(emit, PYBC_YIELD_FROM);
673680
}
674681

675-
static const emit_method_table_t emit_bc_method_table = {
682+
const emit_method_table_t emit_bc_method_table = {
676683
emit_bc_set_native_types,
677684
emit_bc_start_pass,
678685
emit_bc_end_pass,
@@ -767,15 +774,3 @@ static const emit_method_table_t emit_bc_method_table = {
767774
emit_bc_yield_value,
768775
emit_bc_yield_from,
769776
};
770-
771-
void emit_bc_new(emit_t **emit_out, const emit_method_table_t **emit_method_table_out, uint max_num_labels) {
772-
emit_t *emit = m_new(emit_t, 1);
773-
emit->max_num_labels = max_num_labels;
774-
emit->label_offsets = m_new(uint, emit->max_num_labels);
775-
emit->code_offset = 0;
776-
emit->code_size = 0;
777-
emit->code_base = NULL;
778-
779-
*emit_out = emit;
780-
*emit_method_table_out = &emit_bc_method_table;
781-
}

0 commit comments

Comments
 (0)