Compare commits

..

No commits in common. "adf5fa5ac2dde406c065acec8ac3aa6a0dd7f64a" and "d14e861b2e008c2a79abba163085b332c8b3dc94" have entirely different histories.

13 changed files with 17 additions and 144 deletions

View File

@ -8,7 +8,6 @@ extern const char kPythonLibs_bisect[];
extern const char kPythonLibs_builtins[]; extern const char kPythonLibs_builtins[];
extern const char kPythonLibs_cmath[]; extern const char kPythonLibs_cmath[];
extern const char kPythonLibs_collections[]; extern const char kPythonLibs_collections[];
extern const char kPythonLibs_dataclasses[];
extern const char kPythonLibs_datetime[]; extern const char kPythonLibs_datetime[];
extern const char kPythonLibs_functools[]; extern const char kPythonLibs_functools[];
extern const char kPythonLibs_heapq[]; extern const char kPythonLibs_heapq[];

View File

@ -23,7 +23,7 @@ typedef struct py_TypeInfo {
void (*dtor)(void*); void (*dtor)(void*);
py_TValue annotations; // type annotations c11_vector /*T=py_Name*/ annotated_fields;
void (*on_end_subclass)(struct py_TypeInfo*); // backdoor for enum module void (*on_end_subclass)(struct py_TypeInfo*); // backdoor for enum module
void (*gc_mark)(void* ud); void (*gc_mark)(void* ud);

View File

@ -443,9 +443,8 @@ PK_EXPORT char* py_formatexc();
/// Check if an exception is raised. /// Check if an exception is raised.
PK_EXPORT bool py_checkexc(bool ignore_handled); PK_EXPORT bool py_checkexc(bool ignore_handled);
/// Check if the exception is an instance of the given type. /// Check if the exception is an instance of the given type.
/// This function is roughly equivalent to python's `except <T> as e:` block. /// If match, the exception will be set as handled.
/// If match, the exception will be stored in `py_retval()` as handled. PK_EXPORT bool py_matchexc(py_Type type);
PK_EXPORT bool py_matchexc(py_Type type) PY_RETURN;
/// Clear the current exception. /// Clear the current exception.
/// @param p0 the unwinding point. Use `NULL` if not needed. /// @param p0 the unwinding point. Use `NULL` if not needed.
PK_EXPORT void py_clearexc(py_StackRef p0); PK_EXPORT void py_clearexc(py_StackRef p0);

View File

@ -1,75 +0,0 @@
def _get_annotations(cls: type):
inherits = []
while cls is not object:
inherits.append(cls)
cls = cls.__base__
inherits.reverse()
res = {}
for cls in inherits:
res.update(cls.__annotations__)
return res.keys()
def _wrapped__init__(self, *args, **kwargs):
cls = type(self)
cls_d = cls.__dict__
fields = _get_annotations(cls)
i = 0 # index into args
for field in fields:
if field in kwargs:
setattr(self, field, kwargs.pop(field))
else:
if i < len(args):
setattr(self, field, args[i])
i += 1
elif field in cls_d: # has default value
setattr(self, field, cls_d[field])
else:
raise TypeError(f"{cls.__name__} missing required argument {field!r}")
if len(args) > i:
raise TypeError(f"{cls.__name__} takes {len(fields)} positional arguments but {len(args)} were given")
if len(kwargs) > 0:
raise TypeError(f"{cls.__name__} got an unexpected keyword argument {next(iter(kwargs))!r}")
def _wrapped__repr__(self):
fields = _get_annotations(type(self))
obj_d = self.__dict__
args: list = [f"{field}={obj_d[field]!r}" for field in fields]
return f"{type(self).__name__}({', '.join(args)})"
def _wrapped__eq__(self, other):
if type(self) is not type(other):
return False
fields = _get_annotations(type(self))
for field in fields:
if getattr(self, field) != getattr(other, field):
return False
return True
def _wrapped__ne__(self, other):
return not self.__eq__(other)
def dataclass(cls: type):
assert type(cls) is type
cls_d = cls.__dict__
if '__init__' not in cls_d:
cls.__init__ = _wrapped__init__
if '__repr__' not in cls_d:
cls.__repr__ = _wrapped__repr__
if '__eq__' not in cls_d:
cls.__eq__ = _wrapped__eq__
if '__ne__' not in cls_d:
cls.__ne__ = _wrapped__ne__
fields = _get_annotations(cls)
has_default = False
for field in fields:
if field in cls_d:
has_default = True
else:
if has_default:
raise TypeError(f"non-default argument {field!r} follows default argument")
return cls
def asdict(obj) -> dict:
fields = _get_annotations(type(obj))
obj_d = obj.__dict__
return {field: obj_d[field] for field in fields}

File diff suppressed because one or more lines are too long

View File

@ -1930,16 +1930,6 @@ static Error* consume_type_hints(Compiler* self) {
return NULL; return NULL;
} }
static Error* consume_type_hints_sv(Compiler* self, c11_sv* out) {
Error* err;
const char* start = curr()->start;
check(EXPR(self));
const char* end = prev()->start + prev()->length;
*out = (c11_sv){start, end - start};
Ctx__s_pop(ctx());
return NULL;
}
static Error* compile_stmt(Compiler* self); static Error* compile_stmt(Compiler* self);
static Error* compile_block_body(Compiler* self, PrattCallback callback) { static Error* compile_block_body(Compiler* self, PrattCallback callback) {
@ -2611,14 +2601,11 @@ static Error* compile_stmt(Compiler* self) {
// eat variable's type hint if it is a single name // eat variable's type hint if it is a single name
if(Ctx__s_top(ctx())->vt->is_name) { if(Ctx__s_top(ctx())->vt->is_name) {
if(match(TK_COLON)) { if(match(TK_COLON)) {
c11_sv type_hint; check(consume_type_hints(self));
check(consume_type_hints_sv(self, &type_hint));
is_typed_name = true; is_typed_name = true;
if(ctx()->is_compiling_class) { if(ctx()->is_compiling_class) {
NameExpr* ne = (NameExpr*)Ctx__s_top(ctx()); NameExpr* ne = (NameExpr*)Ctx__s_top(ctx());
int index = Ctx__add_const_string(ctx(), type_hint);
Ctx__emit_(ctx(), OP_LOAD_CONST, index, BC_KEEPLINE);
Ctx__emit_(ctx(), OP_ADD_CLASS_ANNOTATION, ne->name, BC_KEEPLINE); Ctx__emit_(ctx(), OP_ADD_CLASS_ANNOTATION, ne->name, BC_KEEPLINE);
} }
} }

View File

@ -477,7 +477,7 @@ static Error* lex_one_token(Lexer* self, bool* eof, bool is_fstring) {
} }
case ',': add_token(self, TK_COMMA); return NULL; case ',': add_token(self, TK_COMMA); return NULL;
case ':': { case ':': {
if(is_fstring) { return eat_fstring_spec(self, eof); } if(is_fstring && self->brackets_level == 0) { return eat_fstring_spec(self, eof); }
add_token(self, TK_COLON); add_token(self, TK_COLON);
return NULL; return NULL;
} }
@ -548,7 +548,7 @@ static Error* lex_one_token(Lexer* self, bool* eof, bool is_fstring) {
return NULL; return NULL;
} }
case '!': case '!':
if(is_fstring) { if(is_fstring && self->brackets_level == 0) {
if(matchchar(self, 'r')) { return eat_fstring_spec(self, eof); } if(matchchar(self, 'r')) { return eat_fstring_spec(self, eof); }
} }
if(matchchar(self, '=')) { if(matchchar(self, '=')) {

View File

@ -913,13 +913,9 @@ FrameResult VM__run_top_frame(VM* self) {
DISPATCH(); DISPATCH();
} }
case OP_ADD_CLASS_ANNOTATION: { case OP_ADD_CLASS_ANNOTATION: {
// [type_hint string]
py_Type type = py_totype(self->__curr_class); py_Type type = py_totype(self->__curr_class);
py_TypeInfo* ti = c11__at(py_TypeInfo, &self->types, type); py_TypeInfo* ti = c11__at(py_TypeInfo, &self->types, type);
if(py_isnil(&ti->annotations)) py_newdict(&ti->annotations); c11_vector__push(py_Name, &ti->annotated_fields, byte.arg);
bool ok = py_dict_setitem_by_str(&ti->annotations, py_name2str(byte.arg), TOP());
if(!ok) goto __ERROR;
POP();
DISPATCH(); DISPATCH();
} }
/////////// ///////////

View File

@ -49,9 +49,11 @@ static void py_TypeInfo__ctor(py_TypeInfo* self,
}; };
self->module = module; self->module = module;
self->annotations = *py_NIL; c11_vector__ctor(&self->annotated_fields, sizeof(py_Name));
} }
static void py_TypeInfo__dtor(py_TypeInfo* self) { c11_vector__dtor(&self->annotated_fields); }
void VM__ctor(VM* self) { void VM__ctor(VM* self) {
self->top_frame = NULL; self->top_frame = NULL;
@ -228,6 +230,7 @@ void VM__dtor(VM* self) {
while(self->top_frame) while(self->top_frame)
VM__pop_frame(self); VM__pop_frame(self);
ModuleDict__dtor(&self->modules); ModuleDict__dtor(&self->modules);
c11__foreach(py_TypeInfo, &self->types, ti) py_TypeInfo__dtor(ti);
c11_vector__dtor(&self->types); c11_vector__dtor(&self->types);
ValueStack__clear(&self->stack); ValueStack__clear(&self->stack);
} }
@ -599,19 +602,16 @@ void ManagedHeap__mark(ManagedHeap* self) {
for(py_TValue* p = vm->stack.begin; p != vm->stack.end; p++) { for(py_TValue* p = vm->stack.begin; p != vm->stack.end; p++) {
pk__mark_value(p); pk__mark_value(p);
} }
// mark types // mark magic slots
py_TypeInfo* types = vm->types.data; py_TypeInfo* types = vm->types.data;
int types_length = vm->types.length; int types_length = vm->types.length;
// 0-th type is placeholder // 0-th type is placeholder
for(int i = 1; i < types_length; i++) { for(int i = 1; i < types_length; i++) {
// mark magic slots
for(int j = 0; j <= __missing__; j++) { for(int j = 0; j <= __missing__; j++) {
py_TValue* slot = types[i].magic + j; py_TValue* slot = types[i].magic + j;
if(py_isnil(slot)) continue; if(py_isnil(slot)) continue;
pk__mark_value(slot); pk__mark_value(slot);
} }
// mark type annotations
pk__mark_value(&types[i].annotations);
} }
// mark frame // mark frame
for(Frame* frame = vm->top_frame; frame; frame = frame->f_back) { for(Frame* frame = vm->top_frame; frame; frame = frame->f_back) {

View File

@ -142,7 +142,6 @@ bool py_matchexc(py_Type type) {
if(ok) { if(ok) {
// if match, then the exception is handled // if match, then the exception is handled
vm->is_curr_exc_handled = true; vm->is_curr_exc_handled = true;
vm->last_retval = vm->curr_exception;
} }
return ok; return ok;
} }

View File

@ -108,18 +108,6 @@ static bool type__module__(int argc, py_Ref argv) {
return true; return true;
} }
static bool type__annotations__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1);
py_Type type = py_totype(argv);
py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, type);
if(py_isnil(&ti->annotations)) {
py_newdict(py_retval());
} else {
py_assign(py_retval(), &ti->annotations);
}
return true;
}
void pk_object__register() { void pk_object__register() {
// TODO: use staticmethod // TODO: use staticmethod
py_bindmagic(tp_object, __new__, pk__object_new); py_bindmagic(tp_object, __new__, pk__object_new);
@ -128,6 +116,7 @@ void pk_object__register() {
py_bindmagic(tp_object, __eq__, object__eq__); py_bindmagic(tp_object, __eq__, object__eq__);
py_bindmagic(tp_object, __ne__, object__ne__); py_bindmagic(tp_object, __ne__, object__ne__);
py_bindmagic(tp_object, __repr__, object__repr__); py_bindmagic(tp_object, __repr__, object__repr__);
py_bindproperty(tp_object, "__dict__", object__dict__, NULL);
py_bindmagic(tp_type, __repr__, type__repr__); py_bindmagic(tp_type, __repr__, type__repr__);
py_bindmagic(tp_type, __new__, type__new__); py_bindmagic(tp_type, __new__, type__new__);
@ -136,6 +125,4 @@ void pk_object__register() {
py_bindproperty(tp_type, "__base__", type__base__, NULL); py_bindproperty(tp_type, "__base__", type__base__, NULL);
py_bindproperty(tp_type, "__name__", type__name__, NULL); py_bindproperty(tp_type, "__name__", type__name__, NULL);
py_bindproperty(tp_object, "__dict__", object__dict__, NULL);
py_bindproperty(tp_type, "__annotations__", type__annotations__, NULL);
} }

View File

@ -206,4 +206,4 @@ assert "{{{}xxx{}x}}".format(1, 2) == "{1xxx2x}"
assert "{{abc}}".format() == "{abc}" assert "{{abc}}".format() == "{abc}"
# test f-string # test f-string
# stack=[1,2,3,4]; assert f"{stack[2:]}" == '[3, 4]' stack=[1,2,3,4]; assert f"{stack[2:]}" == '[3, 4]'

View File

@ -1,3 +1,5 @@
exit()
from dataclasses import dataclass, asdict from dataclasses import dataclass, asdict
@dataclass @dataclass
@ -15,22 +17,3 @@ assert asdict(A(1, '555')) == {'x': 1, 'y': '555'}
assert A(1, 'N') == A(1, 'N') assert A(1, 'N') == A(1, 'N')
assert A(1, 'N') != A(1, 'M') assert A(1, 'N') != A(1, 'M')
#################
@dataclass
class Base:
i: int
j: int
class Derived(Base):
k: str = 'default'
def sum(self):
return self.i + self.j
d = Derived(1, 2)
assert d.i == 1
assert d.j == 2
assert d.k == 'default'
assert d.sum() == 3