unix-cpy: Remove unix-cpy. It's no longer needed.
unix-cpy was originally written to get semantic equivalent with CPython without writing functional tests. When writing the initial implementation of uPy it was a long way between lexer and functional tests, so the half-way test was to make sure that the bytecode was correct. The idea was that if the uPy bytecode matched CPython 1-1 then uPy would be proper Python if the bytecodes acted correctly. And having matching bytecode meant that it was less likely to miss some deep subtlety in the Python semantics that would require an architectural change later on. But that is all history and it no longer makes sense to retain the ability to output CPython bytecode, because: 1. It outputs CPython 3.3 compatible bytecode. CPython's bytecode changes from version to version, and seems to have changed quite a bit in 3.5. There's no point in changing the bytecode output to match CPython anymore. 2. uPy and CPy do different optimisations to the bytecode which makes it harder to match. 3. The bytecode tests are not run. They were never part of Travis and are not run locally anymore. 4. The EMIT_CPYTHON option needs a lot of extra source code which adds heaps of noise, especially in compile.c. 5. Now that there is an extensive test suite (which tests functionality) there is no need to match the bytecode. Some very subtle behaviour is tested with the test suite and passing these tests is a much better way to stay Python-language compliant, rather than trying to match CPy bytecode.
This commit is contained in:
parent
0e978349a5
commit
65dc960e3b
|
@ -16,7 +16,6 @@ before_script:
|
|||
script:
|
||||
- make -C minimal test
|
||||
- make -C unix CC=gcc-4.7
|
||||
- make -C unix-cpy CC=gcc-4.7
|
||||
- make -C bare-arm
|
||||
- make -C qemu-arm test
|
||||
- make -C stmhal
|
||||
|
|
|
@ -47,7 +47,6 @@ Additional components:
|
|||
- pic16bit/ -- a version of Micro Python for 16-bit PIC microcontrollers.
|
||||
- cc3200/ -- a version of Micro Python that runs on the CC3200 from TI.
|
||||
- esp8266/ -- an experimental port for ESP8266 WiFi modules.
|
||||
- unix-cpy/ -- a version of Micro Python that outputs bytecode (for testing).
|
||||
- tests/ -- test framework and test scripts.
|
||||
- tools/ -- various tools, including the pyboard.py module.
|
||||
- examples/ -- a few example Python scripts.
|
||||
|
|
420
py/compile.c
420
py/compile.c
|
@ -49,7 +49,7 @@ typedef enum {
|
|||
PN_const_object, // special node for a constant, generic Python object
|
||||
} pn_kind_t;
|
||||
|
||||
#define NEED_METHOD_TABLE (MICROPY_EMIT_CPYTHON || MICROPY_EMIT_NATIVE)
|
||||
#define NEED_METHOD_TABLE MICROPY_EMIT_NATIVE
|
||||
|
||||
#if NEED_METHOD_TABLE
|
||||
|
||||
|
@ -323,23 +323,6 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
|
|||
|
||||
case PN_power:
|
||||
if (0) {
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
} else if (MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_NULL(pns->nodes[1]) && !MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
|
||||
// int ** x
|
||||
// can overflow; enabled only to compare with CPython
|
||||
mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)pns->nodes[2];
|
||||
if (MP_PARSE_NODE_IS_SMALL_INT(pns2->nodes[0])) {
|
||||
int power = MP_PARSE_NODE_LEAF_SMALL_INT(pns2->nodes[0]);
|
||||
if (power >= 0) {
|
||||
int ans = 1;
|
||||
int base = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
|
||||
for (; power > 0; power--) {
|
||||
ans *= base;
|
||||
}
|
||||
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, ans);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if MICROPY_COMP_MODULE_CONST
|
||||
} else if (MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_trailer_period) && MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
|
||||
// id.id
|
||||
|
@ -464,163 +447,7 @@ STATIC void compile_delete_id(compiler_t *comp, qstr qst) {
|
|||
}
|
||||
}
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
STATIC bool cpython_c_tuple_is_const(mp_parse_node_t pn) {
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_string)) {
|
||||
return true;
|
||||
}
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_bytes)) {
|
||||
return true;
|
||||
}
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_const_object)) {
|
||||
return true;
|
||||
}
|
||||
if (!MP_PARSE_NODE_IS_LEAF(pn)) {
|
||||
return false;
|
||||
}
|
||||
if (MP_PARSE_NODE_IS_ID(pn)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
STATIC void cpython_c_print_quoted_str(vstr_t *vstr, const char *str, uint len, bool bytes) {
|
||||
bool has_single_quote = false;
|
||||
bool has_double_quote = false;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (str[i] == '\'') {
|
||||
has_single_quote = true;
|
||||
} else if (str[i] == '"') {
|
||||
has_double_quote = true;
|
||||
}
|
||||
}
|
||||
if (bytes) {
|
||||
vstr_printf(vstr, "b");
|
||||
}
|
||||
bool quote_single = false;
|
||||
if (has_single_quote && !has_double_quote) {
|
||||
vstr_printf(vstr, "\"");
|
||||
} else {
|
||||
quote_single = true;
|
||||
vstr_printf(vstr, "'");
|
||||
}
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (str[i] == '\n') {
|
||||
vstr_printf(vstr, "\\n");
|
||||
} else if (str[i] == '\\') {
|
||||
vstr_printf(vstr, "\\\\");
|
||||
} else if (str[i] == '\'' && quote_single) {
|
||||
vstr_printf(vstr, "\\'");
|
||||
} else {
|
||||
vstr_printf(vstr, "%c", str[i]);
|
||||
}
|
||||
}
|
||||
if (has_single_quote && !has_double_quote) {
|
||||
vstr_printf(vstr, "\"");
|
||||
} else {
|
||||
vstr_printf(vstr, "'");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void cpython_c_tuple_emit_const(compiler_t *comp, mp_parse_node_t pn, vstr_t *vstr) {
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_string) || MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_bytes)) {
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
|
||||
cpython_c_print_quoted_str(vstr, (const char*)pns->nodes[0], (mp_uint_t)pns->nodes[1], MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_bytes));
|
||||
return;
|
||||
}
|
||||
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_const_object)) {
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
|
||||
mp_obj_print((mp_obj_t)pns->nodes[0], PRINT_REPR);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(MP_PARSE_NODE_IS_LEAF(pn));
|
||||
if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
|
||||
vstr_printf(vstr, INT_FMT, MP_PARSE_NODE_LEAF_SMALL_INT(pn));
|
||||
return;
|
||||
}
|
||||
|
||||
mp_uint_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
|
||||
switch (MP_PARSE_NODE_LEAF_KIND(pn)) {
|
||||
case MP_PARSE_NODE_ID: assert(0);
|
||||
case MP_PARSE_NODE_STRING:
|
||||
case MP_PARSE_NODE_BYTES: {
|
||||
mp_uint_t len;
|
||||
const byte *str = qstr_data(arg, &len);
|
||||
cpython_c_print_quoted_str(vstr, (const char*)str, len, MP_PARSE_NODE_LEAF_KIND(pn) == MP_PARSE_NODE_BYTES);
|
||||
break;
|
||||
}
|
||||
case MP_PARSE_NODE_TOKEN:
|
||||
switch (arg) {
|
||||
case MP_TOKEN_KW_FALSE: vstr_printf(vstr, "False"); break;
|
||||
case MP_TOKEN_KW_NONE: vstr_printf(vstr, "None"); break;
|
||||
case MP_TOKEN_KW_TRUE: vstr_printf(vstr, "True"); break;
|
||||
default: assert(0); // shouldn't happen
|
||||
}
|
||||
break;
|
||||
default: assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void cpython_c_tuple(compiler_t *comp, mp_parse_node_t pn, mp_parse_node_struct_t *pns_list) {
|
||||
int n = 0;
|
||||
if (pns_list != NULL) {
|
||||
n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_list);
|
||||
}
|
||||
int total = n;
|
||||
bool is_const = true;
|
||||
if (!MP_PARSE_NODE_IS_NULL(pn)) {
|
||||
total += 1;
|
||||
if (!cpython_c_tuple_is_const(pn)) {
|
||||
is_const = false;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (!cpython_c_tuple_is_const(pns_list->nodes[i])) {
|
||||
is_const = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (total > 0 && is_const) {
|
||||
bool need_comma = false;
|
||||
vstr_t *vstr = vstr_new();
|
||||
vstr_printf(vstr, "(");
|
||||
if (!MP_PARSE_NODE_IS_NULL(pn)) {
|
||||
cpython_c_tuple_emit_const(comp, pn, vstr);
|
||||
need_comma = true;
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (need_comma) {
|
||||
vstr_printf(vstr, ", ");
|
||||
}
|
||||
cpython_c_tuple_emit_const(comp, pns_list->nodes[i], vstr);
|
||||
need_comma = true;
|
||||
}
|
||||
if (total == 1) {
|
||||
vstr_printf(vstr, ",)");
|
||||
} else {
|
||||
vstr_printf(vstr, ")");
|
||||
}
|
||||
EMIT_ARG(load_const_verbatim_strn, vstr_str(vstr), vstr_len(vstr));
|
||||
vstr_free(vstr);
|
||||
} else {
|
||||
if (!MP_PARSE_NODE_IS_NULL(pn)) {
|
||||
compile_node(comp, pn);
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
compile_node(comp, pns_list->nodes[i]);
|
||||
}
|
||||
EMIT_ARG(build_tuple, total);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// funnelling all tuple creations through this function is purely so we can optionally agree with CPython
|
||||
STATIC void c_tuple(compiler_t *comp, mp_parse_node_t pn, mp_parse_node_struct_t *pns_list) {
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
cpython_c_tuple(comp, pn, pns_list);
|
||||
#else
|
||||
int total = 0;
|
||||
if (!MP_PARSE_NODE_IS_NULL(pn)) {
|
||||
compile_node(comp, pn);
|
||||
|
@ -634,7 +461,6 @@ STATIC void c_tuple(compiler_t *comp, mp_parse_node_t pn, mp_parse_node_struct_t
|
|||
total += n;
|
||||
}
|
||||
EMIT_ARG(build_tuple, total);
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC void compile_generic_tuple(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
|
@ -652,66 +478,7 @@ STATIC bool node_is_const_true(mp_parse_node_t pn) {
|
|||
|| (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) != 0);
|
||||
}
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
// the is_nested variable is purely to match with CPython, which doesn't fully optimise not's
|
||||
STATIC void cpython_c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int label, bool is_nested) {
|
||||
if (node_is_const_false(pn)) {
|
||||
if (jump_if == false) {
|
||||
EMIT_ARG(jump, label);
|
||||
}
|
||||
return;
|
||||
} else if (node_is_const_true(pn)) {
|
||||
if (jump_if == true) {
|
||||
EMIT_ARG(jump, label);
|
||||
}
|
||||
return;
|
||||
} else if (MP_PARSE_NODE_IS_STRUCT(pn)) {
|
||||
mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
|
||||
int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
|
||||
if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_or_test) {
|
||||
if (jump_if == false) {
|
||||
uint label2 = comp_next_label(comp);
|
||||
for (int i = 0; i < n - 1; i++) {
|
||||
cpython_c_if_cond(comp, pns->nodes[i], true, label2, true);
|
||||
}
|
||||
cpython_c_if_cond(comp, pns->nodes[n - 1], false, label, true);
|
||||
EMIT_ARG(label_assign, label2);
|
||||
} else {
|
||||
for (int i = 0; i < n; i++) {
|
||||
cpython_c_if_cond(comp, pns->nodes[i], true, label, true);
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_and_test) {
|
||||
if (jump_if == false) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
cpython_c_if_cond(comp, pns->nodes[i], false, label, true);
|
||||
}
|
||||
} else {
|
||||
uint label2 = comp_next_label(comp);
|
||||
for (int i = 0; i < n - 1; i++) {
|
||||
cpython_c_if_cond(comp, pns->nodes[i], false, label2, true);
|
||||
}
|
||||
cpython_c_if_cond(comp, pns->nodes[n - 1], true, label, true);
|
||||
EMIT_ARG(label_assign, label2);
|
||||
}
|
||||
return;
|
||||
} else if (!is_nested && MP_PARSE_NODE_STRUCT_KIND(pns) == PN_not_test_2) {
|
||||
cpython_c_if_cond(comp, pns->nodes[0], !jump_if, label, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// nothing special, fall back to default compiling for node and jump
|
||||
compile_node(comp, pn);
|
||||
EMIT_ARG(pop_jump_if, jump_if, label);
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int label) {
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
cpython_c_if_cond(comp, pn, jump_if, label, false);
|
||||
#else
|
||||
if (node_is_const_false(pn)) {
|
||||
if (jump_if == false) {
|
||||
EMIT_ARG(jump, label);
|
||||
|
@ -773,7 +540,6 @@ STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int la
|
|||
// nothing special, fall back to default compiling for node and jump
|
||||
compile_node(comp, pn);
|
||||
EMIT_ARG(pop_jump_if, jump_if, label);
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef enum { ASSIGN_STORE, ASSIGN_AUG_LOAD, ASSIGN_AUG_STORE } assign_kind_t;
|
||||
|
@ -992,8 +758,7 @@ STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_
|
|||
compile_syntax_error(comp, pn, "illegal expression for augmented assignment");
|
||||
}
|
||||
|
||||
// stuff for lambda and comprehensions and generators
|
||||
// if we are not in CPython compatibility mode then:
|
||||
// stuff for lambda and comprehensions and generators:
|
||||
// if n_pos_defaults > 0 then there is a tuple on the stack with the positional defaults
|
||||
// if n_kw_defaults > 0 then there is a dictionary on the stack with the keyword defaults
|
||||
// if both exist, the tuple is above the dictionary (ie the first pop gets the tuple)
|
||||
|
@ -1011,12 +776,8 @@ STATIC void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int
|
|||
for (int j = 0; j < this_scope->id_info_len; j++) {
|
||||
id_info_t *id2 = &this_scope->id_info[j];
|
||||
if (id2->kind == ID_INFO_KIND_FREE && id->qst == id2->qst) {
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
EMIT_ARG(load_closure, id->qst, id->local_num);
|
||||
#else
|
||||
// in Micro Python we load closures using LOAD_FAST
|
||||
EMIT_LOAD_FAST(id->qst, id->local_num);
|
||||
#endif
|
||||
nfree += 1;
|
||||
}
|
||||
}
|
||||
|
@ -1085,10 +846,6 @@ STATIC void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
|
|||
|
||||
if (comp->have_star) {
|
||||
comp->num_dict_params += 1;
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pn_id));
|
||||
compile_node(comp, pn_equal);
|
||||
#else
|
||||
// in Micro Python we put the default dict parameters into a dictionary using the bytecode
|
||||
if (comp->num_dict_params == 1) {
|
||||
// in Micro Python we put the default positional parameters into a tuple using the bytecode
|
||||
|
@ -1106,7 +863,6 @@ STATIC void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
|
|||
compile_node(comp, pn_equal);
|
||||
EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pn_id));
|
||||
EMIT(store_map);
|
||||
#endif
|
||||
} else {
|
||||
comp->num_default_params += 1;
|
||||
compile_node(comp, pn_equal);
|
||||
|
@ -1143,14 +899,12 @@ STATIC qstr compile_funcdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns
|
|||
return MP_QSTR_NULL;
|
||||
}
|
||||
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
// in Micro Python we put the default positional parameters into a tuple using the bytecode
|
||||
// the default keywords args may have already made the tuple; if not, do it now
|
||||
if (comp->num_default_params > 0 && comp->num_dict_params == 0) {
|
||||
EMIT_ARG(build_tuple, comp->num_default_params);
|
||||
EMIT(load_null); // sentinel indicating empty default keyword args
|
||||
}
|
||||
#endif
|
||||
|
||||
// get the scope for this function
|
||||
scope_t *fscope = (scope_t*)pns->nodes[4];
|
||||
|
@ -1558,12 +1312,8 @@ STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
|||
EMIT_ARG(load_const_small_int, import_level);
|
||||
|
||||
// build the "fromlist" tuple
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
EMIT_ARG(load_const_verbatim_strn, "('*',)", 6);
|
||||
#else
|
||||
EMIT_ARG(load_const_str, MP_QSTR__star_);
|
||||
EMIT_ARG(build_tuple, 1);
|
||||
#endif
|
||||
|
||||
// do the import
|
||||
qstr dummy_q;
|
||||
|
@ -1576,31 +1326,6 @@ STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
|||
// build the "fromlist" tuple
|
||||
mp_parse_node_t *pn_nodes;
|
||||
int n = mp_parse_node_extract_list(&pns->nodes[1], PN_import_as_names, &pn_nodes);
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
{
|
||||
vstr_t *vstr = vstr_new();
|
||||
vstr_printf(vstr, "(");
|
||||
for (int i = 0; i < n; i++) {
|
||||
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_nodes[i], PN_import_as_name));
|
||||
mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t*)pn_nodes[i];
|
||||
qstr id2 = MP_PARSE_NODE_LEAF_ARG(pns3->nodes[0]); // should be id
|
||||
if (i > 0) {
|
||||
vstr_printf(vstr, ", ");
|
||||
}
|
||||
vstr_printf(vstr, "'");
|
||||
mp_uint_t len;
|
||||
const byte *str = qstr_data(id2, &len);
|
||||
vstr_add_strn(vstr, (const char*)str, len);
|
||||
vstr_printf(vstr, "'");
|
||||
}
|
||||
if (n == 1) {
|
||||
vstr_printf(vstr, ",");
|
||||
}
|
||||
vstr_printf(vstr, ")");
|
||||
EMIT_ARG(load_const_verbatim_strn, vstr_str(vstr), vstr_len(vstr));
|
||||
vstr_free(vstr);
|
||||
}
|
||||
#else
|
||||
for (int i = 0; i < n; i++) {
|
||||
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_nodes[i], PN_import_as_name));
|
||||
mp_parse_node_struct_t *pns3 = (mp_parse_node_struct_t*)pn_nodes[i];
|
||||
|
@ -1608,7 +1333,6 @@ STATIC void compile_import_from(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
|||
EMIT_ARG(load_const_str, id2);
|
||||
}
|
||||
EMIT_ARG(build_tuple, n);
|
||||
#endif
|
||||
|
||||
// do the import
|
||||
qstr dummy_q;
|
||||
|
@ -1704,21 +1428,21 @@ STATIC void compile_if_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
|||
|
||||
uint l_end = comp_next_label(comp);
|
||||
|
||||
// optimisation: don't emit anything when "if False" (not in CPython)
|
||||
if (MICROPY_EMIT_CPYTHON || !node_is_const_false(pns->nodes[0])) {
|
||||
// optimisation: don't emit anything when "if False"
|
||||
if (!node_is_const_false(pns->nodes[0])) {
|
||||
uint l_fail = comp_next_label(comp);
|
||||
c_if_cond(comp, pns->nodes[0], false, l_fail); // if condition
|
||||
|
||||
compile_node(comp, pns->nodes[1]); // if block
|
||||
|
||||
// optimisation: skip everything else when "if True" (not in CPython)
|
||||
if (!MICROPY_EMIT_CPYTHON && node_is_const_true(pns->nodes[0])) {
|
||||
// optimisation: skip everything else when "if True"
|
||||
if (node_is_const_true(pns->nodes[0])) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (
|
||||
// optimisation: don't jump over non-existent elif/else blocks (not in CPython)
|
||||
(MICROPY_EMIT_CPYTHON || !(MP_PARSE_NODE_IS_NULL(pns->nodes[2]) && MP_PARSE_NODE_IS_NULL(pns->nodes[3])))
|
||||
// optimisation: don't jump over non-existent elif/else blocks
|
||||
!(MP_PARSE_NODE_IS_NULL(pns->nodes[2]) && MP_PARSE_NODE_IS_NULL(pns->nodes[3]))
|
||||
// optimisation: don't jump if last instruction was return
|
||||
&& !EMIT(last_emit_was_return_value)
|
||||
) {
|
||||
|
@ -1736,15 +1460,15 @@ STATIC void compile_if_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
|||
assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn_elif[i], PN_if_stmt_elif)); // should be
|
||||
mp_parse_node_struct_t *pns_elif = (mp_parse_node_struct_t*)pn_elif[i];
|
||||
|
||||
// optimisation: don't emit anything when "if False" (not in CPython)
|
||||
if (MICROPY_EMIT_CPYTHON || !node_is_const_false(pns_elif->nodes[0])) {
|
||||
// optimisation: don't emit anything when "if False"
|
||||
if (!node_is_const_false(pns_elif->nodes[0])) {
|
||||
uint l_fail = comp_next_label(comp);
|
||||
c_if_cond(comp, pns_elif->nodes[0], false, l_fail); // elif condition
|
||||
|
||||
compile_node(comp, pns_elif->nodes[1]); // elif block
|
||||
|
||||
// optimisation: skip everything else when "elif True" (not in CPython)
|
||||
if (!MICROPY_EMIT_CPYTHON && node_is_const_true(pns_elif->nodes[0])) {
|
||||
// optimisation: skip everything else when "elif True"
|
||||
if (node_is_const_true(pns_elif->nodes[0])) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -1781,23 +1505,6 @@ done:
|
|||
STATIC void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
START_BREAK_CONTINUE_BLOCK
|
||||
|
||||
// compared to CPython, we have an optimised version of while loops
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
uint done_label = comp_next_label(comp);
|
||||
EMIT_ARG(setup_loop, break_label);
|
||||
EMIT_ARG(label_assign, continue_label);
|
||||
c_if_cond(comp, pns->nodes[0], false, done_label); // condition
|
||||
compile_node(comp, pns->nodes[1]); // body
|
||||
if (!EMIT(last_emit_was_return_value)) {
|
||||
EMIT_ARG(jump, continue_label);
|
||||
}
|
||||
EMIT_ARG(label_assign, done_label);
|
||||
// CPython does not emit POP_BLOCK if the condition was a constant; don't undertand why
|
||||
// this is a small hack to agree with CPython
|
||||
if (!node_is_const_true(pns->nodes[0])) {
|
||||
EMIT(pop_block);
|
||||
}
|
||||
#else
|
||||
if (!node_is_const_false(pns->nodes[0])) { // optimisation: don't emit anything for "while False"
|
||||
uint top_label = comp_next_label(comp);
|
||||
if (!node_is_const_true(pns->nodes[0])) { // optimisation: don't jump to cond for "while True"
|
||||
|
@ -1808,7 +1515,6 @@ STATIC void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
|||
EMIT_ARG(label_assign, continue_label);
|
||||
c_if_cond(comp, pns->nodes[0], true, top_label); // condition
|
||||
}
|
||||
#endif
|
||||
|
||||
// break/continue apply to outer loop (if any) in the else block
|
||||
END_BREAK_CONTINUE_BLOCK
|
||||
|
@ -1818,7 +1524,6 @@ STATIC void compile_while_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
|||
EMIT_ARG(label_assign, break_label);
|
||||
}
|
||||
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
// This function compiles an optimised for-loop of the form:
|
||||
// for <var> in range(<start>, <end>, <step>):
|
||||
// <body>
|
||||
|
@ -1899,10 +1604,8 @@ STATIC void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t p
|
|||
EMIT(pop_top);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
// this bit optimises: for <x> in range(...), turning it into an explicitly incremented variable
|
||||
// this is actually slower, but uses no heap memory
|
||||
// for viper it will be much, much faster
|
||||
|
@ -1945,7 +1648,6 @@ STATIC void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
START_BREAK_CONTINUE_BLOCK
|
||||
comp->break_label |= MP_EMIT_BREAK_FROM_FOR;
|
||||
|
@ -1953,11 +1655,6 @@ STATIC void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
|||
uint pop_label = comp_next_label(comp);
|
||||
uint end_label = comp_next_label(comp);
|
||||
|
||||
// I don't think our implementation needs SETUP_LOOP/POP_BLOCK for for-statements
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
EMIT_ARG(setup_loop, end_label);
|
||||
#endif
|
||||
|
||||
compile_node(comp, pns->nodes[1]); // iterator
|
||||
EMIT(get_iter);
|
||||
EMIT_ARG(label_assign, continue_label);
|
||||
|
@ -1973,10 +1670,6 @@ STATIC void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
|||
// break/continue apply to outer loop (if any) in the else block
|
||||
END_BREAK_CONTINUE_BLOCK
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
EMIT(pop_block);
|
||||
#endif
|
||||
|
||||
compile_node(comp, pns->nodes[3]); // else (not tested)
|
||||
|
||||
EMIT_ARG(label_assign, break_label);
|
||||
|
@ -2233,7 +1926,7 @@ STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
|||
&& MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_star_expr)
|
||||
&& MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns1->nodes[0]) == 2
|
||||
&& MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[0]) == 2) {
|
||||
// optimisation for a, b = c, d; to match CPython's optimisation
|
||||
// optimisation for a, b = c, d
|
||||
mp_parse_node_struct_t *pns10 = (mp_parse_node_struct_t*)pns1->nodes[0];
|
||||
mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns->nodes[0];
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr)
|
||||
|
@ -2251,7 +1944,7 @@ STATIC void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
|||
&& MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_star_expr)
|
||||
&& MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns1->nodes[0]) == 3
|
||||
&& MP_PARSE_NODE_STRUCT_NUM_NODES((mp_parse_node_struct_t*)pns->nodes[0]) == 3) {
|
||||
// optimisation for a, b, c = d, e, f; to match CPython's optimisation
|
||||
// optimisation for a, b, c = d, e, f
|
||||
mp_parse_node_struct_t *pns10 = (mp_parse_node_struct_t*)pns1->nodes[0];
|
||||
mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns->nodes[0];
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr)
|
||||
|
@ -2485,7 +2178,6 @@ STATIC void compile_power(compiler_t *comp, mp_parse_node_struct_t *pns) {
|
|||
STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra) {
|
||||
// function to call is on top of stack
|
||||
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
// this is to handle special super() call
|
||||
if (MP_PARSE_NODE_IS_NULL(pn_arglist) && comp->func_arg_is_super && comp->scope_cur->kind == SCOPE_FUNCTION) {
|
||||
compile_load_id(comp, MP_QSTR___class__);
|
||||
|
@ -2501,7 +2193,6 @@ STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_ar
|
|||
compile_syntax_error(comp, MP_PARSE_NODE_NULL, "super() call cannot find self"); // really a TypeError
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// get the list of arguments
|
||||
mp_parse_node_t *args;
|
||||
|
@ -3184,7 +2875,7 @@ STATIC void compile_scope_comp_iter(compiler_t *comp, mp_parse_node_t pn_iter, m
|
|||
}
|
||||
|
||||
STATIC void check_for_doc_string(compiler_t *comp, mp_parse_node_t pn) {
|
||||
#if MICROPY_EMIT_CPYTHON || MICROPY_ENABLE_DOC_STRING
|
||||
#if MICROPY_ENABLE_DOC_STRING
|
||||
// see http://www.python.org/dev/peps/pep-0257/
|
||||
|
||||
// look for the first statement
|
||||
|
@ -3240,12 +2931,6 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
|
|||
scope->exc_stack_size = 0;
|
||||
}
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
if (comp->pass == MP_PASS_EMIT) {
|
||||
scope_print_info(scope);
|
||||
}
|
||||
#endif
|
||||
|
||||
// compile
|
||||
if (MP_PARSE_NODE_IS_STRUCT_KIND(scope->pn, PN_eval_input)) {
|
||||
assert(scope->kind == SCOPE_MODULE);
|
||||
|
@ -3331,11 +3016,7 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
|
|||
// CPython uses .0, but we should be able to use anything that won't
|
||||
// clash with a user defined variable. Best to use an existing qstr,
|
||||
// so we use the blank qstr.
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
qstr qstr_arg = QSTR_FROM_STR_STATIC(".0");
|
||||
#else
|
||||
qstr qstr_arg = MP_QSTR_;
|
||||
#endif
|
||||
if (comp->pass == MP_PASS_SCOPE) {
|
||||
bool added;
|
||||
id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qstr_arg, &added);
|
||||
|
@ -3395,11 +3076,7 @@ STATIC void compile_scope(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
|
|||
if (id->kind == ID_INFO_KIND_LOCAL) {
|
||||
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
|
||||
} else {
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
EMIT_ARG(load_closure, MP_QSTR___class__, 0); // XXX check this is the correct local num
|
||||
#else
|
||||
EMIT_LOAD_FAST(MP_QSTR___class__, id->local_num);
|
||||
#endif
|
||||
}
|
||||
EMIT(return_value);
|
||||
}
|
||||
|
@ -3547,7 +3224,6 @@ STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind
|
|||
#endif
|
||||
|
||||
STATIC void scope_compute_things(scope_t *scope) {
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
// in Micro Python we put the *x parameter after all other parameters (except **y)
|
||||
if (scope->scope_flags & MP_SCOPE_FLAG_VARARGS) {
|
||||
id_info_t *id_param = NULL;
|
||||
|
@ -3564,7 +3240,6 @@ STATIC void scope_compute_things(scope_t *scope) {
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// in functions, turn implicit globals into explicit globals
|
||||
// compute the index of each local
|
||||
|
@ -3584,19 +3259,9 @@ STATIC void scope_compute_things(scope_t *scope) {
|
|||
}
|
||||
}
|
||||
|
||||
// compute the index of cell vars (freevars[idx] in CPython)
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
int num_cell = 0;
|
||||
#endif
|
||||
// compute the index of cell vars
|
||||
for (int i = 0; i < scope->id_info_len; i++) {
|
||||
id_info_t *id = &scope->id_info[i];
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
// in CPython the cells are numbered starting from 0
|
||||
if (id->kind == ID_INFO_KIND_CELL) {
|
||||
id->local_num = num_cell;
|
||||
num_cell += 1;
|
||||
}
|
||||
#else
|
||||
// in Micro Python the cells come right after the fast locals
|
||||
// parameters are not counted here, since they remain at the start
|
||||
// of the locals, even if they are cell vars
|
||||
|
@ -3604,10 +3269,9 @@ STATIC void scope_compute_things(scope_t *scope) {
|
|||
id->local_num = scope->num_locals;
|
||||
scope->num_locals += 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// compute the index of free vars (freevars[idx] in CPython)
|
||||
// compute the index of free vars
|
||||
// make sure they are in the order of the parent scope
|
||||
if (scope->parent != NULL) {
|
||||
int num_free = 0;
|
||||
|
@ -3618,19 +3282,13 @@ STATIC void scope_compute_things(scope_t *scope) {
|
|||
id_info_t *id2 = &scope->id_info[j];
|
||||
if (id2->kind == ID_INFO_KIND_FREE && id->qst == id2->qst) {
|
||||
assert(!(id2->flags & ID_FLAG_IS_PARAM)); // free vars should not be params
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
// in CPython the frees are numbered after the cells
|
||||
id2->local_num = num_cell + num_free;
|
||||
#else
|
||||
// in Micro Python the frees come first, before the params
|
||||
id2->local_num = num_free;
|
||||
#endif
|
||||
num_free += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
// in Micro Python shift all other locals after the free locals
|
||||
if (num_free > 0) {
|
||||
for (int i = 0; i < scope->id_info_len; i++) {
|
||||
|
@ -3642,23 +3300,9 @@ STATIC void scope_compute_things(scope_t *scope) {
|
|||
scope->num_pos_args += num_free; // free vars are counted as params for passing them into the function
|
||||
scope->num_locals += num_free;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// compute scope_flags
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
// these flags computed here are for CPython compatibility only
|
||||
if (scope->kind == SCOPE_FUNCTION || scope->kind == SCOPE_LAMBDA || scope->kind == SCOPE_LIST_COMP || scope->kind == SCOPE_DICT_COMP || scope->kind == SCOPE_SET_COMP || scope->kind == SCOPE_GEN_EXPR) {
|
||||
assert(scope->parent != NULL);
|
||||
scope->scope_flags |= MP_SCOPE_FLAG_NEWLOCALS;
|
||||
scope->scope_flags |= MP_SCOPE_FLAG_OPTIMISED;
|
||||
if ((SCOPE_FUNCTION <= scope->parent->kind && scope->parent->kind <= SCOPE_SET_COMP) || (scope->parent->kind == SCOPE_CLASS && scope->parent->parent->kind == SCOPE_FUNCTION)) {
|
||||
scope->scope_flags |= MP_SCOPE_FLAG_NESTED;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int num_free = 0;
|
||||
for (int i = 0; i < scope->id_info_len; i++) {
|
||||
id_info_t *id = &scope->id_info[i];
|
||||
|
@ -3688,22 +3332,13 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
|||
mp_map_deinit(&consts);
|
||||
|
||||
// create standard emitter; it's used at least for MP_PASS_SCOPE
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
emit_t *emit_cpython = emit_cpython_new();
|
||||
#else
|
||||
emit_t *emit_bc = emit_bc_new();
|
||||
#endif
|
||||
|
||||
// compile pass 1
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
comp->emit = emit_cpython;
|
||||
comp->emit_method_table = &emit_cpython_method_table;
|
||||
#else
|
||||
comp->emit = emit_bc;
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
comp->emit_method_table = &emit_bc_method_table;
|
||||
#endif
|
||||
#endif
|
||||
#if MICROPY_EMIT_INLINE_THUMB
|
||||
comp->emit_inline_asm = NULL;
|
||||
comp->emit_inline_asm_method_table = NULL;
|
||||
|
@ -3731,21 +3366,15 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
|||
}
|
||||
|
||||
// set max number of labels now that it's calculated
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
emit_cpython_set_max_num_labels(emit_cpython, max_num_labels);
|
||||
#else
|
||||
emit_bc_set_max_num_labels(emit_bc, max_num_labels);
|
||||
#endif
|
||||
|
||||
// compile pass 2 and 3
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
emit_t *emit_native = NULL;
|
||||
#endif
|
||||
#if MICROPY_EMIT_INLINE_THUMB
|
||||
emit_inline_asm_t *emit_inline_thumb = NULL;
|
||||
#endif
|
||||
#endif // !MICROPY_EMIT_CPYTHON
|
||||
for (scope_t *s = comp->scope_head; s != NULL && comp->compile_error == MP_OBJ_NULL; s = s->next) {
|
||||
if (false) {
|
||||
// dummy
|
||||
|
@ -3770,10 +3399,6 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
|||
|
||||
// choose the emit type
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
comp->emit = emit_cpython;
|
||||
comp->emit_method_table = &emit_cpython_method_table;
|
||||
#else
|
||||
switch (s->emit_options) {
|
||||
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
|
@ -3812,7 +3437,6 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
|||
#endif
|
||||
break;
|
||||
}
|
||||
#endif // !MICROPY_EMIT_CPYTHON
|
||||
|
||||
// need a pass to compute stack size
|
||||
compile_scope(comp, s, MP_PASS_STACK_SIZE);
|
||||
|
@ -3840,9 +3464,6 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
|||
|
||||
// free the emitters
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
emit_cpython_free(emit_cpython);
|
||||
#else
|
||||
emit_bc_free(emit_bc);
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
if (emit_native != NULL) {
|
||||
|
@ -3862,7 +3483,6 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
|||
emit_inline_thumb_free(emit_inline_thumb);
|
||||
}
|
||||
#endif
|
||||
#endif // MICROPY_EMIT_CPYTHON
|
||||
|
||||
// free the parse tree
|
||||
mp_parse_node_free(module_scope->pn);
|
||||
|
@ -3882,13 +3502,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
|
|||
if (compile_error != MP_OBJ_NULL) {
|
||||
nlr_raise(compile_error);
|
||||
} else {
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
// can't create code, so just return true
|
||||
(void)outer_raw_code; // to suppress warning that outer_raw_code is unused
|
||||
return mp_const_true;
|
||||
#else
|
||||
// return function that executes the outer module
|
||||
return mp_make_function_from_raw_code(outer_raw_code, MP_OBJ_NULL, MP_OBJ_NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,14 +145,6 @@ typedef struct _emit_method_table_t {
|
|||
// they may or may not emit code
|
||||
void (*start_except_handler)(emit_t *emit);
|
||||
void (*end_except_handler)(emit_t *emit);
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
// these methods are only needed for emitcpy
|
||||
void (*load_const_verbatim_strn)(emit_t *emit, const char *str, mp_uint_t len);
|
||||
void (*load_closure)(emit_t *emit, qstr qst, mp_uint_t local_num);
|
||||
void (*setup_loop)(emit_t *emit, mp_uint_t label);
|
||||
#endif
|
||||
|
||||
} emit_method_table_t;
|
||||
|
||||
void mp_emit_common_get_id_for_load(scope_t *scope, qstr qst);
|
||||
|
|
|
@ -34,8 +34,6 @@
|
|||
#include "py/emit.h"
|
||||
#include "py/bc0.h"
|
||||
|
||||
#if !MICROPY_EMIT_CPYTHON
|
||||
|
||||
#define BYTES_FOR_INT ((BYTES_PER_WORD * 8 + 6) / 7)
|
||||
#define DUMMY_DATA_SIZE (BYTES_FOR_INT)
|
||||
|
||||
|
@ -1030,5 +1028,3 @@ const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_delete_id_ops = {
|
|||
mp_emit_bc_delete_global,
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // !MICROPY_EMIT_CPYTHON
|
||||
|
|
|
@ -33,21 +33,6 @@ void mp_emit_common_get_id_for_load(scope_t *scope, qstr qst) {
|
|||
bool added;
|
||||
id_info_t *id = scope_find_or_add_id(scope, qst, &added);
|
||||
if (added) {
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
if (qst == MP_QSTR_super && scope->kind == SCOPE_FUNCTION) {
|
||||
// special case, super is a global, and also counts as use of __class__
|
||||
id->kind = ID_INFO_KIND_GLOBAL_EXPLICIT;
|
||||
id_info_t *id2 = scope_find_local_in_parent(scope, MP_QSTR___class__);
|
||||
if (id2 != NULL) {
|
||||
id2 = scope_find_or_add_id(scope, MP_QSTR___class__, &added);
|
||||
if (added) {
|
||||
id2->kind = ID_INFO_KIND_FREE;
|
||||
scope_close_over_in_parents(scope, MP_QSTR___class__);
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
id_info_t *id2 = scope_find_local_in_parent(scope, qst);
|
||||
if (id2 != NULL && (id2->kind == ID_INFO_KIND_LOCAL || id2->kind == ID_INFO_KIND_CELL || id2->kind == ID_INFO_KIND_FREE)) {
|
||||
id->kind = ID_INFO_KIND_FREE;
|
||||
|
@ -56,7 +41,6 @@ void mp_emit_common_get_id_for_load(scope_t *scope, qstr qst) {
|
|||
id->kind = ID_INFO_KIND_GLOBAL_IMPLICIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mp_emit_common_get_id_for_modification(scope_t *scope, qstr qst) {
|
||||
|
|
901
py/emitcpy.c
901
py/emitcpy.c
|
@ -1,901 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "py/emit.h"
|
||||
|
||||
// wrapper around everything in this file
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
|
||||
struct _emit_t {
|
||||
int pass;
|
||||
int bytecode_offset;
|
||||
int stack_size;
|
||||
bool last_emit_was_return_value;
|
||||
|
||||
scope_t *scope;
|
||||
|
||||
mp_uint_t max_num_labels;
|
||||
mp_uint_t *label_offsets;
|
||||
};
|
||||
|
||||
emit_t *emit_cpython_new(void) {
|
||||
emit_t *emit = m_new0(emit_t, 1);
|
||||
return emit;
|
||||
}
|
||||
|
||||
void emit_cpython_set_max_num_labels(emit_t* emit, mp_uint_t max_num_labels) {
|
||||
emit->max_num_labels = max_num_labels;
|
||||
emit->label_offsets = m_new(mp_uint_t, max_num_labels);
|
||||
}
|
||||
|
||||
void emit_cpython_free(emit_t *emit) {
|
||||
m_del(mp_uint_t, emit->label_offsets, emit->max_num_labels);
|
||||
m_del_obj(emit_t, emit);
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_set_native_type(emit_t *emit, mp_uint_t op, mp_uint_t arg1, qstr arg2) {
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
|
||||
emit->pass = pass;
|
||||
emit->bytecode_offset = 0;
|
||||
emit->stack_size = 0;
|
||||
emit->last_emit_was_return_value = false;
|
||||
emit->scope = scope;
|
||||
if (pass < MP_PASS_EMIT) {
|
||||
memset(emit->label_offsets, -1, emit->max_num_labels * sizeof(mp_uint_t));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_end_pass(emit_t *emit) {
|
||||
if (emit->pass == MP_PASS_SCOPE) {
|
||||
return;
|
||||
}
|
||||
// check stack is back to zero size
|
||||
if (emit->stack_size != 0) {
|
||||
printf("ERROR: stack size not back to zero; got %d\n", emit->stack_size);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC bool emit_cpy_last_emit_was_return_value(emit_t *emit) {
|
||||
return emit->last_emit_was_return_value;
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_adjust_stack_size(emit_t *emit, mp_int_t delta) {
|
||||
emit->stack_size += delta;
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_set_source_line(emit_t *emit, mp_uint_t source_line) {
|
||||
}
|
||||
|
||||
// TODO: module-polymorphic function (read: name clash if made global)
|
||||
static void emit_pre(emit_t *emit, int stack_size_delta, int bytecode_size) {
|
||||
if (emit->pass == MP_PASS_SCOPE) {
|
||||
return;
|
||||
}
|
||||
emit->stack_size += stack_size_delta;
|
||||
if (emit->stack_size > emit->scope->stack_size) {
|
||||
emit->scope->stack_size = emit->stack_size;
|
||||
}
|
||||
emit->last_emit_was_return_value = false;
|
||||
if (emit->pass == MP_PASS_EMIT && bytecode_size > 0) {
|
||||
if (emit->bytecode_offset >= 1000) {
|
||||
printf("%d ", emit->bytecode_offset);
|
||||
} else {
|
||||
printf("% 4d ", emit->bytecode_offset);
|
||||
}
|
||||
}
|
||||
emit->bytecode_offset += bytecode_size;
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_label_assign(emit_t *emit, mp_uint_t l) {
|
||||
emit_pre(emit, 0, 0);
|
||||
if (emit->pass == MP_PASS_SCOPE) {
|
||||
return;
|
||||
}
|
||||
assert(l < emit->max_num_labels);
|
||||
if (emit->pass < MP_PASS_EMIT) {
|
||||
// assign label offset
|
||||
assert(emit->label_offsets[l] == -1);
|
||||
emit->label_offsets[l] = emit->bytecode_offset;
|
||||
} else {
|
||||
// ensure label offset has not changed from MP_PASS_CODE_SIZE to MP_PASS_EMIT
|
||||
assert(emit->label_offsets[l] == emit->bytecode_offset);
|
||||
//printf("l%d: (at %d)\n", l, emit->bytecode_offset);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_import_name(emit_t *emit, qstr qst) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("IMPORT_NAME %s\n", qstr_str(qst));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_import_from(emit_t *emit, qstr qst) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("IMPORT_FROM %s\n", qstr_str(qst));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_import_star(emit_t *emit) {
|
||||
emit_pre(emit, -1, 1);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("IMPORT_STAR\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_CONST ");
|
||||
switch (tok) {
|
||||
case MP_TOKEN_KW_FALSE: printf("False"); break;
|
||||
case MP_TOKEN_KW_NONE: printf("None"); break;
|
||||
case MP_TOKEN_KW_TRUE: printf("True"); break;
|
||||
default: printf("?=%d\n", tok); return; assert(0);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_const_small_int(emit_t *emit, mp_int_t arg) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_CONST " INT_FMT "\n", arg);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void print_quoted_str(qstr qst) {
|
||||
const char *str = qstr_str(qst);
|
||||
int len = strlen(str);
|
||||
bool has_single_quote = false;
|
||||
bool has_double_quote = false;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (str[i] == '\'') {
|
||||
has_single_quote = true;
|
||||
} else if (str[i] == '"') {
|
||||
has_double_quote = true;
|
||||
}
|
||||
}
|
||||
int quote_char = '\'';
|
||||
if (has_single_quote && !has_double_quote) {
|
||||
quote_char = '"';
|
||||
}
|
||||
printf("%c", quote_char);
|
||||
for (const char *s = str, *top = str + len; s < top; s++) {
|
||||
if (*s == quote_char) {
|
||||
printf("\\%c", quote_char);
|
||||
} else if (*s == '\\') {
|
||||
printf("\\\\");
|
||||
} else if (32 <= *s && *s <= 126) {
|
||||
printf("%c", *s);
|
||||
} else if (*s == '\n') {
|
||||
printf("\\n");
|
||||
// TODO add more escape codes here
|
||||
} else {
|
||||
printf("\\x%02x", (*s) & 0xff);
|
||||
}
|
||||
}
|
||||
printf("%c", quote_char);
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_const_str(emit_t *emit, qstr qst) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_CONST ");
|
||||
print_quoted_str(qst);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_const_obj(emit_t *emit, void *obj) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_CONST ");
|
||||
mp_obj_print(obj, PRINT_REPR);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_null(emit_t *emit) {
|
||||
// unused for cpy
|
||||
assert(0);
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_FAST " UINT_FMT " %s\n", local_num, qstr_str(qst));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_DEREF " UINT_FMT " %s\n", local_num, qstr_str(qst));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_name(emit_t *emit, qstr qst) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_NAME %s\n", qstr_str(qst));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_global(emit_t *emit, qstr qst) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_GLOBAL %s\n", qstr_str(qst));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_attr(emit_t *emit, qstr qst) {
|
||||
emit_pre(emit, 0, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_ATTR %s\n", qstr_str(qst));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_method(emit_t *emit, qstr qst) {
|
||||
emit_cpy_load_attr(emit, qst);
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_build_class(emit_t *emit) {
|
||||
emit_pre(emit, 1, 1);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_BUILD_CLASS\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_subscr(emit_t *emit) {
|
||||
emit_pre(emit, -1, 1);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("BINARY_SUBSCR\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("STORE_FAST " UINT_FMT " %s\n", local_num, qstr_str(qst));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_store_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("STORE_DEREF " UINT_FMT " %s\n", local_num, qstr_str(qst));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_store_name(emit_t *emit, qstr qst) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("STORE_NAME %s\n", qstr_str(qst));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_store_global(emit_t *emit, qstr qst) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("STORE_GLOBAL %s\n", qstr_str(qst));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_store_attr(emit_t *emit, qstr qst) {
|
||||
emit_pre(emit, -2, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("STORE_ATTR %s\n", qstr_str(qst));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_store_subscr(emit_t *emit) {
|
||||
emit_pre(emit, -3, 1);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("STORE_SUBSCR\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_delete_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
|
||||
emit_pre(emit, 0, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("DELETE_FAST " UINT_FMT " %s\n", local_num, qstr_str(qst));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_delete_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
|
||||
emit_pre(emit, 0, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("DELETE_DEREF " UINT_FMT " %s\n", local_num, qstr_str(qst));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_delete_name(emit_t *emit, qstr qst) {
|
||||
emit_pre(emit, 0, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("DELETE_NAME %s\n", qstr_str(qst));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_delete_global(emit_t *emit, qstr qst) {
|
||||
emit_pre(emit, 0, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("DELETE_GLOBAL %s\n", qstr_str(qst));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_delete_attr(emit_t *emit, qstr qst) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("DELETE_ATTR %s\n", qstr_str(qst));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_delete_subscr(emit_t *emit) {
|
||||
emit_pre(emit, -2, 1);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("DELETE_SUBSCR\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_dup_top(emit_t *emit) {
|
||||
emit_pre(emit, 1, 1);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("DUP_TOP\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_dup_top_two(emit_t *emit) {
|
||||
emit_pre(emit, 2, 1);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("DUP_TOP_TWO\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_pop_top(emit_t *emit) {
|
||||
emit_pre(emit, -1, 1);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("POP_TOP\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_rot_two(emit_t *emit) {
|
||||
emit_pre(emit, 0, 1);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("ROT_TWO\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_rot_three(emit_t *emit) {
|
||||
emit_pre(emit, 0, 1);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("ROT_THREE\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_jump(emit_t *emit, mp_uint_t label) {
|
||||
emit_pre(emit, 0, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
int dest = emit->label_offsets[label];
|
||||
if (dest < emit->bytecode_offset) {
|
||||
printf("JUMP_ABSOLUTE " UINT_FMT "\n", emit->label_offsets[label]);
|
||||
} else {
|
||||
printf("JUMP_FORWARD " UINT_FMT "\n", emit->label_offsets[label]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_pop_jump_if(emit_t *emit, bool cond, mp_uint_t label) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
if (cond) {
|
||||
printf("POP_JUMP_IF_TRUE " UINT_FMT "\n", emit->label_offsets[label]);
|
||||
} else {
|
||||
printf("POP_JUMP_IF_FALSE " UINT_FMT "\n", emit->label_offsets[label]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
if (cond) {
|
||||
printf("JUMP_IF_TRUE_OR_POP " UINT_FMT "\n", emit->label_offsets[label]);
|
||||
} else {
|
||||
printf("JUMP_IF_FALSE_OR_POP " UINT_FMT "\n", emit->label_offsets[label]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_break_loop(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) {
|
||||
emit_pre(emit, 0, 1);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("BREAK_LOOP\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_continue_loop(emit_t *emit, mp_uint_t label, mp_uint_t except_depth) {
|
||||
if (except_depth == 0) {
|
||||
emit_cpy_jump(emit, label);
|
||||
} else {
|
||||
emit_pre(emit, 0, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("CONTINUE_LOOP " UINT_FMT "\n", emit->label_offsets[label]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_setup_with(emit_t *emit, mp_uint_t label) {
|
||||
emit_pre(emit, 7, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("SETUP_WITH " UINT_FMT "\n", emit->label_offsets[label]);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_with_cleanup(emit_t *emit) {
|
||||
emit_pre(emit, -7, 1);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("WITH_CLEANUP\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_setup_except(emit_t *emit, mp_uint_t label) {
|
||||
emit_pre(emit, 0, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("SETUP_EXCEPT " UINT_FMT "\n", emit->label_offsets[label]);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_setup_finally(emit_t *emit, mp_uint_t label) {
|
||||
emit_pre(emit, 0, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("SETUP_FINALLY " UINT_FMT "\n", emit->label_offsets[label]);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_end_finally(emit_t *emit) {
|
||||
emit_pre(emit, -1, 1);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("END_FINALLY\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_get_iter(emit_t *emit) {
|
||||
emit_pre(emit, 0, 1);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("GET_ITER\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_for_iter(emit_t *emit, mp_uint_t label) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("FOR_ITER " UINT_FMT "\n", emit->label_offsets[label]);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_for_iter_end(emit_t *emit) {
|
||||
emit_pre(emit, -1, 0);
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_pop_block(emit_t *emit) {
|
||||
emit_pre(emit, 0, 1);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("POP_BLOCK\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_pop_except(emit_t *emit) {
|
||||
emit_pre(emit, 0, 1);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("POP_EXCEPT\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_unary_op(emit_t *emit, mp_unary_op_t op) {
|
||||
emit_pre(emit, 0, 1);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
switch (op) {
|
||||
case MP_UNARY_OP_POSITIVE: printf("UNARY_POSITIVE\n"); break;
|
||||
case MP_UNARY_OP_NEGATIVE: printf("UNARY_NEGATIVE\n"); break;
|
||||
case MP_UNARY_OP_INVERT: printf("UNARY_INVERT\n"); break;
|
||||
case MP_UNARY_OP_NOT: printf("UNARY_NOT\n"); break;
|
||||
default: assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_binary_op(emit_t *emit, mp_binary_op_t op) {
|
||||
if (op <= MP_BINARY_OP_INPLACE_POWER) {
|
||||
// CPython uses a byte code for each binary op
|
||||
emit_pre(emit, -1, 1);
|
||||
} else {
|
||||
// CPython uses a byte code plus an argument for compare ops
|
||||
emit_pre(emit, -1, 3);
|
||||
}
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
switch (op) {
|
||||
case MP_BINARY_OP_OR: printf("BINARY_OR\n"); break;
|
||||
case MP_BINARY_OP_XOR: printf("BINARY_XOR\n"); break;
|
||||
case MP_BINARY_OP_AND: printf("BINARY_AND\n"); break;
|
||||
case MP_BINARY_OP_LSHIFT: printf("BINARY_LSHIFT\n"); break;
|
||||
case MP_BINARY_OP_RSHIFT: printf("BINARY_RSHIFT\n"); break;
|
||||
case MP_BINARY_OP_ADD: printf("BINARY_ADD\n"); break;
|
||||
case MP_BINARY_OP_SUBTRACT: printf("BINARY_SUBTRACT\n"); break;
|
||||
case MP_BINARY_OP_MULTIPLY: printf("BINARY_MULTIPLY\n"); break;
|
||||
case MP_BINARY_OP_FLOOR_DIVIDE: printf("BINARY_FLOOR_DIVIDE\n"); break;
|
||||
case MP_BINARY_OP_TRUE_DIVIDE: printf("BINARY_TRUE_DIVIDE\n"); break;
|
||||
case MP_BINARY_OP_MODULO: printf("BINARY_MODULO\n"); break;
|
||||
case MP_BINARY_OP_POWER: printf("BINARY_POWER\n"); break;
|
||||
case MP_BINARY_OP_INPLACE_OR: printf("INPLACE_OR\n"); break;
|
||||
case MP_BINARY_OP_INPLACE_XOR: printf("INPLACE_XOR\n"); break;
|
||||
case MP_BINARY_OP_INPLACE_AND: printf("INPLACE_AND\n"); break;
|
||||
case MP_BINARY_OP_INPLACE_LSHIFT: printf("INPLACE_LSHIFT\n"); break;
|
||||
case MP_BINARY_OP_INPLACE_RSHIFT: printf("INPLACE_RSHIFT\n"); break;
|
||||
case MP_BINARY_OP_INPLACE_ADD: printf("INPLACE_ADD\n"); break;
|
||||
case MP_BINARY_OP_INPLACE_SUBTRACT: printf("INPLACE_SUBTRACT\n"); break;
|
||||
case MP_BINARY_OP_INPLACE_MULTIPLY: printf("INPLACE_MULTIPLY\n"); break;
|
||||
case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: printf("INPLACE_FLOOR_DIVIDE\n"); break;
|
||||
case MP_BINARY_OP_INPLACE_TRUE_DIVIDE: printf("INPLACE_TRUE_DIVIDE\n"); break;
|
||||
case MP_BINARY_OP_INPLACE_MODULO: printf("INPLACE_MODULO\n"); break;
|
||||
case MP_BINARY_OP_INPLACE_POWER: printf("INPLACE_POWER\n"); break;
|
||||
case MP_BINARY_OP_LESS: printf("COMPARE_OP <\n"); break;
|
||||
case MP_BINARY_OP_MORE: printf("COMPARE_OP >\n"); break;
|
||||
case MP_BINARY_OP_EQUAL: printf("COMPARE_OP ==\n"); break;
|
||||
case MP_BINARY_OP_LESS_EQUAL: printf("COMPARE_OP <=\n"); break;
|
||||
case MP_BINARY_OP_MORE_EQUAL: printf("COMPARE_OP >=\n"); break;
|
||||
case MP_BINARY_OP_NOT_EQUAL: printf("COMPARE_OP !=\n"); break;
|
||||
case MP_BINARY_OP_IN: printf("COMPARE_OP in\n"); break;
|
||||
case MP_BINARY_OP_IS: printf("COMPARE_OP is\n"); break;
|
||||
case MP_BINARY_OP_EXCEPTION_MATCH: printf("COMPARE_OP exception match\n"); break;
|
||||
case MP_BINARY_OP_NOT_IN: printf("COMPARE_OP not in\n"); break;
|
||||
case MP_BINARY_OP_IS_NOT: printf("COMPARE_OP is not\n"); break;
|
||||
default: assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_build_tuple(emit_t *emit, mp_uint_t n_args) {
|
||||
emit_pre(emit, 1 - n_args, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("BUILD_TUPLE " UINT_FMT "\n", n_args);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_build_list(emit_t *emit, mp_uint_t n_args) {
|
||||
emit_pre(emit, 1 - n_args, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("BUILD_LIST " UINT_FMT "\n", n_args);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_list_append(emit_t *emit, mp_uint_t list_index) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LIST_APPEND " UINT_FMT "\n", list_index);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_build_map(emit_t *emit, mp_uint_t n_args) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("BUILD_MAP " UINT_FMT "\n", n_args);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_store_map(emit_t *emit) {
|
||||
emit_pre(emit, -2, 1);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("STORE_MAP\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_map_add(emit_t *emit, mp_uint_t map_index) {
|
||||
emit_pre(emit, -2, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("MAP_ADD " UINT_FMT "\n", map_index);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_build_set(emit_t *emit, mp_uint_t n_args) {
|
||||
emit_pre(emit, 1 - n_args, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("BUILD_SET " UINT_FMT "\n", n_args);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_set_add(emit_t *emit, mp_uint_t set_index) {
|
||||
emit_pre(emit, -1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("SET_ADD " UINT_FMT "\n", set_index);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_build_slice(emit_t *emit, mp_uint_t n_args) {
|
||||
emit_pre(emit, 1 - n_args, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("BUILD_SLICE " UINT_FMT "\n", n_args);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_unpack_sequence(emit_t *emit, mp_uint_t n_args) {
|
||||
emit_pre(emit, -1 + n_args, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("UNPACK_SEQUENCE " UINT_FMT "\n", n_args);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_unpack_ex(emit_t *emit, mp_uint_t n_left, mp_uint_t n_right) {
|
||||
emit_pre(emit, -1 + n_left + n_right + 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("UNPACK_EX " UINT_FMT "\n", n_left | (n_right << 8));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_call_function(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) {
|
||||
mp_int_t s = 0;
|
||||
if (star_flags & MP_EMIT_STAR_FLAG_SINGLE) {
|
||||
s += 1;
|
||||
}
|
||||
if (star_flags & MP_EMIT_STAR_FLAG_DOUBLE) {
|
||||
s += 1;
|
||||
}
|
||||
emit_pre(emit, -(mp_int_t)n_positional - 2 * (mp_int_t)n_keyword - s, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
if (star_flags & MP_EMIT_STAR_FLAG_SINGLE) {
|
||||
if (star_flags & MP_EMIT_STAR_FLAG_DOUBLE) {
|
||||
printf("CALL_FUNCTION_VAR_KW");
|
||||
} else {
|
||||
printf("CALL_FUNCTION_VAR");
|
||||
}
|
||||
} else {
|
||||
if (star_flags & MP_EMIT_STAR_FLAG_DOUBLE) {
|
||||
printf("CALL_FUNCTION_KW");
|
||||
} else {
|
||||
printf("CALL_FUNCTION");
|
||||
}
|
||||
}
|
||||
printf(" " UINT_FMT ", " UINT_FMT "\n", n_positional, n_keyword);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) {
|
||||
emit_cpy_call_function(emit, n_positional, n_keyword, star_flags);
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_return_value(emit_t *emit) {
|
||||
emit_pre(emit, -1, 1);
|
||||
emit->last_emit_was_return_value = true;
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("RETURN_VALUE\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_raise_varargs(emit_t *emit, mp_uint_t n_args) {
|
||||
emit_pre(emit, -n_args, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("RAISE_VARARGS " UINT_FMT "\n", n_args);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void load_cpy_const_code_and_name(emit_t *emit, qstr qst) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_CONST code %s\n", qstr_str(qst));
|
||||
}
|
||||
// load qualified name
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_CONST '");
|
||||
// code just to work out the qualname (or whatever it is)
|
||||
{
|
||||
int depth = 0;
|
||||
for (scope_t *s = emit->scope; s->parent != NULL; s = s->parent) {
|
||||
depth += 1;
|
||||
}
|
||||
for (int wanted_depth = depth; wanted_depth >= 0; wanted_depth--) {
|
||||
scope_t *s = emit->scope;
|
||||
for (int i = 0; i < wanted_depth; i++) {
|
||||
s = s->parent;
|
||||
}
|
||||
if (s->kind == SCOPE_FUNCTION) {
|
||||
printf("%s.<locals>.", qstr_str(s->simple_name));
|
||||
} else if (s->kind == SCOPE_CLASS) {
|
||||
printf("%s.", qstr_str(s->simple_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("%s'\n", qstr_str(qst));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_make_function(emit_t *emit, scope_t *scope, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) {
|
||||
load_cpy_const_code_and_name(emit, scope->simple_name);
|
||||
emit_pre(emit, -1 - n_pos_defaults - 2 * n_kw_defaults, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("MAKE_FUNCTION " UINT_FMT "\n", (n_kw_defaults << 8) | n_pos_defaults);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_make_closure(emit_t *emit, scope_t *scope, mp_uint_t n_closed_over, mp_uint_t n_pos_defaults, mp_uint_t n_kw_defaults) {
|
||||
emit_cpy_build_tuple(emit, n_closed_over);
|
||||
load_cpy_const_code_and_name(emit, scope->simple_name);
|
||||
emit_pre(emit, -2 - n_pos_defaults - 2 * n_kw_defaults, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("MAKE_CLOSURE " UINT_FMT "\n", (n_kw_defaults << 8) | n_pos_defaults);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_yield_value(emit_t *emit) {
|
||||
emit_pre(emit, 0, 1);
|
||||
emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("YIELD_VALUE\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_yield_from(emit_t *emit) {
|
||||
emit_pre(emit, -1, 1);
|
||||
emit->scope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("YIELD_FROM\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_start_except_handler(emit_t *emit) {
|
||||
emit_cpy_adjust_stack_size(emit, 3); // stack adjust for the 3 exception items
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_end_except_handler(emit_t *emit) {
|
||||
emit_cpy_adjust_stack_size(emit, -2); // stack adjust
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_const_verbatim_strn(emit_t *emit, const char *str, mp_uint_t len) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_CONST %.*s\n", (int)len, str);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_load_closure(emit_t *emit, qstr qst, mp_uint_t local_num) {
|
||||
emit_pre(emit, 1, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("LOAD_CLOSURE " UINT_FMT " %s\n", local_num, qstr_str(qst));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void emit_cpy_setup_loop(emit_t *emit, mp_uint_t label) {
|
||||
emit_pre(emit, 0, 3);
|
||||
if (emit->pass == MP_PASS_EMIT) {
|
||||
printf("SETUP_LOOP " UINT_FMT "\n", emit->label_offsets[label]);
|
||||
}
|
||||
}
|
||||
|
||||
const emit_method_table_t emit_cpython_method_table = {
|
||||
emit_cpy_set_native_type,
|
||||
emit_cpy_start_pass,
|
||||
emit_cpy_end_pass,
|
||||
emit_cpy_last_emit_was_return_value,
|
||||
emit_cpy_adjust_stack_size,
|
||||
emit_cpy_set_source_line,
|
||||
|
||||
{
|
||||
emit_cpy_load_fast,
|
||||
emit_cpy_load_deref,
|
||||
emit_cpy_load_name,
|
||||
emit_cpy_load_global,
|
||||
},
|
||||
{
|
||||
emit_cpy_store_fast,
|
||||
emit_cpy_store_deref,
|
||||
emit_cpy_store_name,
|
||||
emit_cpy_store_global,
|
||||
},
|
||||
{
|
||||
emit_cpy_delete_fast,
|
||||
emit_cpy_delete_deref,
|
||||
emit_cpy_delete_name,
|
||||
emit_cpy_delete_global,
|
||||
},
|
||||
|
||||
emit_cpy_label_assign,
|
||||
emit_cpy_import_name,
|
||||
emit_cpy_import_from,
|
||||
emit_cpy_import_star,
|
||||
emit_cpy_load_const_tok,
|
||||
emit_cpy_load_const_small_int,
|
||||
emit_cpy_load_const_str,
|
||||
emit_cpy_load_const_obj,
|
||||
emit_cpy_load_null,
|
||||
emit_cpy_load_attr,
|
||||
emit_cpy_load_method,
|
||||
emit_cpy_load_build_class,
|
||||
emit_cpy_load_subscr,
|
||||
emit_cpy_store_attr,
|
||||
emit_cpy_store_subscr,
|
||||
emit_cpy_delete_attr,
|
||||
emit_cpy_delete_subscr,
|
||||
emit_cpy_dup_top,
|
||||
emit_cpy_dup_top_two,
|
||||
emit_cpy_pop_top,
|
||||
emit_cpy_rot_two,
|
||||
emit_cpy_rot_three,
|
||||
emit_cpy_jump,
|
||||
emit_cpy_pop_jump_if,
|
||||
emit_cpy_jump_if_or_pop,
|
||||
emit_cpy_break_loop,
|
||||
emit_cpy_continue_loop,
|
||||
emit_cpy_setup_with,
|
||||
emit_cpy_with_cleanup,
|
||||
emit_cpy_setup_except,
|
||||
emit_cpy_setup_finally,
|
||||
emit_cpy_end_finally,
|
||||
emit_cpy_get_iter,
|
||||
emit_cpy_for_iter,
|
||||
emit_cpy_for_iter_end,
|
||||
emit_cpy_pop_block,
|
||||
emit_cpy_pop_except,
|
||||
emit_cpy_unary_op,
|
||||
emit_cpy_binary_op,
|
||||
emit_cpy_build_tuple,
|
||||
emit_cpy_build_list,
|
||||
emit_cpy_list_append,
|
||||
emit_cpy_build_map,
|
||||
emit_cpy_store_map,
|
||||
emit_cpy_map_add,
|
||||
emit_cpy_build_set,
|
||||
emit_cpy_set_add,
|
||||
emit_cpy_build_slice,
|
||||
emit_cpy_unpack_sequence,
|
||||
emit_cpy_unpack_ex,
|
||||
emit_cpy_make_function,
|
||||
emit_cpy_make_closure,
|
||||
emit_cpy_call_function,
|
||||
emit_cpy_call_method,
|
||||
emit_cpy_return_value,
|
||||
emit_cpy_raise_varargs,
|
||||
emit_cpy_yield_value,
|
||||
emit_cpy_yield_from,
|
||||
|
||||
emit_cpy_start_except_handler,
|
||||
emit_cpy_end_except_handler,
|
||||
|
||||
// emitcpy specific functions
|
||||
emit_cpy_load_const_verbatim_strn,
|
||||
emit_cpy_load_closure,
|
||||
emit_cpy_setup_loop,
|
||||
};
|
||||
|
||||
#endif // MICROPY_EMIT_CPYTHON
|
|
@ -75,7 +75,7 @@ $(HEADER_BUILD):
|
|||
$(MKDIR) -p $@
|
||||
|
||||
ifneq ($(PROG),)
|
||||
# Build a standalone executable (unix and unix-cpy do this)
|
||||
# Build a standalone executable (unix does this)
|
||||
|
||||
all: $(PROG)
|
||||
|
||||
|
|
|
@ -173,12 +173,6 @@
|
|||
/*****************************************************************************/
|
||||
/* Micro Python emitters */
|
||||
|
||||
// Whether to emit CPython byte codes (for debugging/testing)
|
||||
// Enabling this overrides all other emitters
|
||||
#ifndef MICROPY_EMIT_CPYTHON
|
||||
#define MICROPY_EMIT_CPYTHON (0)
|
||||
#endif
|
||||
|
||||
// Whether to emit x64 native code
|
||||
#ifndef MICROPY_EMIT_X64
|
||||
#define MICROPY_EMIT_X64 (0)
|
||||
|
|
|
@ -548,7 +548,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
|
|||
}
|
||||
}
|
||||
|
||||
#if !MICROPY_EMIT_CPYTHON && !MICROPY_ENABLE_DOC_STRING
|
||||
#if !MICROPY_ENABLE_DOC_STRING
|
||||
// this code discards lonely statements, such as doc strings
|
||||
if (input_kind != MP_PARSE_SINGLE_INPUT && rule->rule_id == RULE_expr_stmt && peek_result(&parser, 0) == MP_PARSE_NODE_NULL) {
|
||||
mp_parse_node_t p = peek_result(&parser, 1);
|
||||
|
@ -559,7 +559,7 @@ mp_parse_node_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// always emit these rules, even if they have only 1 argument
|
||||
if (rule->rule_id == RULE_expr_stmt || rule->rule_id == RULE_yield_stmt) {
|
||||
|
|
1
py/py.mk
1
py/py.mk
|
@ -32,7 +32,6 @@ PY_O_BASENAME = \
|
|||
scope.o \
|
||||
compile.o \
|
||||
emitcommon.o \
|
||||
emitcpy.o \
|
||||
emitbc.o \
|
||||
asmx64.o \
|
||||
emitnx64.o \
|
||||
|
|
56
py/scope.c
56
py/scope.c
|
@ -149,59 +149,3 @@ void scope_close_over_in_parents(scope_t *scope, qstr qst) {
|
|||
}
|
||||
assert(0); // we should have found the variable in one of the parents
|
||||
}
|
||||
|
||||
#if MICROPY_EMIT_CPYTHON
|
||||
#include <stdio.h>
|
||||
|
||||
void scope_print_info(scope_t *s) {
|
||||
if (s->kind == SCOPE_MODULE) {
|
||||
printf("code <module>\n");
|
||||
} else if (s->kind == SCOPE_LAMBDA) {
|
||||
printf("code <lambda>\n");
|
||||
} else if (s->kind == SCOPE_LIST_COMP) {
|
||||
printf("code <listcomp>\n");
|
||||
} else if (s->kind == SCOPE_DICT_COMP) {
|
||||
printf("code <dictcomp>\n");
|
||||
} else if (s->kind == SCOPE_SET_COMP) {
|
||||
printf("code <setcomp>\n");
|
||||
} else if (s->kind == SCOPE_GEN_EXPR) {
|
||||
printf("code <genexpr>\n");
|
||||
} else {
|
||||
printf("code %s\n", qstr_str(s->simple_name));
|
||||
}
|
||||
/*
|
||||
printf("var global:");
|
||||
for (int i = 0; i < s->id_info_len; i++) {
|
||||
if (s->id_info[i].kind == ID_INFO_KIND_GLOBAL_EXPLICIT) {
|
||||
printf(" %s", qstr_str(s->id_info[i].qst));
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
printf("var name:");
|
||||
for (int i = 0; i < s->id_info_len; i++) {
|
||||
if (s->id_info[i].kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
|
||||
printf(" %s", qstr_str(s->id_info[i].qst));
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
printf("var local:");
|
||||
for (int i = 0; i < s->id_info_len; i++) {
|
||||
if (s->id_info[i].kind == ID_INFO_KIND_LOCAL) {
|
||||
printf(" %s", qstr_str(s->id_info[i].qst));
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
printf("var free:");
|
||||
for (int i = 0; i < s->id_info_len; i++) {
|
||||
if (s->id_info[i].kind == ID_INFO_KIND_FREE) {
|
||||
printf(" %s", qstr_str(s->id_info[i].qst));
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
*/
|
||||
printf(" flags %04x\n", s->scope_flags);
|
||||
printf(" argcount %d\n", s->num_pos_args);
|
||||
printf(" nlocals %d\n", s->num_locals);
|
||||
printf(" stacksize %d\n", s->stack_size);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -81,6 +81,5 @@ id_info_t *scope_find(scope_t *scope, qstr qstr);
|
|||
id_info_t *scope_find_global(scope_t *scope, qstr qstr);
|
||||
id_info_t *scope_find_local_in_parent(scope_t *scope, qstr qstr);
|
||||
void scope_close_over_in_parents(scope_t *scope, qstr qstr);
|
||||
void scope_print_info(scope_t *s);
|
||||
|
||||
#endif // __MICROPY_INCLUDED_PY_SCOPE_H__
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
output
|
||||
mp-tests/__pycache__
|
||||
pylib-tests/__pycache__
|
|
@ -1,15 +0,0 @@
|
|||
This directory contains the framework and test files for testing the byte code
|
||||
output of the Micro Python compiler.
|
||||
|
||||
You need to first build the 'cpy' executable in the directory micropython/unix-cpy/.
|
||||
This executable is a minimal version of Micro Python which compiles a single source
|
||||
file and outputs the corresponding byte code.
|
||||
|
||||
The output of Micro Python is checked against CPython 3.4.
|
||||
|
||||
To run the tests use:
|
||||
|
||||
./run-tests
|
||||
|
||||
Note that the tests in pylib-test/ are from the Python 3.3 library, and are licensed
|
||||
under the relevant license, as per pylib-test/LICENSE.txt.
|
|
@ -1,56 +0,0 @@
|
|||
import sys
|
||||
name = sys.argv[1].split('/')[-1].split('.')[0]
|
||||
with open(sys.argv[1]) as f:
|
||||
lines_correct = [l.strip('\n') for l in f.readlines()]
|
||||
lines_me = [l.strip('\n') for l in sys.stdin.readlines()]
|
||||
if len(lines_me) != len(lines_correct):
|
||||
if len(lines_me) == 0:
|
||||
print('{:<20}: no output'.format(name))
|
||||
elif lines_me[0].find('syntax error') >= 0:
|
||||
print('{:<20}: syntax error'.format(name))
|
||||
elif lines_me[0].find(' cannot be compiled') >= 0:
|
||||
print('{:<20}: compile error: {}'.format(name, lines_me[0]))
|
||||
else:
|
||||
print('{:<20}: mismatch in number of lines'.format(name))
|
||||
else:
|
||||
total = len(lines_me)
|
||||
same = 0
|
||||
bad_num_fields = 0
|
||||
bad_2 = 0
|
||||
bad_3 = 0
|
||||
jump_op = ['JUMP_FORWARD', 'JUMP_ABSOLUTE', 'POP_JUMP_IF_FALSE', 'POP_JUMP_IF_TRUE', 'SETUP_LOOP']
|
||||
jump_abs_op = ['JUMP_FORWARD', 'JUMP_ABSOLUTE']
|
||||
for i in range(total):
|
||||
if lines_me[i] == lines_correct[i]:
|
||||
same += 1
|
||||
else:
|
||||
# line is different
|
||||
line_me = lines_me[i].strip().split(' ', 2)
|
||||
line_correct = lines_correct[i].strip().split(' ', 2)
|
||||
allow = False
|
||||
if len(line_me) != len(line_correct):
|
||||
bad_num_fields += 1
|
||||
elif len(line_me) == 2:
|
||||
if line_me[0] == line_correct[0] == 'stacksize':
|
||||
allow = True
|
||||
else:
|
||||
bad_2 += 1
|
||||
else:
|
||||
assert(len(line_me) == 3)
|
||||
if line_me[0] == line_correct[0] and line_me[1] in jump_abs_op and line_correct[1] in jump_abs_op:
|
||||
allow = True
|
||||
elif line_me[0] == line_correct[0] and line_me[1] == line_correct[1] in jump_op:
|
||||
allow = True
|
||||
else:
|
||||
bad_3 += 1
|
||||
#if not allow:
|
||||
# print(line_me, 'vs', line_correct)
|
||||
|
||||
bad_str = ''
|
||||
if bad_num_fields > 0:
|
||||
bad_str += ', {} bad num fields'.format(bad_num_fields)
|
||||
if bad_2 > 0:
|
||||
bad_str += ', {} bad 2-field'.format(bad_2)
|
||||
if bad_3 > 0:
|
||||
bad_str += ', {} bad 3-field'.format(bad_3)
|
||||
print('{:<20}: {:>6} lines, {:>5.1f}% correct{}'.format(name, total, 100 * same / total, bad_str))
|
|
@ -1,2 +0,0 @@
|
|||
assert x
|
||||
assert x, 'test'
|
|
@ -1,10 +0,0 @@
|
|||
[] = ()
|
||||
[] = []
|
||||
a = b
|
||||
(a) = b
|
||||
a, b = c, d
|
||||
a, b, c = d, e, f
|
||||
a, b, c, d = e, f, g, h
|
||||
#(a, b) = c, d
|
||||
#a, b = (c, d)
|
||||
#(a, b) = (c, d)
|
|
@ -1,21 +0,0 @@
|
|||
*a, = b
|
||||
a, *b = c
|
||||
a, *b, = c
|
||||
a, *b, c = d
|
||||
|
||||
[*a] = b
|
||||
[*a,] = b
|
||||
[a, *b] = c
|
||||
[a, *b,] = c
|
||||
[a, *b, c] = d
|
||||
|
||||
(*a,) = x
|
||||
(*a, b) = x
|
||||
(a, *b) = x
|
||||
(*a, b, c) = x
|
||||
(a, *b, c) = x
|
||||
(a, b, *c) = x
|
||||
(*a, b, c, d) = x
|
||||
(a, *b, c, d) = x
|
||||
(a, b, *c, d) = x
|
||||
(a, b, c, *d) = x
|
|
@ -1,5 +0,0 @@
|
|||
[] = ()
|
||||
x += 1
|
||||
x.y += 1
|
||||
x.f().y += 1
|
||||
x[1] += 2
|
|
@ -1 +0,0 @@
|
|||
f(a, b=c)
|
|
@ -1,3 +0,0 @@
|
|||
class C:
|
||||
pass
|
||||
C()
|
|
@ -1,4 +0,0 @@
|
|||
class A:
|
||||
x = 1
|
||||
y = x + z
|
||||
A()
|
|
@ -1,10 +0,0 @@
|
|||
class A:
|
||||
def f(x):
|
||||
return x
|
||||
def g(y):
|
||||
def h(z):
|
||||
return x + y + z
|
||||
h(y)
|
||||
A()
|
||||
A.f(1)
|
||||
A.g(2)(3)
|
|
@ -1,9 +0,0 @@
|
|||
class A:
|
||||
def __init__(self, x):
|
||||
self.x = x
|
||||
self.y = 0
|
||||
|
||||
def get(self):
|
||||
return self.x + self.y
|
||||
A(1)
|
||||
A(2).get()
|
|
@ -1,8 +0,0 @@
|
|||
class A(B):
|
||||
pass
|
||||
class A(object):
|
||||
pass
|
||||
class A(x.y()):
|
||||
pass
|
||||
class A(B, C):
|
||||
pass
|
|
@ -1,7 +0,0 @@
|
|||
class A:
|
||||
def f(self):
|
||||
pass
|
||||
|
||||
class B(A):
|
||||
def f(self):
|
||||
super().f()
|
|
@ -1,6 +0,0 @@
|
|||
# accessing super, but not as a function call
|
||||
|
||||
class A:
|
||||
def f():
|
||||
#x = super
|
||||
print(super)
|
|
@ -1,2 +0,0 @@
|
|||
# basic closure
|
||||
# to write!
|
|
@ -1,7 +0,0 @@
|
|||
# test closing over an argument
|
||||
|
||||
def f(x):
|
||||
y = 2 * x
|
||||
def g(z):
|
||||
return x + y + z
|
||||
return g
|
|
@ -1,12 +0,0 @@
|
|||
# test when different variables are closed over by different functions
|
||||
|
||||
def f():
|
||||
l1 = 1
|
||||
l2 = 2
|
||||
l3 = 3
|
||||
|
||||
def g():
|
||||
return l1 + l2
|
||||
|
||||
def h():
|
||||
return l2 + l3
|
|
@ -1,13 +0,0 @@
|
|||
# test when a function has cell and free vars
|
||||
|
||||
def f():
|
||||
f_local = 1
|
||||
f_cell = 2
|
||||
|
||||
def g():
|
||||
g_local = 3
|
||||
g_cell = f_cell + 4
|
||||
|
||||
def h():
|
||||
h1_local = 4
|
||||
h2_local = f_cell + g_cell
|
|
@ -1,8 +0,0 @@
|
|||
if 1 <= x <= 5:
|
||||
f()
|
||||
|
||||
if 1 <= x <= y <= 7:
|
||||
f()
|
||||
|
||||
if a < b > c in l != c is not d:
|
||||
f()
|
|
@ -1,9 +0,0 @@
|
|||
x = 1
|
||||
#x = 1.2
|
||||
#x = 1.2e5
|
||||
#x = 1.2e+5
|
||||
#x = 1.2e-5
|
||||
x = ()
|
||||
x = (1,)
|
||||
x = (1,2)
|
||||
x = ('a',None,3)
|
|
@ -1,44 +0,0 @@
|
|||
for a in b:
|
||||
continue
|
||||
|
||||
for a in b:
|
||||
try:
|
||||
f()
|
||||
except:
|
||||
continue
|
||||
g()
|
||||
|
||||
for a in b:
|
||||
try:
|
||||
f()
|
||||
continue
|
||||
except:
|
||||
g()
|
||||
|
||||
for a in b:
|
||||
try:
|
||||
f()
|
||||
except:
|
||||
try:
|
||||
g()
|
||||
except:
|
||||
continue
|
||||
|
||||
for a in b:
|
||||
try:
|
||||
f()
|
||||
except:
|
||||
try:
|
||||
g()
|
||||
continue
|
||||
except:
|
||||
h()
|
||||
|
||||
for a in b:
|
||||
try:
|
||||
f()
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
continue
|
||||
g()
|
|
@ -1,20 +0,0 @@
|
|||
@d
|
||||
def f():
|
||||
pass
|
||||
|
||||
@d
|
||||
@e
|
||||
def g():
|
||||
pass
|
||||
|
||||
@d.e.f
|
||||
def h():
|
||||
pass
|
||||
|
||||
@d(a + 1)
|
||||
def i():
|
||||
pass
|
||||
|
||||
@d(a + 1, b + 2)
|
||||
def i():
|
||||
pass
|
|
@ -1,16 +0,0 @@
|
|||
del x
|
||||
del x.y
|
||||
del x().y
|
||||
del g
|
||||
del x[a]
|
||||
def f():
|
||||
global g
|
||||
del x
|
||||
del g
|
||||
local = 1
|
||||
local2 = 2
|
||||
local3 = 3
|
||||
del local, local2, local3
|
||||
def f2():
|
||||
nonlocal local3
|
||||
del local2, local3
|
|
@ -1,11 +0,0 @@
|
|||
del x
|
||||
del x,
|
||||
del x, y
|
||||
del x, y,
|
||||
del x, y, z
|
||||
del (x)
|
||||
del (x,)
|
||||
del (x, y)
|
||||
del (x, y,)
|
||||
del (x, y, z)
|
||||
del a, (b, c)
|
|
@ -1,3 +0,0 @@
|
|||
x = {}
|
||||
x = {'a':1}
|
||||
x = {'a':1, 'b':2}
|
|
@ -1,2 +0,0 @@
|
|||
x = {a:None for a in l}
|
||||
x = {b:c for c, b in l if c}
|
|
@ -1,8 +0,0 @@
|
|||
"""Module"""
|
||||
|
||||
class A:
|
||||
"""Class"""
|
||||
pass
|
||||
|
||||
class B:
|
||||
"""Class B"""
|
|
@ -1,3 +0,0 @@
|
|||
# comment before doc string
|
||||
|
||||
"""Doc string"""
|
|
@ -1,2 +0,0 @@
|
|||
def f(*args):
|
||||
g(*args)
|
|
@ -1,23 +0,0 @@
|
|||
def f(*, b):
|
||||
return b
|
||||
|
||||
def f(a, *, b):
|
||||
return a + b
|
||||
|
||||
def f(a, *, b, c):
|
||||
return a + b + c
|
||||
|
||||
def f(a, *, b=c):
|
||||
return a + b
|
||||
|
||||
def f(a, *, b=c, c):
|
||||
return a + b + c
|
||||
|
||||
def f(a, *, b=c, c=d):
|
||||
return a + b + c
|
||||
|
||||
def f(a, *, b=c, c, d=e):
|
||||
return a + b + c + d
|
||||
|
||||
def f(a=None, *, b=None):
|
||||
return a + b
|
|
@ -1,3 +0,0 @@
|
|||
def f(a, b):
|
||||
def g(c, d=None, *, e=True):
|
||||
return a + b + c + d + e
|
|
@ -1,5 +0,0 @@
|
|||
def f(a, b=1, *c, d):
|
||||
pass
|
||||
#print(a,b,c,d) # bug in uPy!
|
||||
f = lambda a, b, *c, d: None # default arg
|
||||
#f = lambda a, b=1, *c, d: None # default arg for lambda not implemented
|
|
@ -1,24 +0,0 @@
|
|||
if x:
|
||||
x()
|
||||
if x:
|
||||
x()
|
||||
elif y:
|
||||
y()
|
||||
if x:
|
||||
x()
|
||||
else:
|
||||
zz()
|
||||
if x:
|
||||
x()
|
||||
elif y:
|
||||
y()
|
||||
else:
|
||||
zz()
|
||||
if x:
|
||||
x()
|
||||
elif y:
|
||||
y()
|
||||
elif z:
|
||||
z()
|
||||
else:
|
||||
zz()
|
|
@ -1,26 +0,0 @@
|
|||
def f(x):
|
||||
if x:
|
||||
return
|
||||
if x:
|
||||
return
|
||||
elif y:
|
||||
return
|
||||
if x:
|
||||
return
|
||||
else:
|
||||
return
|
||||
if x:
|
||||
return
|
||||
elif y:
|
||||
return
|
||||
else:
|
||||
return
|
||||
if x:
|
||||
return
|
||||
elif y:
|
||||
return
|
||||
elif z:
|
||||
return
|
||||
else:
|
||||
return
|
||||
return None
|
|
@ -1,6 +0,0 @@
|
|||
if a and b:
|
||||
f()
|
||||
if a or b:
|
||||
f()
|
||||
if a and (b or c):
|
||||
f()
|
|
@ -1,8 +0,0 @@
|
|||
if not a:
|
||||
f()
|
||||
if not a and b:
|
||||
f()
|
||||
if not a and not b:
|
||||
f()
|
||||
while not a:
|
||||
f()
|
|
@ -1 +0,0 @@
|
|||
x = 1 if a else 2
|
|
@ -1,5 +0,0 @@
|
|||
a = 1
|
||||
def f():
|
||||
global a
|
||||
import a
|
||||
import b, c
|
|
@ -1 +0,0 @@
|
|||
from a import b
|
|
@ -1,8 +0,0 @@
|
|||
import a.b
|
||||
import a.b.c
|
||||
from a.b import d
|
||||
from a.b.c import d
|
||||
|
||||
from a import *
|
||||
from a import d, e
|
||||
from a import (d, e)
|
|
@ -1,3 +0,0 @@
|
|||
import a as y
|
||||
import a.b as y
|
||||
import a.b.c as y
|
|
@ -1,4 +0,0 @@
|
|||
from a import b as c
|
||||
from a.b import c as d
|
||||
from a.b.c import d as e
|
||||
from a.b.c import d as e, f as h
|
|
@ -1,14 +0,0 @@
|
|||
from . import bar
|
||||
from .. import bar
|
||||
from ... import bar
|
||||
from .... import bar
|
||||
from ..... import bar
|
||||
from ...... import bar
|
||||
from . import bar as abc
|
||||
from .foo import bar
|
||||
from ..foo import bar
|
||||
from ...foo import bar
|
||||
from .foo.bar import baz
|
||||
from ..foo.bar import baz
|
||||
from ...foo.bar import baz
|
||||
from .foo.bar import baz as abc
|
|
@ -1,2 +0,0 @@
|
|||
f = lambda: 0
|
||||
f = lambda x: 1 + x
|
|
@ -1 +0,0 @@
|
|||
f = lambda *args: args
|
|
@ -1,8 +0,0 @@
|
|||
x = []
|
||||
x = [1]
|
||||
x = [1,] # not implemented
|
||||
x = [1, 2]
|
||||
x = [1, 2,]
|
||||
x = [1, 2, 3]
|
||||
x = [1, 2, 3, 4]
|
||||
x = [1, 2, 3, 4, 5]
|
|
@ -1,8 +0,0 @@
|
|||
x = [()]
|
||||
x = [(a)]
|
||||
x = [(a,)]
|
||||
x = [(a)]
|
||||
x = [(a,)]
|
||||
x = [a, b]
|
||||
x = [(a, b)]
|
||||
x = [(a, b, c)]
|
|
@ -1,4 +0,0 @@
|
|||
x = (a for a in l)
|
||||
|
||||
f(a for a in l)
|
||||
f(a + b for a, b in f())
|
|
@ -1 +0,0 @@
|
|||
[x.y for x in k.l]
|
|
@ -1,3 +0,0 @@
|
|||
x = (a + 1 for a in l if a.f())
|
||||
|
||||
x = [a + 1 for a in l if a.f()]
|
|
@ -1,4 +0,0 @@
|
|||
# closing over a local variable in a list comprehension
|
||||
def f():
|
||||
a = 1
|
||||
x = [a + b for b in l]
|
|
@ -1,11 +0,0 @@
|
|||
# nested ifs
|
||||
x = [a for a in l if a if a + 1]
|
||||
x = [a for a in l if a if a + 1 if a + 2]
|
||||
|
||||
# nested for loops
|
||||
x = [a for a in l for l in ls]
|
||||
x = [a for ls in lss for l in ls for a in l]
|
||||
x = [a for a in l for l in ls for ls in lss]
|
||||
|
||||
# nested ifs and for loops
|
||||
x = [a for a in l if a for l in ls if l if a for ls in lss if ls]
|
|
@ -1,22 +0,0 @@
|
|||
# to test the order of locals and arguments (LOAD_FAST, STORE_FAST)
|
||||
|
||||
def f1():
|
||||
b = 1
|
||||
a = 2
|
||||
return a + b
|
||||
|
||||
def f2(b):
|
||||
a = 2
|
||||
return a + b
|
||||
|
||||
def f3():
|
||||
def f3f():
|
||||
return True
|
||||
a = 1
|
||||
return f3f(a)
|
||||
|
||||
def f4():
|
||||
x = 1
|
||||
def f3f():
|
||||
return True
|
||||
return f3f(x)
|
|
@ -1,269 +0,0 @@
|
|||
import sys
|
||||
import os
|
||||
import os.path
|
||||
import datetime
|
||||
import argparse
|
||||
from xml.etree.ElementTree import Element, SubElement, tostring
|
||||
|
||||
from log import Log
|
||||
from texparser import TexParser
|
||||
from latexparser import LatexParser
|
||||
from gettexfile import file_has_suffix
|
||||
from gettexfile import get_tex_file
|
||||
|
||||
from xiwi.common.misc import buildFileList
|
||||
from xiwi.common import arxivid
|
||||
from xiwi.common.stats import Statistics
|
||||
|
||||
def str_contains(s1, s2):
|
||||
return s1.find(s2) != -1
|
||||
|
||||
def str_contains_one_of(st, st_list):
|
||||
for st2 in st_list:
|
||||
if str_contains(st, st2):
|
||||
return True
|
||||
return False
|
||||
|
||||
def detect_file_kind(file_obj):
|
||||
"""Simple detection of kind of source file."""
|
||||
kind = 'unknown'
|
||||
firstline = file_obj.readline()
|
||||
while firstline.isspace():
|
||||
firstline = file_obj.readline()
|
||||
if firstline.startswith('%!PS'):
|
||||
kind = 'PS'
|
||||
elif firstline.startswith('%auto-ignore'):
|
||||
kind = 'auto-ignore'
|
||||
else:
|
||||
file_obj.seek(0)
|
||||
for line in file_obj:
|
||||
if str_contains(line, '\\def'):
|
||||
# might be tex, if we don't find anything else
|
||||
kind = 'tex'
|
||||
if str_contains(line, '\\input'):
|
||||
# might be tex, if we don't find anything else
|
||||
kind = 'tex'
|
||||
if str_contains(line, 'amstex') or str_contains(line, 'harvmac'):
|
||||
# definitely tex
|
||||
kind = 'tex'
|
||||
break
|
||||
if str_contains(line, '\\documentclass'):
|
||||
# definitely latex
|
||||
kind = 'latex'
|
||||
break
|
||||
if str_contains(line, '\\documentstyle'):
|
||||
# could be tex or latex
|
||||
if str_contains(line, 'amsppt'):
|
||||
kind = 'tex'
|
||||
break
|
||||
else:
|
||||
kind = 'latex'
|
||||
break
|
||||
file_obj.seek(0)
|
||||
return kind
|
||||
|
||||
class WithdrawnPaper(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def __getitem__(self, item):
|
||||
if item == 'refs':
|
||||
return []
|
||||
elif item == 'success':
|
||||
return True
|
||||
|
||||
def parse(self):
|
||||
pass
|
||||
|
||||
def process_article(filename):
|
||||
"""Returns TexParserBase derived object on success, None on failure."""
|
||||
|
||||
# get the tex file
|
||||
filename, file_obj, tarfile_obj = get_tex_file(filename)
|
||||
if file_obj is None:
|
||||
return None
|
||||
|
||||
# detect the type of file
|
||||
kind = detect_file_kind(file_obj)
|
||||
|
||||
# act on the type of file
|
||||
parser = None
|
||||
if kind == 'PS':
|
||||
print('skipping postscript file')
|
||||
elif kind == 'auto-ignore':
|
||||
print('asked to ignore file, most likely it was withdrawn')
|
||||
parser = WithdrawnPaper()
|
||||
if kind == 'tex':
|
||||
print('parsing as TeX')
|
||||
parser = TexParser(filename, file_obj, tarfile_obj)
|
||||
elif kind == 'latex':
|
||||
print('parsing as LaTeX')
|
||||
parser = LatexParser(filename, file_obj, tarfile_obj)
|
||||
else:
|
||||
print('cannot determine kind of file')
|
||||
|
||||
# attempt to parse the document
|
||||
try:
|
||||
if parser is not None:
|
||||
parser.parse()
|
||||
except Exception as e:
|
||||
print('exception while trying to parse file:')
|
||||
print(str(e))
|
||||
parser = None
|
||||
|
||||
# close the files
|
||||
file_obj.close()
|
||||
if tarfile_obj is not None:
|
||||
tarfile_obj.close()
|
||||
|
||||
# return the parsed document
|
||||
return parser
|
||||
|
||||
arxiv_classes = [
|
||||
'acc-phys', 'adap-org', 'alg-geom', 'ao-sci', 'astro-ph', 'atom-ph',
|
||||
'bayes-an', 'chao-dyn', 'chem-ph', 'cmp-lg', 'comp-gas', 'cond-mat',
|
||||
'cs', 'dg-ga', 'funct-an', 'gr-qc', 'hep-ex', 'hep-lat',
|
||||
'hep-ph', 'hep-th', 'math', 'math-ph', 'mtrl-th', 'nlin',
|
||||
'nucl-ex', 'nucl-th', 'patt-sol', 'physics', 'plasm-ph', 'q-alg',
|
||||
'q-bio', 'quant-ph', 'solv-int', 'supr-con'
|
||||
]
|
||||
|
||||
def do_single_file(file_name, print_xml, write_xml_dir):
|
||||
arxiv_id, arxiv_version = arxivid.filenameToArxivAndVersion(file_name)
|
||||
if arxiv_id is None:
|
||||
print('WARN: could not determine arXiv identifier for', file_name)
|
||||
arxiv_id = '<unknown>'
|
||||
arxiv_version = 0
|
||||
|
||||
Log.reset()
|
||||
Statistics.begin_item(arxiv_id)
|
||||
|
||||
if file_has_suffix(file_name, '.pdf'):
|
||||
Statistics.count('1) pdf')
|
||||
succ = True
|
||||
else:
|
||||
Statistics.count('2) processed')
|
||||
|
||||
parser = process_article(file_name)
|
||||
|
||||
if parser is not None :
|
||||
succ = parser['success']
|
||||
bib_refs = parser['refs']
|
||||
else :
|
||||
succ = False
|
||||
bib_refs = []
|
||||
|
||||
if str_contains_one_of(arxiv_id, ['gr-qc', 'hep-']):
|
||||
Statistics.count('hep-processed')
|
||||
if succ:
|
||||
Statistics.count('hep-success')
|
||||
if succ:
|
||||
print('-success--------')
|
||||
Statistics.count('3) success')
|
||||
else:
|
||||
print('-fail-----------')
|
||||
Statistics.count('4) fail')
|
||||
|
||||
show_ref = False
|
||||
|
||||
if succ and show_ref:
|
||||
for bib_ref in bib_refs:
|
||||
print(bib_ref.key, 'with', bib_ref.cite_count, 'citations in paper')
|
||||
if len(bib_ref.bib_info) == 0:
|
||||
print('no reference')
|
||||
else:
|
||||
print(bib_ref.bib_info_as_str(keep_comments=True))
|
||||
|
||||
if succ and (print_xml or write_xml_dir):
|
||||
xml = Element('article')
|
||||
SubElement(xml, 'id').text = arxiv_id
|
||||
if arxiv_version > 0:
|
||||
SubElement(xml, 'version').text = str(arxiv_version)
|
||||
refs = SubElement(xml, 'refs')
|
||||
for bib_ref in bib_refs:
|
||||
bib_text = bib_ref.bib_info_as_str(keep_comments=True)
|
||||
if len(bib_text) != 0:
|
||||
ncites = bib_ref.cite_count
|
||||
if ncites < 1:
|
||||
ncites = 1
|
||||
ref = SubElement(refs, 'ref', order=str(bib_ref.ref_order_num), freq=str(ncites))
|
||||
ref.text = bib_text
|
||||
if print_xml:
|
||||
print(tostring(xml))
|
||||
if isinstance(write_xml_dir, str):
|
||||
if arxiv_id != '<unknown>':
|
||||
xml_file_name = os.path.join(write_xml_dir, arxiv_id.replace('/', '') + '.xml')
|
||||
else:
|
||||
fname = os.path.split(file_name)[1]
|
||||
if fname.rfind('.') > 0:
|
||||
fname = fname[:fname.rfind('.')]
|
||||
xml_file_name = write_xml_dir + '/' + fname + '.xml'
|
||||
file_obj = open(xml_file_name, 'wb')
|
||||
file_obj.write(tostring(xml, encoding='utf-8'))
|
||||
file_obj.close()
|
||||
|
||||
Statistics.end_item()
|
||||
|
||||
return succ
|
||||
|
||||
summaryStrs = []
|
||||
|
||||
if __name__ == "__main__":
|
||||
cmd_parser = argparse.ArgumentParser(description='Parse TeX/LaTeX to find references.')
|
||||
cmd_parser.add_argument('--filelist', action='store_true', help='file names on the command line each contain a list of files to process')
|
||||
cmd_parser.add_argument('--print-xml', action='store_true', help='print XML output to stdout')
|
||||
cmd_parser.add_argument('--write-xml', metavar='<dir>', help='destination directory to write XML output files')
|
||||
cmd_parser.add_argument('--failed', metavar='<file>', help='output file to write list of failed files')
|
||||
cmd_parser.add_argument('files', nargs='+', help='input files')
|
||||
args = cmd_parser.parse_args()
|
||||
|
||||
# print date stamp
|
||||
timeStart = datetime.datetime.now()
|
||||
print('[ptex] started processing at', str(timeStart))
|
||||
|
||||
print('given', len(args.files), 'files, first file:', args.files[0])
|
||||
print('================')
|
||||
|
||||
Statistics.clear('article')
|
||||
|
||||
# build list of files to process
|
||||
file_list = buildFileList(args.filelist, args.files)
|
||||
|
||||
# ensure the destination directory exists
|
||||
if args.write_xml is not None and os.path.exists(args.write_xml):
|
||||
try:
|
||||
os.makedirs(args.write_xml)
|
||||
except:
|
||||
pass
|
||||
|
||||
# process the files
|
||||
failed_files = []
|
||||
for file_name in file_list:
|
||||
success = do_single_file(file_name, args.print_xml, args.write_xml)
|
||||
if not success:
|
||||
failed_files.append(file_name)
|
||||
|
||||
# write the failed files to an output file, if requested
|
||||
if args.failed is not None:
|
||||
file_obj = open(args.failed, 'w')
|
||||
file_obj.writelines(f + '\n' for f in failed_files)
|
||||
file_obj.close()
|
||||
|
||||
print('================')
|
||||
Statistics.show()
|
||||
Statistics.show_detail('fail')
|
||||
#Statistics.show_detail('cite-range')
|
||||
#Statistics.show_detail('bad-ascii')
|
||||
#Statistics.show_detail('non-ascii')
|
||||
|
||||
print('================')
|
||||
|
||||
# print date stamp
|
||||
timeEnd = datetime.datetime.now()
|
||||
print('[ptex] finished processing at', str(timeEnd))
|
||||
|
||||
# print summary for email
|
||||
summaryStrs.extend(Statistics.get_summary())
|
||||
summaryStrs.insert(0, 'started processing at %s, took %.1f minutes' % (timeStart.strftime('%H:%M'), (timeEnd - timeStart).total_seconds() / 60))
|
||||
for s in summaryStrs:
|
||||
print('**SUMMARY** [ptex]', s)
|
|
@ -1,11 +0,0 @@
|
|||
def f():
|
||||
raise
|
||||
def g():
|
||||
raise 1
|
||||
def h():
|
||||
raise 1 from 2
|
||||
def i():
|
||||
try:
|
||||
f()
|
||||
except:
|
||||
raise
|
|
@ -1,7 +0,0 @@
|
|||
x = 1
|
||||
print(x)
|
||||
|
||||
# local store after load
|
||||
def f():
|
||||
print(x)
|
||||
x = 1
|
|
@ -1,6 +0,0 @@
|
|||
x = 1
|
||||
print(x)
|
||||
def f1():
|
||||
print(x)
|
||||
def f2(x):
|
||||
print(x)
|
|
@ -1,18 +0,0 @@
|
|||
# scope
|
||||
|
||||
gl = 1
|
||||
|
||||
def f(x):
|
||||
global gl
|
||||
gl += 2
|
||||
lo1 = 3
|
||||
lo2 = 4
|
||||
lo3 = 5
|
||||
|
||||
def f2(x, y):
|
||||
global gl
|
||||
nonlocal lo3
|
||||
lo3 = 5
|
||||
lo4 = gl + lo2 + lo3
|
||||
|
||||
return f2
|
|
@ -1,11 +0,0 @@
|
|||
# test nested functions and scope
|
||||
|
||||
def f(x):
|
||||
def f2(y):
|
||||
return y + x
|
||||
print(f2(x))
|
||||
return f2
|
||||
x=f(2)
|
||||
print(x, x(5))
|
||||
f=123
|
||||
print(f(f))
|
|
@ -1,14 +0,0 @@
|
|||
# test scope
|
||||
|
||||
def f(x):
|
||||
global x42
|
||||
print(x, x42)
|
||||
x42 = x
|
||||
|
||||
x42 = 123
|
||||
f(1)
|
||||
print(x42)
|
||||
|
||||
x42 = 456
|
||||
f(2)
|
||||
print(x42)
|
|
@ -1,12 +0,0 @@
|
|||
# test scope
|
||||
|
||||
def f(x):
|
||||
def f2(y):
|
||||
print(y, x42, y42)
|
||||
x42 = x = y42 = 123
|
||||
myf2 = f2
|
||||
x42 = 456
|
||||
return myf2
|
||||
|
||||
myf = f(1)
|
||||
myf(1)
|
|
@ -1,7 +0,0 @@
|
|||
# closed over variable 2 deep
|
||||
|
||||
def f():
|
||||
x = 1
|
||||
def g():
|
||||
def h():
|
||||
return 1 + x
|
|
@ -1,15 +0,0 @@
|
|||
# test order of closed over locals
|
||||
# not that CPython seems to sort closed over variables (but not fast locals)
|
||||
|
||||
def f():
|
||||
l1 = 1
|
||||
l2 = 4
|
||||
l3 = 3
|
||||
l4 = 2
|
||||
l5 = 5
|
||||
|
||||
def g():
|
||||
return l1 + l4 + l3 + l2 + l5
|
||||
|
||||
def h():
|
||||
return l1 + l2 + l3 + l4 + l5
|
|
@ -1,6 +0,0 @@
|
|||
x = set()
|
||||
x = {1}
|
||||
x = {1,}
|
||||
x = {1, 2}
|
||||
x = {1, 2,}
|
||||
x = {1, 2, 3}
|
|
@ -1,2 +0,0 @@
|
|||
x = {a for a in l}
|
||||
x = {a + b for a, b in l if b}
|
|
@ -1,16 +0,0 @@
|
|||
x = x[:]
|
||||
x = x[::]
|
||||
x = x[::c]
|
||||
x = x[:b]
|
||||
x = x[:b:]
|
||||
x = x[:b:c]
|
||||
x = x[a]
|
||||
x = x[a:]
|
||||
x = x[a::]
|
||||
x = x[a::c]
|
||||
x = x[a:b]
|
||||
x = x[a:b:]
|
||||
x = x[a:b:c]
|
||||
|
||||
x[0] = 1
|
||||
x[x] = x
|
|
@ -1,3 +0,0 @@
|
|||
x = x[a, b]
|
||||
|
||||
x[a, b] = x
|
|
@ -1,11 +0,0 @@
|
|||
x = 'abc'
|
||||
x = "abc"
|
||||
x = r'abc'
|
||||
x = 'abc' \
|
||||
'def'
|
||||
x = ('abc'
|
||||
'def')
|
||||
|
||||
x = 'ab"c'
|
||||
x = "ab'c"
|
||||
x = '''ab'c'''
|
|
@ -1,14 +0,0 @@
|
|||
'abc'
|
||||
class f:
|
||||
u"123"
|
||||
pass
|
||||
x = 'abc'
|
||||
x = u"abc"
|
||||
x = u"ab\\c"
|
||||
x = r"ab\\c"
|
||||
x = b"abc"
|
||||
x = rb"abc"
|
||||
x = b"ab\\c"
|
||||
x = rb"ab\\c"
|
||||
x = """abc"""
|
||||
x = b"""abc"""
|
|
@ -1,17 +0,0 @@
|
|||
class A(B):
|
||||
def f():
|
||||
super.a()
|
||||
|
||||
class B(C):
|
||||
def g():
|
||||
def h():
|
||||
super.a()
|
||||
|
||||
super.a()
|
||||
|
||||
def i():
|
||||
super.a()
|
||||
|
||||
def j():
|
||||
def k():
|
||||
super.a()
|
|
@ -1,13 +0,0 @@
|
|||
def f(x):
|
||||
try:
|
||||
f(x)
|
||||
except:
|
||||
f(x)
|
||||
try:
|
||||
f(x)
|
||||
except Exception:
|
||||
f(x)
|
||||
try:
|
||||
f(x)
|
||||
except Exception as e:
|
||||
f(x, e)
|
|
@ -1,5 +0,0 @@
|
|||
def f():
|
||||
try:
|
||||
f()
|
||||
finally:
|
||||
g()
|
|
@ -1,14 +0,0 @@
|
|||
def f():
|
||||
try:
|
||||
f()
|
||||
except:
|
||||
g()
|
||||
finally:
|
||||
f()
|
||||
|
||||
try:
|
||||
f()
|
||||
except Exception:
|
||||
g()
|
||||
finally:
|
||||
f()
|
|
@ -1,22 +0,0 @@
|
|||
try:
|
||||
f()
|
||||
except A:
|
||||
g()
|
||||
except:
|
||||
h()
|
||||
|
||||
try:
|
||||
f()
|
||||
except A:
|
||||
g()
|
||||
except B as c:
|
||||
h()
|
||||
|
||||
try:
|
||||
f()
|
||||
except A:
|
||||
g()
|
||||
except B as c:
|
||||
h()
|
||||
except:
|
||||
i()
|
|
@ -1,8 +0,0 @@
|
|||
try:
|
||||
f()
|
||||
except A:
|
||||
g()
|
||||
except B as b:
|
||||
h()
|
||||
finally:
|
||||
i()
|
|
@ -1,15 +0,0 @@
|
|||
try:
|
||||
f()
|
||||
except:
|
||||
g()
|
||||
else:
|
||||
h()
|
||||
|
||||
try:
|
||||
f()
|
||||
except:
|
||||
g()
|
||||
else:
|
||||
h()
|
||||
finally:
|
||||
i()
|
|
@ -1,17 +0,0 @@
|
|||
x = ()
|
||||
x = a
|
||||
x = a,
|
||||
x = a, 2
|
||||
x = a, 2,
|
||||
x = a, 2, 3
|
||||
x = a, 2, 3, 4
|
||||
x = a, 2, 3, 4, 5
|
||||
|
||||
x = ()
|
||||
x = (a)
|
||||
x = (a,)
|
||||
x = (a, 2)
|
||||
x = (a, 2,)
|
||||
x = (a, 2, 3)
|
||||
x = (a, 2, 3, 4)
|
||||
x = (a, 2, 3, 4, 5)
|
|
@ -1,15 +0,0 @@
|
|||
x = t
|
||||
x, = t
|
||||
x, y = t
|
||||
x, y, = t
|
||||
x, y, z = t
|
||||
x, y, z, = t
|
||||
x, y, z, z = a, b, c, d
|
||||
|
||||
(x) = t
|
||||
(x,) = t
|
||||
(x, y) = t
|
||||
(x, y,) = t
|
||||
(x, y, z) = t
|
||||
(x, y, z,) = t
|
||||
(x, y, z, z) = a, b, c, d
|
|
@ -1,4 +0,0 @@
|
|||
def f(x):
|
||||
return x, x + 1
|
||||
for a in b, c:
|
||||
f(a)
|
|
@ -1,8 +0,0 @@
|
|||
with x:
|
||||
f()
|
||||
with x():
|
||||
f()
|
||||
with f() as x:
|
||||
f(x)
|
||||
with f() as x, g() as y:
|
||||
f(x, y)
|
|
@ -1,17 +0,0 @@
|
|||
# generators and yield
|
||||
|
||||
def main():
|
||||
def f():
|
||||
print(123)
|
||||
yield
|
||||
print(456)
|
||||
yield 2
|
||||
print(789)
|
||||
|
||||
a = f()
|
||||
print(a)
|
||||
print(a.__next__())
|
||||
print(a.__next__())
|
||||
#print(a.__next__())
|
||||
|
||||
main()
|
|
@ -1,7 +0,0 @@
|
|||
def f():
|
||||
yield from a
|
||||
yield from (a, b)
|
||||
yield from f(a)
|
||||
|
||||
lambda:(yield)
|
||||
lambda:(yield 1) + 2
|
|
@ -1,254 +0,0 @@
|
|||
A. HISTORY OF THE SOFTWARE
|
||||
==========================
|
||||
|
||||
Python was created in the early 1990s by Guido van Rossum at Stichting
|
||||
Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
|
||||
as a successor of a language called ABC. Guido remains Python's
|
||||
principal author, although it includes many contributions from others.
|
||||
|
||||
In 1995, Guido continued his work on Python at the Corporation for
|
||||
National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
|
||||
in Reston, Virginia where he released several versions of the
|
||||
software.
|
||||
|
||||
In May 2000, Guido and the Python core development team moved to
|
||||
BeOpen.com to form the BeOpen PythonLabs team. In October of the same
|
||||
year, the PythonLabs team moved to Digital Creations (now Zope
|
||||
Corporation, see http://www.zope.com). In 2001, the Python Software
|
||||
Foundation (PSF, see http://www.python.org/psf/) was formed, a
|
||||
non-profit organization created specifically to own Python-related
|
||||
Intellectual Property. Zope Corporation is a sponsoring member of
|
||||
the PSF.
|
||||
|
||||
All Python releases are Open Source (see http://www.opensource.org for
|
||||
the Open Source Definition). Historically, most, but not all, Python
|
||||
releases have also been GPL-compatible; the table below summarizes
|
||||
the various releases.
|
||||
|
||||
Release Derived Year Owner GPL-
|
||||
from compatible? (1)
|
||||
|
||||
0.9.0 thru 1.2 1991-1995 CWI yes
|
||||
1.3 thru 1.5.2 1.2 1995-1999 CNRI yes
|
||||
1.6 1.5.2 2000 CNRI no
|
||||
2.0 1.6 2000 BeOpen.com no
|
||||
1.6.1 1.6 2001 CNRI yes (2)
|
||||
2.1 2.0+1.6.1 2001 PSF no
|
||||
2.0.1 2.0+1.6.1 2001 PSF yes
|
||||
2.1.1 2.1+2.0.1 2001 PSF yes
|
||||
2.1.2 2.1.1 2002 PSF yes
|
||||
2.1.3 2.1.2 2002 PSF yes
|
||||
2.2 and above 2.1.1 2001-now PSF yes
|
||||
|
||||
Footnotes:
|
||||
|
||||
(1) GPL-compatible doesn't mean that we're distributing Python under
|
||||
the GPL. All Python licenses, unlike the GPL, let you distribute
|
||||
a modified version without making your changes open source. The
|
||||
GPL-compatible licenses make it possible to combine Python with
|
||||
other software that is released under the GPL; the others don't.
|
||||
|
||||
(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
|
||||
because its license has a choice of law clause. According to
|
||||
CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
|
||||
is "not incompatible" with the GPL.
|
||||
|
||||
Thanks to the many outside volunteers who have worked under Guido's
|
||||
direction to make these releases possible.
|
||||
|
||||
|
||||
B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
|
||||
===============================================================
|
||||
|
||||
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
|
||||
--------------------------------------------
|
||||
|
||||
1. This LICENSE AGREEMENT is between the Python Software Foundation
|
||||
("PSF"), and the Individual or Organization ("Licensee") accessing and
|
||||
otherwise using this software ("Python") in source or binary form and
|
||||
its associated documentation.
|
||||
|
||||
2. Subject to the terms and conditions of this License Agreement, PSF hereby
|
||||
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
|
||||
analyze, test, perform and/or display publicly, prepare derivative works,
|
||||
distribute, and otherwise use Python alone or in any derivative version,
|
||||
provided, however, that PSF's License Agreement and PSF's notice of copyright,
|
||||
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||
2011, 2012, 2013 Python Software Foundation; All Rights Reserved" are retained
|
||||
in Python alone or in any derivative version prepared by Licensee.
|
||||
|
||||
3. In the event Licensee prepares a derivative work that is based on
|
||||
or incorporates Python or any part thereof, and wants to make
|
||||
the derivative work available to others as provided herein, then
|
||||
Licensee hereby agrees to include in any such work a brief summary of
|
||||
the changes made to Python.
|
||||
|
||||
4. PSF is making Python available to Licensee on an "AS IS"
|
||||
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
|
||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
|
||||
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||
|
||||
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
||||
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
||||
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
|
||||
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||
|
||||
6. This License Agreement will automatically terminate upon a material
|
||||
breach of its terms and conditions.
|
||||
|
||||
7. Nothing in this License Agreement shall be deemed to create any
|
||||
relationship of agency, partnership, or joint venture between PSF and
|
||||
Licensee. This License Agreement does not grant permission to use PSF
|
||||
trademarks or trade name in a trademark sense to endorse or promote
|
||||
products or services of Licensee, or any third party.
|
||||
|
||||
8. By copying, installing or otherwise using Python, Licensee
|
||||
agrees to be bound by the terms and conditions of this License
|
||||
Agreement.
|
||||
|
||||
|
||||
BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
|
||||
-------------------------------------------
|
||||
|
||||
BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
|
||||
|
||||
1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
|
||||
office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
|
||||
Individual or Organization ("Licensee") accessing and otherwise using
|
||||
this software in source or binary form and its associated
|
||||
documentation ("the Software").
|
||||
|
||||
2. Subject to the terms and conditions of this BeOpen Python License
|
||||
Agreement, BeOpen hereby grants Licensee a non-exclusive,
|
||||
royalty-free, world-wide license to reproduce, analyze, test, perform
|
||||
and/or display publicly, prepare derivative works, distribute, and
|
||||
otherwise use the Software alone or in any derivative version,
|
||||
provided, however, that the BeOpen Python License is retained in the
|
||||
Software, alone or in any derivative version prepared by Licensee.
|
||||
|
||||
3. BeOpen is making the Software available to Licensee on an "AS IS"
|
||||
basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
|
||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
|
||||
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||
|
||||
4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
|
||||
SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
|
||||
AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
|
||||
DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||
|
||||
5. This License Agreement will automatically terminate upon a material
|
||||
breach of its terms and conditions.
|
||||
|
||||
6. This License Agreement shall be governed by and interpreted in all
|
||||
respects by the law of the State of California, excluding conflict of
|
||||
law provisions. Nothing in this License Agreement shall be deemed to
|
||||
create any relationship of agency, partnership, or joint venture
|
||||
between BeOpen and Licensee. This License Agreement does not grant
|
||||
permission to use BeOpen trademarks or trade names in a trademark
|
||||
sense to endorse or promote products or services of Licensee, or any
|
||||
third party. As an exception, the "BeOpen Python" logos available at
|
||||
http://www.pythonlabs.com/logos.html may be used according to the
|
||||
permissions granted on that web page.
|
||||
|
||||
7. By copying, installing or otherwise using the software, Licensee
|
||||
agrees to be bound by the terms and conditions of this License
|
||||
Agreement.
|
||||
|
||||
|
||||
CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
|
||||
---------------------------------------
|
||||
|
||||
1. This LICENSE AGREEMENT is between the Corporation for National
|
||||
Research Initiatives, having an office at 1895 Preston White Drive,
|
||||
Reston, VA 20191 ("CNRI"), and the Individual or Organization
|
||||
("Licensee") accessing and otherwise using Python 1.6.1 software in
|
||||
source or binary form and its associated documentation.
|
||||
|
||||
2. Subject to the terms and conditions of this License Agreement, CNRI
|
||||
hereby grants Licensee a nonexclusive, royalty-free, world-wide
|
||||
license to reproduce, analyze, test, perform and/or display publicly,
|
||||
prepare derivative works, distribute, and otherwise use Python 1.6.1
|
||||
alone or in any derivative version, provided, however, that CNRI's
|
||||
License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
|
||||
1995-2001 Corporation for National Research Initiatives; All Rights
|
||||
Reserved" are retained in Python 1.6.1 alone or in any derivative
|
||||
version prepared by Licensee. Alternately, in lieu of CNRI's License
|
||||
Agreement, Licensee may substitute the following text (omitting the
|
||||
quotes): "Python 1.6.1 is made available subject to the terms and
|
||||
conditions in CNRI's License Agreement. This Agreement together with
|
||||
Python 1.6.1 may be located on the Internet using the following
|
||||
unique, persistent identifier (known as a handle): 1895.22/1013. This
|
||||
Agreement may also be obtained from a proxy server on the Internet
|
||||
using the following URL: http://hdl.handle.net/1895.22/1013".
|
||||
|
||||
3. In the event Licensee prepares a derivative work that is based on
|
||||
or incorporates Python 1.6.1 or any part thereof, and wants to make
|
||||
the derivative work available to others as provided herein, then
|
||||
Licensee hereby agrees to include in any such work a brief summary of
|
||||
the changes made to Python 1.6.1.
|
||||
|
||||
4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
|
||||
basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
|
||||
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
|
||||
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
|
||||
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
|
||||
INFRINGE ANY THIRD PARTY RIGHTS.
|
||||
|
||||
5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
|
||||
1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
||||
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
|
||||
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||
|
||||
6. This License Agreement will automatically terminate upon a material
|
||||
breach of its terms and conditions.
|
||||
|
||||
7. This License Agreement shall be governed by the federal
|
||||
intellectual property law of the United States, including without
|
||||
limitation the federal copyright law, and, to the extent such
|
||||
U.S. federal law does not apply, by the law of the Commonwealth of
|
||||
Virginia, excluding Virginia's conflict of law provisions.
|
||||
Notwithstanding the foregoing, with regard to derivative works based
|
||||
on Python 1.6.1 that incorporate non-separable material that was
|
||||
previously distributed under the GNU General Public License (GPL), the
|
||||
law of the Commonwealth of Virginia shall govern this License
|
||||
Agreement only as to issues arising under or with respect to
|
||||
Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
|
||||
License Agreement shall be deemed to create any relationship of
|
||||
agency, partnership, or joint venture between CNRI and Licensee. This
|
||||
License Agreement does not grant permission to use CNRI trademarks or
|
||||
trade name in a trademark sense to endorse or promote products or
|
||||
services of Licensee, or any third party.
|
||||
|
||||
8. By clicking on the "ACCEPT" button where indicated, or by copying,
|
||||
installing or otherwise using Python 1.6.1, Licensee agrees to be
|
||||
bound by the terms and conditions of this License Agreement.
|
||||
|
||||
ACCEPT
|
||||
|
||||
|
||||
CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
|
||||
--------------------------------------------------
|
||||
|
||||
Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
|
||||
The Netherlands. All rights reserved.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation for any purpose and without fee is hereby granted,
|
||||
provided that the above copyright notice appear in all copies and that
|
||||
both that copyright notice and this permission notice appear in
|
||||
supporting documentation, and that the name of Stichting Mathematisch
|
||||
Centrum or CWI not be used in advertising or publicity pertaining to
|
||||
distribution of the software without specific, written prior
|
||||
permission.
|
||||
|
||||
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
|
||||
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
|
||||
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
@ -1,81 +0,0 @@
|
|||
# This module is used to map the old Python 2 names to the new names used in
|
||||
# Python 3 for the pickle module. This needed to make pickle streams
|
||||
# generated with Python 2 loadable by Python 3.
|
||||
|
||||
# This is a copy of lib2to3.fixes.fix_imports.MAPPING. We cannot import
|
||||
# lib2to3 and use the mapping defined there, because lib2to3 uses pickle.
|
||||
# Thus, this could cause the module to be imported recursively.
|
||||
IMPORT_MAPPING = {
|
||||
'StringIO': 'io',
|
||||
'cStringIO': 'io',
|
||||
'cPickle': 'pickle',
|
||||
'__builtin__' : 'builtins',
|
||||
'copy_reg': 'copyreg',
|
||||
'Queue': 'queue',
|
||||
'SocketServer': 'socketserver',
|
||||
'ConfigParser': 'configparser',
|
||||
'repr': 'reprlib',
|
||||
'FileDialog': 'tkinter.filedialog',
|
||||
'tkFileDialog': 'tkinter.filedialog',
|
||||
'SimpleDialog': 'tkinter.simpledialog',
|
||||
'tkSimpleDialog': 'tkinter.simpledialog',
|
||||
'tkColorChooser': 'tkinter.colorchooser',
|
||||
'tkCommonDialog': 'tkinter.commondialog',
|
||||
'Dialog': 'tkinter.dialog',
|
||||
'Tkdnd': 'tkinter.dnd',
|
||||
'tkFont': 'tkinter.font',
|
||||
'tkMessageBox': 'tkinter.messagebox',
|
||||
'ScrolledText': 'tkinter.scrolledtext',
|
||||
'Tkconstants': 'tkinter.constants',
|
||||
'Tix': 'tkinter.tix',
|
||||
'ttk': 'tkinter.ttk',
|
||||
'Tkinter': 'tkinter',
|
||||
'markupbase': '_markupbase',
|
||||
'_winreg': 'winreg',
|
||||
'thread': '_thread',
|
||||
'dummy_thread': '_dummy_thread',
|
||||
'dbhash': 'dbm.bsd',
|
||||
'dumbdbm': 'dbm.dumb',
|
||||
'dbm': 'dbm.ndbm',
|
||||
'gdbm': 'dbm.gnu',
|
||||
'xmlrpclib': 'xmlrpc.client',
|
||||
'DocXMLRPCServer': 'xmlrpc.server',
|
||||
'SimpleXMLRPCServer': 'xmlrpc.server',
|
||||
'httplib': 'http.client',
|
||||
'htmlentitydefs' : 'html.entities',
|
||||
'HTMLParser' : 'html.parser',
|
||||
'Cookie': 'http.cookies',
|
||||
'cookielib': 'http.cookiejar',
|
||||
'BaseHTTPServer': 'http.server',
|
||||
'SimpleHTTPServer': 'http.server',
|
||||
'CGIHTTPServer': 'http.server',
|
||||
'test.test_support': 'test.support',
|
||||
'commands': 'subprocess',
|
||||
'UserString' : 'collections',
|
||||
'UserList' : 'collections',
|
||||
'urlparse' : 'urllib.parse',
|
||||
'robotparser' : 'urllib.robotparser',
|
||||
'whichdb': 'dbm',
|
||||
'anydbm': 'dbm'
|
||||
}
|
||||
|
||||
|
||||
# This contains rename rules that are easy to handle. We ignore the more
|
||||
# complex stuff (e.g. mapping the names in the urllib and types modules).
|
||||
# These rules should be run before import names are fixed.
|
||||
NAME_MAPPING = {
|
||||
('__builtin__', 'xrange'): ('builtins', 'range'),
|
||||
('__builtin__', 'reduce'): ('functools', 'reduce'),
|
||||
('__builtin__', 'intern'): ('sys', 'intern'),
|
||||
('__builtin__', 'unichr'): ('builtins', 'chr'),
|
||||
('__builtin__', 'basestring'): ('builtins', 'str'),
|
||||
('__builtin__', 'long'): ('builtins', 'int'),
|
||||
('itertools', 'izip'): ('builtins', 'zip'),
|
||||
('itertools', 'imap'): ('builtins', 'map'),
|
||||
('itertools', 'ifilter'): ('builtins', 'filter'),
|
||||
('itertools', 'ifilterfalse'): ('itertools', 'filterfalse'),
|
||||
}
|
||||
|
||||
# Same, but for 3.x to 2.x
|
||||
REVERSE_IMPORT_MAPPING = dict((v, k) for (k, v) in IMPORT_MAPPING.items())
|
||||
REVERSE_NAME_MAPPING = dict((v, k) for (k, v) in NAME_MAPPING.items())
|
|
@ -1,246 +0,0 @@
|
|||
"""Thread-local objects.
|
||||
|
||||
(Note that this module provides a Python version of the threading.local
|
||||
class. Depending on the version of Python you're using, there may be a
|
||||
faster one available. You should always import the `local` class from
|
||||
`threading`.)
|
||||
|
||||
Thread-local objects support the management of thread-local data.
|
||||
If you have data that you want to be local to a thread, simply create
|
||||
a thread-local object and use its attributes:
|
||||
|
||||
>>> mydata = local()
|
||||
>>> mydata.number = 42
|
||||
>>> mydata.number
|
||||
42
|
||||
|
||||
You can also access the local-object's dictionary:
|
||||
|
||||
>>> mydata.__dict__
|
||||
{'number': 42}
|
||||
>>> mydata.__dict__.setdefault('widgets', [])
|
||||
[]
|
||||
>>> mydata.widgets
|
||||
[]
|
||||
|
||||
What's important about thread-local objects is that their data are
|
||||
local to a thread. If we access the data in a different thread:
|
||||
|
||||
>>> log = []
|
||||
>>> def f():
|
||||
... items = sorted(mydata.__dict__.items())
|
||||
... log.append(items)
|
||||
... mydata.number = 11
|
||||
... log.append(mydata.number)
|
||||
|
||||
>>> import threading
|
||||
>>> thread = threading.Thread(target=f)
|
||||
>>> thread.start()
|
||||
>>> thread.join()
|
||||
>>> log
|
||||
[[], 11]
|
||||
|
||||
we get different data. Furthermore, changes made in the other thread
|
||||
don't affect data seen in this thread:
|
||||
|
||||
>>> mydata.number
|
||||
42
|
||||
|
||||
Of course, values you get from a local object, including a __dict__
|
||||
attribute, are for whatever thread was current at the time the
|
||||
attribute was read. For that reason, you generally don't want to save
|
||||
these values across threads, as they apply only to the thread they
|
||||
came from.
|
||||
|
||||
You can create custom local objects by subclassing the local class:
|
||||
|
||||
>>> class MyLocal(local):
|
||||
... number = 2
|
||||
... initialized = False
|
||||
... def __init__(self, **kw):
|
||||
... if self.initialized:
|
||||
... raise SystemError('__init__ called too many times')
|
||||
... self.initialized = True
|
||||
... self.__dict__.update(kw)
|
||||
... def squared(self):
|
||||
... return self.number ** 2
|
||||
|
||||
This can be useful to support default values, methods and
|
||||
initialization. Note that if you define an __init__ method, it will be
|
||||
called each time the local object is used in a separate thread. This
|
||||
is necessary to initialize each thread's dictionary.
|
||||
|
||||
Now if we create a local object:
|
||||
|
||||
>>> mydata = MyLocal(color='red')
|
||||
|
||||
Now we have a default number:
|
||||
|
||||
>>> mydata.number
|
||||
2
|
||||
|
||||
an initial color:
|
||||
|
||||
>>> mydata.color
|
||||
'red'
|
||||
>>> del mydata.color
|
||||
|
||||
And a method that operates on the data:
|
||||
|
||||
>>> mydata.squared()
|
||||
4
|
||||
|
||||
As before, we can access the data in a separate thread:
|
||||
|
||||
>>> log = []
|
||||
>>> thread = threading.Thread(target=f)
|
||||
>>> thread.start()
|
||||
>>> thread.join()
|
||||
>>> log
|
||||
[[('color', 'red'), ('initialized', True)], 11]
|
||||
|
||||
without affecting this thread's data:
|
||||
|
||||
>>> mydata.number
|
||||
2
|
||||
>>> mydata.color
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
AttributeError: 'MyLocal' object has no attribute 'color'
|
||||
|
||||
Note that subclasses can define slots, but they are not thread
|
||||
local. They are shared across threads:
|
||||
|
||||
>>> class MyLocal(local):
|
||||
... __slots__ = 'number'
|
||||
|
||||
>>> mydata = MyLocal()
|
||||
>>> mydata.number = 42
|
||||
>>> mydata.color = 'red'
|
||||
|
||||
So, the separate thread:
|
||||
|
||||
>>> thread = threading.Thread(target=f)
|
||||
>>> thread.start()
|
||||
>>> thread.join()
|
||||
|
||||
affects what we see:
|
||||
|
||||
>>> mydata.number
|
||||
11
|
||||
|
||||
>>> del mydata
|
||||
"""
|
||||
|
||||
from weakref import ref
|
||||
from contextlib import contextmanager
|
||||
|
||||
__all__ = ["local"]
|
||||
|
||||
# We need to use objects from the threading module, but the threading
|
||||
# module may also want to use our `local` class, if support for locals
|
||||
# isn't compiled in to the `thread` module. This creates potential problems
|
||||
# with circular imports. For that reason, we don't import `threading`
|
||||
# until the bottom of this file (a hack sufficient to worm around the
|
||||
# potential problems). Note that all platforms on CPython do have support
|
||||
# for locals in the `thread` module, and there is no circular import problem
|
||||
# then, so problems introduced by fiddling the order of imports here won't
|
||||
# manifest.
|
||||
|
||||
class _localimpl:
|
||||
"""A class managing thread-local dicts"""
|
||||
__slots__ = 'key', 'dicts', 'localargs', 'locallock', '__weakref__'
|
||||
|
||||
def __init__(self):
|
||||
# The key used in the Thread objects' attribute dicts.
|
||||
# We keep it a string for speed but make it unlikely to clash with
|
||||
# a "real" attribute.
|
||||
self.key = '_threading_local._localimpl.' + str(id(self))
|
||||
# { id(Thread) -> (ref(Thread), thread-local dict) }
|
||||
self.dicts = {}
|
||||
|
||||
def get_dict(self):
|
||||
"""Return the dict for the current thread. Raises KeyError if none
|
||||
defined."""
|
||||
thread = current_thread()
|
||||
return self.dicts[id(thread)][1]
|
||||
|
||||
def create_dict(self):
|
||||
"""Create a new dict for the current thread, and return it."""
|
||||
localdict = {}
|
||||
key = self.key
|
||||
thread = current_thread()
|
||||
idt = id(thread)
|
||||
def local_deleted(_, key=key):
|
||||
# When the localimpl is deleted, remove the thread attribute.
|
||||
thread = wrthread()
|
||||
if thread is not None:
|
||||
del thread.__dict__[key]
|
||||
def thread_deleted(_, idt=idt):
|
||||
# When the thread is deleted, remove the local dict.
|
||||
# Note that this is suboptimal if the thread object gets
|
||||
# caught in a reference loop. We would like to be called
|
||||
# as soon as the OS-level thread ends instead.
|
||||
local = wrlocal()
|
||||
if local is not None:
|
||||
dct = local.dicts.pop(idt)
|
||||
wrlocal = ref(self, local_deleted)
|
||||
wrthread = ref(thread, thread_deleted)
|
||||
thread.__dict__[key] = wrlocal
|
||||
self.dicts[idt] = wrthread, localdict
|
||||
return localdict
|
||||
|
||||
|
||||
@contextmanager
|
||||
def _patch(self):
|
||||
impl = object.__getattribute__(self, '_local__impl')
|
||||
try:
|
||||
dct = impl.get_dict()
|
||||
except KeyError:
|
||||
dct = impl.create_dict()
|
||||
args, kw = impl.localargs
|
||||
self.__init__(*args, **kw)
|
||||
with impl.locallock:
|
||||
object.__setattr__(self, '__dict__', dct)
|
||||
yield
|
||||
|
||||
|
||||
class local:
|
||||
__slots__ = '_local__impl', '__dict__'
|
||||
|
||||
def __new__(cls, *args, **kw):
|
||||
if (args or kw) and (cls.__init__ is object.__init__):
|
||||
raise TypeError("Initialization arguments are not supported")
|
||||
self = object.__new__(cls)
|
||||
impl = _localimpl()
|
||||
impl.localargs = (args, kw)
|
||||
impl.locallock = RLock()
|
||||
object.__setattr__(self, '_local__impl', impl)
|
||||
# We need to create the thread dict in anticipation of
|
||||
# __init__ being called, to make sure we don't call it
|
||||
# again ourselves.
|
||||
impl.create_dict()
|
||||
return self
|
||||
|
||||
def __getattribute__(self, name):
|
||||
with _patch(self):
|
||||
return object.__getattribute__(self, name)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if name == '__dict__':
|
||||
raise AttributeError(
|
||||
"%r object attribute '__dict__' is read-only"
|
||||
% self.__class__.__name__)
|
||||
with _patch(self):
|
||||
return object.__setattr__(self, name, value)
|
||||
|
||||
def __delattr__(self, name):
|
||||
if name == '__dict__':
|
||||
raise AttributeError(
|
||||
"%r object attribute '__dict__' is read-only"
|
||||
% self.__class__.__name__)
|
||||
with _patch(self):
|
||||
return object.__delattr__(self, name)
|
||||
|
||||
|
||||
from threading import current_thread, RLock
|
|
@ -1,194 +0,0 @@
|
|||
# Access WeakSet through the weakref module.
|
||||
# This code is separated-out because it is needed
|
||||
# by abc.py to load everything else at startup.
|
||||
|
||||
from _weakref import ref
|
||||
|
||||
__all__ = ['WeakSet']
|
||||
|
||||
|
||||
class _IterationGuard:
|
||||
# This context manager registers itself in the current iterators of the
|
||||
# weak container, such as to delay all removals until the context manager
|
||||
# exits.
|
||||
# This technique should be relatively thread-safe (since sets are).
|
||||
|
||||
def __init__(self, weakcontainer):
|
||||
# Don't create cycles
|
||||
self.weakcontainer = ref(weakcontainer)
|
||||
|
||||
def __enter__(self):
|
||||
w = self.weakcontainer()
|
||||
if w is not None:
|
||||
w._iterating.add(self)
|
||||
return self
|
||||
|
||||
def __exit__(self, e, t, b):
|
||||
w = self.weakcontainer()
|
||||
if w is not None:
|
||||
s = w._iterating
|
||||
s.remove(self)
|
||||
if not s:
|
||||
w._commit_removals()
|
||||
|
||||
|
||||
class WeakSet:
|
||||
def __init__(self, data=None):
|
||||
self.data = set()
|
||||
def _remove(item, selfref=ref(self)):
|
||||
self = selfref()
|
||||
if self is not None:
|
||||
if self._iterating:
|
||||
self._pending_removals.append(item)
|
||||
else:
|
||||
self.data.discard(item)
|
||||
self._remove = _remove
|
||||
# A list of keys to be removed
|
||||
self._pending_removals = []
|
||||
self._iterating = set()
|
||||
if data is not None:
|
||||
self.update(data)
|
||||
|
||||
def _commit_removals(self):
|
||||
l = self._pending_removals
|
||||
discard = self.data.discard
|
||||
while l:
|
||||
discard(l.pop())
|
||||
|
||||
def __iter__(self):
|
||||
with _IterationGuard(self):
|
||||
for itemref in self.data:
|
||||
item = itemref()
|
||||
if item is not None:
|
||||
yield item
|
||||
|
||||
def __len__(self):
|
||||
return len(self.data) - len(self._pending_removals)
|
||||
|
||||
def __contains__(self, item):
|
||||
try:
|
||||
wr = ref(item)
|
||||
except TypeError:
|
||||
return False
|
||||
return wr in self.data
|
||||
|
||||
def __reduce__(self):
|
||||
return (self.__class__, (list(self),),
|
||||
getattr(self, '__dict__', None))
|
||||
|
||||
def add(self, item):
|
||||
if self._pending_removals:
|
||||
self._commit_removals()
|
||||
self.data.add(ref(item, self._remove))
|
||||
|
||||
def clear(self):
|
||||
if self._pending_removals:
|
||||
self._commit_removals()
|
||||
self.data.clear()
|
||||
|
||||
def copy(self):
|
||||
return self.__class__(self)
|
||||
|
||||
def pop(self):
|
||||
if self._pending_removals:
|
||||
self._commit_removals()
|
||||
while True:
|
||||
try:
|
||||
itemref = self.data.pop()
|
||||
except KeyError:
|
||||
raise KeyError('pop from empty WeakSet')
|
||||
item = itemref()
|
||||
if item is not None:
|
||||
return item
|
||||
|
||||
def remove(self, item):
|
||||
if self._pending_removals:
|
||||
self._commit_removals()
|
||||
self.data.remove(ref(item))
|
||||
|
||||
def discard(self, item):
|
||||
if self._pending_removals:
|
||||
self._commit_removals()
|
||||
self.data.discard(ref(item))
|
||||
|
||||
def update(self, other):
|
||||
if self._pending_removals:
|
||||
self._commit_removals()
|
||||
for element in other:
|
||||
self.add(element)
|
||||
|
||||
def __ior__(self, other):
|
||||
self.update(other)
|
||||
return self
|
||||
|
||||
def difference(self, other):
|
||||
newset = self.copy()
|
||||
newset.difference_update(other)
|
||||
return newset
|
||||
__sub__ = difference
|
||||
|
||||
def difference_update(self, other):
|
||||
self.__isub__(other)
|
||||
def __isub__(self, other):
|
||||
if self._pending_removals:
|
||||
self._commit_removals()
|
||||
if self is other:
|
||||
self.data.clear()
|
||||
else:
|
||||
self.data.difference_update(ref(item) for item in other)
|
||||
return self
|
||||
|
||||
def intersection(self, other):
|
||||
return self.__class__(item for item in other if item in self)
|
||||
__and__ = intersection
|
||||
|
||||
def intersection_update(self, other):
|
||||
self.__iand__(other)
|
||||
def __iand__(self, other):
|
||||
if self._pending_removals:
|
||||
self._commit_removals()
|
||||
self.data.intersection_update(ref(item) for item in other)
|
||||
return self
|
||||
|
||||
def issubset(self, other):
|
||||
return self.data.issubset(ref(item) for item in other)
|
||||
__le__ = issubset
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.data < set(ref(item) for item in other)
|
||||
|
||||
def issuperset(self, other):
|
||||
return self.data.issuperset(ref(item) for item in other)
|
||||
__ge__ = issuperset
|
||||
|
||||
def __gt__(self, other):
|
||||
return self.data > set(ref(item) for item in other)
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, self.__class__):
|
||||
return NotImplemented
|
||||
return self.data == set(ref(item) for item in other)
|
||||
|
||||
def symmetric_difference(self, other):
|
||||
newset = self.copy()
|
||||
newset.symmetric_difference_update(other)
|
||||
return newset
|
||||
__xor__ = symmetric_difference
|
||||
|
||||
def symmetric_difference_update(self, other):
|
||||
self.__ixor__(other)
|
||||
def __ixor__(self, other):
|
||||
if self._pending_removals:
|
||||
self._commit_removals()
|
||||
if self is other:
|
||||
self.data.clear()
|
||||
else:
|
||||
self.data.symmetric_difference_update(ref(item, self._remove) for item in other)
|
||||
return self
|
||||
|
||||
def union(self, other):
|
||||
return self.__class__(e for s in (self, other) for e in s)
|
||||
__or__ = union
|
||||
|
||||
def isdisjoint(self, other):
|
||||
return len(self.intersection(other)) == 0
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue