summaryrefslogtreecommitdiff
path: root/py
diff options
context:
space:
mode:
Diffstat (limited to 'py')
-rw-r--r--py/argcheck.c2
-rw-r--r--py/bc.c6
-rw-r--r--py/bc0.h4
-rw-r--r--py/emitnative.c43
-rw-r--r--py/formatfloat.c13
-rw-r--r--py/makeqstrdata.py10
-rw-r--r--py/mkenv.mk6
-rw-r--r--py/mkrules.mk6
-rw-r--r--py/modbuiltins.c25
-rw-r--r--py/modmath.c73
-rw-r--r--py/mpconfig.h22
-rw-r--r--py/mpstate.h2
-rw-r--r--py/nativeglue.c3
-rw-r--r--py/objarray.c2
-rw-r--r--py/objlist.c4
-rw-r--r--py/objtype.c98
-rw-r--r--py/persistentcode.c2
-rw-r--r--py/runtime.c7
-rw-r--r--py/runtime.h4
-rw-r--r--py/runtime0.h38
-rw-r--r--py/showbc.c4
-rw-r--r--py/vmentrytable.h4
22 files changed, 223 insertions, 155 deletions
diff --git a/py/argcheck.c b/py/argcheck.c
index 46be126ac..2a606d613 100644
--- a/py/argcheck.c
+++ b/py/argcheck.c
@@ -136,11 +136,9 @@ void mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args,
mp_arg_parse_all(n_pos, args, &kw_args, n_allowed, allowed, out_vals);
}
-#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE || defined(_MSC_VER)
NORETURN void mp_arg_error_terse_mismatch(void) {
mp_raise_TypeError("argument num/types mismatch");
}
-#endif
#if MICROPY_CPYTHON_COMPAT
NORETURN void mp_arg_error_unimpl_kw(void) {
diff --git a/py/bc.c b/py/bc.c
index 1f6819295..381daa24d 100644
--- a/py/bc.c
+++ b/py/bc.c
@@ -322,7 +322,7 @@ STATIC const byte opcode_format_table[64] = {
OC4(O, O, U, U), // 0x38-0x3b
OC4(U, O, B, O), // 0x3c-0x3f
OC4(O, B, B, O), // 0x40-0x43
- OC4(B, B, O, U), // 0x44-0x47
+ OC4(B, B, O, B), // 0x44-0x47
OC4(U, U, U, U), // 0x48-0x4b
OC4(U, U, U, U), // 0x4c-0x4f
OC4(V, V, U, V), // 0x50-0x53
@@ -362,7 +362,7 @@ STATIC const byte opcode_format_table[64] = {
OC4(B, B, B, B), // 0xcc-0xcf
OC4(B, B, B, B), // 0xd0-0xd3
- OC4(B, B, B, B), // 0xd4-0xd7
+ OC4(U, U, U, B), // 0xd4-0xd7
OC4(B, B, B, B), // 0xd8-0xdb
OC4(B, B, B, B), // 0xdc-0xdf
@@ -373,7 +373,7 @@ STATIC const byte opcode_format_table[64] = {
OC4(B, B, B, B), // 0xf0-0xf3
OC4(B, B, B, B), // 0xf4-0xf7
- OC4(B, B, B, U), // 0xf8-0xfb
+ OC4(U, U, U, U), // 0xf8-0xfb
OC4(U, U, U, U), // 0xfc-0xff
};
#undef OC4
diff --git a/py/bc0.h b/py/bc0.h
index 38e23c0fd..70acfb0ca 100644
--- a/py/bc0.h
+++ b/py/bc0.h
@@ -113,7 +113,7 @@
#define MP_BC_LOAD_CONST_SMALL_INT_MULTI (0x70) // + N(64)
#define MP_BC_LOAD_FAST_MULTI (0xb0) // + N(16)
#define MP_BC_STORE_FAST_MULTI (0xc0) // + N(16)
-#define MP_BC_UNARY_OP_MULTI (0xd0) // + op(<MP_UNARY_OP_NON_BYTECODE)
-#define MP_BC_BINARY_OP_MULTI (0xd7) // + op(36)
+#define MP_BC_UNARY_OP_MULTI (0xd0) // + op(<MP_UNARY_OP_NUM_BYTECODE)
+#define MP_BC_BINARY_OP_MULTI (0xd7) // + op(<MP_BINARY_OP_NUM_BYTECODE)
#endif // MICROPY_INCLUDED_PY_BC0_H
diff --git a/py/emitnative.c b/py/emitnative.c
index b2c9a7366..8e97dda11 100644
--- a/py/emitnative.c
+++ b/py/emitnative.c
@@ -123,6 +123,8 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
[MP_F_NEW_CELL] = 1,
[MP_F_MAKE_CLOSURE_FROM_RAW_CODE] = 3,
[MP_F_SETUP_CODE_STATE] = 5,
+ [MP_F_SMALL_INT_FLOOR_DIVIDE] = 2,
+ [MP_F_SMALL_INT_MODULO] = 2,
};
#include "py/asmx86.h"
@@ -1823,18 +1825,20 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
vtype_kind_t vtype_lhs = peek_vtype(emit, 1);
vtype_kind_t vtype_rhs = peek_vtype(emit, 0);
if (vtype_lhs == VTYPE_INT && vtype_rhs == VTYPE_INT) {
+ // for integers, inplace and normal ops are equivalent, so use just normal ops
+ if (MP_BINARY_OP_INPLACE_OR <= op && op <= MP_BINARY_OP_INPLACE_POWER) {
+ op += MP_BINARY_OP_OR - MP_BINARY_OP_INPLACE_OR;
+ }
+
#if N_X64 || N_X86
// special cases for x86 and shifting
- if (op == MP_BINARY_OP_LSHIFT
- || op == MP_BINARY_OP_INPLACE_LSHIFT
- || op == MP_BINARY_OP_RSHIFT
- || op == MP_BINARY_OP_INPLACE_RSHIFT) {
+ if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_RSHIFT) {
#if N_X64
emit_pre_pop_reg_reg(emit, &vtype_rhs, ASM_X64_REG_RCX, &vtype_lhs, REG_RET);
#else
emit_pre_pop_reg_reg(emit, &vtype_rhs, ASM_X86_REG_ECX, &vtype_lhs, REG_RET);
#endif
- if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_INPLACE_LSHIFT) {
+ if (op == MP_BINARY_OP_LSHIFT) {
ASM_LSL_REG(emit->as, REG_RET);
} else {
ASM_ASR_REG(emit->as, REG_RET);
@@ -1843,35 +1847,48 @@ STATIC void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) {
return;
}
#endif
+
+ // special cases for floor-divide and module because we dispatch to helper functions
+ if (op == MP_BINARY_OP_FLOOR_DIVIDE || op == MP_BINARY_OP_MODULO) {
+ emit_pre_pop_reg_reg(emit, &vtype_rhs, REG_ARG_2, &vtype_lhs, REG_ARG_1);
+ if (op == MP_BINARY_OP_FLOOR_DIVIDE) {
+ emit_call(emit, MP_F_SMALL_INT_FLOOR_DIVIDE);
+ } else {
+ emit_call(emit, MP_F_SMALL_INT_MODULO);
+ }
+ emit_post_push_reg(emit, VTYPE_INT, REG_RET);
+ return;
+ }
+
int reg_rhs = REG_ARG_3;
emit_pre_pop_reg_flexible(emit, &vtype_rhs, &reg_rhs, REG_RET, REG_ARG_2);
emit_pre_pop_reg(emit, &vtype_lhs, REG_ARG_2);
if (0) {
// dummy
#if !(N_X64 || N_X86)
- } else if (op == MP_BINARY_OP_LSHIFT || op == MP_BINARY_OP_INPLACE_LSHIFT) {
+ } else if (op == MP_BINARY_OP_LSHIFT) {
ASM_LSL_REG_REG(emit->as, REG_ARG_2, reg_rhs);
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
- } else if (op == MP_BINARY_OP_RSHIFT || op == MP_BINARY_OP_INPLACE_RSHIFT) {
+ } else if (op == MP_BINARY_OP_RSHIFT) {
ASM_ASR_REG_REG(emit->as, REG_ARG_2, reg_rhs);
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
#endif
- } else if (op == MP_BINARY_OP_OR || op == MP_BINARY_OP_INPLACE_OR) {
+ } else if (op == MP_BINARY_OP_OR) {
ASM_OR_REG_REG(emit->as, REG_ARG_2, reg_rhs);
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
- } else if (op == MP_BINARY_OP_XOR || op == MP_BINARY_OP_INPLACE_XOR) {
+ } else if (op == MP_BINARY_OP_XOR) {
ASM_XOR_REG_REG(emit->as, REG_ARG_2, reg_rhs);
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
- } else if (op == MP_BINARY_OP_AND || op == MP_BINARY_OP_INPLACE_AND) {
+ } else if (op == MP_BINARY_OP_AND) {
ASM_AND_REG_REG(emit->as, REG_ARG_2, reg_rhs);
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
- } else if (op == MP_BINARY_OP_ADD || op == MP_BINARY_OP_INPLACE_ADD) {
+ } else if (op == MP_BINARY_OP_ADD) {
ASM_ADD_REG_REG(emit->as, REG_ARG_2, reg_rhs);
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
- } else if (op == MP_BINARY_OP_SUBTRACT || op == MP_BINARY_OP_INPLACE_SUBTRACT) {
+ } else if (op == MP_BINARY_OP_SUBTRACT) {
ASM_SUB_REG_REG(emit->as, REG_ARG_2, reg_rhs);
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
- } else if (op == MP_BINARY_OP_MULTIPLY || op == MP_BINARY_OP_INPLACE_MULTIPLY) {
+ } else if (op == MP_BINARY_OP_MULTIPLY) {
ASM_MUL_REG_REG(emit->as, REG_ARG_2, reg_rhs);
emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2);
} else if (MP_BINARY_OP_LESS <= op && op <= MP_BINARY_OP_NOT_EQUAL) {
diff --git a/py/formatfloat.c b/py/formatfloat.c
index 35cd5d51a..4228f99ff 100644
--- a/py/formatfloat.c
+++ b/py/formatfloat.c
@@ -30,6 +30,7 @@
#include <assert.h>
#include <stdlib.h>
#include <stdint.h>
+#include <math.h>
#include "py/formatfloat.h"
/***********************************************************************
@@ -68,12 +69,10 @@ union floatbits {
uint32_t u;
};
static inline int fp_signbit(float x) { union floatbits fb = {x}; return fb.u & FLT_SIGN_MASK; }
-static inline int fp_isspecial(float x) { union floatbits fb = {x}; return (fb.u & FLT_EXP_MASK) == FLT_EXP_MASK; }
-static inline int fp_isinf(float x) { union floatbits fb = {x}; return (fb.u & FLT_MAN_MASK) == 0; }
+#define fp_isnan(x) isnan(x)
+#define fp_isinf(x) isinf(x)
static inline int fp_iszero(float x) { union floatbits fb = {x}; return fb.u == 0; }
static inline int fp_isless1(float x) { union floatbits fb = {x}; return fb.u < 0x3f800000; }
-// Assumes both fp_isspecial() and fp_isinf() were applied before
-#define fp_isnan(x) 1
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
@@ -82,9 +81,7 @@ static inline int fp_isless1(float x) { union floatbits fb = {x}; return fb.u <
#define FPROUND_TO_ONE 0.999999999995
#define FPDECEXP 256
#define FPMIN_BUF_SIZE 7 // +9e+199
-#include <math.h>
#define fp_signbit(x) signbit(x)
-#define fp_isspecial(x) 1
#define fp_isnan(x) isnan(x)
#define fp_isinf(x) isinf(x)
#define fp_iszero(x) (x == 0)
@@ -122,7 +119,7 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
}
return buf_size >= 2;
}
- if (fp_signbit(f)) {
+ if (fp_signbit(f) && !fp_isnan(f)) {
*s++ = '-';
f = -f;
} else {
@@ -135,7 +132,7 @@ int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, ch
// It is buf_size minus room for the sign and null byte.
int buf_remaining = buf_size - 1 - (s - buf);
- if (fp_isspecial(f)) {
+ {
char uc = fmt & 0x20;
if (fp_isinf(f)) {
*s++ = 'I' ^ uc;
diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py
index 7249769f4..38fde1a9c 100644
--- a/py/makeqstrdata.py
+++ b/py/makeqstrdata.py
@@ -108,7 +108,15 @@ def parse_input_headers(infiles):
continue
# add the qstr to the list, with order number to retain original order in file
- qstrs[ident] = (len(qstrs), ident, qstr)
+ order = len(qstrs)
+ # but put special method names like __add__ at the top of list, so
+ # that their id's fit into a byte
+ if ident == "":
+ # Sort empty qstr above all still
+ order = -200000
+ elif ident.startswith("__"):
+ order -= 100000
+ qstrs[ident] = (order, ident, qstr)
if not qcfgs:
sys.stderr.write("ERROR: Empty preprocessor output - check for errors above\n")
diff --git a/py/mkenv.mk b/py/mkenv.mk
index 507fa6eab..5a118854a 100644
--- a/py/mkenv.mk
+++ b/py/mkenv.mk
@@ -68,13 +68,7 @@ LD += -m32
endif
MAKE_FROZEN = $(TOP)/tools/make-frozen.py
-# allow mpy-cross (for WSL) and mpy-cross.exe (for cygwin) to coexist
-ifeq ($(OS),Windows_NT)
-MPY_CROSS = $(TOP)/mpy-cross/mpy-cross.exe
-PROG_EXT = .exe
-else
MPY_CROSS = $(TOP)/mpy-cross/mpy-cross
-endif
MPY_TOOL = $(TOP)/tools/mpy-tool.py
all:
diff --git a/py/mkrules.mk b/py/mkrules.mk
index e26b94939..1d6f11fc9 100644
--- a/py/mkrules.mk
+++ b/py/mkrules.mk
@@ -144,13 +144,13 @@ $(PROG): $(OBJ)
# we may want to compile using Thumb, but link with non-Thumb libc.
$(Q)$(CC) -o $@ $^ $(LIB) $(LDFLAGS)
ifndef DEBUG
- $(Q)$(STRIP) $(STRIPFLAGS_EXTRA) $(PROG)$(PROG_EXT)
+ $(Q)$(STRIP) $(STRIPFLAGS_EXTRA) $(PROG)
endif
- $(Q)$(SIZE) $$(find $(BUILD) -path "$(BUILD)/build/frozen*.o") $(PROG)$(PROG_EXT)
+ $(Q)$(SIZE) $$(find $(BUILD) -path "$(BUILD)/build/frozen*.o") $(PROG)
clean: clean-prog
clean-prog:
- $(RM) -f $(PROG)$(PROG_EXT)
+ $(RM) -f $(PROG)
$(RM) -f $(PROG).map
.PHONY: clean-prog
diff --git a/py/modbuiltins.c b/py/modbuiltins.c
index 991feda8c..728309292 100644
--- a/py/modbuiltins.c
+++ b/py/modbuiltins.c
@@ -348,31 +348,16 @@ STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) {
if (MP_OBJ_IS_STR(o_in)) {
len = unichar_charlen(str, len);
if (len == 1) {
- if (!UTF8_IS_NONASCII(*str)) {
- goto return_first_byte;
- }
- mp_int_t ord = *str++ & 0x7F;
- for (mp_int_t mask = 0x40; ord & mask; mask >>= 1) {
- ord &= ~mask;
- }
- while (UTF8_IS_CONT(*str)) {
- ord = (ord << 6) | (*str++ & 0x3F);
- }
- return mp_obj_new_int(ord);
+ return mp_obj_new_int(utf8_get_char((const byte*)str));
}
- } else {
- // a bytes object
+ } else
+ #endif
+ {
+ // a bytes object, or a str without unicode support (don't sign extend the char)
if (len == 1) {
- return_first_byte:
return MP_OBJ_NEW_SMALL_INT(((const byte*)str)[0]);
}
}
- #else
- if (len == 1) {
- // don't sign extend when converting to ord
- return mp_obj_new_int(((const byte*)str)[0]);
- }
- #endif
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
mp_raise_TypeError("ord expects a character");
diff --git a/py/modmath.c b/py/modmath.c
index 909780596..56ceb14bd 100644
--- a/py/modmath.c
+++ b/py/modmath.c
@@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
- * Copyright (c) 2013, 2014 Damien P. George
+ * Copyright (c) 2013-2017 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
@@ -40,14 +40,31 @@ STATIC NORETURN void math_error(void) {
mp_raise_ValueError("math domain error");
}
+STATIC mp_obj_t math_generic_1(mp_obj_t x_obj, mp_float_t (*f)(mp_float_t)) {
+ mp_float_t x = mp_obj_get_float(x_obj);
+ mp_float_t ans = f(x);
+ if ((isnan(ans) && !isnan(x)) || (isinf(ans) && !isinf(x))) {
+ math_error();
+ }
+ return mp_obj_new_float(ans);
+}
+
+STATIC mp_obj_t math_generic_2(mp_obj_t x_obj, mp_obj_t y_obj, mp_float_t (*f)(mp_float_t, mp_float_t)) {
+ mp_float_t x = mp_obj_get_float(x_obj);
+ mp_float_t y = mp_obj_get_float(y_obj);
+ mp_float_t ans = f(x, y);
+ if ((isnan(ans) && !isnan(x) && !isnan(y)) || (isinf(ans) && !isinf(x))) {
+ math_error();
+ }
+ return mp_obj_new_float(ans);
+}
+
#define MATH_FUN_1(py_name, c_name) \
- STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \
+ STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { \
+ return math_generic_1(x_obj, MICROPY_FLOAT_C_FUN(c_name)); \
+ } \
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name);
-#define MATH_FUN_2(py_name, c_name) \
- STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj, mp_obj_t y_obj) { return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj), mp_obj_get_float(y_obj))); } \
- STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_math_## py_name ## _obj, mp_math_ ## py_name);
-
#define MATH_FUN_1_TO_BOOL(py_name, c_name) \
STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_bool(c_name(mp_obj_get_float(x_obj))); } \
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name);
@@ -56,23 +73,29 @@ STATIC NORETURN void math_error(void) {
STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { return mp_obj_new_int_from_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name);
-#define MATH_FUN_1_ERRCOND(py_name, c_name, error_condition) \
- STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj) { \
- mp_float_t x = mp_obj_get_float(x_obj); \
- if (error_condition) { \
- math_error(); \
- } \
- return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(x)); \
+#define MATH_FUN_2(py_name, c_name) \
+ STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj, mp_obj_t y_obj) { \
+ return math_generic_2(x_obj, y_obj, MICROPY_FLOAT_C_FUN(c_name)); \
} \
- STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_## py_name ## _obj, mp_math_ ## py_name);
+ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_math_## py_name ## _obj, mp_math_ ## py_name);
-#ifdef MP_NEED_LOG2
+#define MATH_FUN_2_FLT_INT(py_name, c_name) \
+ STATIC mp_obj_t mp_math_ ## py_name(mp_obj_t x_obj, mp_obj_t y_obj) { \
+ return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj), mp_obj_get_int(y_obj))); \
+ } \
+ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_math_## py_name ## _obj, mp_math_ ## py_name);
+
+#if MP_NEED_LOG2
+#undef log2
+#undef log2f
// 1.442695040888963407354163704 is 1/_M_LN2
-#define log2(x) (log(x) * 1.442695040888963407354163704)
+mp_float_t MICROPY_FLOAT_C_FUN(log2)(mp_float_t x) {
+ return MICROPY_FLOAT_C_FUN(log)(x) * MICROPY_FLOAT_CONST(1.442695040888963407354163704);
+}
#endif
// sqrt(x): returns the square root of x
-MATH_FUN_1_ERRCOND(sqrt, sqrt, (x < (mp_float_t)0.0))
+MATH_FUN_1(sqrt, sqrt)
// pow(x, y): returns x to the power of y
MATH_FUN_2(pow, pow)
// exp(x)
@@ -81,9 +104,9 @@ MATH_FUN_1(exp, exp)
// expm1(x)
MATH_FUN_1(expm1, expm1)
// log2(x)
-MATH_FUN_1_ERRCOND(log2, log2, (x <= (mp_float_t)0.0))
+MATH_FUN_1(log2, log2)
// log10(x)
-MATH_FUN_1_ERRCOND(log10, log10, (x <= (mp_float_t)0.0))
+MATH_FUN_1(log10, log10)
// cosh(x)
MATH_FUN_1(cosh, cosh)
// sinh(x)
@@ -114,9 +137,15 @@ MATH_FUN_2(atan2, atan2)
// ceil(x)
MATH_FUN_1_TO_INT(ceil, ceil)
// copysign(x, y)
-MATH_FUN_2(copysign, copysign)
+STATIC mp_float_t MICROPY_FLOAT_C_FUN(copysign_func)(mp_float_t x, mp_float_t y) {
+ return MICROPY_FLOAT_C_FUN(copysign)(x, y);
+}
+MATH_FUN_2(copysign, copysign_func)
// fabs(x)
-MATH_FUN_1(fabs, fabs)
+STATIC mp_float_t MICROPY_FLOAT_C_FUN(fabs_func)(mp_float_t x) {
+ return MICROPY_FLOAT_C_FUN(fabs)(x);
+}
+MATH_FUN_1(fabs, fabs_func)
// floor(x)
MATH_FUN_1_TO_INT(floor, floor) //TODO: delegate to x.__floor__() if x is not a float
// fmod(x, y)
@@ -130,7 +159,7 @@ MATH_FUN_1_TO_BOOL(isnan, isnan)
// trunc(x)
MATH_FUN_1_TO_INT(trunc, trunc)
// ldexp(x, exp)
-MATH_FUN_2(ldexp, ldexp)
+MATH_FUN_2_FLT_INT(ldexp, ldexp)
#if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
// erf(x): return the error function of x
MATH_FUN_1(erf, erf)
diff --git a/py/mpconfig.h b/py/mpconfig.h
index cec9fb748..252ab7f37 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -775,16 +775,24 @@ typedef double mp_float_t;
#define MICROPY_PY_BUILTINS_TIMEOUTERROR (0)
#endif
-// Whether to support complete set of special methods
-// for user classes, or only the most used ones. "Reverse"
-// methods are controlled by MICROPY_PY_REVERSE_SPECIAL_METHODS
-// below.
+// Whether to support complete set of special methods for user
+// classes, or only the most used ones. "Inplace" methods are
+// controlled by MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS below.
+// "Reverse" methods are controlled by
+// MICROPY_PY_REVERSE_SPECIAL_METHODS below.
#ifndef MICROPY_PY_ALL_SPECIAL_METHODS
#define MICROPY_PY_ALL_SPECIAL_METHODS (0)
#endif
-// Whether to support reverse arithmetic operarions methods
-// (__radd__, etc.)
+// Whether to support all inplace arithmetic operarion methods
+// (__imul__, etc.)
+#ifndef MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS
+#define MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS (0)
+#endif
+
+// Whether to support reverse arithmetic operarion methods
+// (__radd__, etc.). Additionally gated by
+// MICROPY_PY_ALL_SPECIAL_METHODS.
#ifndef MICROPY_PY_REVERSE_SPECIAL_METHODS
#define MICROPY_PY_REVERSE_SPECIAL_METHODS (0)
#endif
@@ -1111,6 +1119,8 @@ typedef double mp_float_t;
#ifndef MICROPY_PY_USSL
#define MICROPY_PY_USSL (0)
+// Whether to add finaliser code to ussl objects
+#define MICROPY_PY_USSL_FINALISER (0)
#endif
#ifndef MICROPY_PY_WEBSOCKET
diff --git a/py/mpstate.h b/py/mpstate.h
index 1ffb5213c..23133cb7e 100644
--- a/py/mpstate.h
+++ b/py/mpstate.h
@@ -168,7 +168,7 @@ typedef struct _mp_state_vm_t {
// root pointers for extmod
#ifdef MICROPY_PY_OS_DUPTERM
- mp_obj_t term_obj;
+ mp_obj_t dupterm_objs[MICROPY_PY_OS_DUPTERM];
mp_obj_t dupterm_arr_obj;
#endif
diff --git a/py/nativeglue.c b/py/nativeglue.c
index 61b624ec7..e63c2fcda 100644
--- a/py/nativeglue.c
+++ b/py/nativeglue.c
@@ -29,6 +29,7 @@
#include <assert.h>
#include "py/runtime.h"
+#include "py/smallint.h"
#include "py/emitglue.h"
#include "py/bc.h"
@@ -170,6 +171,8 @@ void *const mp_fun_table[MP_F_NUMBER_OF] = {
mp_obj_new_cell,
mp_make_closure_from_raw_code,
mp_setup_code_state,
+ mp_small_int_floor_divide,
+ mp_small_int_modulo,
};
/*
diff --git a/py/objarray.c b/py/objarray.c
index b8dca32f7..a1a979b56 100644
--- a/py/objarray.c
+++ b/py/objarray.c
@@ -286,7 +286,7 @@ STATIC mp_obj_t array_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs
// Otherwise, can only look for a scalar numeric value in an array
if (MP_OBJ_IS_INT(rhs_in) || mp_obj_is_float(rhs_in)) {
- mp_raise_NotImplementedError("");
+ mp_raise_NotImplementedError(NULL);
}
return mp_const_false;
diff --git a/py/objlist.c b/py/objlist.c
index c6e85f2c8..0cbf68c2f 100644
--- a/py/objlist.c
+++ b/py/objlist.c
@@ -158,7 +158,7 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
mp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);
mp_bound_slice_t slice;
if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) {
- mp_raise_NotImplementedError("");
+ mp_raise_NotImplementedError(NULL);
}
mp_int_t len_adj = slice.start - slice.stop;
@@ -198,7 +198,7 @@ STATIC mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
mp_obj_get_array(value, &value_len, &value_items);
mp_bound_slice_t slice_out;
if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice_out)) {
- mp_raise_NotImplementedError("");
+ mp_raise_NotImplementedError(NULL);
}
mp_int_t len_adj = value_len - (slice_out.stop - slice_out.start);
//printf("Len adj: %d\n", len_adj);
diff --git a/py/objtype.c b/py/objtype.c
index d57cec703..2fefc65ad 100644
--- a/py/objtype.c
+++ b/py/objtype.c
@@ -335,7 +335,9 @@ mp_obj_t mp_obj_instance_make_new(const mp_obj_type_t *self, size_t n_args, size
return MP_OBJ_FROM_PTR(o);
}
-const uint16_t mp_unary_op_method_name[] = {
+// Qstrs for special methods are guaranteed to have a small value, so we use byte
+// type to represent them.
+const byte mp_unary_op_method_name[MP_UNARY_OP_NUM_RUNTIME] = {
[MP_UNARY_OP_BOOL] = MP_QSTR___bool__,
[MP_UNARY_OP_LEN] = MP_QSTR___len__,
[MP_UNARY_OP_HASH] = MP_QSTR___hash__,
@@ -343,11 +345,11 @@ const uint16_t mp_unary_op_method_name[] = {
[MP_UNARY_OP_POSITIVE] = MP_QSTR___pos__,
[MP_UNARY_OP_NEGATIVE] = MP_QSTR___neg__,
[MP_UNARY_OP_INVERT] = MP_QSTR___invert__,
+ [MP_UNARY_OP_ABS] = MP_QSTR___abs__,
#endif
#if MICROPY_PY_SYS_GETSIZEOF
- [MP_UNARY_OP_SIZEOF] = MP_QSTR_getsizeof,
+ [MP_UNARY_OP_SIZEOF] = MP_QSTR___sizeof__,
#endif
- [MP_UNARY_OP_NOT] = MP_QSTR_, // don't need to implement this, used to make sure array has full size
};
STATIC mp_obj_t instance_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
@@ -409,59 +411,69 @@ STATIC mp_obj_t instance_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
}
}
-const uint16_t mp_binary_op_method_name[] = {
- /*
- MP_BINARY_OP_OR,
- MP_BINARY_OP_XOR,
- MP_BINARY_OP_AND,
- MP_BINARY_OP_LSHIFT,
- MP_BINARY_OP_RSHIFT,
- */
+// Binary-op enum values not listed here will have the default value of 0 in the
+// table, corresponding to MP_QSTR_NULL, and are therefore unsupported (a lookup will
+// fail). They can be added at the expense of code size for the qstr.
+// Qstrs for special methods are guaranteed to have a small value, so we use byte
+// type to represent them.
+const byte mp_binary_op_method_name[MP_BINARY_OP_NUM_RUNTIME] = {
+ [MP_BINARY_OP_LESS] = MP_QSTR___lt__,
+ [MP_BINARY_OP_MORE] = MP_QSTR___gt__,
+ [MP_BINARY_OP_EQUAL] = MP_QSTR___eq__,
+ [MP_BINARY_OP_LESS_EQUAL] = MP_QSTR___le__,
+ [MP_BINARY_OP_MORE_EQUAL] = MP_QSTR___ge__,
+ // MP_BINARY_OP_NOT_EQUAL, // a != b calls a == b and inverts result
+ [MP_BINARY_OP_IN] = MP_QSTR___contains__,
+
+ // All inplace methods are optional, and normal methods will be used
+ // as a fallback.
+ [MP_BINARY_OP_INPLACE_ADD] = MP_QSTR___iadd__,
+ [MP_BINARY_OP_INPLACE_SUBTRACT] = MP_QSTR___isub__,
+ #if MICROPY_PY_ALL_INPLACE_SPECIAL_METHODS
+ [MP_BINARY_OP_INPLACE_MULTIPLY] = MP_QSTR___imul__,
+ [MP_BINARY_OP_INPLACE_FLOOR_DIVIDE] = MP_QSTR___ifloordiv__,
+ [MP_BINARY_OP_INPLACE_TRUE_DIVIDE] = MP_QSTR___itruediv__,
+ [MP_BINARY_OP_INPLACE_MODULO] = MP_QSTR___imod__,
+ [MP_BINARY_OP_INPLACE_POWER] = MP_QSTR___ipow__,
+ [MP_BINARY_OP_INPLACE_OR] = MP_QSTR___ior__,
+ [MP_BINARY_OP_INPLACE_XOR] = MP_QSTR___ixor__,
+ [MP_BINARY_OP_INPLACE_AND] = MP_QSTR___iand__,
+ [MP_BINARY_OP_INPLACE_LSHIFT] = MP_QSTR___ilshift__,
+ [MP_BINARY_OP_INPLACE_RSHIFT] = MP_QSTR___irshift__,
+ #endif
+
[MP_BINARY_OP_ADD] = MP_QSTR___add__,
[MP_BINARY_OP_SUBTRACT] = MP_QSTR___sub__,
#if MICROPY_PY_ALL_SPECIAL_METHODS
[MP_BINARY_OP_MULTIPLY] = MP_QSTR___mul__,
[MP_BINARY_OP_FLOOR_DIVIDE] = MP_QSTR___floordiv__,
[MP_BINARY_OP_TRUE_DIVIDE] = MP_QSTR___truediv__,
+ [MP_BINARY_OP_MODULO] = MP_QSTR___mod__,
+ [MP_BINARY_OP_DIVMOD] = MP_QSTR___divmod__,
+ [MP_BINARY_OP_POWER] = MP_QSTR___pow__,
+ [MP_BINARY_OP_OR] = MP_QSTR___or__,
+ [MP_BINARY_OP_XOR] = MP_QSTR___xor__,
+ [MP_BINARY_OP_AND] = MP_QSTR___and__,
+ [MP_BINARY_OP_LSHIFT] = MP_QSTR___lshift__,
+ [MP_BINARY_OP_RSHIFT] = MP_QSTR___rshift__,
#endif
- /*
- MP_BINARY_OP_MODULO,
- MP_BINARY_OP_POWER,
- MP_BINARY_OP_DIVMOD,
- MP_BINARY_OP_INPLACE_OR,
- MP_BINARY_OP_INPLACE_XOR,
- MP_BINARY_OP_INPLACE_AND,
- MP_BINARY_OP_INPLACE_LSHIFT,
- MP_BINARY_OP_INPLACE_RSHIFT,*/
- #if MICROPY_PY_ALL_SPECIAL_METHODS
- [MP_BINARY_OP_INPLACE_ADD] = MP_QSTR___iadd__,
- [MP_BINARY_OP_INPLACE_SUBTRACT] = MP_QSTR___isub__,
- #endif
- /*MP_BINARY_OP_INPLACE_MULTIPLY,
- MP_BINARY_OP_INPLACE_FLOOR_DIVIDE,
- MP_BINARY_OP_INPLACE_TRUE_DIVIDE,
- MP_BINARY_OP_INPLACE_MODULO,
- MP_BINARY_OP_INPLACE_POWER,*/
#if MICROPY_PY_REVERSE_SPECIAL_METHODS
[MP_BINARY_OP_REVERSE_ADD] = MP_QSTR___radd__,
[MP_BINARY_OP_REVERSE_SUBTRACT] = MP_QSTR___rsub__,
+ #if MICROPY_PY_ALL_SPECIAL_METHODS
[MP_BINARY_OP_REVERSE_MULTIPLY] = MP_QSTR___rmul__,
+ [MP_BINARY_OP_REVERSE_FLOOR_DIVIDE] = MP_QSTR___rfloordiv__,
+ [MP_BINARY_OP_REVERSE_TRUE_DIVIDE] = MP_QSTR___rtruediv__,
+ [MP_BINARY_OP_REVERSE_MODULO] = MP_QSTR___rmod__,
+ [MP_BINARY_OP_REVERSE_POWER] = MP_QSTR___rpow__,
+ [MP_BINARY_OP_REVERSE_OR] = MP_QSTR___ror__,
+ [MP_BINARY_OP_REVERSE_XOR] = MP_QSTR___rxor__,
+ [MP_BINARY_OP_REVERSE_AND] = MP_QSTR___rand__,
+ [MP_BINARY_OP_REVERSE_LSHIFT] = MP_QSTR___rlshift__,
+ [MP_BINARY_OP_REVERSE_RSHIFT] = MP_QSTR___rrshift__,
+ #endif
#endif
-
- [MP_BINARY_OP_LESS] = MP_QSTR___lt__,
- [MP_BINARY_OP_MORE] = MP_QSTR___gt__,
- [MP_BINARY_OP_EQUAL] = MP_QSTR___eq__,
- [MP_BINARY_OP_LESS_EQUAL] = MP_QSTR___le__,
- [MP_BINARY_OP_MORE_EQUAL] = MP_QSTR___ge__,
- /*
- MP_BINARY_OP_NOT_EQUAL, // a != b calls a == b and inverts result
- */
- [MP_BINARY_OP_IN] = MP_QSTR___contains__,
- /*
- MP_BINARY_OP_IS,
- */
- [MP_BINARY_OP_LAST] = 0, // used to make sure array has full size, TODO: FIXME
};
STATIC mp_obj_t instance_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
diff --git a/py/persistentcode.c b/py/persistentcode.c
index 42efcbfbb..477ba7501 100644
--- a/py/persistentcode.c
+++ b/py/persistentcode.c
@@ -39,7 +39,7 @@
#include "py/smallint.h"
// The current version of .mpy files
-#define MPY_VERSION (2)
+#define MPY_VERSION (3)
// The feature flags byte encodes the compile-time config options that
// affect the generate bytecode.
diff --git a/py/runtime.c b/py/runtime.c
index 4af17dd09..cbec82f17 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -108,6 +108,13 @@ void mp_init(void) {
MP_STATE_VM(mp_module_builtins_override_dict) = NULL;
#endif
+ #ifdef MICROPY_PY_OS_DUPTERM
+ for (size_t i = 0; i < MICROPY_PY_OS_DUPTERM; ++i) {
+ MP_STATE_VM(dupterm_objs[i]) = MP_OBJ_NULL;
+ }
+ MP_STATE_VM(dupterm_arr_obj) = MP_OBJ_NULL;
+ #endif
+
#ifdef MICROPY_FSUSERMOUNT
// zero out the pointers to the user-mounted devices
memset(MP_STATE_VM(fs_user_mount) + MICROPY_FATFS_NUM_PERSISTENT, 0,
diff --git a/py/runtime.h b/py/runtime.h
index 79f5cbc92..a8b6312ff 100644
--- a/py/runtime.h
+++ b/py/runtime.h
@@ -57,8 +57,8 @@ typedef struct _mp_arg_t {
} mp_arg_t;
// Tables mapping operator enums to qstrs, defined in objtype.c
-extern const uint16_t mp_unary_op_method_name[];
-extern const uint16_t mp_binary_op_method_name[];
+extern const byte mp_unary_op_method_name[];
+extern const byte mp_binary_op_method_name[];
void mp_init(void);
void mp_deinit(void);
diff --git a/py/runtime0.h b/py/runtime0.h
index 8e95b68cf..4709430fb 100644
--- a/py/runtime0.h
+++ b/py/runtime0.h
@@ -53,41 +53,38 @@ typedef enum {
MP_UNARY_OP_NOT,
// Following ops cannot appear in the bytecode
- MP_UNARY_OP_NON_BYTECODE,
+ MP_UNARY_OP_NUM_BYTECODE,
- MP_UNARY_OP_BOOL = MP_UNARY_OP_NON_BYTECODE, // __bool__
+ MP_UNARY_OP_BOOL = MP_UNARY_OP_NUM_BYTECODE, // __bool__
MP_UNARY_OP_LEN, // __len__
MP_UNARY_OP_HASH, // __hash__; must return a small int
MP_UNARY_OP_ABS, // __abs__
MP_UNARY_OP_SIZEOF, // for sys.getsizeof()
+
+ MP_UNARY_OP_NUM_RUNTIME,
} mp_unary_op_t;
-// Note: the first 35 of these are used in bytecode and changing
+// Note: the first 9+12+12 of these are used in bytecode and changing
// them requires changing the bytecode version.
typedef enum {
- // Relational operations, should return a bool
+ // 9 relational operations, should return a bool
MP_BINARY_OP_LESS,
MP_BINARY_OP_MORE,
MP_BINARY_OP_EQUAL,
MP_BINARY_OP_LESS_EQUAL,
MP_BINARY_OP_MORE_EQUAL,
MP_BINARY_OP_NOT_EQUAL,
-
MP_BINARY_OP_IN,
MP_BINARY_OP_IS,
MP_BINARY_OP_EXCEPTION_MATCH,
- // these are not supported by the runtime and must be synthesised by the emitter
- MP_BINARY_OP_NOT_IN,
- MP_BINARY_OP_IS_NOT,
- // Arithmetic operations
+ // 12 inplace arithmetic operations
MP_BINARY_OP_INPLACE_OR,
MP_BINARY_OP_INPLACE_XOR,
MP_BINARY_OP_INPLACE_AND,
MP_BINARY_OP_INPLACE_LSHIFT,
MP_BINARY_OP_INPLACE_RSHIFT,
MP_BINARY_OP_INPLACE_ADD,
-
MP_BINARY_OP_INPLACE_SUBTRACT,
MP_BINARY_OP_INPLACE_MULTIPLY,
MP_BINARY_OP_INPLACE_FLOOR_DIVIDE,
@@ -95,13 +92,13 @@ typedef enum {
MP_BINARY_OP_INPLACE_MODULO,
MP_BINARY_OP_INPLACE_POWER,
+ // 12 normal arithmetic operations
MP_BINARY_OP_OR,
MP_BINARY_OP_XOR,
MP_BINARY_OP_AND,
MP_BINARY_OP_LSHIFT,
MP_BINARY_OP_RSHIFT,
MP_BINARY_OP_ADD,
-
MP_BINARY_OP_SUBTRACT,
MP_BINARY_OP_MULTIPLY,
MP_BINARY_OP_FLOOR_DIVIDE,
@@ -111,16 +108,16 @@ typedef enum {
// Operations below this line don't appear in bytecode, they
// just identify special methods.
+ MP_BINARY_OP_NUM_BYTECODE,
// MP_BINARY_OP_REVERSE_* must follow immediately after MP_BINARY_OP_*
#if MICROPY_PY_REVERSE_SPECIAL_METHODS
- MP_BINARY_OP_REVERSE_OR,
+ MP_BINARY_OP_REVERSE_OR = MP_BINARY_OP_NUM_BYTECODE,
MP_BINARY_OP_REVERSE_XOR,
MP_BINARY_OP_REVERSE_AND,
MP_BINARY_OP_REVERSE_LSHIFT,
MP_BINARY_OP_REVERSE_RSHIFT,
MP_BINARY_OP_REVERSE_ADD,
-
MP_BINARY_OP_REVERSE_SUBTRACT,
MP_BINARY_OP_REVERSE_MULTIPLY,
MP_BINARY_OP_REVERSE_FLOOR_DIVIDE,
@@ -129,9 +126,18 @@ typedef enum {
MP_BINARY_OP_REVERSE_POWER,
#endif
- MP_BINARY_OP_DIVMOD, // not emitted by the compiler but supported by the runtime
+ // This is not emitted by the compiler but is supported by the runtime
+ MP_BINARY_OP_DIVMOD
+ #if !MICROPY_PY_REVERSE_SPECIAL_METHODS
+ = MP_BINARY_OP_NUM_BYTECODE
+ #endif
+ ,
+
+ MP_BINARY_OP_NUM_RUNTIME,
- MP_BINARY_OP_LAST,
+ // These 2 are not supported by the runtime and must be synthesised by the emitter
+ MP_BINARY_OP_NOT_IN,
+ MP_BINARY_OP_IS_NOT,
} mp_binary_op_t;
typedef enum {
@@ -181,6 +187,8 @@ typedef enum {
MP_F_NEW_CELL,
MP_F_MAKE_CLOSURE_FROM_RAW_CODE,
MP_F_SETUP_CODE_STATE,
+ MP_F_SMALL_INT_FLOOR_DIVIDE,
+ MP_F_SMALL_INT_MODULO,
MP_F_NUMBER_OF,
} mp_fun_kind_t;
diff --git a/py/showbc.c b/py/showbc.c
index 728d8d983..3deb18cd3 100644
--- a/py/showbc.c
+++ b/py/showbc.c
@@ -539,9 +539,9 @@ const byte *mp_bytecode_print_str(const byte *ip) {
printf("LOAD_FAST " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_LOAD_FAST_MULTI);
} else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) {
printf("STORE_FAST " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_STORE_FAST_MULTI);
- } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NON_BYTECODE) {
+ } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE) {
printf("UNARY_OP " UINT_FMT, (mp_uint_t)ip[-1] - MP_BC_UNARY_OP_MULTI);
- } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + 36) {
+ } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE) {
mp_uint_t op = ip[-1] - MP_BC_BINARY_OP_MULTI;
printf("BINARY_OP " UINT_FMT " %s", op, qstr_str(mp_binary_op_method_name[op]));
} else {
diff --git a/py/vmentrytable.h b/py/vmentrytable.h
index e634e2b41..615f4e2ce 100644
--- a/py/vmentrytable.h
+++ b/py/vmentrytable.h
@@ -109,8 +109,8 @@ static const void *const entry_table[256] = {
[MP_BC_LOAD_CONST_SMALL_INT_MULTI ... MP_BC_LOAD_CONST_SMALL_INT_MULTI + 63] = &&entry_MP_BC_LOAD_CONST_SMALL_INT_MULTI,
[MP_BC_LOAD_FAST_MULTI ... MP_BC_LOAD_FAST_MULTI + 15] = &&entry_MP_BC_LOAD_FAST_MULTI,
[MP_BC_STORE_FAST_MULTI ... MP_BC_STORE_FAST_MULTI + 15] = &&entry_MP_BC_STORE_FAST_MULTI,
- [MP_BC_UNARY_OP_MULTI ... MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NON_BYTECODE - 1] = &&entry_MP_BC_UNARY_OP_MULTI,
- [MP_BC_BINARY_OP_MULTI ... MP_BC_BINARY_OP_MULTI + 35] = &&entry_MP_BC_BINARY_OP_MULTI,
+ [MP_BC_UNARY_OP_MULTI ... MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE - 1] = &&entry_MP_BC_UNARY_OP_MULTI,
+ [MP_BC_BINARY_OP_MULTI ... MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE - 1] = &&entry_MP_BC_BINARY_OP_MULTI,
};
#if __clang__